[UNVERIFIED] update to spec 1.10, parser rewrite.
This commit is contained in:
		
							parent
							
								
									cff855b9cb
								
							
						
					
					
						commit
						f2b551a586
					
				@ -1,5 +1,5 @@
 | 
			
		||||
# 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
 | 
			
		||||
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
 | 
			
		||||
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
 | 
			
		||||
$print Hello Labashki!
 | 
			
		||||
@ -12,6 +12,9 @@ pub enum RunError {
 | 
			
		||||
    UnknownLabel(u16),
 | 
			
		||||
    InvalidExpressionUnknownOperator(String),
 | 
			
		||||
    MemoryEmpty,
 | 
			
		||||
    AttemptToInsertHashOrStringInst,
 | 
			
		||||
    AttemptToInsertEmptyConst,
 | 
			
		||||
    AttemptToInsertALabel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Display for RunError {
 | 
			
		||||
@ -28,18 +31,21 @@ impl Display for RunError {
 | 
			
		||||
            RunError::UnknownLabel(label_name) => write!(f, "Unknown label: {}", label_name),
 | 
			
		||||
            RunError::InvalidExpressionUnknownOperator(name) => write!(f, "Invalid expression: unknown operator '{}'", name),
 | 
			
		||||
            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 {
 | 
			
		||||
    DataNotAUInt(String, usize)
 | 
			
		||||
    ArgumentNotRequired(String, usize, String)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Display for ParseError {
 | 
			
		||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
        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() {
 | 
			
		||||
            // Stack operations
 | 
			
		||||
            "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),
 | 
			
		||||
            "dup"  => instructions::dup::dup(&mut stack.memory),
 | 
			
		||||
            "swap" => instructions::swap::swap(&mut stack.memory),
 | 
			
		||||
            "meow" => instructions::meow::meow(&mut stack.memory),
 | 
			
		||||
            "dump" => instructions::dump::dump(&mut stack.memory),
 | 
			
		||||
            "size" => instructions::size::size(&mut stack.memory),
 | 
			
		||||
            "maxsize" => instructions::maxsize::maxsize(&mut stack.memory),
 | 
			
		||||
            "pick" => instructions::pick::pick(&mut stack.memory, &instruction.data),
 | 
			
		||||
 | 
			
		||||
            "#expr" => instructions::expr::expr(&mut stack.memory, &instruction.arg),
 | 
			
		||||
 | 
			
		||||
            // 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
 | 
			
		||||
            // Math
 | 
			
		||||
            "add" => instructions::add::add(&mut stack.memory),
 | 
			
		||||
            "sub" => instructions::sub::sub(&mut stack.memory),
 | 
			
		||||
            "mul" => instructions::mul::mul(&mut stack.memory),
 | 
			
		||||
            "div" => instructions::div::div(&mut stack.memory),
 | 
			
		||||
            "mod" => instructions::modulo::modulo(&mut stack.memory),
 | 
			
		||||
 | 
			
		||||
            // Logic
 | 
			
		||||
            "and"   => instructions::and::and(&mut stack.memory),
 | 
			
		||||
            "or"    => instructions::or::or(&mut stack.memory),
 | 
			
		||||
            "xor"   => instructions::xor::xor(&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),
 | 
			
		||||
            "bor"   => instructions::bor::bor(&mut stack.memory),
 | 
			
		||||
            "bxor"  => instructions::bxor::bxor(&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
 | 
			
		||||
            "putc" => instructions::putc::putc(&mut stack.memory),
 | 
			
		||||
            "getc" => instructions::getc::getc(&mut stack.memory),
 | 
			
		||||
            "scan" => instructions::scan::scan(&mut stack.memory),
 | 
			
		||||
            // 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),
 | 
			
		||||
            "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
 | 
			
		||||
            "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);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 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")] 
 | 
			
		||||
            "_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);
 | 
			
		||||
                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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if memory.last() != Some(&0) {
 | 
			
		||||
    if memory.pop() != Some(0) {
 | 
			
		||||
        *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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if memory.last() == Some(&0) {
 | 
			
		||||
    if memory.pop() == Some(0) {
 | 
			
		||||
        *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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -32,4 +32,8 @@ pub mod band;
 | 
			
		||||
pub mod bor;
 | 
			
		||||
pub mod bxor;
 | 
			
		||||
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();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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 mut arg: String = String::new();
 | 
			
		||||
@ -21,16 +23,19 @@ pub fn parse(stack: &mut Stack, file_content: &str) {
 | 
			
		||||
 | 
			
		||||
        name = command[0].clone();
 | 
			
		||||
 | 
			
		||||
        if command.len() >= 2 {
 | 
			
		||||
            match name.chars().nth(0) {
 | 
			
		||||
                Some('#') => arg = command[1].to_string(),
 | 
			
		||||
                _ => {
 | 
			
		||||
                    if command[1] == "-1" { // required for _UNIX_RANDOM instruction
 | 
			
		||||
                        data = 65535;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        data = command[1].parse().expect(&format!("{}", ParseError::DataNotAUInt(command[0].to_string(), i + 1)))
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
        if !command[1].is_empty() {
 | 
			
		||||
            if name.chars().nth(0) == Some('#') || name.chars().nth(1) == Some('#') {    
 | 
			
		||||
                let splited_data: Vec<String> = command[1].split_whitespace().map(String::from).collect();
 | 
			
		||||
                arg = splited_data.get(0).unwrap().clone();
 | 
			
		||||
            } else if name.chars().nth(0) == Some('$') || name.chars().nth(1) == Some('$') {
 | 
			
		||||
                arg = command[1].clone();
 | 
			
		||||
            } else if command[1] == "-1" { // required for
 | 
			
		||||
                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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user