From 0a61a599c1c3837a430b75cc8b6889f7bf1c6b71 Mon Sep 17 00:00:00 2001 From: MCorange Date: Sat, 1 Apr 2023 17:49:41 +0300 Subject: [PATCH] added support for macros inside macros --- include/compat.mcl | 5 ++++ include/mem.mcl | 27 ------------------- include/std.mcl | 3 ++- src/compile/linux_x86_64.rs | 36 +++++++++++++++++++++++-- src/constants.rs | 12 +++++++-- src/interpret/linux_x86_64/mod.rs | 37 +++++++++++++++++++++++--- src/interpret/linux_x86_64/syscalls.rs | 4 +-- src/lexer.rs | 2 +- src/parser.rs | 6 +++++ src/preprocessor.rs | 30 ++++++++++++++++----- src/typechecker.rs | 16 +++++++++++ test.mcl | 4 ++- 12 files changed, 136 insertions(+), 46 deletions(-) create mode 100644 include/compat.mcl diff --git a/include/compat.mcl b/include/compat.mcl new file mode 100644 index 0000000..2630b05 --- /dev/null +++ b/include/compat.mcl @@ -0,0 +1,5 @@ +macro __compat__ + macro !8 load8 end + macro @8 store8 end + +end \ No newline at end of file diff --git a/include/mem.mcl b/include/mem.mcl index 2f1ae8e..e69de29 100644 --- a/include/mem.mcl +++ b/include/mem.mcl @@ -1,27 +0,0 @@ - -macro load8 @8 end -macro store8 !8 end - -macro load64 - 7 + 0 - 8 shl over !8 + swap 1 - swap - 8 shl over !8 + swap 1 - swap - 8 shl over !8 + swap 1 - swap - 8 shl over !8 + swap 1 - swap - 8 shl over !8 + swap 1 - swap - 8 shl over !8 + swap 1 - swap - 8 shl over !8 + swap 1 - swap - 8 shl over !8 + swap drop -end - -macro store64 - 2dup 255 band @8 shr swap 1 + swap - 2dup 255 band @8 shr swap 1 + swap - 2dup 255 band @8 shr swap 1 + swap - 2dup 255 band @8 shr swap 1 + swap - 2dup 255 band @8 shr swap 1 + swap - 2dup 255 band @8 shr swap 1 + swap - 2dup 255 band @8 shr swap 1 + swap - 2dup 255 band @8 shr swap 2drop -end - diff --git a/include/std.mcl b/include/std.mcl index 78fcb01..e4e2146 100644 --- a/include/std.mcl +++ b/include/std.mcl @@ -2,4 +2,5 @@ include "linux.mcl" include "io.mcl" include "util.mcl" include "int.mcl" -include "fs.mcl" \ No newline at end of file +include "fs.mcl" +include "compat.mcl" \ No newline at end of file diff --git a/src/compile/linux_x86_64.rs b/src/compile/linux_x86_64.rs index 098d1b5..286c170 100644 --- a/src/compile/linux_x86_64.rs +++ b/src/compile/linux_x86_64.rs @@ -156,7 +156,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ writeln!(writer, " ;; -- load")?; writeln!(writer, " pop rax")?; writeln!(writer, " xor rbx, rbx")?; - writeln!(writer, " mov bl, [rax]")?; + writeln!(writer, " mov bl, byte [rax]")?; writeln!(writer, " push rbx")?; ti += 1; } @@ -165,7 +165,39 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ writeln!(writer, " ;; -- store")?; writeln!(writer, " pop rbx")?; writeln!(writer, " pop rax")?; - writeln!(writer, " mov [rax], bl")?; + writeln!(writer, " mov byte [rax], bl")?; + ti += 1; + } + InstructionType::Load32 => { + writeln!(writer, " ;; -- load")?; + writeln!(writer, " pop rax")?; + writeln!(writer, " xor rbx, rbx")?; + writeln!(writer, " mov bl, dword [rax]")?; + writeln!(writer, " push rbx")?; + ti += 1; + } + + InstructionType::Store32 => { + writeln!(writer, " ;; -- store")?; + writeln!(writer, " pop rbx")?; + writeln!(writer, " pop rax")?; + writeln!(writer, " mov dword[rax], bl")?; + ti += 1; + } + InstructionType::Load64 => { + writeln!(writer, " ;; -- load")?; + writeln!(writer, " pop rax")?; + writeln!(writer, " xor rbx, rbx")?; + writeln!(writer, " mov bl, qword [rax]")?; + writeln!(writer, " push rbx")?; + ti += 1; + } + + InstructionType::Store64 => { + writeln!(writer, " ;; -- store")?; + writeln!(writer, " pop rbx")?; + writeln!(writer, " pop rax")?; + writeln!(writer, " mov qword [rax], bl")?; ti += 1; } diff --git a/src/constants.rs b/src/constants.rs index 99111d5..d4f2cf2 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -36,6 +36,10 @@ pub enum InstructionType { Mem, Load8, Store8, + Load32, + Store32, + Load64, + Store64, // syscalls Syscall0, @@ -129,8 +133,12 @@ impl OpType { InstructionType::DivMod => "divmod", InstructionType::Mul => "*", InstructionType::Mem => "mem", - InstructionType::Load8 => "!8", - InstructionType::Store8 => "@8", + InstructionType::Load8 => "load8", + InstructionType::Store8 => "store8", + InstructionType::Load32 => "load32", + InstructionType::Store32 => "store32", + InstructionType::Load64 => "load64", + InstructionType::Store64 => "store64", InstructionType::Syscall0 => "syscall0", InstructionType::Syscall1 => "syscall1", InstructionType::Syscall2 => "syscall2", diff --git a/src/interpret/linux_x86_64/mod.rs b/src/interpret/linux_x86_64/mod.rs index 31b10ac..8052461 100644 --- a/src/interpret/linux_x86_64/mod.rs +++ b/src/interpret/linux_x86_64/mod.rs @@ -16,7 +16,7 @@ fn stack_pop(stack: &mut Vec, pos: &Loc) -> Result { pub fn run(tokens: &[crate::constants::Operator]) -> Result{ let mut stack: Vec = Vec::new(); let mut ti = 0; - let mut mem: Vec = vec![0; crate::compile::MEM_SZ + crate::compile::STRING_SZ]; + let mut mem: Vec = vec![0; crate::compile::MEM_SZ + crate::compile::STRING_SZ]; let mut string_idx = 0; let mut memories: HashMap = HashMap::new(); @@ -41,7 +41,7 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result{ stack.push(string_idx + crate::compile::MEM_SZ); for c in token.text.bytes() { - mem[crate::compile::MEM_SZ + string_idx] = c; + mem[crate::compile::MEM_SZ + string_idx] = c as u64; string_idx += 1; } } else { @@ -102,7 +102,9 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result{ stack.push(0); ti += 1; } - InstructionType::Load8 => { + InstructionType::Load8 | + InstructionType::Load32 | + InstructionType::Load64 => { let a = stack_pop(&mut stack, &pos)?; if a > crate::compile::MEM_SZ { lerror!(&token.loc, "Invalid memory address {a}"); @@ -122,7 +124,34 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result{ return Ok(1); } - mem[addr] = (val & 0xFF) as u8; + mem[addr] = val as u8 as u64; + ti += 1; + } + #[allow(clippy::cast_possible_truncation)] + InstructionType::Store32 => { + let val = stack_pop(&mut stack, &pos)?; + let addr = stack_pop(&mut stack, &pos)?; + + if addr > crate::compile::MEM_SZ { + lerror!(&token.loc, "Invalid memory address {addr}"); + return Ok(1); + } + + mem[addr] = val as u32 as u64; + ti += 1; + } + + #[allow(clippy::cast_possible_truncation)] + InstructionType::Store64 => { + let val = stack_pop(&mut stack, &pos)?; + let addr = stack_pop(&mut stack, &pos)?; + + if addr > crate::compile::MEM_SZ { + lerror!(&token.loc, "Invalid memory address {addr}"); + return Ok(1); + } + + mem[addr] = val as u64; ti += 1; } diff --git a/src/interpret/linux_x86_64/syscalls.rs b/src/interpret/linux_x86_64/syscalls.rs index c764c95..0db7e49 100644 --- a/src/interpret/linux_x86_64/syscalls.rs +++ b/src/interpret/linux_x86_64/syscalls.rs @@ -1,10 +1,10 @@ -pub fn sys_write(sys_n: usize, fd: usize, buff: usize, count: usize, mem: &Vec ) -> usize { +pub fn sys_write(sys_n: usize, fd: usize, buff: usize, count: usize, mem: &Vec ) -> usize { let mem = (*mem).clone(); // println!("{:?}", &mem[buff..(buff + count)]); // return 0 ; let s = &mem[buff..(buff + count)].iter().map(|i| { - char::from_u32(u32::from(*i)).unwrap_or('_').to_string() + char::from_u32(u32::from(*i as u8)).unwrap_or('_').to_string() }).collect::(); match fd { diff --git a/src/lexer.rs b/src/lexer.rs index a1f41df..8c39140 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -122,7 +122,7 @@ pub fn lex + std::marker::Copy>(code: &str, file: S, args: &Args // println!("tok: {:?}", token.text); // } if preprocessing { - tokens = preprocess(tokens, args)?; + (tokens, _) = preprocess(tokens, args)?; } Ok(tokens) diff --git a/src/parser.rs b/src/parser.rs index 2e21f55..243d3da 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -26,6 +26,7 @@ pub fn cross_ref(mut program: Vec) -> Result> { OpType::Keyword(KeywordType::End) => { let block_ip = stack.pop().unwrap(); + if program[block_ip].typ == OpType::Keyword(KeywordType::If) || program[block_ip].typ == OpType::Keyword(KeywordType::Else) { @@ -51,6 +52,7 @@ pub fn cross_ref(mut program: Vec) -> Result> { } if !stack.is_empty() { + println!("{:?}", stack); lerror!(&program[stack.pop().expect("Empy stack")].clone().loc,"Unclosed block"); return Err(eyre!("Unclosed block")); } @@ -149,6 +151,10 @@ pub fn lookup_word>(s: &str, _pos: P) -> OpType { "mem" => OpType::Instruction(InstructionType::Mem), "load8" => OpType::Instruction(InstructionType::Load8), "store8" => OpType::Instruction(InstructionType::Store8), + "load32" => OpType::Instruction(InstructionType::Load32), + "store32" => OpType::Instruction(InstructionType::Store32), + "load64" => OpType::Instruction(InstructionType::Load64), + "store64" => OpType::Instruction(InstructionType::Store64), "syscall0" => OpType::Instruction(InstructionType::Syscall0), "syscall1" => OpType::Instruction(InstructionType::Syscall1), diff --git a/src/preprocessor.rs b/src/preprocessor.rs index cdc6c89..29aa55f 100644 --- a/src/preprocessor.rs +++ b/src/preprocessor.rs @@ -19,7 +19,7 @@ pub struct Macro { type Macros = HashMap; type Memories = HashMap; -pub fn preprocess(tokens: Vec, args: &Args) -> Result>{ +pub fn preprocess(tokens: Vec, args: &Args) -> Result<(Vec, Macros)>{ let mut program: Vec = Vec::new(); @@ -57,7 +57,7 @@ pub fn preprocess(tokens: Vec, args: &Args) -> Result>{ } let mut macr = Macro{ loc: macro_name.loc(), tokens: Vec::new() }; - + let mut reprocess = false; let mut depth = 0; while !rtokens.is_empty() { let t = rtokens.pop().unwrap(); @@ -67,7 +67,12 @@ pub fn preprocess(tokens: Vec, args: &Args) -> Result>{ } else if typ == OpType::Keyword(KeywordType::End) && depth != 0 { depth -= 1; macr.tokens.push(t); - } else if typ == OpType::Keyword(KeywordType::If) || typ == OpType::Keyword(KeywordType::Do) { + } else if typ == OpType::Keyword(KeywordType::If) || + typ == OpType::Keyword(KeywordType::Do) { + macr.tokens.push(t); + depth += 1; + } else if typ == OpType::Keyword(KeywordType::Macro) { + reprocess = true; macr.tokens.push(t); depth += 1; } else { @@ -75,6 +80,9 @@ pub fn preprocess(tokens: Vec, args: &Args) -> Result>{ } } + if reprocess { + (macr.tokens, macros) = preprocess(macr.tokens, args)?; + } macros.insert(macro_name.text, macr); @@ -205,13 +213,13 @@ pub fn preprocess(tokens: Vec, args: &Args) -> Result>{ } - Ok(program) + Ok((program, macros)) } pub fn expand(tokens: Vec, macros: &Macros, mems: &Memories) -> Result> { let mut program: Vec = Vec::new(); - let mut rtokens = tokens; + let mut rtokens = tokens.clone(); rtokens.reverse(); while !rtokens.is_empty() { @@ -223,7 +231,17 @@ pub fn expand(tokens: Vec, macros: &Macros, mems: &Memories) -> Result>().contains(&true) { + // println!("yas"); + // toks = preprocess(toks, args)?; + // } + program.append(&mut toks); + // println!("{:?}", program); } else if let Some(mem) = mem { let mut t = op; diff --git a/src/typechecker.rs b/src/typechecker.rs index c5e4302..5fd36c7 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -155,6 +155,22 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result>{ stack_pop(&mut stack, &op, &[Types::Int])?; stack_pop(&mut stack, &op, &[Types::Ptr])?; }, + InstructionType::Load32 => { + stack_pop(&mut stack, &op, &[Types::Ptr])?; + stack.push(Types::Int); + }, + InstructionType::Store32 => { + stack_pop(&mut stack, &op, &[Types::Int])?; + stack_pop(&mut stack, &op, &[Types::Ptr])?; + }, + InstructionType::Load64 => { + stack_pop(&mut stack, &op, &[Types::Ptr])?; + stack.push(Types::Int); + }, + InstructionType::Store64 => { + stack_pop(&mut stack, &op, &[Types::Int])?; + stack_pop(&mut stack, &op, &[Types::Ptr])?; + }, InstructionType::Syscall0 => { stack_pop(&mut stack, &op, &[Types::Int])?; stack.push(Types::Int); diff --git a/test.mcl b/test.mcl index 6f45b83..e20706d 100644 --- a/test.mcl +++ b/test.mcl @@ -1,6 +1,8 @@ +include "compat.mcl" +__compat__ memory m 10 end -m 69 store8 +m 69 @8 m load8 print \ No newline at end of file