finaly implemented macros properly
This commit is contained in:
parent
5cc80619c2
commit
30214808e5
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
/target
|
||||
a
|
||||
/a
|
|
@ -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
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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);
|
|
@ -223,7 +223,11 @@ pub fn run(tokens: Vec<crate::constants::Operator>) -> Result<()>{
|
|||
} else {
|
||||
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!()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -4,6 +4,7 @@ mod util;
|
|||
mod compile;
|
||||
mod parser;
|
||||
mod lexer;
|
||||
mod preprocessor;
|
||||
|
||||
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([
|
||||
//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
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