implemented local memory

This commit is contained in:
MCorange 2023-04-01 16:54:02 +03:00
parent 09bccc8079
commit f5d8b3ebca
11 changed files with 431 additions and 127 deletions

6
.gitignore vendored
View File

@ -1,2 +1,6 @@
/target /target
/a /a
test
test.nasm
test.o

View File

@ -26,7 +26,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
let file = fs::File::create(&of_a)?; let file = fs::File::create(&of_a)?;
let mut writer = BufWriter::new(&file); let mut writer = BufWriter::new(&file);
let mut memories: Vec<(usize, usize)> = Vec::new();
// println!("{}", tokens.len()); // println!("{}", tokens.len());
let mut strings: Vec<String> = Vec::new(); let mut strings: Vec<String> = Vec::new();
@ -373,6 +373,11 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
writeln!(writer, " push rax")?; writeln!(writer, " push rax")?;
ti += 1; ti += 1;
}, },
InstructionType::MemUse => {
writeln!(writer, " ;; -- MemUse")?;
writeln!(writer, " push mem_{}", token.addr.unwrap())?;
ti += 1;
},
InstructionType::None => unreachable!(), InstructionType::None => unreachable!(),
InstructionType::CastBool => ti += 1, InstructionType::CastBool => ti += 1,
InstructionType::CastPtr => ti += 1, InstructionType::CastPtr => ti += 1,
@ -415,6 +420,10 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
} }
ti += 1; ti += 1;
}, },
KeywordType::Memory => {
memories.push((token.addr.unwrap(), token.value));
ti += 1;
}
KeywordType::Macro | KeywordType::Macro |
KeywordType::Include KeywordType::Include
=> unreachable!() => unreachable!()
@ -432,9 +441,12 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
let s_list = s_chars.join(","); let s_list = s_chars.join(",");
writeln!(writer, " str_{}: db {} ; {}", i, s_list, s.escape_default())?; writeln!(writer, " str_{}: db {} ; {}", i, s_list, s.escape_default())?;
} }
writeln!(writer, "segment .bss")?; writeln!(writer, "segment .bss")?;
writeln!(writer, "mem: resb {}", crate::compile::MEM_SZ)?; for (_, s) in memories.iter().enumerate() {
writeln!(writer, " mem_{}: resb {}", s.0, s.1)?;
}
writeln!(writer, " mem: resb {}", crate::compile::MEM_SZ)?;
writer.flush()?; writer.flush()?;
linux_x86_64_compile_and_link(&of_a, &of_o, &of_c, args.quiet)?; linux_x86_64_compile_and_link(&of_a, &of_o, &of_c, args.quiet)?;

View File

