implemented local memory
This commit is contained in:
parent
09bccc8079
commit
f5d8b3ebca
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,2 +1,6 @@
|
||||||
/target
|
/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 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!()
|
||||||
|
@ -434,7 +443,10 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
||||||
}
|
}
|
||||||
|
|
||||||
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)?;
|
||||||
|
|
113
src/constants.rs
113
src/constants.rs
|
@ -50,6 +50,7 @@ pub enum InstructionType {
|
||||||
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)]
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -109,6 +117,11 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
|
||||||
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,16 +259,23 @@ 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) => {
|
||||||
|
match k {
|
||||||
// blocks
|
// blocks
|
||||||
OpType::Keyword(KeywordType::If) => {
|
KeywordType::If => {
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
let a = stack_pop(&mut stack, &pos)?;
|
||||||
if a == 0 {
|
if a == 0 {
|
||||||
// println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp);
|
// println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp);
|
||||||
|
@ -264,13 +284,13 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
OpType::Keyword(KeywordType::Else) | OpType::Keyword(KeywordType::End) => {
|
KeywordType::Else | KeywordType::End => {
|
||||||
ti = token.jmp;
|
ti = token.jmp;
|
||||||
}
|
}
|
||||||
OpType::Keyword(KeywordType::While) => {
|
KeywordType::While => {
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
OpType::Keyword(KeywordType::Do) => {
|
KeywordType::Do => {
|
||||||
let a = stack.pop().unwrap();
|
let a = stack.pop().unwrap();
|
||||||
if a == 0 {
|
if a == 0 {
|
||||||
ti = token.jmp;
|
ti = token.jmp;
|
||||||
|
@ -278,7 +298,14 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| OpType::Keyword(KeywordType::Macro) | OpType::Keyword(KeywordType::Include) => unreachable!()
|
KeywordType::Memory => {
|
||||||
|
memories.insert(token.addr.unwrap(), token.value);
|
||||||
|
ti += 1;
|
||||||
|
},
|
||||||
|
KeywordType::Macro | 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,
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -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,19 +144,11 @@ 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),
|
||||||
|
@ -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
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::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 program: Vec<Token> = Vec::new();
|
||||||
let mut macros: HashMap<String, Macro> = HashMap::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, ¯os)?;
|
program = expand(program, ¯os, &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
|
||||||
|
if let Some(mem) = mem {
|
||||||
|
let mut t = op;
|
||||||
|
t.addr = Some(*mem);
|
||||||
|
t.op_typ = InstructionType::MemUse;
|
||||||
|
program.push(t);
|
||||||
}
|
}
|
||||||
} else {
|
else {
|
||||||
lerror!(&op.loc(), "Unknown word '{}'", op.text.clone());
|
lerror!(&op.loc(), "Unknown word '{}'", op.text.clone());
|
||||||
return Err(eyre!(""));
|
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 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 => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue
Block a user