implement /example/rule110.mcl and fix interpreting syscalls

This commit is contained in:
MCorange 2023-03-18 18:41:57 +02:00
parent 8a53271a91
commit 8421fbf379
16 changed files with 449 additions and 222 deletions

1
Cargo.lock generated
View File

@ -215,6 +215,7 @@ version = "0.1.0"
dependencies = [
"clap",
"color-eyre",
"eyre",
]
[[package]]

View File

@ -8,3 +8,4 @@ edition = "2021"
[dependencies]
clap = { version = "4.1.8", features = ["derive"] }
color-eyre = "0.6.2"
eyre = "0.6.8"

38
examples/rule110.mcl Normal file → Executable file
View File

@ -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

172
src/bin/mcl_test_dev.rs Normal file
View File

@ -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<P: Into<PathBuf> + std::convert::AsRef<std::ffi::OsStr>>(f_in: PathBuf, f_out: &PathBuf, compiler: P, compile_mode: bool, stdin: String) -> Result<TestOutput> {
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::<String>();
let stderr = out.stderr.iter().map(|c| {
char::from_u32((*c) as u32).expect("Failed to parse stderr char").to_string()
}).collect::<String>();
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(())
}

View File

@ -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<String>, quiet: bool) -> Result<()> {
pub fn linux_x86_64_run(_bin: &PathBuf, args: Vec<String>, 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(())

View File

@ -18,7 +18,9 @@ pub fn compile(tokens: Vec<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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<Operator>, 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)?;

View File

@ -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,

View File

@ -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<u64>) -> Result<u64, &'static str> {
fn stack_pop(stack: &mut Vec<u64>, pos: &(String, u32, u32)) -> Result<u64> {
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<crate::constants::Operator>) -> Result<(), &'static str>{
pub fn run(tokens: Vec<crate::constants::Operator>) -> Result<()>{
let mut stack: Vec<u64> = Vec::new();
let mut ti = 0;
let mut mem: Vec<u8> = 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<crate::constants::Operator>) -> 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<crate::constants::Operator>) -> 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<crate::constants::Operator>) -> 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;
},
}
}

View File

@ -1,13 +1,24 @@
pub fn sys_write(rax: u64, rdi: u64, rsi: u64, rdx: u64, mem: &Vec<u8> ) -> 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<u8> ) -> 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::<Vec<String>>().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
}

View File

@ -22,7 +22,14 @@ fn lex_line(text: String) -> Result<Vec<(u32, String)>> {
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<Vec<(u32, String)>> {
pub fn lex(code: String, file: &String) -> Result<Vec<Token>> {
let lines: Vec<(usize, &str)> = code
.split("//").collect::<Vec<&str>>()[0]
.split(['\n', '\r'])
.enumerate()
.collect();
@ -52,6 +58,10 @@ pub fn lex(code: String, file: &String) -> Result<Vec<Token>> {
tokens.push(t);
}
}
// println!("{}", tokens.len());
// for token in tokens.clone() {
// println!("tok: {:?}", token.text);
// }
Ok(tokens)
}

View File

@ -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");
}

View File

@ -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<Operator>) -> Vec<Operator> {
pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
let mut stack: Vec<u32> = 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<Operator>) -> Vec<Operator> {
}
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<Vec<Operator>, ()> {
pub fn parse(&mut self) -> Result<Vec<Operator>> {
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)?)
}
}

View File

@ -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

View File

@ -1,3 +0,0 @@
txt = "TODO: Make this!\n"
sp = list(txt)
print([ord(x) for x in sp])

View File

@ -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

7
tests/math.mcl Normal file
View File

@ -0,0 +1,7 @@
34 35 + print
800 380 - print
10 5 * print
40 5 / print