@ -4,7 +4,7 @@ pub const ALLOW_MACRO_REDEFINITION: bool = true;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum InstructionType { pub enum InstructionType {
// stack // stack
PushInt, PushInt,
PushStr, PushStr,
@ -30,13 +30,13 @@ pub enum InstructionType {
Shl, // << Shl, // <<
DivMod, // / DivMod, // /
Mul, Mul,
// mem // mem
Mem, Mem,
Load8, Load8,
Store8, Store8,
// syscalls // syscalls
Syscall0, Syscall0,
Syscall1, Syscall1,
@ -48,8 +48,9 @@ pub enum InstructionType {
CastBool, CastBool,
CastPtr, CastPtr,
CastInt, CastInt,
MemUse,
None // Used for macros and any other non built in word definitions None // Used for macros and any other non built in word definitions
} }
@ -62,6 +63,7 @@ pub enum KeywordType {
Do, Do,
Macro, Macro,
Include, Include,
Memory
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -77,7 +79,7 @@ pub struct Operator{
pub text: String, //? only used for OpType::PushStr pub text: String, //? only used for OpType::PushStr
pub addr: Option<usize>, //? only used for OpType::PushStr pub addr: Option<usize>, //? only used for OpType::PushStr
pub jmp: usize, pub jmp: usize,
pub loc: (String, usize, usize) pub loc: Loc
} }
impl Operator { impl Operator {
@ -91,55 +93,71 @@ impl Operator {
loc: (file, row, col) loc: (file, row, col)
} }
} }
pub fn set_addr(mut self, addr: usize) -> Self {
self.addr = Some(addr);
self
}
} }
impl OpType { impl OpType {
pub fn human(&self) -> String { pub fn human(&self) -> String {
match *self { match (*self).clone() {
OpType::Instruction(InstructionType::PushInt) => "Number", OpType::Instruction(instruction) => {
OpType::Instruction(InstructionType::PushStr) => "String", match instruction {
OpType::Instruction(InstructionType::Print) => "print",
OpType::Instruction(InstructionType::Dup) => "dup", InstructionType::PushInt => "Number",
OpType::Instruction(InstructionType::Drop) => "drop", InstructionType::PushStr => "String",
OpType::Instruction(InstructionType::Rot) => "rot", InstructionType::Print => "print",
OpType::Instruction(InstructionType::Over) => "over", InstructionType::Dup => "dup",
OpType::Instruction(InstructionType::Swap) => "swap", InstructionType::Drop => "drop",
OpType::Instruction(InstructionType::Plus) => "+", InstructionType::Rot => "rot",
OpType::Instruction(InstructionType::Minus) => "-", InstructionType::Over => "over",
OpType::Instruction(InstructionType::Equals) => "=", InstructionType::Swap => "swap",
OpType::Instruction(InstructionType::Gt) => ">", InstructionType::Plus => "+",
OpType::Instruction(InstructionType::Lt) => "<", InstructionType::Minus => "-",
OpType::Instruction(InstructionType::NotEquals) => "!=", InstructionType::Equals => "=",
OpType::Instruction(InstructionType::Le) => "<=", InstructionType::Gt => ">",
OpType::Instruction(InstructionType::Ge) => ">=", InstructionType::Lt => "<",
OpType::Instruction(InstructionType::Band) => "band", InstructionType::NotEquals => "!=",
OpType::Instruction(InstructionType::Bor) => "bor", InstructionType::Le => "<=",
OpType::Instruction(InstructionType::Shr) => "shr", InstructionType::Ge => ">=",
OpType::Instruction(InstructionType::Shl) => "shl", InstructionType::Band => "band",
OpType::Instruction(InstructionType::DivMod) => "divmod", InstructionType::Bor => "bor",
OpType::Instruction(InstructionType::Mul) => "*", InstructionType::Shr => "shr",
OpType::Keyword(KeywordType::If) => "if", InstructionType::Shl => "shl",
OpType::Keyword(KeywordType::Else) => "else", InstructionType::DivMod => "divmod",
OpType::Keyword(KeywordType::End) => "end", InstructionType::Mul => "*",
OpType::Keyword(KeywordType::While) => "while", InstructionType::Mem => "mem",
OpType::Keyword(KeywordType::Do) => "do", InstructionType::Load8 => "!8",
OpType::Keyword(KeywordType::Macro) => "macro", InstructionType::Store8 => "@8",
OpType::Keyword(KeywordType::Include) => "include", InstructionType::Syscall0 => "syscall0",
OpType::Instruction(InstructionType::Mem) => "mem", InstructionType::Syscall1 => "syscall1",
OpType::Instruction(InstructionType::Load8) => "!8", InstructionType::Syscall2 => "syscall2",
OpType::Instruction(InstructionType::Store8) => "@8", InstructionType::Syscall3 => "syscall3",
OpType::Instruction(InstructionType::Syscall0) => "syscall0", InstructionType::Syscall4 => "syscall4",
OpType::Instruction(InstructionType::Syscall1) => "syscall1", InstructionType::Syscall5 => "syscall5",
OpType::Instruction(InstructionType::Syscall2) => "syscall2", InstructionType::Syscall6 => "syscall6",
OpType::Instruction(InstructionType::Syscall3) => "syscall3", InstructionType::CastBool => "cast(bool",
OpType::Instruction(InstructionType::Syscall4) => "syscall4", InstructionType::CastPtr => "cast(ptr)",
OpType::Instruction(InstructionType::Syscall5) => "syscall5", InstructionType::CastInt => "cast(int)",
OpType::Instruction(InstructionType::Syscall6) => "syscall6", InstructionType::MemUse => "MemUse",
OpType::Instruction(InstructionType::CastBool) => "cast(bool", InstructionType::None => "None",
OpType::Instruction(InstructionType::CastPtr) => "cast(ptr)", }
OpType::Instruction(InstructionType::CastInt) => "cast(int)", }
OpType::Instruction(InstructionType::None) => "None", OpType::Keyword(keyword) => {
match keyword {
KeywordType::If => "if",
KeywordType::Else => "else",
KeywordType::End => "end",
KeywordType::While => "while",
KeywordType::Do => "do",
KeywordType::Macro => "macro",
KeywordType::Include => "include",
KeywordType::Memory => "memory"
}
}
}.to_string() }.to_string()
} }
} }
@ -150,7 +168,10 @@ pub struct Token {
pub line: usize, pub line: usize,
pub col: usize, pub col: usize,
pub text: String, pub text: String,
pub typ: TokenType pub typ: TokenType,
pub value: Option<usize>, //* only used for Memories
pub addr: Option<usize>, //* only used for Memories
pub op_typ: InstructionType //* only used for Memories
} }
#[derive(Debug, Clone, PartialEq, Copy)] #[derive(Debug, Clone, PartialEq, Copy)]

