From 8421fbf379aadf16eced64a2bfa71b1936237246 Mon Sep 17 00:00:00 2001 From: MCorange Date: Sat, 18 Mar 2023 18:41:57 +0200 Subject: [PATCH] implement /example/rule110.mcl and fix interpreting syscalls --- Cargo.lock | 1 + Cargo.toml | 1 + examples/rule110.mcl | 38 +++++- src/bin/mcl_test_dev.rs | 172 +++++++++++++++++++++++++ src/compile/commands.rs | 27 ++-- src/compile/linux_x86_64.rs | 113 ++++++++-------- src/constants.rs | 4 +- src/interpret/linux_x86_64/mod.rs | 159 ++++++++++++----------- src/interpret/linux_x86_64/syscalls.rs | 33 +++-- src/lexer.rs | 14 +- src/main.rs | 15 +-- src/parser.rs | 59 +++++---- test.mcl | 19 +-- test.py | 3 - test13.mcl | 6 - tests/math.mcl | 7 + 16 files changed, 449 insertions(+), 222 deletions(-) mode change 100644 => 100755 examples/rule110.mcl create mode 100644 src/bin/mcl_test_dev.rs delete mode 100644 test.py delete mode 100644 test13.mcl create mode 100644 tests/math.mcl diff --git a/Cargo.lock b/Cargo.lock index ca54c0a..54e6f9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,6 +215,7 @@ version = "0.1.0" dependencies = [ "clap", "color-eyre", + "eyre", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0673af0..f806427 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,4 @@ edition = "2021" [dependencies] clap = { version = "4.1.8", features = ["derive"] } color-eyre = "0.6.2" +eyre = "0.6.8" diff --git a/examples/rule110.mcl b/examples/rule110.mcl old mode 100644 new mode 100755 index 1b597f2..0664381 --- a/examples/rule110.mcl +++ b/examples/rule110.mcl @@ -1 +1,37 @@ -// TODO: Make this +mem 98 + 1 @8 + +0 while dup 98 < do + 0 while dup 100 < do + dup mem + !8 if + mem 100 + 42 @8 + else + mem 100 + 32 @8 + end + 1 mem 100 + 1 1 syscall3 drop + + 1 + + end + drop + + mem 100 + 10 @8 + 1 mem 100 + 1 1 syscall3 drop + + // pattern + mem !8 1 shl + mem 1 + !8 + bor + + 1 while dup 98 < do + swap 1 shl 7 band + over mem + 1 + !8 bor + 2dup 110 swap shr 1 band + swap mem + swap @8 + swap + + 1 + + end + drop drop + + 1 + +end +drop \ No newline at end of file diff --git a/src/bin/mcl_test_dev.rs b/src/bin/mcl_test_dev.rs new file mode 100644 index 0000000..0893642 --- /dev/null +++ b/src/bin/mcl_test_dev.rs @@ -0,0 +1,172 @@ + +use std::path::PathBuf; +use std::process::Stdio; +use std::{process, fs}; +use clap::Parser; +use color_eyre::Result; +use eyre::eyre; + +pub mod color { + #![allow(dead_code)] + pub const NONE: &str = "\x1b[0m"; + pub const RESET: &str = "\x1b[0m"; + pub const BRIGHT: &str = "\x1b[1m"; + pub const DIM: &str = "\x1b[2m"; + pub const UNDERSCORE: &str = "\x1b[4m"; + pub const BLINK: &str = "\x1b[5m"; + pub const REVERSE: &str = "\x1b[7m"; + pub const HIDDEN: &str = "\x1b[8m"; + pub const FG_BLACK: &str = "\x1b[30m"; + pub const FG_RED: &str = "\x1b[31m"; + pub const FG_GREEN: &str = "\x1b[32m"; + pub const FG_YELLOW: &str = "\x1b[33m"; + pub const FG_BLUE: &str = "\x1b[34m"; + pub const FG_MAGENTA: &str = "\x1b[35m"; + pub const FG_CYAN: &str = "\x1b[36m"; + pub const FG_WHITE: &str = "\x1b[37m"; + pub const BG_BLACK: &str = "\x1b[40m"; + pub const BG_RED: &str = "\x1b[41m"; + pub const BG_GREEN: &str = "\x1b[42m"; + pub const BG_YELLOW: &str = "\x1b[43m"; + pub const BG_BLUE: &str = "\x1b[44m"; + pub const BG_MAGENTA: &str = "\x1b[45m"; + pub const BG_CYAN: &str = "\x1b[46m"; + pub const BG_WHITE: &str = "\x1b[47m"; +} + +#[allow(dead_code)] +#[derive(Debug)] +struct TestOutput { + stdout: String, + stderr: String, + stdin: String, + status: i32 +} + +fn run_test + std::convert::AsRef>(f_in: PathBuf, f_out: &PathBuf, compiler: P, compile_mode: bool, stdin: String) -> Result { + let mut command = process::Command::new(compiler); + command.stdout(Stdio::piped()); + command.stderr(Stdio::piped()); + if !compile_mode { + command.arg("-sq"); + } else { + command.arg("-cqr"); + } + + command.arg("-i"); + command.arg(f_in); + command.arg("-o"); + command.arg(f_out); + + let child = command.spawn()?; + + let out = child.wait_with_output()?; + + let stdout = out.stdout.iter().map(|c| { + char::from_u32((*c) as u32).expect("Failed to parse stdout char").to_string() + }).collect::(); + + let stderr = out.stderr.iter().map(|c| { + char::from_u32((*c) as u32).expect("Failed to parse stderr char").to_string() + }).collect::(); + + + Ok(TestOutput { + stdout: stdout, + stderr: stderr, + stdin: stdin, + status: out.status.code().unwrap() + }) +} + +fn run_tests(args: Args) -> Result<()>{ + + let files = fs::read_dir(args.input)?; + + for file in files { + let file = file?; + let f_name = file.file_name().to_string_lossy().to_string(); + let f_out = PathBuf::from(&args.output).join(f_name); + + + let intp = run_test(file.path(), &f_out, &args.compiler_path, false, String::new())?; + let comp = run_test(file.path(), &f_out, &args.compiler_path, true, String::new())?; + compare_results(intp, comp, file.path())?; + } + + Ok(()) +} + + +fn compare_results(intp: TestOutput, comp: TestOutput, f_in: PathBuf) -> Result<()> { + + if intp.stdout != comp.stdout { + println!("{b}[ {r}ERR{rs}{b} ]{rs} {f} compiled and interpreted stdout versions differ", r=color::FG_RED, rs=color::RESET, b=color::BRIGHT, f=f_in.display()); + println!("compiled:\n{}", comp.stdout); + println!("interpreted:\n{}", intp.stdout); + return Err(eyre!("Testing failed")); + } + + if intp.stderr != comp.stderr { + println!("{b}[ {r}ERR{rs}{b} ]{rs} {f} compiled and interpreted stderr versions differ", r=color::FG_RED, rs=color::RESET, b=color::BRIGHT, f=f_in.display()); + println!("compiled:\n{}", comp.stderr); + println!("interpreted:\n{}", intp.stderr); + return Err(eyre!("Testing failed")); + } + + if intp.status != comp.status { + println!("{b}[ {r}ERR{rs}{b} ]{rs} {f} compiled and interpreted status codes differ", r=color::FG_RED, rs=color::RESET, b=color::BRIGHT, f=f_in.display()); + println!("compiled:\n{}", comp.status); + println!("interpreted:\n{}", intp.status); + return Err(eyre!("Testing failed")); + } + + println!("{b}[ {g}OK{rs}{b} ]{rs} {f} ", g=color::FG_GREEN, rs=color::RESET, b=color::BRIGHT, f=f_in.display()); + Ok(()) +} + +#[derive(Parser, Debug, Clone)] +#[command(author, version, about, long_about = None)] +struct Args { + + /// Mode, allowed modes: test, record + #[arg(long, short)] + mode: String, + + /// Use compile mode + #[arg(long, short)] + compile: bool, + + /// Use interpret mode + #[arg(long, short='s')] + interpret: bool, + + /// Output folder + #[arg(long, short, default_value_t=String::from("./target/mcl_test_dev"))] + output: String, + + /// Input folder + #[arg(long, short, default_value_t=String::from("./tests"))] + input: String, + + /// Compiler path + #[arg(long, short, default_value_t=String::from("./target/release/mclang"))] + compiler_path: String + + +} + +fn main() -> Result<()> { + let args = Args::parse(); + fs::create_dir_all(&args.output)?; + match args.mode.as_str() { + "test" => run_tests(args), + "record" => todo!("Implement test result recording"), + s => { + eprintln!("Unknown mode '{s}'"); + return Err(eyre!("Bad subcommand")); + } + }?; + + Ok(()) +} \ No newline at end of file diff --git a/src/compile/commands.rs b/src/compile/commands.rs index 15efa90..f2c9847 100644 --- a/src/compile/commands.rs +++ b/src/compile/commands.rs @@ -28,12 +28,12 @@ pub fn linux_x86_64_compile_and_link(of_a: &PathBuf, of_o: &PathBuf, of_c: &Path .stderr(Stdio::inherit()) .spawn()? }; - if !quiet{ + if !quiet { logger::info(format!("running 'nasm {}'", nasm_args.join(" ")).as_str()); } let exit = proc.wait()?; - if (!quiet) { + if !quiet { logger::info(format!("nasm process exited with code {}", exit).as_str()); } @@ -47,11 +47,11 @@ pub fn linux_x86_64_compile_and_link(of_a: &PathBuf, of_o: &PathBuf, of_c: &Path .stderr(Stdio::inherit()) .spawn()? }; - if (!quiet) { + if !quiet { logger::info(format!("running 'ld {}'", ld_args.join(" ")).as_str()); } let exit2 = proc2.wait()?; - if (!quiet) { + if !quiet { logger::info(format!("ld process exited with code {}", exit2).as_str()); } @@ -60,23 +60,28 @@ pub fn linux_x86_64_compile_and_link(of_a: &PathBuf, of_o: &PathBuf, of_c: &Path Ok(()) } -pub fn linux_x86_64_run(bin: &PathBuf, args: Vec, quiet: bool) -> Result<()> { +pub fn linux_x86_64_run(_bin: &PathBuf, args: Vec, quiet: bool) -> Result<()> { + + let bin = PathBuf::from( + format!("./{}", _bin.to_string_lossy()) + ); + let mut proc = if cfg!(target_os = "windows") { return Ok(()); } else { Command::new(bin) - //.args(&nasm_args) + .args(&args) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .spawn()? }; - - if (!quiet) { - logger::info(format!("running '{} {}'", bin.to_string_lossy() ,args.join(" ")).as_str()); + // println!("{}", quiet); + if !quiet { + logger::info(format!("running {} {}", _bin.to_string_lossy(), args.join(" ")).as_str()); } let exit = proc.wait()?; - if (!quiet) { - logger::info(format!("{} process exited with code {}", bin.to_string_lossy(), exit).as_str()); + if !quiet { + logger::info(format!("{} process exited with code {}", _bin.to_string_lossy(), exit).as_str()); } Ok(()) diff --git a/src/compile/linux_x86_64.rs b/src/compile/linux_x86_64.rs index 3f1c59e..1b0be5c 100644 --- a/src/compile/linux_x86_64.rs +++ b/src/compile/linux_x86_64.rs @@ -18,7 +18,9 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ let file = fs::File::create(&of_a)?; let mut writer = BufWriter::new(&file); - writeln!(writer, "global _start")?; + // println!("{}", tokens.len()); + + writeln!(writer, "BITS 64")?; writeln!(writer, "segment .text")?; writeln!(writer, "print:")?; @@ -54,7 +56,8 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ writeln!(writer, " syscall")?; writeln!(writer, " add rsp, 40")?; writeln!(writer, " ret")?; - + + writeln!(writer, "global _start")?; writeln!(writer, "_start:")?; let mut ti = 0; @@ -65,26 +68,26 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ match token.typ { // stack OpType::Push => { - writeln!(writer, " ; -- PUSH {}", token.value)?; + writeln!(writer, " ;; -- push {} --", token.value)?; writeln!(writer, " mov rax, {}", token.value)?; writeln!(writer, " push rax")?; ti += 1; }, - OpType::Pop => { - writeln!(writer, " ; -- POP")?; - writeln!(writer, " pop")?; + OpType::Drop => { + writeln!(writer, " ;; -- drop --")?; + writeln!(writer, " pop rax")?; ti += 1; }, OpType::Print => { - writeln!(writer, " ; -- PRINT")?; + writeln!(writer, " ;; -- print --")?; writeln!(writer, " pop rdi")?; writeln!(writer, " call print")?; ti += 1; }, OpType::Dup => { - writeln!(writer, " ; -- DUP")?; + writeln!(writer, " ;; -- dup --")?; writeln!(writer, " pop rax")?; writeln!(writer, " push rax")?; writeln!(writer, " push rax")?; @@ -92,19 +95,19 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ ti += 1; }, OpType::Dup2 => { - writeln!(writer, " ; -- DUP2")?; - writeln!(writer, " pop rax")?; + writeln!(writer, " ;; -- 2dup --")?; writeln!(writer, " pop rbx")?; - writeln!(writer, " push rbx")?; + writeln!(writer, " pop rax")?; writeln!(writer, " push rax")?; writeln!(writer, " push rbx")?; writeln!(writer, " push rax")?; + writeln!(writer, " push rbx")?; ti += 1; }, OpType::Rot => { - writeln!(writer, " ; -- DUP")?; + writeln!(writer, " ;; -- rot --")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; writeln!(writer, " pop rcx")?; @@ -115,16 +118,16 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ ti += 1; }, OpType::Swap => { - writeln!(writer, " ; -- DUP")?; + writeln!(writer, " ;; -- swap --")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; - writeln!(writer, " push rbx")?; writeln!(writer, " push rax")?; + writeln!(writer, " push rbx")?; ti += 1; }, OpType::Over => { - writeln!(writer, " ; -- DUP")?; + writeln!(writer, " ;; -- over --")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; writeln!(writer, " push rbx")?; @@ -136,12 +139,12 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ //mem OpType::Mem => { - writeln!(writer, " ; -- MEM")?; + writeln!(writer, " ;; -- mem --")?; writeln!(writer, " push mem")?; ti += 1; } OpType::Load8 => { - writeln!(writer, " ; -- LOAD64")?; + writeln!(writer, " ;; -- load --")?; writeln!(writer, " pop rax")?; writeln!(writer, " xor rbx, rbx")?; writeln!(writer, " mov bl, [rax]")?; @@ -150,7 +153,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ } OpType::Store8 => { - writeln!(writer, " ; -- STORE64")?; + writeln!(writer, " ;; -- store --")?; writeln!(writer, " pop rbx")?; writeln!(writer, " pop rax")?; writeln!(writer, " mov [rax], bl")?; @@ -159,7 +162,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ // math OpType::Plus => { - writeln!(writer, " ; -- PLUS")?; + writeln!(writer, " ;; -- plus --")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; writeln!(writer, " add rax, rbx")?; @@ -167,7 +170,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ ti += 1; }, OpType::Minus => { - writeln!(writer, " ; -- MINUS")?; + writeln!(writer, " ;; -- minus --")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; writeln!(writer, " sub rbx, rax")?; @@ -175,7 +178,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ ti += 1; }, OpType::Equals => { - writeln!(writer, " ; -- EQUALS")?; + writeln!(writer, " ;; -- equals --")?; writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rdx, 1")?; writeln!(writer, " pop rax")?; @@ -187,7 +190,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ }, OpType::Lt => { - writeln!(writer, " ; -- LT")?; + writeln!(writer, " ;; -- lt --")?; writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rdx, 1")?; writeln!(writer, " pop rbx")?; @@ -199,7 +202,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ }, OpType::Gt => { - writeln!(writer, " ; -- GT")?; + writeln!(writer, " ;; -- gt --")?; writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rdx, 1")?; writeln!(writer, " pop rbx")?; @@ -211,49 +214,49 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ }, OpType::Band => { - writeln!(writer, " ; -- BAND")?; + writeln!(writer, " ;; -- band --")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; - writeln!(writer, " and rax, rbx")?; - writeln!(writer, " push rax")?; + writeln!(writer, " and rbx, rax")?; + writeln!(writer, " push rbx")?; ti += 1; }, OpType::Bor => { - writeln!(writer, " ; -- BOR")?; + writeln!(writer, " ;; -- bor --")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; - writeln!(writer, " or rax, rbx")?; - writeln!(writer, " push rax")?; + writeln!(writer, " or rbx, rax")?; + writeln!(writer, " push rbx")?; ti += 1; }, OpType::Shr => { - writeln!(writer, " ; -- SHR")?; - writeln!(writer, " pop rax")?; + writeln!(writer, " ;; -- shr --")?; + writeln!(writer, " pop rcx")?; writeln!(writer, " pop rbx")?; - writeln!(writer, " shr rax, rbx")?; - writeln!(writer, " push rax")?; + writeln!(writer, " shr rbx, cl")?; + writeln!(writer, " push rbx")?; ti += 1; }, OpType::Shl => { - writeln!(writer, " ; -- SHL")?; - writeln!(writer, " pop rax")?; + writeln!(writer, " ;; -- shl --")?; + writeln!(writer, " pop rcx")?; writeln!(writer, " pop rbx")?; - writeln!(writer, " shl rax, rbx")?; - writeln!(writer, " push rax")?; + writeln!(writer, " shl rbx, cl")?; + writeln!(writer, " push rbx")?; ti += 1; }, OpType::Div => { - writeln!(writer, " ; -- DIV")?; + writeln!(writer, " ;; -- div --")?; writeln!(writer, " xor rdx, rdx")?; - writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; + writeln!(writer, " pop rax")?; writeln!(writer, " div rbx")?; writeln!(writer, " push rax")?; //writeln!(writer, " push rdx")?; ti += 1; }, OpType::Mul => { - writeln!(writer, " ; -- MUL")?; + writeln!(writer, " ;; -- mul --")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; writeln!(writer, " mul rbx")?; @@ -265,42 +268,44 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ // block OpType::If => { - writeln!(writer, " ; -- IF")?; + writeln!(writer, " ;; -- if --")?; writeln!(writer, " pop rax")?; writeln!(writer, " test rax, rax")?; writeln!(writer, " jz addr_{}", token.jmp)?; ti += 1; }, OpType::Else => { - writeln!(writer, " ; -- ELSE")?; + writeln!(writer, " ;; -- else --")?; writeln!(writer, " jmp addr_{}", token.jmp)?; ti += 1; }, OpType::While => { - writeln!(writer, " ; -- WHILE")?; + writeln!(writer, " ;; -- while --")?; ti += 1; } OpType::Do => { - writeln!(writer, " ; -- DO")?; + writeln!(writer, " ;; -- do --")?; writeln!(writer, " pop rax")?; writeln!(writer, " test rax, rax")?; writeln!(writer, " jz addr_{}", token.jmp)?; ti += 1; } OpType::End => { - writeln!(writer, " ; -- END")?; - writeln!(writer, " jmp addr_{}", token.jmp)?; + writeln!(writer, " ;; -- end --")?; + if ti + 1 != token.jmp as usize { + writeln!(writer, " jmp addr_{}", token.jmp)?; + } ti += 1; }, OpType::Syscall0 => { - writeln!(writer, " ; -- SYSCALL0")?; + writeln!(writer, " ;; -- syscall0 --")?; writeln!(writer, " pop rax")?; writeln!(writer, " syscall")?; writeln!(writer, " push rax")?; ti += 1; }, OpType::Syscall1 => { - writeln!(writer, " ; -- SYSCALL1")?; + writeln!(writer, " ;; -- syscall1 --")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; writeln!(writer, " syscall")?; @@ -308,7 +313,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ ti += 1; }, OpType::Syscall2 => { - writeln!(writer, " ; -- SYSCALL2")?; + writeln!(writer, " ;; -- syscall2 --")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; writeln!(writer, " pop rsi")?; @@ -317,7 +322,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ ti += 1; }, OpType::Syscall3 => { - writeln!(writer, " ; -- SYSCALL3")?; + writeln!(writer, " ;; -- syscall3 --")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; writeln!(writer, " pop rsi")?; @@ -328,7 +333,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ ti += 1; }, OpType::Syscall4 => { - writeln!(writer, " ; -- SYSCALL4")?; + writeln!(writer, " ;; -- syscall4 --")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; writeln!(writer, " pop rsi")?; @@ -339,7 +344,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ ti += 1; }, OpType::Syscall5 => { - writeln!(writer, " ; -- SYSCALL5")?; + writeln!(writer, " ;; -- syscall5 --")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; writeln!(writer, " pop rsi")?; @@ -351,7 +356,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ ti += 1; }, OpType::Syscall6 => { - writeln!(writer, " ; -- SYSCALL6")?; + writeln!(writer, " ;; -- syscall6 --")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; writeln!(writer, " pop rsi")?; @@ -371,7 +376,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result<()>{ writeln!(writer, " syscall")?; writeln!(writer, "segment .bss")?; - writeln!(writer, " mem: resb {}", crate::compile::MEM_SZ)?; + writeln!(writer, "mem: resb {}", crate::compile::MEM_SZ)?; writer.flush()?; linux_x86_64_compile_and_link(&of_a, &of_o, &of_c, args.quiet)?; diff --git a/src/constants.rs b/src/constants.rs index 4da2bd1..daed688 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -4,7 +4,7 @@ pub enum OpType { // stack Push, - Pop, + Drop, Print, Dup, Dup2, // a b => a b a b @@ -70,7 +70,7 @@ impl Operator { } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Token { pub file: String, pub line: u32, diff --git a/src/interpret/linux_x86_64/mod.rs b/src/interpret/linux_x86_64/mod.rs index f4859f2..19734f1 100644 --- a/src/interpret/linux_x86_64/mod.rs +++ b/src/interpret/linux_x86_64/mod.rs @@ -1,45 +1,51 @@ -use std::fmt::format; - -use crate::{constants::OpType, util::logger}; +use crate::{constants::OpType, util::{logger, self}}; // use crate::util::logger; use color_eyre::Result; - +use eyre::eyre; mod syscalls; -fn stack_pop(stack: &mut Vec) -> Result { +fn stack_pop(stack: &mut Vec, pos: &(String, u32, u32)) -> Result { match stack.pop() { Some(i) => Ok(i), - None => Err("Stack underflow"), + None => { + util::logger::pos_error(pos.clone(), "Stack underflow"); + Err(eyre!("Stack underflow")) + }, } } -pub fn run(tokens: Vec) -> Result<(), &'static str>{ +pub fn run(tokens: Vec) -> Result<()>{ let mut stack: Vec = Vec::new(); let mut ti = 0; let mut mem: Vec = vec![0; crate::compile::MEM_SZ as usize]; + // for token in &tokens { + // println!("{{typ: \"{:?}\", val: {}, jmp: {}}}", token.typ, token.value, token.jmp); + // } while ti < tokens.len() { let token = &tokens[ti]; - + let pos = token.pos.clone(); + // println!("{:?}", token.typ); match token.typ { + // stack OpType::Push => { stack.push(token.value as u64); ti += 1; }, - OpType::Pop => { + OpType::Drop => { stack.pop(); ti += 1; }, OpType::Dup => { - let a = stack_pop(&mut stack)?; + let a = stack_pop(&mut stack, &pos)?; stack.push(a); stack.push(a); ti += 1; }, OpType::Dup2 => { - let a = stack_pop(&mut stack)?; - let b = stack_pop(&mut stack)?; + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; stack.push(b); stack.push(a); stack.push(b); @@ -47,24 +53,24 @@ pub fn run(tokens: Vec) -> Result<(), &'static str>{ ti += 1; } OpType::Rot => { - let a = stack_pop(&mut stack)?; - let b = stack_pop(&mut stack)?; - let c = stack_pop(&mut stack)?; + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; + let c = stack_pop(&mut stack, &pos)?; stack.push(b); stack.push(a); stack.push(c); ti += 1; } OpType::Swap => { - let a = stack_pop(&mut stack)?; - let b = stack_pop(&mut stack)?; - stack.push(b); + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; stack.push(a); + stack.push(b); ti += 1; } OpType::Over => { - let a = stack_pop(&mut stack)?; - let b = stack_pop(&mut stack)?; + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; stack.push(b); stack.push(a); stack.push(b); @@ -72,7 +78,7 @@ pub fn run(tokens: Vec) -> Result<(), &'static str>{ } OpType::Print => { - let a = stack_pop(&mut stack)?; + let a = stack_pop(&mut stack, &pos)?; println!("{a}"); // let _ = io::stdout().flush(); ti += 1; @@ -84,159 +90,162 @@ pub fn run(tokens: Vec) -> Result<(), &'static str>{ ti += 1; } OpType::Load8 => { - let a = stack_pop(&mut stack)?; - - stack.push(mem[a as usize] as u64); + let a = stack_pop(&mut stack, &pos)?; + let byte = mem[a as usize]; + stack.push(byte as u64); ti += 1; } OpType::Store8 => { - let a = stack_pop(&mut stack)?; - let b = stack_pop(&mut stack)?; + let val = stack_pop(&mut stack, &pos)?; + let addr = stack_pop(&mut stack, &pos)?; - mem[b as usize] = a as u8; + mem[addr as usize] = (val & 0xFF) as u8; ti += 1; } // math OpType::Plus => { - let a = stack_pop(&mut stack)?; - let b = stack_pop(&mut stack)?; + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; stack.push(b + a); ti += 1; }, OpType::Minus => { - let a = stack_pop(&mut stack)?; - let b = stack_pop(&mut stack)?; + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; stack.push(b - a); ti += 1; }, OpType::Equals => { - let a = stack_pop(&mut stack)?; - let b = stack_pop(&mut stack)?; - stack.push((a == b) as u64); + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; + stack.push((b == a) as u64); ti += 1; }, OpType::Gt => { - let b = stack_pop(&mut stack)?; - let a = stack_pop(&mut stack)?; - stack.push((a > b) as u64); + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; + stack.push((b > a) as u64); ti += 1; }, OpType::Lt => { - let b = stack_pop(&mut stack)?; - let a = stack_pop(&mut stack)?; - stack.push((a < b) as u64); + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; + stack.push((b < a) as u64); ti += 1; }, OpType::Band => { - let b = stack_pop(&mut stack)?; - let a = stack_pop(&mut stack)?; + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; stack.push((a & b) as u64); ti += 1; } OpType::Bor => { - let b = stack_pop(&mut stack)?; - let a = stack_pop(&mut stack)?; + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; stack.push((a | b) as u64); ti += 1; } OpType::Shr => { - let b = stack_pop(&mut stack)?; - let a = stack_pop(&mut stack)?; - stack.push((a >> b) as u64); + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; + stack.push((b >> a) as u64); ti += 1; } OpType::Shl => { - let b = stack_pop(&mut stack)?; - let a = stack_pop(&mut stack)?; - stack.push((a << b) as u64); + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; + stack.push((b << a) as u64); ti += 1; } OpType::Div => { - let b = stack_pop(&mut stack)?; - let a = stack_pop(&mut stack)?; - stack.push((a / b) as u64); + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; + stack.push((b / a) as u64); ti += 1; } OpType::Mul => { - let b = stack_pop(&mut stack)?; - let a = stack_pop(&mut stack)?; - stack.push((a * b) as u64); + let a = stack_pop(&mut stack, &pos)?; + let b = stack_pop(&mut stack, &pos)?; + stack.push((b * a) as u64); ti += 1; } // blocks OpType::If => { - let a = stack_pop(&mut stack)?; + let a = stack_pop(&mut stack, &pos)?; if a == 0 { + // println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp); ti = (token.jmp) as usize; } else { ti += 1; } }, OpType::Else => { - ti = token.jmp as usize; + // println!("Else({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp); + ti = (token.jmp) as usize; }, - + OpType::End => { + // println!("End({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp); + ti = (token.jmp) as usize; + } OpType::While => { ti += 1; } OpType::Do => { let a = stack.pop().unwrap(); if a == 0 { - ti = token.jmp as usize; + ti = (token.jmp) as usize; } else { ti += 1; } } - OpType::End => { - ti = token.jmp as usize; - } OpType::Syscall0 => { todo!(); - ti += 1; + // ti += 1; }, OpType::Syscall1 => { todo!(); - ti += 1; + // ti += 1; }, OpType::Syscall2 => { todo!(); - ti += 1; + // ti += 1; }, OpType::Syscall3 => { - let rax = stack_pop(&mut stack)?; - let rdi = stack_pop(&mut stack)?; - let rsi = stack_pop(&mut stack)?; - let rdx = stack_pop(&mut stack)?; - + let rax = stack_pop(&mut stack, &pos)?; + let rdi = stack_pop(&mut stack, &pos)?; + let rsi = stack_pop(&mut stack, &pos)?; + let rdx = stack_pop(&mut stack, &pos)?; + // println!("yes"); let ret = match rax { 1 => syscalls::sys_write(rax, rdi, rsi, rdx, &mem), _ => { logger::error(format!("Syscall(3) #{} is not implemented", rax).as_str()); - return Err("Exiting"); + return Err(eyre!("Syscall not implemented")); } }; stack.push(ret); + // println!("{}", stack.len()); ti += 1; }, OpType::Syscall4 => { todo!(); - ti += 1; + // ti += 1; }, OpType::Syscall5 => { todo!(); - ti += 1; + // ti += 1; }, OpType::Syscall6 => { todo!(); - ti += 1; + // ti += 1; }, } } diff --git a/src/interpret/linux_x86_64/syscalls.rs b/src/interpret/linux_x86_64/syscalls.rs index 467f009..4fb6919 100644 --- a/src/interpret/linux_x86_64/syscalls.rs +++ b/src/interpret/linux_x86_64/syscalls.rs @@ -1,13 +1,24 @@ -pub fn sys_write(rax: u64, rdi: u64, rsi: u64, rdx: u64, mem: &Vec ) -> u64 { - for c in rsi..rdx { - match rdi { - 1 => print!("{}", unsafe { char::from_u32_unchecked((mem[(rsi + c) as usize]) as u32) }), - 2 => eprint!("{}", unsafe { char::from_u32_unchecked((mem[(rsi + c) as usize]) as u32) }), - _ => panic!("Unknown file {}", rdi) - }; - let _ = std::io::Write::flush(&mut std::io::stdout()); - let _ = std::io::Write::flush(&mut std::io::stderr()); - } - rax +pub fn sys_write(sys_n: u64, fd: u64, buff: u64, count: u64, mem: &Vec ) -> u64 { + let mem = (*mem).clone(); + let buff = buff as usize; + let count = count as usize; + // println!("{:?}", &mem[buff..(buff + count)]); + // return 0 ; + let s = &mem[buff..(buff + count)].iter().map(|i| { + char::from_u32((*i) as u32).unwrap_or('_').to_string() + }).collect::>().join(""); + + match fd { + 1 => { + print!("{}", s); + }, + 2 => { + eprint!("{}", s); + }, + _ => panic!("Unknown file {}", fd) + }; + let _ = std::io::Write::flush(&mut std::io::stdout()); + let _ = std::io::Write::flush(&mut std::io::stderr()); + sys_n } \ No newline at end of file diff --git a/src/lexer.rs b/src/lexer.rs index e61b168..ba9b1e9 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -22,7 +22,14 @@ fn lex_line(text: String) -> Result> { while col_end < text.clone().len() as u32 { col_end = find_col(text.clone(), col, |x| x.is_whitespace())?; let t = &text[(col as usize)..((col_end as usize))]; - tokens.push((col, t.to_string())); + + if t == "//" { + return Ok(tokens); + } + + if !t.is_empty() { + tokens.push((col, t.to_string())); + } col = find_col(text.clone(), col_end, |x| !x.is_whitespace())?; } @@ -31,7 +38,6 @@ fn lex_line(text: String) -> Result> { pub fn lex(code: String, file: &String) -> Result> { let lines: Vec<(usize, &str)> = code - .split("//").collect::>()[0] .split(['\n', '\r']) .enumerate() .collect(); @@ -52,6 +58,10 @@ pub fn lex(code: String, file: &String) -> Result> { tokens.push(t); } } + // println!("{}", tokens.len()); + // for token in tokens.clone() { + // println!("tok: {:?}", token.text); + // } Ok(tokens) } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index b131451..79aef36 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,28 +39,25 @@ pub struct Args { } -fn main() -> Result<(), ()> { +fn main() -> Result<()> { let args = Args::parse(); - let code = fs::read_to_string(&args.in_file).unwrap(); - let tokens = lexer::lex(code, &args.in_file).unwrap(); + let code = fs::read_to_string(&args.in_file)?; + let tokens = lexer::lex(code, &args.in_file)?; // for token in &tokens { // println!("(f: {}, l: {}, c: {}, t: {})", token.file, token.line, token.col, token.text); // } let mut parser = parser::Parser::new(tokens); - let tokens = match parser.parse(){ - Ok(t) => t, - Err(_) => return Ok(()) - }; + let tokens = parser.parse()?; if args.compile && args.interpret { util::logger::error("Cannot compile and interpret at the same time"); } else if args.interpret { - let _ = interpret::linux_x86_64::run(tokens); + interpret::linux_x86_64::run(tokens)?; } else if args.compile { - let _ = compile::linux_x86_64::compile(tokens, args); + compile::linux_x86_64::compile(tokens, args)?; } else { util::logger::error("Did not choose to compile or to interpret, exiting"); } diff --git a/src/parser.rs b/src/parser.rs index ced6720..51603fe 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,46 +1,39 @@ use crate::{constants::{Operator, OpType, Token}, util}; use color_eyre::Result; +use eyre::eyre; -pub fn cross_ref(mut tokens: Vec) -> Vec { +pub fn cross_ref(mut program: Vec) -> Result> { let mut stack: Vec = Vec::new(); - for ip in 0..tokens.len() { - let op = &tokens.clone()[ip]; + for ip in 0..program.len() { + let op = &program.clone()[ip]; match op.typ { OpType::If => { stack.push(ip as u32) } OpType::Else => { let if_ip = stack.pop().unwrap(); - let mut if_og = &mut tokens[if_ip as usize]; - if !vec![OpType::If].contains(&(*if_og).typ) { + if program[if_ip as usize].typ != OpType::If { util::logger::pos_error(op.clone().pos,"'end' can only close 'if' blocks"); std::process::exit(1); // idc } - - (*if_og).jmp = (ip + 1) as i32; + + // let mut if_og = &mut tokens[if_ip as usize]; + // (*if_og).jmp = (ip + 1) as i32; + program[if_ip as usize].jmp = (ip + 1) as i32; stack.push(ip as u32); }, OpType::End => { let block_ip = stack.pop().unwrap(); - let mut block_og = &mut tokens[block_ip as usize].clone(); - if vec![OpType::If, OpType::Else].contains(&(*block_og).typ) { + // let mut block_og = &mut tokens[block_ip as usize].clone(); + if program[block_ip as usize].typ == OpType::If || + program[block_ip as usize].typ == OpType::Else { - (*block_og).jmp = ip as i32; - tokens[block_ip as usize] = block_og.clone(); + program[block_ip as usize].jmp = ip as i32; + program[ip as usize].jmp = (ip + 1)as i32; - let do_og = &mut tokens[ip as usize].clone(); - do_og.jmp = (ip + 1) as i32; - - tokens[ip as usize] = (*do_og).clone(); - - } else if (*block_og).typ == OpType::Do { - let do_og = &mut tokens[ip as usize]; - do_og.jmp = block_og.jmp; - - tokens[ip as usize] = (*do_og).clone(); - let mut block_og = block_og.clone(); - block_og.jmp = (ip + 1) as i32; - tokens[block_ip as usize] = block_og.clone(); + } else if program[block_ip as usize].typ == OpType::Do { + program[ip].jmp = program[block_ip as usize].jmp; + program[block_ip as usize].jmp = (ip + 1) as i32; } else { util::logger::pos_error(op.clone().pos,"'end' can only close 'if' blocks"); std::process::exit(1); // idc @@ -52,14 +45,19 @@ pub fn cross_ref(mut tokens: Vec) -> Vec { } OpType::Do => { let while_ip = stack.pop().unwrap(); - (&mut tokens[ip as usize]).jmp = while_ip as i32; + program[ip as usize].jmp = while_ip as i32; stack.push(ip as u32); } _ => () } } - tokens.clone() + if stack.len() > 0 { + util::logger::pos_error(program[stack.pop().expect("Empy stack") as usize].clone().pos,"Unclosed block"); + return Err(eyre!("Unclosed block")); + } + + Ok(program.clone()) } pub struct Parser { @@ -73,7 +71,7 @@ impl Parser { } } - pub fn parse(&mut self) -> Result, ()> { + pub fn parse(&mut self) -> Result> { let mut tokens = Vec::new(); for token in &self.tokens { @@ -91,7 +89,7 @@ impl Parser { // stack "dup" => tokens.push(Operator::new(OpType::Dup, 0, token.file.clone(), token.line, token.col)), - "drop" => tokens.push(Operator::new(OpType::Pop, 0, token.file.clone(), token.line, token.col)), + "drop" => tokens.push(Operator::new(OpType::Drop, 0, token.file.clone(), token.line, token.col)), "2dup" => tokens.push(Operator::new(OpType::Dup2, 0, token.file.clone(), token.line, token.col)), "rot" => tokens.push(Operator::new(OpType::Rot, 0, token.file.clone(), token.line, token.col)), "over" => tokens.push(Operator::new(OpType::Over, 0, token.file.clone(), token.line, token.col)), @@ -108,6 +106,7 @@ impl Parser { "shr" => tokens.push(Operator::new(OpType::Shr, 0, token.file.clone(), token.line, token.col)), "shl" => tokens.push(Operator::new(OpType::Shl, 0, token.file.clone(), token.line, token.col)), "/" => tokens.push(Operator::new(OpType::Div, 0, token.file.clone(), token.line, token.col)), + "*" => tokens.push(Operator::new(OpType::Mul, 0, token.file.clone(), token.line, token.col)), // block "if" => tokens.push(Operator::new(OpType::If, 0, token.file.clone(), token.line, token.col)), @@ -134,11 +133,11 @@ impl Parser { t => { util::logger::pos_error(pos, format!("Unknown token '{}'", t).as_str()); - return Err(()); + return Err(eyre!("Unknown token")); } } } - Ok(cross_ref(tokens)) + Ok(cross_ref(tokens)?) } } \ No newline at end of file diff --git a/test.mcl b/test.mcl index b206a6d..2fbba06 100644 --- a/test.mcl +++ b/test.mcl @@ -1,18 +1 @@ - -mem dup 72 @8 -1 + dup 101 @8 -1 + dup 110 @8 -1 + dup 108 @8 -1 + dup 111 @8 -1 + dup 32 @8 -1 + dup 119 @8 -1 + dup 111 @8 -1 + dup 114 @8 -1 + dup 108 @8 -1 + dup 100 @8 -1 + dup 33 @8 -1 + dup 10 @8 -1 + - -mem - mem 1 1 syscall3 - +1 2 3 2dup print print print print print \ No newline at end of file diff --git a/test.py b/test.py deleted file mode 100644 index 0dce136..0000000 --- a/test.py +++ /dev/null @@ -1,3 +0,0 @@ -txt = "TODO: Make this!\n" -sp = list(txt) -print([ord(x) for x in sp]) \ No newline at end of file diff --git a/test13.mcl b/test13.mcl deleted file mode 100644 index 2d7211a..0000000 --- a/test13.mcl +++ /dev/null @@ -1,6 +0,0 @@ -//we dont have text yet, its so early stages still -//cant it do putchar(getchar()) -// not yet -// ;-; ;-; ;-; ;-; ;-; -// ping me on dsc -//..., im working on it, rn im gonna make elif i think, you can watch, lemme clean my table gimme 5 mins \ No newline at end of file diff --git a/tests/math.mcl b/tests/math.mcl new file mode 100644 index 0000000..89d4cd5 --- /dev/null +++ b/tests/math.mcl @@ -0,0 +1,7 @@ +34 35 + print + +800 380 - print + +10 5 * print + +40 5 / print \ No newline at end of file