From ee1418c67386d8f437e40954da5b26cc84b1ebd1 Mon Sep 17 00:00:00 2001 From: Servostar Date: Thu, 1 Dec 2022 00:34:34 +0100 Subject: [PATCH] fixed variable store --- src/main.rs | 39 ++---- src/vmrt/mod.rs | 332 +++++++++++++++++++++++++++++++++++++-------- src/vmrt/output.rs | 20 +++ 3 files changed, 301 insertions(+), 90 deletions(-) create mode 100644 src/vmrt/output.rs diff --git a/src/main.rs b/src/main.rs index ddb7201..eb2e3f7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,38 +23,15 @@ where fn main() { let source = r" -# surely this is pi -pi = rat 5.1415926535 -foo(x:int, y:rat) = bool { - x:int = 5 + 6 - - unless (x < 6) { - yield true - - please { - - } - - unless(x < 6) { - yield true - } - } - - -- comment - yield true +foo(x:int) = int { + x / 2 } main() = int { - - a = 4 - b = pi - c = true - r = foo(3, 4.0) - h = foo(3,5.0) - b:int = 4 - - 9 + a = foo(4) + + a } "; @@ -64,8 +41,10 @@ main() = int { if let Ok(mut tokens) = tokenize(source, &mut diagnostics) { if let Ok((fs, ds)) = parse(&mut tokens, &mut diagnostics, &settings) { - if let Ok(prog) = vmrt::compile(&fs, &ds) { - vmrt::execute(&prog); + if let Ok(prog) = vmrt::compile(&fs, &ds, &settings) { + if let Ok(exit_code) = vmrt::execute(&prog) { + crate::message(MessageType::Info, format!("Program exited with {}", exit_code)); + } } } } diff --git a/src/vmrt/mod.rs b/src/vmrt/mod.rs index b62062b..91f5ae7 100644 --- a/src/vmrt/mod.rs +++ b/src/vmrt/mod.rs @@ -1,6 +1,11 @@ -use std::collections::{VecDeque, HashMap}; +mod output; -use crate::{parser::data::*, token::{Token, NumHint, Prim}}; +use std::collections::{HashMap, VecDeque}; + +use crate::{ + parser::data::*, + token::{NumHint, Prim, Token}, +}; #[derive(Debug, Clone, Copy)] enum Data { @@ -10,6 +15,29 @@ enum Data { Off(u64), } +impl Data { + fn to_int(&self) -> Result { + return match self { + Data::Int(v) => Ok(*v), + _ => Err(()), + }; + } + + fn to_float(&self) -> Result { + return match self { + Data::Rat(v) => Ok(*v), + _ => Err(()), + }; + } + + fn to_bool(&self) -> Result { + return match self { + Data::Bool(v) => Ok(*v), + _ => Err(()), + }; + } +} + #[derive(Debug)] enum IntOp { CmpEq, @@ -22,7 +50,7 @@ enum IntOp { Add, Sub, Mul, - Div + Div, } #[derive(Debug)] @@ -37,24 +65,24 @@ enum RatOp { Add, Sub, Mul, - Div + Div, } #[derive(Debug)] enum BoolOp { CmpEq, CmpNEq, - + And, Or, - Xor + Xor, } #[derive(Debug)] enum Operation { Int(IntOp), Rat(RatOp), - Bool(BoolOp) + Bool(BoolOp), } #[derive(Debug)] @@ -63,7 +91,7 @@ enum Instr { Push(Data), /// delete the last value from stack Pop, - + /// push the value stored at offset from the local stack onto the local stack Load(usize), /// store the value stored at the stack[0](offset) stack[1](value) onto the stack @@ -75,14 +103,11 @@ enum Instr { Operation(Operation), - Exit + Exit, } - /// function stack layout /// +----------------------------------+ -/// | Return address | -/// +----------------------------------+ /// | Parameter (0) | /// +----------------------------------+ /// | Parameter (1) | @@ -92,14 +117,17 @@ enum Instr { /// | Parameter (n) | /// +----------------------------------+ struct Proc { + // executable code code: Vec, + // number of expected arguments args: usize, + // hashed declaration is used as "address" addr: u64, } #[derive(Default)] pub struct Program { - code: HashMap + procs: HashMap, } #[derive(Default)] @@ -108,35 +136,40 @@ struct Compiletime<'a> { stacksize: usize, } -fn parse_term<'a>(term: &VecDeque>, x: usize, declr: &Vec>, ct: &mut Compiletime<'a>, code: &mut Vec) -> Result<(), ()>{ +fn parse_term<'a>( + term: &VecDeque>, + x: usize, + declr: &Vec>, + ct: &mut Compiletime<'a>, + code: &mut Vec, +) -> Result<(), ()> { for token in term.iter() { let instr = match token { Token::Number(value, hint, _) => { code.push(Instr::Push(match hint { - NumHint::Int => Data::Int(value.parse::().unwrap()), - NumHint::Rat => Data::Rat(value.parse::().unwrap()), - })); + NumHint::Int => Data::Int(value.parse::().unwrap()), + NumHint::Rat => Data::Rat(value.parse::().unwrap()), + })); ct.stacksize += 1; - }, - Token::Bool(value, _) => { + } + Token::Bool(value, _) => { code.push(Instr::Push(Data::Bool(*value))); ct.stacksize += 1; - }, + } Token::Arg(name, _) => { let off = declr[x].get_arg_ord(name); - code.push(Instr::Load(off + 1)); + code.push(Instr::Load(off)); ct.stacksize += 1; - }, + } Token::Assign(name, _, _) => { ct.vartable.insert(name.clone(), ct.stacksize - 1); - }, + } Token::Var(name, _) => { code.push(Instr::Load(*ct.vartable.get(name).unwrap())); ct.stacksize += 1; } Token::Operator(op, hint, _) => { - code.push(match op { crate::token::Operator::Or => Instr::Operation(Operation::Bool(BoolOp::Or)), crate::token::Operator::And => Instr::Operation(Operation::Bool(BoolOp::And)), @@ -145,96 +178,112 @@ fn parse_term<'a>(term: &VecDeque>, x: usize, declr: &Vec>, crate::token::Operator::Add => match hint.unwrap() { Prim::Int => Instr::Operation(Operation::Int(IntOp::Add)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Add)), - _ => panic!() + _ => panic!(), }, crate::token::Operator::Sub => match hint.unwrap() { Prim::Int => Instr::Operation(Operation::Int(IntOp::Sub)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Sub)), - _ => panic!() + _ => panic!(), }, crate::token::Operator::Mul => match hint.unwrap() { Prim::Int => Instr::Operation(Operation::Int(IntOp::Mul)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Mul)), - _ => panic!() + _ => panic!(), }, crate::token::Operator::Div => match hint.unwrap() { Prim::Int => Instr::Operation(Operation::Int(IntOp::Div)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Div)), - _ => panic!() + _ => panic!(), }, - + crate::token::Operator::Eq => match hint.unwrap() { Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpEq)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpEq)), Prim::Bool => Instr::Operation(Operation::Bool(BoolOp::CmpEq)), - _ => panic!() + _ => panic!(), }, crate::token::Operator::NotEq => match hint.unwrap() { Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpNEq)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpNEq)), Prim::Bool => Instr::Operation(Operation::Bool(BoolOp::CmpNEq)), - _ => panic!() + _ => panic!(), }, crate::token::Operator::Lt => match hint.unwrap() { Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpLt)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpLt)), - _ => panic!() + _ => panic!(), }, crate::token::Operator::Gt => match hint.unwrap() { Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpGt)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpGt)), - _ => panic!() + _ => panic!(), }, crate::token::Operator::GtEq => match hint.unwrap() { Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpGtEq)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpGtEq)), - _ => panic!() + _ => panic!(), }, crate::token::Operator::LtEq => match hint.unwrap() { Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpLtEq)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpLtEq)), - _ => panic!() + _ => panic!(), }, crate::token::Operator::Assign => { - crate::message(crate::token::MessageType::Critical, format!("Invalid operator: {:?}", op)); + crate::message( + crate::token::MessageType::Critical, + format!("Invalid operator: {:?}", op), + ); return Err(()); } }); - - // TODO: operatiors - // we pop 2 values as arguments and push 1 as result (-2 + 1 = 1) + ct.stacksize -= 1; - }, + } Token::Func(name, _) => { for decl in declr.iter() { if decl.name.as_ref().unwrap() == name { - code.push(Instr::Call(decl.uuid())) + code.push(Instr::Call(decl.uuid())); + + if decl.results { + ct.stacksize += 1; + } } } } - Token::Keyword(keyword, _) => { - match keyword { - crate::token::Keyword::Yield | crate::token::Keyword::Return => code.push(Instr::Return), - _ => () + Token::Keyword(keyword, _) => match keyword { + crate::token::Keyword::Yield | crate::token::Keyword::Return => { + code.push(Instr::Return) } - } - + _ => (), + }, - _ => () + _ => (), }; } Ok(()) } -fn parse_block<'a>(block: &VecDeque>, x: usize, declr: &Vec>, ct: &mut Compiletime<'a>, prog: &mut Vec) -> Result<(), ()> { +fn parse_block<'a>( + block: &VecDeque>, + x: usize, + declr: &Vec>, + ct: &mut Compiletime<'a>, + prog: &mut Vec, +) -> Result<(), ()> { for expr in block.iter() { compile_expr(expr, x, declr, ct, prog)?; } Ok(()) } -fn compile_expr<'a>(expr: &Expr<'a>, x: usize, declr: &Vec>, ct: &mut Compiletime<'a>, prog: &mut Vec) -> Result<(), ()> { +fn compile_expr<'a>( + expr: &Expr<'a>, + x: usize, + declr: &Vec>, + ct: &mut Compiletime<'a>, + prog: &mut Vec, +) -> Result<(), ()> { match expr { Expr::Block(block) => parse_block(block, x, declr, ct, prog)?, Expr::Term(term) => parse_term(term, x, declr, ct, prog)?, @@ -243,34 +292,197 @@ fn compile_expr<'a>(expr: &Expr<'a>, x: usize, declr: &Vec>, ct: &mut Ok(()) } -pub fn compile<'a>(funcs: &Vec>, declrs: &Vec>) -> Result { +fn create_proc(declr: &Declr, code: Vec) -> Proc { + Proc { + code, + args: if let Some(args) = &declr.args { + args.len() + } else { + 0 + }, + addr: declr.uuid(), + } +} + +pub fn compile<'a>(funcs: &Vec>, declrs: &Vec>, settings: &crate::conf::Settings) -> Result { let mut prog = Program::default(); for (x, func) in funcs.iter().enumerate() { let mut code = vec![]; let mut ct = Compiletime::default(); - // at beginn the is the return address and the parameter on the stack - ct.stacksize = declrs[x].args.as_ref().unwrap_or(&vec![]).len() + 1; + //at the beginning there are all parameters on the stack + ct.stacksize = declrs[x].args.as_ref().unwrap_or(&vec![]).len(); compile_expr(func.expr.as_ref().unwrap(), x, declrs, &mut ct, &mut code)?; - println!("{:#?}", code); - - prog.code.insert(declrs[x].uuid(), code); + prog.procs + .insert(declrs[x].uuid(), create_proc(&declrs[x], code)); } + + + Ok(prog) } +struct Runtimestack { + stack: Vec, +} + +impl Runtimestack { + pub fn new() -> Runtimestack { + Self { stack: vec![] } + } + + pub fn push(&mut self, data: Data) { + self.stack.push(data); + } + + pub fn pop(&mut self) -> Option { + self.stack.pop() + } + + pub fn peek(&mut self, index: usize) -> Data { + self.stack[index] + } +} + +fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result, ()> { + let mut stack = Runtimestack::new(); + + // build local procedure stack + for i in 0..proc.args { + stack.push(superstack[superstack.len() - i - 1].clone()); + } + + for instr in proc.code.iter() { + match instr { + Instr::Pop => { + stack.pop(); + } + Instr::Return => { + return Ok(stack.pop()); + } + Instr::Push(data) => stack.push(*data), + Instr::Load(offset) => { + let v = stack.peek(*offset); + stack.push(v); + }, + Instr::Call(addr) => { + if let Some(value) = call_fn(prog, prog.procs.get(addr).unwrap(), &stack.stack)? { + stack.push(value); + } + }, + Instr::Operation(op) => { + let op0:Data = if let Some(data) = stack.pop() { + data + } else { + return Err(()); + }; + let op1:Data = if let Some(data) = stack.pop() { + data + } else { + return Err(()); + }; + + match op { + Operation::Int(op) => match op { + IntOp::Add => stack.push(Data::Int(op1.to_int()? + op0.to_int()?)), + IntOp::Sub => stack.push(Data::Int(op1.to_int()? - op0.to_int()?)), + IntOp::Mul => stack.push(Data::Int(op1.to_int()? * op0.to_int()?)), + IntOp::Div => stack.push(Data::Int(op1.to_int()? / op0.to_int()?)), + + IntOp::CmpEq => { + stack.push(Data::Bool(op1.to_int()? == op0.to_int()?)) + } + IntOp::CmpNEq => { + stack.push(Data::Bool(op1.to_int()? != op0.to_int()?)) + } + IntOp::CmpLt => stack.push(Data::Bool(op1.to_int()? < op0.to_int()?)), + IntOp::CmpGt => stack.push(Data::Bool(op1.to_int()? > op0.to_int()?)), + IntOp::CmpGtEq => { + stack.push(Data::Bool(op1.to_int()? <= op0.to_int()?)) + } + IntOp::CmpLtEq => { + stack.push(Data::Bool(op1.to_int()? >= op0.to_int()?)) + } + }, + Operation::Rat(op) => match op { + RatOp::Add => { + stack.push(Data::Rat(op1.to_float()? + op0.to_float()?)) + } + RatOp::Sub => { + stack.push(Data::Rat(op1.to_float()? - op0.to_float()?)) + } + RatOp::Mul => { + stack.push(Data::Rat(op1.to_float()? * op0.to_float()?)) + } + RatOp::Div => { + stack.push(Data::Rat(op1.to_float()? / op0.to_float()?)) + } + + RatOp::CmpEq => { + stack.push(Data::Bool(op1.to_float()? == op0.to_float()?)) + } + RatOp::CmpNEq => { + stack.push(Data::Bool(op1.to_float()? != op0.to_float()?)) + } + RatOp::CmpLt => { + stack.push(Data::Bool(op1.to_float()? < op0.to_float()?)) + } + RatOp::CmpGt => { + stack.push(Data::Bool(op1.to_float()? > op0.to_float()?)) + } + RatOp::CmpGtEq => { + stack.push(Data::Bool(op1.to_float()? <= op0.to_float()?)) + } + RatOp::CmpLtEq => { + stack.push(Data::Bool(op1.to_float()? >= op0.to_float()?)) + } + }, + Operation::Bool(op) => match op { + BoolOp::Or => { + stack.push(Data::Bool(op1.to_bool()? || op0.to_bool()?)) + } + BoolOp::And => { + stack.push(Data::Bool(op1.to_bool()? && op0.to_bool()?)) + } + BoolOp::Xor => { + stack.push(Data::Bool(op1.to_bool()? ^ op0.to_bool()?)) + } + BoolOp::CmpEq => { + stack.push(Data::Bool(op1.to_bool()? == op0.to_bool()?)) + } + BoolOp::CmpNEq => { + stack.push(Data::Bool(op1.to_bool()? != op0.to_bool()?)) + } + }, + } + } + _ => (), + } + } + + Ok(stack.pop()) +} + pub fn execute(prog: &Program) -> Result { // declaration of entry function let main_fn_declr = crate::parser::data::Declr::main(); - if let Some(main_fn) = prog.code.get(&main_fn_declr.uuid()) { - - Ok(0) + if let Some(main_fn) = prog.procs.get(&main_fn_declr.uuid()) { + + if let Some(exit_code) = call_fn(prog, main_fn, &[])? { + return Ok(exit_code.to_int()?); + } + + crate::message(crate::token::MessageType::Critical, "main procedure did not return exit code"); + return Err(()); } else { - crate::message(crate::token::MessageType::Critical, "Program has no main() = int function"); + crate::message( + crate::token::MessageType::Critical, + "Program has no main() = int function", + ); return Err(()); } } diff --git a/src/vmrt/output.rs b/src/vmrt/output.rs new file mode 100644 index 0000000..d74631b --- /dev/null +++ b/src/vmrt/output.rs @@ -0,0 +1,20 @@ +use std::io::Write; + +fn print_to_file(file: &mut std::fs::File, prog: &crate::vmrt::Program) -> std::io::Result<()> { + for proc in prog.procs.iter() { + writeln!(file, "\n0x{:#x}:", proc.0)?; + + for instr in proc.1.code.iter() { + writeln!(file, "{}", instr)?; + } + } + Ok(()) +} + +pub fn dump_program(prog: &crate::vmrt::Program) { + let mut file = std::fs::OpenOptions::new().write(true).create(true).truncate(true).open("prog.vsasm").unwrap(); + + if print_to_file(&mut file, prog).is_err() { + + } +}