finaly implemented macros properly
This commit is contained in:
parent
5cc80619c2
commit
30214808e5
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,2 +1,2 @@
|
||||||
/target
|
/target
|
||||||
a
|
/a
|
|
@ -1,25 +1,30 @@
|
||||||
mem 98 + 1 @8
|
|
||||||
|
|
||||||
0 while dup 98 < do
|
macro puts 1 1 syscall3 drop end
|
||||||
0 while dup 100 < do
|
|
||||||
|
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 + !8 if
|
||||||
dup mem + 100 + 42 @8
|
dup mem + BOARD_SIZE + 42 @8
|
||||||
else
|
else
|
||||||
dup mem + 100 + 32 @8
|
dup mem + BOARD_SIZE + 32 @8
|
||||||
end
|
end
|
||||||
1 +
|
1 +
|
||||||
end
|
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
|
// pattern
|
||||||
mem !8 1 shl
|
mem !8 1 shl
|
||||||
mem 1 + !8
|
mem 1 + !8
|
||||||
bor
|
bor
|
||||||
|
|
||||||
1 while dup 98 < do
|
1 while dup BOARD_SIZE 2 - < do
|
||||||
swap 1 shl 7 band
|
swap 1 shl 7 band
|
||||||
over mem + 1 + !8 bor
|
over mem + 1 + !8 bor
|
||||||
2dup 110 swap shr 1 band
|
2dup 110 swap shr 1 band
|
||||||
|
|
|
@ -312,6 +312,10 @@ pub fn compile(tokens: Vec<Operator>, args: Args) -> Result<()>{
|
||||||
}
|
}
|
||||||
ti += 1;
|
ti += 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
OpType::Macro => {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
OpType::Syscall0 => {
|
OpType::Syscall0 => {
|
||||||
writeln!(writer, " ;; -- syscall0")?;
|
writeln!(writer, " ;; -- syscall0")?;
|
||||||
writeln!(writer, " pop rax")?;
|
writeln!(writer, " pop rax")?;
|
||||||
|
@ -383,6 +387,7 @@ pub fn compile(tokens: Vec<Operator>, args: Args) -> Result<()>{
|
||||||
writeln!(writer, " push rax")?;
|
writeln!(writer, " push rax")?;
|
||||||
ti += 1;
|
ti += 1;
|
||||||
},
|
},
|
||||||
|
OpType::None => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeln!(writer, "addr_{}:", ti)?;
|
writeln!(writer, "addr_{}:", ti)?;
|
||||||
|
|
|
@ -38,6 +38,7 @@ pub enum OpType {
|
||||||
End,
|
End,
|
||||||
While,
|
While,
|
||||||
Do,
|
Do,
|
||||||
|
Macro,
|
||||||
|
|
||||||
// syscalls
|
// syscalls
|
||||||
Syscall0,
|
Syscall0,
|
||||||
|
@ -48,6 +49,7 @@ pub enum OpType {
|
||||||
Syscall5,
|
Syscall5,
|
||||||
Syscall6,
|
Syscall6,
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,8 +74,52 @@ impl Operator {
|
||||||
pos: (file, row, col)
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
|
@ -92,4 +138,24 @@ pub enum TokenType {
|
||||||
//TODO: Add char
|
//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);
|
pub type Loc = (String, u32, u32);
|
|
@ -223,7 +223,11 @@ pub fn run(tokens: Vec<crate::constants::Operator>) -> Result<()>{
|
||||||
} else {
|
} else {
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
OpType::Macro => {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
||||||
OpType::Syscall0 => {
|
OpType::Syscall0 => {
|
||||||
todo!();
|
todo!();
|
||||||
// ti += 1;
|
// ti += 1;
|
||||||
|
@ -265,6 +269,7 @@ pub fn run(tokens: Vec<crate::constants::Operator>) -> Result<()>{
|
||||||
todo!();
|
todo!();
|
||||||
// ti += 1;
|
// ti += 1;
|
||||||
},
|
},
|
||||||
|
OpType::None => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
use crate::constants::{Token, TokenType};
|
use crate::{constants::{Token, TokenType}, preprocessor::preprocess};
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
|
|
||||||
fn lex_word(s: String, tok_type: TokenType) -> (TokenType, String) {
|
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())?;
|
col = find_col(text.clone(), col_end, |x, _| !x.is_whitespace())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(tokens)
|
Ok(tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,5 +112,6 @@ pub fn lex(code: String, file: &String) -> Result<Vec<Token>> {
|
||||||
// for token in tokens.clone() {
|
// for token in tokens.clone() {
|
||||||
// println!("tok: {:?}", token.text);
|
// println!("tok: {:?}", token.text);
|
||||||
// }
|
// }
|
||||||
|
tokens = preprocess(tokens)?;
|
||||||
Ok(tokens)
|
Ok(tokens)
|
||||||
}
|
}
|
|
@ -4,6 +4,7 @@ mod util;
|
||||||
mod compile;
|
mod compile;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
|
mod preprocessor;
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
|
|
|
@ -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([
|
let lookup_table: HashMap<&str, OpType> = HashMap::from([
|
||||||
//stack
|
//stack
|
||||||
("print", OpType::Print),
|
("print", OpType::Print),
|
||||||
|
@ -133,6 +133,7 @@ fn lookup_word<P: Deref<Target = (String, u32, u32)>>(s: String, pos: P) -> Resu
|
||||||
("end", OpType::End),
|
("end", OpType::End),
|
||||||
("while", OpType::While),
|
("while", OpType::While),
|
||||||
("do", OpType::Do),
|
("do", OpType::Do),
|
||||||
|
("macro", OpType::Macro),
|
||||||
|
|
||||||
// mem
|
// mem
|
||||||
("mem", OpType::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()) {
|
match lookup_table.get(s.as_str()) {
|
||||||
Some(v) => Ok(v.clone()),
|
Some(v) => Ok(v.clone()),
|
||||||
None => {
|
None => {
|
||||||
lerror!(pos, "Unknown word '{}'", s);
|
Ok(OpType::None)
|
||||||
return Err(eyre!("Unknown word"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
125
src/preprocessor.rs
Normal file
125
src/preprocessor.rs
Normal 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!(¯o_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(), ¯o_name.loc())?;
|
||||||
|
if word != OpType::None {
|
||||||
|
lerror!(¯o_name.loc(), "Macro name cannot be a built in word, got '{}'", word.human());
|
||||||
|
return Err(eyre!(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if macros.get(¯o_name.text.clone()).is_some() { //? Maybe allow?
|
||||||
|
lerror!(¯o_name.loc(), "Macro redefinition is not allowed");
|
||||||
|
lnote!(¯os.get(¯o_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)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user