forked from n3tael/labast
[UNVERIFIED] update to spec 1.10, parser rewrite.
This commit is contained in:
parent
cff855b9cb
commit
f2b551a586
@ -1,5 +1,5 @@
|
|||||||
# Labast
|
# Labast
|
||||||
A zero-dependencies Labaski interpreter written in Rust. Fully supports Labashki specs 1.7.1.
|
A zero-dependencies Labaski interpreter written in Rust. Fully supports Labashki specs 1.10.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
See `scripts` directory.
|
See `scripts` directory.
|
26
scripts/calc.lb
Normal file
26
scripts/calc.lb
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
; written by Labashki developer - aeris
|
||||||
|
@ 0
|
||||||
|
scan
|
||||||
|
scan
|
||||||
|
scan
|
||||||
|
|jmp 0
|
||||||
|
|
||||||
|
@ 1
|
||||||
|
add
|
||||||
|
meow
|
||||||
|
quit
|
||||||
|
|
||||||
|
@ 2
|
||||||
|
sub
|
||||||
|
meow dkdkd
|
||||||
|
quit
|
||||||
|
|
||||||
|
@ 3
|
||||||
|
mul
|
||||||
|
meow
|
||||||
|
quit
|
||||||
|
|
||||||
|
@ 4
|
||||||
|
div
|
||||||
|
meow
|
||||||
|
quit
|
30
scripts/hello-world-old.lb
Normal file
30
scripts/hello-world-old.lb
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
push 72 ; H
|
||||||
|
putc ; Print to console
|
||||||
|
push 101 ; e
|
||||||
|
putc
|
||||||
|
push 108 ; l
|
||||||
|
putc
|
||||||
|
push 108 ; l
|
||||||
|
putc
|
||||||
|
push 111 ; o
|
||||||
|
putc
|
||||||
|
push 32 ; <space>
|
||||||
|
putc
|
||||||
|
push 76 ; L
|
||||||
|
putc
|
||||||
|
push 97 ; a
|
||||||
|
putc
|
||||||
|
push 98 ; b
|
||||||
|
putc
|
||||||
|
push 97 ; a
|
||||||
|
putc
|
||||||
|
push 115 ; s
|
||||||
|
putc
|
||||||
|
push 104 ; h
|
||||||
|
putc
|
||||||
|
push 107 ; k
|
||||||
|
putc
|
||||||
|
push 105 ; i
|
||||||
|
putc
|
||||||
|
push 33 ; !
|
||||||
|
putc
|
@ -1,30 +1 @@
|
|||||||
push 72 ; H
|
$print Hello Labashki!
|
||||||
putc ; Print to console
|
|
||||||
push 101 ; e
|
|
||||||
putc
|
|
||||||
push 108 ; l
|
|
||||||
putc
|
|
||||||
push 108 ; l
|
|
||||||
putc
|
|
||||||
push 111 ; o
|
|
||||||
putc
|
|
||||||
push 32 ; <space>
|
|
||||||
putc
|
|
||||||
push 76 ; L
|
|
||||||
putc
|
|
||||||
push 97 ; a
|
|
||||||
putc
|
|
||||||
push 98 ; b
|
|
||||||
putc
|
|
||||||
push 97 ; a
|
|
||||||
putc
|
|
||||||
push 115 ; s
|
|
||||||
putc
|
|
||||||
push 104 ; h
|
|
||||||
putc
|
|
||||||
push 107 ; k
|
|
||||||
putc
|
|
||||||
push 105 ; i
|
|
||||||
putc
|
|
||||||
push 33 ; !
|
|
||||||
putc
|
|
@ -12,6 +12,9 @@ pub enum RunError {
|
|||||||
UnknownLabel(u16),
|
UnknownLabel(u16),
|
||||||
InvalidExpressionUnknownOperator(String),
|
InvalidExpressionUnknownOperator(String),
|
||||||
MemoryEmpty,
|
MemoryEmpty,
|
||||||
|
AttemptToInsertHashOrStringInst,
|
||||||
|
AttemptToInsertEmptyConst,
|
||||||
|
AttemptToInsertALabel
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for RunError {
|
impl Display for RunError {
|
||||||
@ -28,18 +31,21 @@ impl Display for RunError {
|
|||||||
RunError::UnknownLabel(label_name) => write!(f, "Unknown label: {}", label_name),
|
RunError::UnknownLabel(label_name) => write!(f, "Unknown label: {}", label_name),
|
||||||
RunError::InvalidExpressionUnknownOperator(name) => write!(f, "Invalid expression: unknown operator '{}'", name),
|
RunError::InvalidExpressionUnknownOperator(name) => write!(f, "Invalid expression: unknown operator '{}'", name),
|
||||||
RunError::MemoryEmpty => write!(f, "No elements in memory!"),
|
RunError::MemoryEmpty => write!(f, "No elements in memory!"),
|
||||||
|
RunError::AttemptToInsertHashOrStringInst => write!(f, "Attempt to insert a hash/string-instruction"),
|
||||||
|
RunError::AttemptToInsertEmptyConst => write!(f, "Attempt to insert an empty constant"),
|
||||||
|
RunError::AttemptToInsertALabel => write!(f, "Attempt to insert a label"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ParseError {
|
pub enum ParseError {
|
||||||
DataNotAUInt(String, usize)
|
ArgumentNotRequired(String, usize, String)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for ParseError {
|
impl Display for ParseError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
ParseError::DataNotAUInt(name, line) => write!(f, "Argument for {0} at {1} isn't a number", name, line),
|
ParseError::ArgumentNotRequired(name, line_number, line) => write!(f, "ParseError:\n{1} | {2}\nerror: string argument for {0} not required", name, line_number, line),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -68,43 +68,46 @@ pub fn execute(stack: &mut Stack, mut origin_stack: Option<&mut Stack>, mod_name
|
|||||||
match instruction.name.as_str() {
|
match instruction.name.as_str() {
|
||||||
// Stack operations
|
// Stack operations
|
||||||
"push" => instructions::push::push(&mut stack.memory, &instruction.data),
|
"push" => instructions::push::push(&mut stack.memory, &instruction.data),
|
||||||
"pick" => instructions::pick::pick(&mut stack.memory, &instruction.data),
|
|
||||||
"pop" => instructions::pop::pop(&mut stack.memory),
|
"pop" => instructions::pop::pop(&mut stack.memory),
|
||||||
"dup" => instructions::dup::dup(&mut stack.memory),
|
"dup" => instructions::dup::dup(&mut stack.memory),
|
||||||
"swap" => instructions::swap::swap(&mut stack.memory),
|
"swap" => instructions::swap::swap(&mut stack.memory),
|
||||||
"meow" => instructions::meow::meow(&mut stack.memory),
|
"pick" => instructions::pick::pick(&mut stack.memory, &instruction.data),
|
||||||
"dump" => instructions::dump::dump(&mut stack.memory),
|
|
||||||
"size" => instructions::size::size(&mut stack.memory),
|
|
||||||
"maxsize" => instructions::maxsize::maxsize(&mut stack.memory),
|
|
||||||
|
|
||||||
"#expr" => instructions::expr::expr(&mut stack.memory, &instruction.arg),
|
// Math
|
||||||
|
|
||||||
// Labels
|
|
||||||
"jmp" => instructions::jmp::jmp(&mut stack.labels, &mut stack.program_counter, &instruction.data),
|
|
||||||
"jnz" => instructions::jnz::jnz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, &instruction.data),
|
|
||||||
"jz" => instructions::jz::jz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, &instruction.data),
|
|
||||||
|
|
||||||
// Math operations
|
|
||||||
"add" => instructions::add::add(&mut stack.memory),
|
"add" => instructions::add::add(&mut stack.memory),
|
||||||
"sub" => instructions::sub::sub(&mut stack.memory),
|
"sub" => instructions::sub::sub(&mut stack.memory),
|
||||||
"mul" => instructions::mul::mul(&mut stack.memory),
|
"mul" => instructions::mul::mul(&mut stack.memory),
|
||||||
"div" => instructions::div::div(&mut stack.memory),
|
"div" => instructions::div::div(&mut stack.memory),
|
||||||
"mod" => instructions::modulo::modulo(&mut stack.memory),
|
"mod" => instructions::modulo::modulo(&mut stack.memory),
|
||||||
|
|
||||||
|
// Logic
|
||||||
"and" => instructions::and::and(&mut stack.memory),
|
"and" => instructions::and::and(&mut stack.memory),
|
||||||
"or" => instructions::or::or(&mut stack.memory),
|
"or" => instructions::or::or(&mut stack.memory),
|
||||||
"xor" => instructions::xor::xor(&mut stack.memory),
|
"xor" => instructions::xor::xor(&mut stack.memory),
|
||||||
"nand" => instructions::nand::nand(&mut stack.memory),
|
"nand" => instructions::nand::nand(&mut stack.memory),
|
||||||
|
"not" => instructions::not::not(&mut stack.memory),
|
||||||
|
|
||||||
|
// Bitwise
|
||||||
"band" => instructions::band::band(&mut stack.memory),
|
"band" => instructions::band::band(&mut stack.memory),
|
||||||
"bor" => instructions::bor::bor(&mut stack.memory),
|
"bor" => instructions::bor::bor(&mut stack.memory),
|
||||||
"bxor" => instructions::bxor::bxor(&mut stack.memory),
|
"bxor" => instructions::bxor::bxor(&mut stack.memory),
|
||||||
"bnand" => instructions::bnand::bnand(&mut stack.memory),
|
"bnand" => instructions::bnand::bnand(&mut stack.memory),
|
||||||
"not" => instructions::not::not(&mut stack.memory),
|
"bnot" => instructions::not::not(&mut stack.memory),
|
||||||
|
|
||||||
// Console operations
|
// Labels
|
||||||
"putc" => instructions::putc::putc(&mut stack.memory),
|
"jmp" => instructions::jmp::jmp(&mut stack.labels, &mut stack.program_counter, &instruction.data),
|
||||||
"getc" => instructions::getc::getc(&mut stack.memory),
|
"jnz" => instructions::jnz::jnz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, &instruction.data),
|
||||||
"scan" => instructions::scan::scan(&mut stack.memory),
|
"jz" => instructions::jz::jz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, &instruction.data),
|
||||||
|
"kjnz" => instructions::kjnz::kjnz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, &instruction.data),
|
||||||
|
"kjz" => instructions::kjz::kjz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, &instruction.data),
|
||||||
|
|
||||||
|
// Input/Output
|
||||||
|
"putc" => instructions::putc::putc(&mut stack.memory),
|
||||||
|
"getc" => instructions::getc::getc(&mut stack.memory),
|
||||||
|
"scan" => instructions::scan::scan(&mut stack.memory),
|
||||||
|
"meow" => instructions::meow::meow(&mut stack.memory),
|
||||||
|
"#print" => instructions::print::print(&instruction.arg),
|
||||||
|
"$print" => instructions::print::print(&instruction.arg),
|
||||||
|
|
||||||
// Modules
|
// Modules
|
||||||
"args" => instructions::args::args(&mut stack.memory, &mut origin_stack, &instruction.data),
|
"args" => instructions::args::args(&mut stack.memory, &mut origin_stack, &instruction.data),
|
||||||
@ -113,14 +116,28 @@ pub fn execute(stack: &mut Stack, mut origin_stack: Option<&mut Stack>, mod_name
|
|||||||
instructions::exec::exec(stack, &arg, &mod_name);
|
instructions::exec::exec(stack, &arg, &mod_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Self-modifying
|
||||||
|
|
||||||
|
"#insert" => {
|
||||||
|
let arg = instruction.arg.clone();
|
||||||
|
let data = instruction.data.clone();
|
||||||
|
|
||||||
|
instructions::insert::insert(&mut stack.program, &arg, &data)
|
||||||
|
},
|
||||||
|
|
||||||
|
// Special
|
||||||
|
"dump" => instructions::dump::dump(&mut stack.memory),
|
||||||
|
"size" => instructions::size::size(&mut stack.memory),
|
||||||
|
"maxsize" => instructions::maxsize::maxsize(&mut stack.memory),
|
||||||
|
"#expr" => instructions::expr::expr(&mut stack.memory, &instruction.arg),
|
||||||
|
"nop" => continue,
|
||||||
|
"quit" => std::process::exit(0),
|
||||||
|
"exit" => instructions::exit::exit(&instruction.data),
|
||||||
|
|
||||||
|
// Platform-specific
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
"_unix_random" => instructions::_unix_random::_unix_random(&mut stack.memory),
|
"_unix_random" => instructions::_unix_random::_unix_random(&mut stack.memory),
|
||||||
|
|
||||||
// ?
|
|
||||||
"nop" => continue,
|
|
||||||
"exit" => instructions::exit::exit(&instruction.data),
|
|
||||||
"quit" => std::process::exit(0),
|
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
eprintln!("Unknown instruction: {}", instruction.name);
|
eprintln!("Unknown instruction: {}", instruction.name);
|
||||||
std::process::exit(2);
|
std::process::exit(2);
|
||||||
|
26
src/instructions/insert.rs
Normal file
26
src/instructions/insert.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use crate::{errors::RunError, stack::Instruction};
|
||||||
|
|
||||||
|
pub fn insert(program: &mut Vec<Instruction>, arg: &String, data: &u16) {
|
||||||
|
let args: Vec<char> = arg.chars().collect();
|
||||||
|
|
||||||
|
if args[0] == '#' || args[0] == '$' {
|
||||||
|
eprintln!("{}", RunError::AttemptToInsertHashOrStringInst);
|
||||||
|
std::process::exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if args[0] == '\n' {
|
||||||
|
eprintln!("{}", RunError::AttemptToInsertEmptyConst);
|
||||||
|
std::process::exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if args[0] == '@' || args[1] == ' ' {
|
||||||
|
eprintln!("{}", RunError::AttemptToInsertALabel);
|
||||||
|
std::process::exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
program.push(Instruction {
|
||||||
|
name: arg.to_string(),
|
||||||
|
arg: "\n".to_string(),
|
||||||
|
data: *data
|
||||||
|
});
|
||||||
|
}
|
@ -6,7 +6,7 @@ pub fn jnz(memory: &mut Vec<u16>, labels: &mut [Option<i16>; 256], program_count
|
|||||||
std::process::exit(2);
|
std::process::exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if memory.last() != Some(&0) {
|
if memory.pop() != Some(0) {
|
||||||
*program_counter = (labels[*data as usize].unwrap() - 1) as u16;
|
*program_counter = (labels[*data as usize].unwrap() - 1) as u16;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,7 +6,7 @@ pub fn jz(memory: &mut Vec<u16>, labels: &mut [Option<i16>; 256], program_counte
|
|||||||
std::process::exit(2);
|
std::process::exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if memory.last() == Some(&0) {
|
if memory.pop() == Some(0) {
|
||||||
*program_counter = (labels[*data as usize].unwrap() - 1) as u16;
|
*program_counter = (labels[*data as usize].unwrap() - 1) as u16;
|
||||||
}
|
}
|
||||||
}
|
}
|
12
src/instructions/kjnz.rs
Normal file
12
src/instructions/kjnz.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use crate::errors::RunError;
|
||||||
|
|
||||||
|
pub fn kjnz(memory: &mut Vec<u16>, labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: &u16) {
|
||||||
|
if labels[*data as usize].is_none() {
|
||||||
|
eprintln!("{}", RunError::UnknownLabel(*data));
|
||||||
|
std::process::exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if memory.last() != Some(&0) {
|
||||||
|
*program_counter = (labels[*data as usize].unwrap() - 1) as u16;
|
||||||
|
}
|
||||||
|
}
|
12
src/instructions/kjz.rs
Normal file
12
src/instructions/kjz.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use crate::errors::RunError;
|
||||||
|
|
||||||
|
pub fn kjz(memory: &mut Vec<u16>, labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: &u16) {
|
||||||
|
if labels[*data as usize].is_none() {
|
||||||
|
eprintln!("{}", RunError::UnknownLabel(*data));
|
||||||
|
std::process::exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if memory.last() == Some(&0) {
|
||||||
|
*program_counter = (labels[*data as usize].unwrap() - 1) as u16;
|
||||||
|
}
|
||||||
|
}
|
@ -33,3 +33,7 @@ pub mod bor;
|
|||||||
pub mod bxor;
|
pub mod bxor;
|
||||||
pub mod bnand;
|
pub mod bnand;
|
||||||
pub mod not;
|
pub mod not;
|
||||||
|
pub mod kjnz;
|
||||||
|
pub mod kjz;
|
||||||
|
pub mod print;
|
||||||
|
pub mod insert;
|
3
src/instructions/print.rs
Normal file
3
src/instructions/print.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub fn print(arg: &String) {
|
||||||
|
println!("{}", arg);
|
||||||
|
}
|
27
src/parse.rs
27
src/parse.rs
@ -13,7 +13,9 @@ pub fn parse(stack: &mut Stack, file_content: &str) {
|
|||||||
inst_line = line.trim().chars().collect();
|
inst_line = line.trim().chars().collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
let command: Vec<String> = inst_line.split_whitespace().map(String::from).collect();
|
let command: [String; 2] = inst_line.split_once(char::is_whitespace)
|
||||||
|
.map_or_else(|| [inst_line.to_string(), "".to_string()],
|
||||||
|
|(first, second)| [first.to_string(), second.to_string()]);
|
||||||
|
|
||||||
let name: String;
|
let name: String;
|
||||||
let mut arg: String = String::new();
|
let mut arg: String = String::new();
|
||||||
@ -21,16 +23,19 @@ pub fn parse(stack: &mut Stack, file_content: &str) {
|
|||||||
|
|
||||||
name = command[0].clone();
|
name = command[0].clone();
|
||||||
|
|
||||||
if command.len() >= 2 {
|
if !command[1].is_empty() {
|
||||||
match name.chars().nth(0) {
|
if name.chars().nth(0) == Some('#') || name.chars().nth(1) == Some('#') {
|
||||||
Some('#') => arg = command[1].to_string(),
|
let splited_data: Vec<String> = command[1].split_whitespace().map(String::from).collect();
|
||||||
_ => {
|
arg = splited_data.get(0).unwrap().clone();
|
||||||
if command[1] == "-1" { // required for _UNIX_RANDOM instruction
|
} else if name.chars().nth(0) == Some('$') || name.chars().nth(1) == Some('$') {
|
||||||
data = 65535;
|
arg = command[1].clone();
|
||||||
} else {
|
} else if command[1] == "-1" { // required for
|
||||||
data = command[1].parse().expect(&format!("{}", ParseError::DataNotAUInt(command[0].to_string(), i + 1)))
|
data = 65535; // _unix_random
|
||||||
}
|
} else if let Ok(number) = command[1].parse() {
|
||||||
}
|
data = number;
|
||||||
|
} else {
|
||||||
|
eprintln!("{}", ParseError::ArgumentNotRequired(command[0].to_string(), i + 1, line.to_string()));
|
||||||
|
std::process::exit(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user