finaly implemented macros properly

This commit is contained in:
MCorange 2023-03-20 13:39:04 +02:00
parent 5cc80619c2
commit 30214808e5
10 changed files with 226 additions and 20 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
/target
a
/a

View File

@ -1,25 +1,30 @@
mem 98 + 1 @8
0 while dup 98 < do
0 while dup 100 < do
macro puts 1 1 syscall3 drop end
macro BOARD_SIZE 100 end
mem BOARD_SIZE 2 - + 1 @8
0 while dup BOARD_SIZE 2 - < do
0 while dup BOARD_SIZE < do
dup mem + !8 if
dup mem + 100 + 42 @8
dup mem + BOARD_SIZE + 42 @8
else
dup mem + 100 + 32 @8
dup mem + BOARD_SIZE + 32 @8
end
1 +
end
mem + 100 + 10 @8
mem + BOARD_SIZE + 10 @8
101 mem 100 + 1 1 syscall3 drop
BOARD_SIZE 1 + mem BOARD_SIZE + puts
// pattern
mem !8 1 shl
mem 1 + !8
bor
1 while dup 98 < do
1 while dup BOARD_SIZE 2 - < do
swap 1 shl 7 band
over mem + 1 + !8 bor
2dup 110 swap shr 1 band

View File

@ -312,6 +312,10 @@ pub fn compile(tokens: Vec<Operator>, args: Args) -> Result<()>{
}
ti += 1;
},
OpType::Macro => {
panic!();
}
OpType::Syscall0 => {
writeln!(writer, " ;; -- syscall0")?;
writeln!(writer, " pop rax")?;
@ -383,6 +387,7 @@ pub fn compile(tokens: Vec<Operator>, args: Args) -> Result<()>{
writeln!(writer, " push rax")?;
ti += 1;
},
OpType::None => unreachable!()
}
}
writeln!(writer, "addr_{}:", ti)?;

View File

@ -38,6 +38,7 @@ pub enum OpType {
End,
While,
Do,
Macro,
// syscalls
Syscall0,
@ -48,6 +49,7 @@ pub enum OpType {
Syscall5,
Syscall6,
None
}
@ -72,8 +74,52 @@ impl Operator {
pos: (file, row, col)
}
}
}
impl OpType {
pub fn human(&self) -> String {
match self {
&OpType::PushInt => "Number",
&OpType::PushStr => "String",
&OpType::Print => "print",
&OpType::Dup => "dup",
&OpType::Drop => "drop",
&OpType::Dup2 => "2dup",
&OpType::Rot => "rot",
&OpType::Over => "over",
&OpType::Swap => "swap",
&OpType::Plus => "+",
&OpType::Minus => "-",
&OpType::Equals => "=",
&OpType::Gt => ">",
&OpType::Lt => "<",
&OpType::Band => "band",
&OpType::Bor => "bor",
&OpType::Shr => "shr",
&OpType::Shl => "shl",
&OpType::Div => "/",
&OpType::Mul => "*",
&OpType::If => "if",
&OpType::Else => "else",
&OpType::End => "end",
&OpType::While => "while",
&OpType::Do => "do",
&OpType::Macro => "macro",
&OpType::Mem => "mem",
&OpType::Load8 => "!8",
&OpType::Store8 => "@8",
&OpType::Syscall0 => "syscall0",
&OpType::Syscall1 => "syscall1",
&OpType::Syscall2 => "syscall2",
&OpType::Syscall3 => "syscall3",
&OpType::Syscall4 => "syscall4",
&OpType::Syscall5 => "syscall5",
&OpType::Syscall6 => "syscall6",
&OpType::None => "None"
}.to_string()
}
}
#[derive(Debug, Clone)]
pub struct Token {
@ -92,4 +138,24 @@ pub enum TokenType {
//TODO: Add char
}
impl Token {
pub fn loc(&self) -> Loc {
(
self.file.clone(),
self.line,
self.col
)
}
}
impl TokenType {
pub fn human(&self) -> String {
match self {
TokenType::Word => "Word",
TokenType::Int => "Int",
TokenType::String => "String",
}.to_string()
}
}
pub type Loc = (String, u32, u32);

View File

@ -224,6 +224,10 @@ pub fn run(tokens: Vec<crate::constants::Operator>) -> Result<()>{
ti += 1;
}
}
OpType::Macro => {
panic!();
}
OpType::Syscall0 => {
todo!();
// ti += 1;
@ -265,6 +269,7 @@ pub fn run(tokens: Vec<crate::constants::Operator>) -> Result<()>{
todo!();
// ti += 1;
},
OpType::None => unreachable!()
}
}

View File

@ -1,5 +1,5 @@
use crate::constants::{Token, TokenType};
use crate::{constants::{Token, TokenType}, preprocessor::preprocess};
use color_eyre::Result;
fn lex_word(s: String, tok_type: TokenType) -> (TokenType, String) {
@ -65,7 +65,6 @@ fn lex_line(text: String) -> Result<Vec<(u32, String, TokenType)>> {
col = find_col(text.clone(), col_end, |x, _| !x.is_whitespace())?;
}
}
Ok(tokens)
}
@ -113,5 +112,6 @@ pub fn lex(code: String, file: &String) -> Result<Vec<Token>> {
// for token in tokens.clone() {
// println!("tok: {:?}", token.text);
// }
tokens = preprocess(tokens)?;
Ok(tokens)
}