View File

@ -1,3 +1,5 @@
use std::collections::HashMap;
use crate::{constants::{OpType, Loc, InstructionType, KeywordType}, lerror, error}; use crate::{constants::{OpType, Loc, InstructionType, KeywordType}, lerror, error};
// use crate::util::logger; // use crate::util::logger;
use color_eyre::Result; use color_eyre::Result;
@ -16,6 +18,8 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
let mut ti = 0; let mut ti = 0;
let mut mem: Vec<u8> = vec![0; crate::compile::MEM_SZ + crate::compile::STRING_SZ]; let mut mem: Vec<u8> = vec![0; crate::compile::MEM_SZ + crate::compile::STRING_SZ];
let mut string_idx = 0; let mut string_idx = 0;
let mut memories: HashMap<usize, usize> = HashMap::new();
// for token in &tokens { // for token in &tokens {
// println!("{{typ: \"{:?}\", val: {}, jmp: {}}}", token.typ, token.value, token.jmp); // println!("{{typ: \"{:?}\", val: {}, jmp: {}}}", token.typ, token.value, token.jmp);
@ -100,6 +104,10 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
} }
InstructionType::Load8 => { InstructionType::Load8 => {
let a = stack_pop(&mut stack, &pos)?; let a = stack_pop(&mut stack, &pos)?;
if a > crate::compile::MEM_SZ {
lerror!(&token.loc, "Invalid memory address {a}");
return Ok(1);
}
let byte = mem[a]; let byte = mem[a];
stack.push(byte as usize); stack.push(byte as usize);
ti += 1; ti += 1;
@ -108,7 +116,12 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
InstructionType::Store8 => { InstructionType::Store8 => {
let val = stack_pop(&mut stack, &pos)?; let val = stack_pop(&mut stack, &pos)?;
let addr = 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 & 0xFF) as u8; mem[addr] = (val & 0xFF) as u8;
ti += 1; ti += 1;
} }
@ -246,39 +259,53 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
todo!(); todo!();
// ti += 1; // ti += 1;
}, },
InstructionType::MemUse => {
let m = memories.get(&token.addr.unwrap()).unwrap();
stack.push(*m);
ti += 1;
},
InstructionType::CastBool => ti += 1, InstructionType::CastBool => ti += 1,
InstructionType::CastPtr => ti += 1, InstructionType::CastPtr => ti += 1,
InstructionType::CastInt => ti += 1, InstructionType::CastInt => ti += 1,
InstructionType::None => unreachable!() InstructionType::None => unreachable!(),
} }
} }
OpType::Keyword(k) => {
// blocks match k {
OpType::Keyword(KeywordType::If) => { // blocks
let a = stack_pop(&mut stack, &pos)?; KeywordType::If => {
if a == 0 { let a = stack_pop(&mut stack, &pos)?;
// println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp); if a == 0 {
ti = token.jmp; // println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp);
} else { ti = token.jmp;
ti += 1; } else {
} ti += 1;
}, }
OpType::Keyword(KeywordType::Else) | OpType::Keyword(KeywordType::End) => { },
ti = token.jmp; KeywordType::Else | KeywordType::End => {
} ti = token.jmp;
OpType::Keyword(KeywordType::While) => { }
ti += 1; KeywordType::While => {
} ti += 1;
OpType::Keyword(KeywordType::Do) => { }
let a = stack.pop().unwrap(); KeywordType::Do => {
if a == 0 { let a = stack.pop().unwrap();
ti = token.jmp; if a == 0 {
} else { ti = token.jmp;
ti += 1; } else {
ti += 1;
}
}
KeywordType::Memory => {
memories.insert(token.addr.unwrap(), token.value);
ti += 1;
},
KeywordType::Macro | KeywordType::Include => unreachable!(),
} }
} }
| OpType::Keyword(KeywordType::Macro) | OpType::Keyword(KeywordType::Include) => unreachable!()
} }
} }

