added support for macros inside macros

This commit is contained in:
MCorange 2023-04-01 17:49:41 +03:00
parent f5d8b3ebca
commit 0a61a599c1
12 changed files with 136 additions and 46 deletions

5
include/compat.mcl Normal file
View File

@ -0,0 +1,5 @@
macro __compat__
macro !8 load8 end
macro @8 store8 end
end

View File

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

View File

@ -3,3 +3,4 @@ include "io.mcl"
include "util.mcl"
include "int.mcl"
include "fs.mcl"
include "compat.mcl"

View File

@ -156,7 +156,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
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<i32>{
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;
}

View File

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

View File

@ -16,7 +16,7 @@ fn stack_pop(stack: &mut Vec<usize>, pos: &Loc) -> Result<usize> {
pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
let mut stack: Vec<usize> = Vec::new();
let mut ti = 0;
let mut mem: Vec<u8> = vec![0; crate::compile::MEM_SZ + crate::compile::STRING_SZ];
let mut mem: Vec<u64> = vec![0; crate::compile::MEM_SZ + crate::compile::STRING_SZ];
let mut string_idx = 0;
let mut memories: HashMap<usize, usize> = HashMap::new();
@ -41,7 +41,7 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
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<i32>{
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<i32>{
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;
}

View File

@ -1,10 +1,10 @@
pub fn sys_write(sys_n: usize, fd: usize, buff: usize, count: usize, mem: &Vec<u8> ) -> usize {
pub fn sys_write(sys_n: usize, fd: usize, buff: usize, count: usize, mem: &Vec<u64> ) -> 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::<String>();
match fd {

View File

@ -122,7 +122,7 @@ pub fn lex<S: Into<String> + 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)

View File

@ -26,6 +26,7 @@ pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
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<Operator>) -> Result<Vec<Operator>> {
}
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<P: Deref<Target = Loc>>(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),

View File

@ -19,7 +19,7 @@ pub struct Macro {
type Macros = HashMap<String, Macro>;
type Memories = HashMap<String, usize>;
pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<(Vec<Token>, Macros)>{
let mut program: Vec<Token> = Vec::new();
@ -57,7 +57,7 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
}
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<Token>, args: &Args) -> Result<Vec<Token>>{
} 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<Token>, args: &Args) -> Result<Vec<Token>>{
}
}
if reprocess {
(macr.tokens, macros) = preprocess(macr.tokens, args)?;
}
macros.insert(macro_name.text, macr);
@ -205,13 +213,13 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
}
Ok(program)
Ok((program, macros))
}
pub fn expand(tokens: Vec<Token>, macros: &Macros, mems: &Memories) -> Result<Vec<Token>> {
let mut program: Vec<Token> = 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<Token>, macros: &Macros, mems: &Memories) -> Result<Ve
let m = macros.get(&op.text);
let mem = mems.get(&op.text);
if let Some(m) = m {
program.append(&mut m.tokens.clone());
// println!("{:#?}", macros);
let mut toks = m.tokens.clone();
// if toks.iter().map(|t| {
// let w = lookup_word(&t.text, &t.loc());
// w == OpType::Keyword(KeywordType::Macro)
// }).collect::<Vec<bool>>().contains(&true) {
// println!("yas");
// toks = preprocess(toks, args)?;
// }
program.append(&mut toks);
// println!("{:?}", program);
} else
if let Some(mem) = mem {
let mut t = op;

View File

@ -155,6 +155,22 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
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);

View File

@ -1,6 +1,8 @@
include "compat.mcl"
__compat__
memory m 10 end
m 69 store8
m 69 @8
m load8 print