implemented local memory
This commit is contained in:
parent
09bccc8079
commit
f5d8b3ebca
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1,2 +1,6 @@
|
|||
/target
|
||||
/a
|
||||
/a
|
||||
|
||||
test
|
||||
test.nasm
|
||||
test.o
|
|
@ -26,7 +26,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
|
||||
let file = fs::File::create(&of_a)?;
|
||||
let mut writer = BufWriter::new(&file);
|
||||
|
||||
let mut memories: Vec<(usize, usize)> = Vec::new();
|
||||
// println!("{}", tokens.len());
|
||||
let mut strings: Vec<String> = Vec::new();
|
||||
|
||||
|
@ -373,6 +373,11 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
writeln!(writer, " push rax")?;
|
||||
ti += 1;
|
||||
},
|
||||
InstructionType::MemUse => {
|
||||
writeln!(writer, " ;; -- MemUse")?;
|
||||
writeln!(writer, " push mem_{}", token.addr.unwrap())?;
|
||||
ti += 1;
|
||||
},
|
||||
InstructionType::None => unreachable!(),
|
||||
InstructionType::CastBool => ti += 1,
|
||||
InstructionType::CastPtr => ti += 1,
|
||||
|
@ -415,6 +420,10 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
}
|
||||
ti += 1;
|
||||
},
|
||||
KeywordType::Memory => {
|
||||
memories.push((token.addr.unwrap(), token.value));
|
||||
ti += 1;
|
||||
}
|
||||
KeywordType::Macro |
|
||||
KeywordType::Include
|
||||
=> unreachable!()
|
||||
|
@ -432,9 +441,12 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
let s_list = s_chars.join(",");
|
||||
writeln!(writer, " str_{}: db {} ; {}", i, s_list, s.escape_default())?;
|
||||
}
|
||||
|
||||
|
||||
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()?;
|
||||
linux_x86_64_compile_and_link(&of_a, &of_o, &of_c, args.quiet)?;
|
||||
|
|
125
src/constants.rs
125
src/constants.rs
|
@ -4,7 +4,7 @@ pub const ALLOW_MACRO_REDEFINITION: bool = true;
|
|||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum InstructionType {
|
||||
|
||||
|
||||
// stack
|
||||
PushInt,
|
||||
PushStr,
|
||||
|
@ -30,13 +30,13 @@ pub enum InstructionType {
|
|||
Shl, // <<
|
||||
DivMod, // /
|
||||
Mul,
|
||||
|
||||
|
||||
|
||||
|
||||
// mem
|
||||
Mem,
|
||||
Load8,
|
||||
Store8,
|
||||
|
||||
|
||||
// syscalls
|
||||
Syscall0,
|
||||
Syscall1,
|
||||
|
@ -48,8 +48,9 @@ pub enum InstructionType {
|
|||
|
||||
CastBool,
|
||||
CastPtr,
|
||||
CastInt,
|
||||
CastInt,
|
||||
|
||||
MemUse,
|
||||
None // Used for macros and any other non built in word definitions
|
||||
|
||||
}
|
||||
|
@ -62,6 +63,7 @@ pub enum KeywordType {
|
|||
Do,
|
||||
Macro,
|
||||
Include,
|
||||
Memory
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -77,7 +79,7 @@ pub struct Operator{
|
|||
pub text: String, //? only used for OpType::PushStr
|
||||
pub addr: Option<usize>, //? only used for OpType::PushStr
|
||||
pub jmp: usize,
|
||||
pub loc: (String, usize, usize)
|
||||
pub loc: Loc
|
||||
}
|
||||
|
||||
impl Operator {
|
||||
|
@ -91,55 +93,71 @@ impl Operator {
|
|||
loc: (file, row, col)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_addr(mut self, addr: usize) -> Self {
|
||||
self.addr = Some(addr);
|
||||
self
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl OpType {
|
||||
pub fn human(&self) -> String {
|
||||
match *self {
|
||||
OpType::Instruction(InstructionType::PushInt) => "Number",
|
||||
OpType::Instruction(InstructionType::PushStr) => "String",
|
||||
OpType::Instruction(InstructionType::Print) => "print",
|
||||
OpType::Instruction(InstructionType::Dup) => "dup",
|
||||
OpType::Instruction(InstructionType::Drop) => "drop",
|
||||
OpType::Instruction(InstructionType::Rot) => "rot",
|
||||
OpType::Instruction(InstructionType::Over) => "over",
|
||||
OpType::Instruction(InstructionType::Swap) => "swap",
|
||||
OpType::Instruction(InstructionType::Plus) => "+",
|
||||
OpType::Instruction(InstructionType::Minus) => "-",
|
||||
OpType::Instruction(InstructionType::Equals) => "=",
|
||||
OpType::Instruction(InstructionType::Gt) => ">",
|
||||
OpType::Instruction(InstructionType::Lt) => "<",
|
||||
OpType::Instruction(InstructionType::NotEquals) => "!=",
|
||||
OpType::Instruction(InstructionType::Le) => "<=",
|
||||
OpType::Instruction(InstructionType::Ge) => ">=",
|
||||
OpType::Instruction(InstructionType::Band) => "band",
|
||||
OpType::Instruction(InstructionType::Bor) => "bor",
|
||||
OpType::Instruction(InstructionType::Shr) => "shr",
|
||||
OpType::Instruction(InstructionType::Shl) => "shl",
|
||||
OpType::Instruction(InstructionType::DivMod) => "divmod",
|
||||
OpType::Instruction(InstructionType::Mul) => "*",
|
||||
OpType::Keyword(KeywordType::If) => "if",
|
||||
OpType::Keyword(KeywordType::Else) => "else",
|
||||
OpType::Keyword(KeywordType::End) => "end",
|
||||
OpType::Keyword(KeywordType::While) => "while",
|
||||
OpType::Keyword(KeywordType::Do) => "do",
|
||||
OpType::Keyword(KeywordType::Macro) => "macro",
|
||||
OpType::Keyword(KeywordType::Include) => "include",
|
||||
OpType::Instruction(InstructionType::Mem) => "mem",
|
||||
OpType::Instruction(InstructionType::Load8) => "!8",
|
||||
OpType::Instruction(InstructionType::Store8) => "@8",
|
||||
OpType::Instruction(InstructionType::Syscall0) => "syscall0",
|
||||
OpType::Instruction(InstructionType::Syscall1) => "syscall1",
|
||||
OpType::Instruction(InstructionType::Syscall2) => "syscall2",
|
||||
OpType::Instruction(InstructionType::Syscall3) => "syscall3",
|
||||
OpType::Instruction(InstructionType::Syscall4) => "syscall4",
|
||||
OpType::Instruction(InstructionType::Syscall5) => "syscall5",
|
||||
OpType::Instruction(InstructionType::Syscall6) => "syscall6",
|
||||
OpType::Instruction(InstructionType::CastBool) => "cast(bool",
|
||||
OpType::Instruction(InstructionType::CastPtr) => "cast(ptr)",
|
||||
OpType::Instruction(InstructionType::CastInt) => "cast(int)",
|
||||
OpType::Instruction(InstructionType::None) => "None",
|
||||
match (*self).clone() {
|
||||
OpType::Instruction(instruction) => {
|
||||
match instruction {
|
||||
|
||||
InstructionType::PushInt => "Number",
|
||||
InstructionType::PushStr => "String",
|
||||
InstructionType::Print => "print",
|
||||
InstructionType::Dup => "dup",
|
||||
InstructionType::Drop => "drop",
|
||||
InstructionType::Rot => "rot",
|
||||
InstructionType::Over => "over",
|
||||
InstructionType::Swap => "swap",
|
||||
InstructionType::Plus => "+",
|
||||
InstructionType::Minus => "-",
|
||||
InstructionType::Equals => "=",
|
||||
InstructionType::Gt => ">",
|
||||
InstructionType::Lt => "<",
|
||||
InstructionType::NotEquals => "!=",
|
||||
InstructionType::Le => "<=",
|
||||
InstructionType::Ge => ">=",
|
||||
InstructionType::Band => "band",
|
||||
InstructionType::Bor => "bor",
|
||||
InstructionType::Shr => "shr",
|
||||
InstructionType::Shl => "shl",
|
||||
InstructionType::DivMod => "divmod",
|
||||
InstructionType::Mul => "*",
|
||||
InstructionType::Mem => "mem",
|
||||
InstructionType::Load8 => "!8",
|
||||
InstructionType::Store8 => "@8",
|
||||
InstructionType::Syscall0 => "syscall0",
|
||||
InstructionType::Syscall1 => "syscall1",
|
||||
InstructionType::Syscall2 => "syscall2",
|
||||
InstructionType::Syscall3 => "syscall3",
|
||||
InstructionType::Syscall4 => "syscall4",
|
||||
InstructionType::Syscall5 => "syscall5",
|
||||
InstructionType::Syscall6 => "syscall6",
|
||||
InstructionType::CastBool => "cast(bool",
|
||||
InstructionType::CastPtr => "cast(ptr)",
|
||||
InstructionType::CastInt => "cast(int)",
|
||||
InstructionType::MemUse => "MemUse",
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +168,10 @@ pub struct Token {
|
|||
pub line: usize,
|
||||
pub col: usize,
|
||||
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)]
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::{constants::{OpType, Loc, InstructionType, KeywordType}, lerror, error};
|
||||
// use crate::util::logger;
|
||||
use color_eyre::Result;
|
||||
|
@ -16,6 +18,8 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
|
|||
let mut ti = 0;
|
||||
let mut mem: Vec<u8> = vec![0; crate::compile::MEM_SZ + crate::compile::STRING_SZ];
|
||||
let mut string_idx = 0;
|
||||
|
||||
let mut memories: HashMap<usize, usize> = HashMap::new();
|
||||
// for token in &tokens {
|
||||
// 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 => {
|
||||
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];
|
||||
stack.push(byte as usize);
|
||||
ti += 1;
|
||||
|
@ -108,7 +116,12 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
|
|||
InstructionType::Store8 => {
|
||||
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 & 0xFF) as u8;
|
||||
ti += 1;
|
||||
}
|
||||
|
@ -246,39 +259,53 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
|
|||
todo!();
|
||||
// ti += 1;
|
||||
},
|
||||
InstructionType::MemUse => {
|
||||
|
||||
let m = memories.get(&token.addr.unwrap()).unwrap();
|
||||
stack.push(*m);
|
||||
ti += 1;
|
||||
},
|
||||
InstructionType::CastBool => ti += 1,
|
||||
InstructionType::CastPtr => ti += 1,
|
||||
InstructionType::CastInt => ti += 1,
|
||||
InstructionType::None => unreachable!()
|
||||
InstructionType::None => unreachable!(),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// blocks
|
||||
OpType::Keyword(KeywordType::If) => {
|
||||
let a = stack_pop(&mut stack, &pos)?;
|
||||
if a == 0 {
|
||||
// println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp);
|
||||
ti = token.jmp;
|
||||
} else {
|
||||
ti += 1;
|
||||
}
|
||||
},
|
||||
OpType::Keyword(KeywordType::Else) | OpType::Keyword(KeywordType::End) => {
|
||||
ti = token.jmp;
|
||||
}
|
||||
OpType::Keyword(KeywordType::While) => {
|
||||
ti += 1;
|
||||
}
|
||||
OpType::Keyword(KeywordType::Do) => {
|
||||
let a = stack.pop().unwrap();
|
||||
if a == 0 {
|
||||
ti = token.jmp;
|
||||
} else {
|
||||
ti += 1;
|
||||
OpType::Keyword(k) => {
|
||||
match k {
|
||||
// blocks
|
||||
KeywordType::If => {
|
||||
let a = stack_pop(&mut stack, &pos)?;
|
||||
if a == 0 {
|
||||
// println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp);
|
||||
ti = token.jmp;
|
||||
} else {
|
||||
ti += 1;
|
||||
}
|
||||
},
|
||||
KeywordType::Else | KeywordType::End => {
|
||||
ti = token.jmp;
|
||||
}
|
||||
KeywordType::While => {
|
||||
ti += 1;
|
||||
}
|
||||
KeywordType::Do => {
|
||||
let a = stack.pop().unwrap();
|
||||
if a == 0 {
|
||||
ti = token.jmp;
|
||||
} 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!()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -108,7 +108,10 @@ pub fn lex<S: Into<String> + std::marker::Copy>(code: &str, file: S, args: &Args
|
|||
line: row + 1,
|
||||
col,
|
||||
text: tok,
|
||||
typ: tok_type
|
||||
typ: tok_type,
|
||||
value: None,
|
||||
addr: None,
|
||||
op_typ: crate::constants::InstructionType::None
|
||||
};
|
||||
tokens.push(t);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ mod parser;
|
|||
mod lexer;
|
||||
mod preprocessor;
|
||||
mod typechecker;
|
||||
mod precompiler;
|
||||
|
||||
use std::fs;
|
||||
|
||||
|
@ -17,6 +18,8 @@ pub const DEFAULT_INCLUDES: [&str;2] = [
|
|||
"~/.mclang/include",
|
||||
];
|
||||
|
||||
|
||||
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct Args {
|
||||
|
@ -48,6 +51,9 @@ pub struct Args {
|
|||
#[arg(long, short='I')]
|
||||
include: Vec<String>,
|
||||
|
||||
/// Unsafe mode, disables typechecking
|
||||
#[arg(long="unsafe", default_value_t = false)]
|
||||
unsaf: bool
|
||||
|
||||
//#[arg(long, short='F')]
|
||||
//features: Vec<String>,
|
||||
|
|
|
@ -79,8 +79,13 @@ impl Parser {
|
|||
let pos = (token.file.clone(), token.line, token.col);
|
||||
match token.typ {
|
||||
TokenType::Word => {
|
||||
let word_type = lookup_word(&token.text, &pos);
|
||||
tokens.push(Operator::new(word_type, 0, token.text.clone(), token.file.clone(), token.line, token.col));
|
||||
let word_type = if token.op_typ == InstructionType::MemUse {
|
||||
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
|
||||
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 {
|
||||
let n = s.parse::<usize>();
|
||||
if let Ok(_) = n {
|
||||
return OpType::Instruction(InstructionType::PushInt);
|
||||
}
|
||||
match s {
|
||||
//stack
|
||||
"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),
|
||||
"*" => 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" => OpType::Instruction(InstructionType::Mem),
|
||||
"!8" => OpType::Instruction(InstructionType::Load8),
|
||||
"@8" => OpType::Instruction(InstructionType::Store8),
|
||||
|
||||
"load8" => OpType::Instruction(InstructionType::Load8),
|
||||
"store8" => OpType::Instruction(InstructionType::Store8),
|
||||
|
||||
"syscall0" => OpType::Instruction(InstructionType::Syscall0),
|
||||
"syscall1" => OpType::Instruction(InstructionType::Syscall1),
|
||||
"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(ptr)" => OpType::Instruction(InstructionType::CastPtr),
|
||||
"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)
|
||||
}
|
||||
|
||||
|
|
154
src/precompiler.rs
Normal file
154
src/precompiler.rs
Normal 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)
|
||||
}
|
|
@ -6,7 +6,8 @@ use eyre::eyre;
|
|||
|
||||
use crate::constants::{Token, Loc, OpType, TokenType, KeywordType, InstructionType};
|
||||
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;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -15,14 +16,20 @@ pub struct Macro {
|
|||
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>>{
|
||||
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;
|
||||
rtokens.reverse();
|
||||
while !rtokens.is_empty() {
|
||||
let token = rtokens.pop().unwrap();
|
||||
let mut token = rtokens.pop().unwrap();
|
||||
|
||||
let op_type = lookup_word(&token.text, &token.loc());
|
||||
match token.clone() {
|
||||
|
@ -66,7 +73,6 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
|
|||
} else {
|
||||
macr.tokens.push(t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -120,6 +126,57 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
|
|||
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);
|
||||
|
@ -131,7 +188,7 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
|
|||
//* i wanna kms
|
||||
let mut times = 0;
|
||||
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())
|
||||
} else {
|
||||
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");
|
||||
break
|
||||
}
|
||||
program = expand_macros(program, ¯os)?;
|
||||
program = expand(program, ¯os, &memories)?;
|
||||
times += 1;
|
||||
}
|
||||
|
||||
|
@ -151,7 +208,7 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<Vec<Token>>{
|
|||
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 rtokens = tokens;
|
||||
|
@ -164,11 +221,17 @@ pub fn expand_macros(tokens: Vec<Token>, macros: &HashMap<String, Macro>) -> Res
|
|||
match op_type {
|
||||
OpType::Instruction(InstructionType::None) => {
|
||||
let m = macros.get(&op.text);
|
||||
if m.is_some() {
|
||||
if let Some(m) = m {
|
||||
program.append(&mut m.tokens.clone());
|
||||
}
|
||||
} else {
|
||||
let mem = mems.get(&op.text);
|
||||
if let Some(m) = m {
|
||||
program.append(&mut m.tokens.clone());
|
||||
} 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());
|
||||
return Err(eyre!(""));
|
||||
}
|
||||
|
|
|
@ -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 eyre::eyre;
|
||||
|
||||
|
||||
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();
|
||||
|
||||
|
@ -13,25 +19,17 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
|
|||
match keyword {
|
||||
KeywordType::If => {
|
||||
stack_pop(&mut stack, &op, &[Types::Bool])?;
|
||||
},
|
||||
KeywordType::Else => {
|
||||
|
||||
},
|
||||
KeywordType::End => {
|
||||
|
||||
},
|
||||
KeywordType::While => {
|
||||
|
||||
},
|
||||
KeywordType::Do => {
|
||||
stack_pop(&mut stack, &op, &[Types::Bool])?;
|
||||
},
|
||||
KeywordType::Macro => {
|
||||
|
||||
},
|
||||
KeywordType::Include => {
|
||||
|
||||
},
|
||||
KeywordType::Else |
|
||||
KeywordType::End |
|
||||
KeywordType::While |
|
||||
KeywordType::Macro |
|
||||
KeywordType::Include |
|
||||
KeywordType::Memory => (),
|
||||
}
|
||||
},
|
||||
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.push(Types::Int);
|
||||
},
|
||||
InstructionType::MemUse => {
|
||||
stack.push(Types::Ptr);
|
||||
},
|
||||
InstructionType::None => {},
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue
Block a user