View File

@ -108,7 +108,10 @@ pub fn lex<S: Into<String> + std::marker::Copy>(code: &str, file: S, args: &Args
line: row + 1, line: row + 1,
col, col,
text: tok, text: tok,
typ: tok_type typ: tok_type,
value: None,
addr: None,
op_typ: crate::constants::InstructionType::None
}; };
tokens.push(t); tokens.push(t);
} }

View File

@ -6,6 +6,7 @@ mod parser;
mod lexer; mod lexer;
mod preprocessor; mod preprocessor;
mod typechecker; mod typechecker;
mod precompiler;
use std::fs; use std::fs;
@ -17,6 +18,8 @@ pub const DEFAULT_INCLUDES: [&str;2] = [
"~/.mclang/include", "~/.mclang/include",
]; ];
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
#[command(author, version, about, long_about = None)] #[command(author, version, about, long_about = None)]
pub struct Args { pub struct Args {
@ -48,6 +51,9 @@ pub struct Args {
#[arg(long, short='I')] #[arg(long, short='I')]
include: Vec<String>, include: Vec<String>,
/// Unsafe mode, disables typechecking
#[arg(long="unsafe", default_value_t = false)]
unsaf: bool
//#[arg(long, short='F')] //#[arg(long, short='F')]
//features: Vec<String>, //features: Vec<String>,

View File

@ -79,8 +79,13 @@ impl Parser {
let pos = (token.file.clone(), token.line, token.col); let pos = (token.file.clone(), token.line, token.col);
match token.typ { match token.typ {
TokenType::Word => { TokenType::Word => {
let word_type = lookup_word(&token.text, &pos); let word_type = if token.op_typ == InstructionType::MemUse {
tokens.push(Operator::new(word_type, 0, token.text.clone(), token.file.clone(), token.line, token.col)); OpType::Instruction(InstructionType::MemUse)
} else {
lookup_word(&token.text, &pos)
};
tokens.push(Operator::new(word_type, token.value.unwrap_or(0), token.text.clone(), token.file.clone(), token.line, token.col).set_addr(token.addr.unwrap_or(0)));
}, },
TokenType::Int => {// negative numbers not yet implemented TokenType::Int => {// negative numbers not yet implemented
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.text.parse::<usize>()?, String::new(), token.file.clone(), token.line, token.col)); tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.text.parse::<usize>()?, String::new(), token.file.clone(), token.line, token.col));
@ -109,6 +114,10 @@ impl Parser {
pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType { pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
let n = s.parse::<usize>();
if let Ok(_) = n {
return OpType::Instruction(InstructionType::PushInt);
}
match s { match s {
//stack //stack
"print" => OpType::Instruction(InstructionType::Print), "print" => OpType::Instruction(InstructionType::Print),
@ -135,20 +144,12 @@ pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
"divmod" => OpType::Instruction(InstructionType::DivMod), "divmod" => OpType::Instruction(InstructionType::DivMod),
"*" => OpType::Instruction(InstructionType::Mul), "*" => OpType::Instruction(InstructionType::Mul),
// block
"if" => OpType::Keyword(KeywordType::If),
"else" => OpType::Keyword(KeywordType::Else),
"end" => OpType::Keyword(KeywordType::End),
"while" => OpType::Keyword(KeywordType::While),
"do" => OpType::Keyword(KeywordType::Do),
"macro" => OpType::Keyword(KeywordType::Macro),
"include" => OpType::Keyword(KeywordType::Include),
// mem // mem
"mem" => OpType::Instruction(InstructionType::Mem), "mem" => OpType::Instruction(InstructionType::Mem),
"!8" => OpType::Instruction(InstructionType::Load8), "load8" => OpType::Instruction(InstructionType::Load8),
"@8" => OpType::Instruction(InstructionType::Store8), "store8" => OpType::Instruction(InstructionType::Store8),
"syscall0" => OpType::Instruction(InstructionType::Syscall0), "syscall0" => OpType::Instruction(InstructionType::Syscall0),
"syscall1" => OpType::Instruction(InstructionType::Syscall1), "syscall1" => OpType::Instruction(InstructionType::Syscall1),
"syscall2" => OpType::Instruction(InstructionType::Syscall2), "syscall2" => OpType::Instruction(InstructionType::Syscall2),
@ -159,6 +160,15 @@ pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
"cast(bool" => OpType::Instruction(InstructionType::CastBool), "cast(bool" => OpType::Instruction(InstructionType::CastBool),
"cast(ptr)" => OpType::Instruction(InstructionType::CastPtr), "cast(ptr)" => OpType::Instruction(InstructionType::CastPtr),
"cast(int)" => OpType::Instruction(InstructionType::CastInt), "cast(int)" => OpType::Instruction(InstructionType::CastInt),
// block
"if" => OpType::Keyword(KeywordType::If),
"else" => OpType::Keyword(KeywordType::Else),
"end" => OpType::Keyword(KeywordType::End),
"while" => OpType::Keyword(KeywordType::While),
"do" => OpType::Keyword(KeywordType::Do),
"macro" => OpType::Keyword(KeywordType::Macro),
"include" => OpType::Keyword(KeywordType::Include),
"memory" => OpType::Keyword(KeywordType::Memory),
_ => OpType::Instruction(InstructionType::None) _ => OpType::Instruction(InstructionType::None)
} }

154
src/precompiler.rs Normal file
View File

@ -0,0 +1,154 @@
use color_eyre::Result;
use eyre::eyre;
use crate::{constants::{Token, OpType, InstructionType, Loc}, parser::lookup_word, lerror};
fn stack_pop(stack: &mut Vec<usize>, loc: &Loc) -> Result<usize> {
if let Some(i) = stack.pop() { Ok(i) } else {
lerror!(&loc.clone(), "Stack underflow");
Err(eyre!("Stack underflow"))
}
}
pub fn precompile(tokens: &Vec<Token>) -> Result<Vec<usize>>{
let mut stack: Vec<usize> = Vec::new();
for token in tokens.iter() {
let typ = lookup_word(&token.text, &token.loc());
match typ {
OpType::Instruction(i) => {
let loc = token.loc();
match i {
InstructionType::PushInt => {
if let Ok(i) = token.text.parse::<usize>() {
stack.push(i);
} else {
lerror!(&token.loc(), "Bad number");
return Err(eyre!(""));
}
},
InstructionType::Plus => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(b + a);
},
InstructionType::Minus => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(b - a);
},
InstructionType::Equals => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(usize::from(b == a));
},
InstructionType::Gt => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(usize::from(b > a));
},
InstructionType::Lt => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(usize::from(b < a));
},
InstructionType::NotEquals => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(usize::from(b != a));
},
InstructionType::Ge => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(usize::from(b >= a));
},
InstructionType::Le => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(usize::from(b <= a));
},
InstructionType::Band => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(a & b);
}
InstructionType::Bor => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(a | b);
}
InstructionType::Shr => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(b >> a);
}
InstructionType::Shl => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(b << a);
}
InstructionType::DivMod => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(b / a);
stack.push(b % a);
}
InstructionType::Mul => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(b * a);
}
InstructionType::Drop => {
stack.pop();
},
InstructionType::Dup => {
let a = stack_pop(&mut stack, &loc)?;
stack.push(a);
stack.push(a);
},
InstructionType::Rot => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
let c = stack_pop(&mut stack, &loc)?;
stack.push(b);
stack.push(a);
stack.push(c);
}
InstructionType::Swap => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(a);
stack.push(b);
}
InstructionType::Over => {
let a = stack_pop(&mut stack, &loc)?;
let b = stack_pop(&mut stack, &loc)?;
stack.push(b);
stack.push(a);
stack.push(b);
}
_ => {
lerror!(&token.loc(), "Unsupported precompiler instruction {:?}", i);
dbg!(tokens);
return Err(eyre!(""));
}
}
}
_ => {
lerror!(&token.loc(), "Unsupported precompiler keyword {:?}", typ);
dbg!(tokens);
return Err(eyre!(""));
}
}
}
Ok(stack)
}