View File

@ -4,6 +4,7 @@ mod util;
mod compile;
mod parser;
mod lexer;
mod preprocessor;
use std::fs;

View File

@ -103,7 +103,7 @@ impl Parser {
}
fn lookup_word<P: Deref<Target = (String, u32, u32)>>(s: String, pos: P) -> Result<OpType>{
pub fn lookup_word<P: Deref<Target = (String, u32, u32)>>(s: String, _pos: P) -> Result<OpType>{
let lookup_table: HashMap<&str, OpType> = HashMap::from([
//stack
("print", OpType::Print),
@ -133,6 +133,7 @@ fn lookup_word<P: Deref<Target = (String, u32, u32)>>(s: String, pos: P) -> Resu
("end", OpType::End),
("while", OpType::While),
("do", OpType::Do),
("macro", OpType::Macro),
// mem
("mem", OpType::Mem),
@ -151,8 +152,7 @@ fn lookup_word<P: Deref<Target = (String, u32, u32)>>(s: String, pos: P) -> Resu
match lookup_table.get(s.as_str()) {
Some(v) => Ok(v.clone()),
None => {
lerror!(pos, "Unknown word '{}'", s);
return Err(eyre!("Unknown word"))
Ok(OpType::None)
}
}
}

125
src/preprocessor.rs Normal file
View File

@ -0,0 +1,125 @@
use std::collections::HashMap;
use color_eyre::Result;
use eyre::eyre;
use crate::constants::{Token, Loc, OpType, TokenType};
use crate::{lerror, lnote};
use crate::parser::lookup_word;
#[derive(Debug)]
pub struct Macro {
pub loc: Loc,
pub tokens: Vec<Token>
}
pub fn preprocess(tokens: Vec<Token>) -> Result<Vec<Token>>{
let mut program: Vec<Token> = Vec::new();
let mut macros: HashMap<String, Macro> = HashMap::new();
let mut rtokens = tokens.clone();
rtokens.reverse();
while rtokens.len() > 0 {
let token = rtokens.pop().unwrap();
let op_type = lookup_word(token.text.clone(), &token.loc())?;
match token.clone() {
_ if op_type == OpType::Macro => {
if rtokens.len() == 0 {
lerror!(&token.loc(), "Macro name not found, expected {} but found nothing", TokenType::Word.human());
return Err(eyre!(""));
}
let macro_name = rtokens.pop().unwrap();
if macro_name.typ != TokenType::Word {
lerror!(&macro_name.loc(), "Bad macro name, expected {} but found {}", TokenType::Word.human(), macro_name.typ.human());
return Err(eyre!(""));
}
let word = lookup_word(macro_name.text.clone(), &macro_name.loc())?;
if word != OpType::None {
lerror!(&macro_name.loc(), "Macro name cannot be a built in word, got '{}'", word.human());
return Err(eyre!(""));
}
if macros.get(&macro_name.text.clone()).is_some() { //? Maybe allow?
lerror!(&macro_name.loc(), "Macro redefinition is not allowed");
lnote!(&macros.get(&macro_name.text.clone()).unwrap().loc, "First definition here");
return Err(eyre!(""));
}
let mut macr = Macro{ loc: macro_name.loc(), tokens: Vec::new() };
let mut depth = 0;
while rtokens.len() > 0 {
let t = rtokens.pop().unwrap();
let typ = lookup_word(t.text.clone(), &t.loc())?;
if typ == OpType::End && depth == 0 {
break;
} else if typ == OpType::End && depth != 0 {
depth -= 1;
macr.tokens.push(t);
} else {
if typ == OpType::If || typ == OpType::Do {
macr.tokens.push(t);
depth += 1;
} else {
macr.tokens.push(t);
}
}
}
macros.insert(macro_name.text, macr);
}
_ => {
program.push(token);
}
}
}
program = expand_macros(program, macros)?;
Ok(program)
}
pub fn expand_macros(tokens: Vec<Token>, macros: HashMap<String, Macro>) -> Result<Vec<Token>> {
let mut program: Vec<Token> = Vec::new();
let mut rtokens = tokens.clone();
rtokens.reverse();
while rtokens.len() > 0 {
let op = rtokens.pop().unwrap();
let op_type = lookup_word(op.text.clone(), &op.loc())?;
if op.typ == TokenType::Word {
match op_type {
OpType::None => {
let m = macros.get(&op.text);
if m.is_some() {
program.append(&mut m.unwrap().tokens.clone())
} else {
lerror!(&op.loc(), "Unknown word '{}'", op.text.clone());
return Err(eyre!(""));
}
}
_ => {
program.push(op);
}
}
} else {
program.push(op);
}
}
Ok(program)
}

View File

@ -1,6 +1,5 @@
mem 0 @8
macro write
1 1 syscall3 drop
end
while mem !8 10 < do
"Hello world!\n" 1 1 syscall3 drop
mem !8 1 + mem swap @8
end drop
"HEnlo world!\n" write