View File

@ -6,7 +6,8 @@ use eyre::eyre;
use crate::constants::{Token, Loc, OpType, TokenType, KeywordType, InstructionType}; use crate::constants::{Token, Loc, OpType, TokenType, KeywordType, InstructionType};
use crate::lexer::lex; use crate::lexer::lex;
use crate::{lerror, lnote, Args, warn}; use crate::precompiler::precompile;
use crate::{lerror, lnote, Args, warn, linfo};
use crate::parser::lookup_word; use crate::parser::lookup_word;
#[derive(Debug)] #[derive(Debug)]
@ -15,14 +16,20 @@ pub struct Macro {
pub tokens: Vec<Token> pub tokens: Vec<Token>
} }
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>>{
let mut program: Vec<Token> = Vec::new();
let mut macros: HashMap<String, Macro> = HashMap::new();
let mut program: Vec<Token> = Vec::new();
let mut macros: Macros = HashMap::new();
let mut memories: Memories = HashMap::new();
let mut rtokens = tokens; let mut rtokens = tokens;
rtokens.reverse(); rtokens.reverse();
while !rtokens.is_empty() { while !rtokens.is_empty() {
let token = rtokens.pop().unwrap(); let mut token = rtokens.pop().unwrap();
let op_type = lookup_word(&token.text, &token.loc()); let op_type = lookup_word(&token.text, &token.loc());
match token.clone() { match token.clone() {
@ -66,7 +73,6 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
} else { } else {
macr.tokens.push(t); macr.tokens.push(t);
} }
} }
@ -120,6 +126,57 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
rtokens.append(&mut code); rtokens.append(&mut code);
}
_ if op_type == OpType::Keyword(KeywordType::Memory) => {
if rtokens.is_empty() {
lerror!(&token.loc(), "Memory name not found, expected {} but found nothing", TokenType::String.human());
return Err(eyre!(""));
}
let memory_name = rtokens.pop().unwrap();
if memory_name.typ != TokenType::Word {
lerror!(&memory_name.loc(), "Bad memory name, expected {} but found {}", TokenType::Word.human(), memory_name.typ.human());
return Err(eyre!(""));
}
if macros.get(&memory_name.text).is_some() {
lerror!(&memory_name.loc(), "Memory name cannot replace macro name, got {}", memory_name.text);
let m = macros.get(&memory_name.text).unwrap();
linfo!(&m.loc, "Macro found here");
return Err(eyre!(""));
}
let mut code: Vec<Token> = Vec::new();
let mut depth = 0;
while !rtokens.is_empty() {
let t = rtokens.pop().unwrap();
let typ = lookup_word(&t.text, &t.loc());
if typ == OpType::Keyword(KeywordType::End) && depth == 0 {
break;
} else if typ == OpType::Keyword(KeywordType::End) && depth != 0 {
depth -= 1;
code.push(t);
} else if typ == OpType::Keyword(KeywordType::If) || typ == OpType::Keyword(KeywordType::Do) {
code.push(t);
depth += 1;
} else {
code.push(t);
}
}
let res = precompile(&code)?;
if res.len() != 1 {
lerror!(&token.loc(), "Expected 1 number, got {:?}", res);
return Err(eyre!(""));
}
token.value = Some(res[0]);
token.addr = Some(memories.len());
program.push(token);
memories.insert(memory_name.text, memories.len());
} }
_ => { _ => {
program.push(token); program.push(token);
@ -131,7 +188,7 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
//* i wanna kms //* i wanna kms
let mut times = 0; let mut times = 0;
while program.iter().map(|f| { while program.iter().map(|f| {
if f.typ == TokenType::Word { if f.typ == TokenType::Word && f.op_typ != InstructionType::MemUse {
lookup_word(&f.text, &f.loc()) lookup_word(&f.text, &f.loc())
} else { } else {
OpType::Instruction(InstructionType::PushInt) // i hate myself, this is a randomly picked optype so its happy and works OpType::Instruction(InstructionType::PushInt) // i hate myself, this is a randomly picked optype so its happy and works
@ -143,7 +200,7 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
warn!("File import depth maxed out, if the program crashes try reducing the import depth, good luck youll need it"); warn!("File import depth maxed out, if the program crashes try reducing the import depth, good luck youll need it");
break break
} }
program = expand_macros(program, &macros)?; program = expand(program, &macros, &memories)?;
times += 1; times += 1;
} }
@ -151,7 +208,7 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
Ok(program) Ok(program)
} }
pub fn expand_macros(tokens: Vec<Token>, macros: &HashMap<String, Macro>) -> Result<Vec<Token>> { pub fn expand(tokens: Vec<Token>, macros: &Macros, mems: &Memories) -> Result<Vec<Token>> {
let mut program: Vec<Token> = Vec::new(); let mut program: Vec<Token> = Vec::new();
let mut rtokens = tokens; let mut rtokens = tokens;
@ -164,11 +221,17 @@ pub fn expand_macros(tokens: Vec<Token>, macros: &HashMap<String, Macro>) -> Res
match op_type { match op_type {
OpType::Instruction(InstructionType::None) => { OpType::Instruction(InstructionType::None) => {
let m = macros.get(&op.text); let m = macros.get(&op.text);
if m.is_some() { let mem = mems.get(&op.text);
if let Some(m) = m { if let Some(m) = m {
program.append(&mut m.tokens.clone()); program.append(&mut m.tokens.clone());
} } else
} else { if let Some(mem) = mem {
let mut t = op;
t.addr = Some(*mem);
t.op_typ = InstructionType::MemUse;
program.push(t);
}
else {
lerror!(&op.loc(), "Unknown word '{}'", op.text.clone()); lerror!(&op.loc(), "Unknown word '{}'", op.text.clone());
return Err(eyre!("")); return Err(eyre!(""));
} }

View File

@ -1,9 +1,15 @@
use crate::{constants::{Operator, Types, OpType, KeywordType, InstructionType}, Args, lerror}; use crate::{constants::{Operator, Types, OpType, KeywordType, InstructionType}, Args, lerror, warn};
use color_eyre::Result; use color_eyre::Result;
use eyre::eyre; use eyre::eyre;
pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{ pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
if args.unsaf {
if !args.quiet {
warn!("Unsafe mode enabled, disabling typechecker, goodluck");
}
return Ok(ops.to_vec());
}
let mut stack: Vec<Types> = Vec::new(); let mut stack: Vec<Types> = Vec::new();
@ -13,25 +19,17 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
match keyword { match keyword {
KeywordType::If => { KeywordType::If => {
stack_pop(&mut stack, &op, &[Types::Bool])?; stack_pop(&mut stack, &op, &[Types::Bool])?;
},
KeywordType::Else => {
},
KeywordType::End => {
},
KeywordType::While => {
}, },
KeywordType::Do => { KeywordType::Do => {
stack_pop(&mut stack, &op, &[Types::Bool])?; stack_pop(&mut stack, &op, &[Types::Bool])?;
}, },
KeywordType::Macro => {
}, KeywordType::Else |
KeywordType::Include => { KeywordType::End |
KeywordType::While |
}, KeywordType::Macro |
KeywordType::Include |
KeywordType::Memory => (),
} }
}, },
OpType::Instruction(instruction) => { OpType::Instruction(instruction) => {
@ -218,6 +216,9 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?;
stack.push(Types::Int); stack.push(Types::Int);
}, },
InstructionType::MemUse => {
stack.push(Types::Ptr);
},
InstructionType::None => {}, InstructionType::None => {},
} }
}, },

View File

@ -1,3 +1,6 @@
include "./asd.mcl" memory m 10 end
1 test m 69 store8
m load8 print