fixed variable store

This commit is contained in:
Sven Vogel 2022-12-01 00:34:34 +01:00
parent 2d7cf80101
commit ee1418c673
3 changed files with 301 additions and 90 deletions

View File

@ -23,38 +23,15 @@ where
fn main() { fn main() {
let source = r" let source = r"
# surely this is pi
pi = rat 5.1415926535
foo(x:int, y:rat) = bool { foo(x:int) = int {
x:int = 5 + 6 x / 2
unless (x < 6) {
yield true
please {
}
unless(x < 6) {
yield true
}
}
-- comment
yield true
} }
main() = int { main() = int {
a = foo(4)
a = 4
b = pi a
c = true
r = foo(3, 4.0)
h = foo(3,5.0)
b:int = 4
9
} }
"; ";
@ -64,8 +41,10 @@ main() = int {
if let Ok(mut tokens) = tokenize(source, &mut diagnostics) { if let Ok(mut tokens) = tokenize(source, &mut diagnostics) {
if let Ok((fs, ds)) = parse(&mut tokens, &mut diagnostics, &settings) { if let Ok((fs, ds)) = parse(&mut tokens, &mut diagnostics, &settings) {
if let Ok(prog) = vmrt::compile(&fs, &ds) { if let Ok(prog) = vmrt::compile(&fs, &ds, &settings) {
vmrt::execute(&prog); if let Ok(exit_code) = vmrt::execute(&prog) {
crate::message(MessageType::Info, format!("Program exited with {}", exit_code));
}
} }
} }
} }

View File

@ -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)] #[derive(Debug, Clone, Copy)]
enum Data { enum Data {
@ -10,6 +15,29 @@ enum Data {
Off(u64), Off(u64),
} }
impl Data {
fn to_int(&self) -> Result<i64, ()> {
return match self {
Data::Int(v) => Ok(*v),
_ => Err(()),
};
}
fn to_float(&self) -> Result<f64, ()> {
return match self {
Data::Rat(v) => Ok(*v),
_ => Err(()),
};
}
fn to_bool(&self) -> Result<bool, ()> {
return match self {
Data::Bool(v) => Ok(*v),
_ => Err(()),
};
}
}
#[derive(Debug)] #[derive(Debug)]
enum IntOp { enum IntOp {
CmpEq, CmpEq,
@ -22,7 +50,7 @@ enum IntOp {
Add, Add,
Sub, Sub,
Mul, Mul,
Div Div,
} }
#[derive(Debug)] #[derive(Debug)]
@ -37,24 +65,24 @@ enum RatOp {
Add, Add,
Sub, Sub,
Mul, Mul,
Div Div,
} }
#[derive(Debug)] #[derive(Debug)]
enum BoolOp { enum BoolOp {
CmpEq, CmpEq,
CmpNEq, CmpNEq,
And, And,
Or, Or,
Xor Xor,
} }
#[derive(Debug)] #[derive(Debug)]
enum Operation { enum Operation {
Int(IntOp), Int(IntOp),
Rat(RatOp), Rat(RatOp),
Bool(BoolOp) Bool(BoolOp),
} }
#[derive(Debug)] #[derive(Debug)]
@ -63,7 +91,7 @@ enum Instr {
Push(Data), Push(Data),
/// delete the last value from stack /// delete the last value from stack
Pop, Pop,
/// push the value stored at offset from the local stack onto the local stack /// push the value stored at offset from the local stack onto the local stack
Load(usize), Load(usize),
/// store the value stored at the stack[0](offset) stack[1](value) onto the stack /// store the value stored at the stack[0](offset) stack[1](value) onto the stack
@ -75,14 +103,11 @@ enum Instr {
Operation(Operation), Operation(Operation),
Exit Exit,
} }
/// function stack layout /// function stack layout
/// +----------------------------------+ /// +----------------------------------+
/// | Return address |
/// +----------------------------------+
/// | Parameter (0) | /// | Parameter (0) |
/// +----------------------------------+ /// +----------------------------------+
/// | Parameter (1) | /// | Parameter (1) |
@ -92,14 +117,17 @@ enum Instr {
/// | Parameter (n) | /// | Parameter (n) |
/// +----------------------------------+ /// +----------------------------------+
struct Proc { struct Proc {
// executable code
code: Vec<Instr>, code: Vec<Instr>,
// number of expected arguments
args: usize, args: usize,
// hashed declaration is used as "address"
addr: u64, addr: u64,
} }
#[derive(Default)] #[derive(Default)]
pub struct Program { pub struct Program {
code: HashMap<u64, Proc> procs: HashMap<u64, Proc>,
} }
#[derive(Default)] #[derive(Default)]
@ -108,35 +136,40 @@ struct Compiletime<'a> {
stacksize: usize, stacksize: usize,
} }
fn parse_term<'a>(term: &VecDeque<Token<'a>>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut Compiletime<'a>, code: &mut Vec<Instr>) -> Result<(), ()>{ fn parse_term<'a>(
term: &VecDeque<Token<'a>>,
x: usize,
declr: &Vec<Declr<'a>>,
ct: &mut Compiletime<'a>,
code: &mut Vec<Instr>,
) -> Result<(), ()> {
for token in term.iter() { for token in term.iter() {
let instr = match token { let instr = match token {
Token::Number(value, hint, _) => { Token::Number(value, hint, _) => {
code.push(Instr::Push(match hint { code.push(Instr::Push(match hint {
NumHint::Int => Data::Int(value.parse::<i64>().unwrap()), NumHint::Int => Data::Int(value.parse::<i64>().unwrap()),
NumHint::Rat => Data::Rat(value.parse::<f64>().unwrap()), NumHint::Rat => Data::Rat(value.parse::<f64>().unwrap()),
})); }));
ct.stacksize += 1; ct.stacksize += 1;
}, }
Token::Bool(value, _) => { Token::Bool(value, _) => {
code.push(Instr::Push(Data::Bool(*value))); code.push(Instr::Push(Data::Bool(*value)));
ct.stacksize += 1; ct.stacksize += 1;
}, }
Token::Arg(name, _) => { Token::Arg(name, _) => {
let off = declr[x].get_arg_ord(name); let off = declr[x].get_arg_ord(name);
code.push(Instr::Load(off + 1)); code.push(Instr::Load(off));
ct.stacksize += 1; ct.stacksize += 1;
}, }
Token::Assign(name, _, _) => { Token::Assign(name, _, _) => {
ct.vartable.insert(name.clone(), ct.stacksize - 1); ct.vartable.insert(name.clone(), ct.stacksize - 1);
}, }
Token::Var(name, _) => { Token::Var(name, _) => {
code.push(Instr::Load(*ct.vartable.get(name).unwrap())); code.push(Instr::Load(*ct.vartable.get(name).unwrap()));
ct.stacksize += 1; ct.stacksize += 1;
} }
Token::Operator(op, hint, _) => { Token::Operator(op, hint, _) => {
code.push(match op { code.push(match op {
crate::token::Operator::Or => Instr::Operation(Operation::Bool(BoolOp::Or)), crate::token::Operator::Or => Instr::Operation(Operation::Bool(BoolOp::Or)),
crate::token::Operator::And => Instr::Operation(Operation::Bool(BoolOp::And)), crate::token::Operator::And => Instr::Operation(Operation::Bool(BoolOp::And)),
@ -145,96 +178,112 @@ fn parse_term<'a>(term: &VecDeque<Token<'a>>, x: usize, declr: &Vec<Declr<'a>>,
crate::token::Operator::Add => match hint.unwrap() { crate::token::Operator::Add => match hint.unwrap() {
Prim::Int => Instr::Operation(Operation::Int(IntOp::Add)), Prim::Int => Instr::Operation(Operation::Int(IntOp::Add)),
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Add)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Add)),
_ => panic!() _ => panic!(),
}, },
crate::token::Operator::Sub => match hint.unwrap() { crate::token::Operator::Sub => match hint.unwrap() {
Prim::Int => Instr::Operation(Operation::Int(IntOp::Sub)), Prim::Int => Instr::Operation(Operation::Int(IntOp::Sub)),
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Sub)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Sub)),
_ => panic!() _ => panic!(),
}, },
crate::token::Operator::Mul => match hint.unwrap() { crate::token::Operator::Mul => match hint.unwrap() {
Prim::Int => Instr::Operation(Operation::Int(IntOp::Mul)), Prim::Int => Instr::Operation(Operation::Int(IntOp::Mul)),
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Mul)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Mul)),
_ => panic!() _ => panic!(),
}, },
crate::token::Operator::Div => match hint.unwrap() { crate::token::Operator::Div => match hint.unwrap() {
Prim::Int => Instr::Operation(Operation::Int(IntOp::Div)), Prim::Int => Instr::Operation(Operation::Int(IntOp::Div)),
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Div)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Div)),
_ => panic!() _ => panic!(),
}, },
crate::token::Operator::Eq => match hint.unwrap() { crate::token::Operator::Eq => match hint.unwrap() {
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpEq)), Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpEq)),
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpEq)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpEq)),
Prim::Bool => Instr::Operation(Operation::Bool(BoolOp::CmpEq)), Prim::Bool => Instr::Operation(Operation::Bool(BoolOp::CmpEq)),
_ => panic!() _ => panic!(),
}, },
crate::token::Operator::NotEq => match hint.unwrap() { crate::token::Operator::NotEq => match hint.unwrap() {
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpNEq)), Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpNEq)),
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpNEq)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpNEq)),
Prim::Bool => Instr::Operation(Operation::Bool(BoolOp::CmpNEq)), Prim::Bool => Instr::Operation(Operation::Bool(BoolOp::CmpNEq)),
_ => panic!() _ => panic!(),
}, },
crate::token::Operator::Lt => match hint.unwrap() { crate::token::Operator::Lt => match hint.unwrap() {
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpLt)), Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpLt)),
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpLt)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpLt)),
_ => panic!() _ => panic!(),
}, },
crate::token::Operator::Gt => match hint.unwrap() { crate::token::Operator::Gt => match hint.unwrap() {
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpGt)), Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpGt)),
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpGt)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpGt)),
_ => panic!() _ => panic!(),
}, },
crate::token::Operator::GtEq => match hint.unwrap() { crate::token::Operator::GtEq => match hint.unwrap() {
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpGtEq)), Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpGtEq)),
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpGtEq)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpGtEq)),
_ => panic!() _ => panic!(),
}, },
crate::token::Operator::LtEq => match hint.unwrap() { crate::token::Operator::LtEq => match hint.unwrap() {
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpLtEq)), Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpLtEq)),
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpLtEq)), Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpLtEq)),
_ => panic!() _ => panic!(),
}, },
crate::token::Operator::Assign => { 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(()); return Err(());
} }
}); });
// TODO: operatiors
// we pop 2 values as arguments and push 1 as result (-2 + 1 = 1)
ct.stacksize -= 1; ct.stacksize -= 1;
}, }
Token::Func(name, _) => { Token::Func(name, _) => {
for decl in declr.iter() { for decl in declr.iter() {
if decl.name.as_ref().unwrap() == name { 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, _) => { Token::Keyword(keyword, _) => match keyword {
match keyword { crate::token::Keyword::Yield | crate::token::Keyword::Return => {
crate::token::Keyword::Yield | crate::token::Keyword::Return => code.push(Instr::Return), code.push(Instr::Return)
_ => ()
} }
} _ => (),
},
_ => () _ => (),
}; };
} }
Ok(()) Ok(())
} }
fn parse_block<'a>(block: &VecDeque<Expr<'a>>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut Compiletime<'a>, prog: &mut Vec<Instr>) -> Result<(), ()> { fn parse_block<'a>(
block: &VecDeque<Expr<'a>>,
x: usize,
declr: &Vec<Declr<'a>>,
ct: &mut Compiletime<'a>,
prog: &mut Vec<Instr>,
) -> Result<(), ()> {
for expr in block.iter() { for expr in block.iter() {
compile_expr(expr, x, declr, ct, prog)?; compile_expr(expr, x, declr, ct, prog)?;
} }
Ok(()) Ok(())
} }
fn compile_expr<'a>(expr: &Expr<'a>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut Compiletime<'a>, prog: &mut Vec<Instr>) -> Result<(), ()> { fn compile_expr<'a>(
expr: &Expr<'a>,
x: usize,
declr: &Vec<Declr<'a>>,
ct: &mut Compiletime<'a>,
prog: &mut Vec<Instr>,
) -> Result<(), ()> {
match expr { match expr {
Expr::Block(block) => parse_block(block, x, declr, ct, prog)?, Expr::Block(block) => parse_block(block, x, declr, ct, prog)?,
Expr::Term(term) => parse_term(term, 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<Declr<'a>>, ct: &mut
Ok(()) Ok(())
} }
pub fn compile<'a>(funcs: &Vec<Func<'a>>, declrs: &Vec<Declr<'a>>) -> Result<Program, ()> { fn create_proc(declr: &Declr, code: Vec<Instr>) -> Proc {
Proc {
code,
args: if let Some(args) = &declr.args {
args.len()
} else {
0
},
addr: declr.uuid(),
}
}
pub fn compile<'a>(funcs: &Vec<Func<'a>>, declrs: &Vec<Declr<'a>>, settings: &crate::conf::Settings) -> Result<Program, ()> {
let mut prog = Program::default(); let mut prog = Program::default();
for (x, func) in funcs.iter().enumerate() { for (x, func) in funcs.iter().enumerate() {
let mut code = vec![]; let mut code = vec![];
let mut ct = Compiletime::default(); let mut ct = Compiletime::default();
// at beginn the is the return address and the parameter on the stack //at the beginning there are all parameters on the stack
ct.stacksize = declrs[x].args.as_ref().unwrap_or(&vec![]).len() + 1; ct.stacksize = declrs[x].args.as_ref().unwrap_or(&vec![]).len();
compile_expr(func.expr.as_ref().unwrap(), x, declrs, &mut ct, &mut code)?; compile_expr(func.expr.as_ref().unwrap(), x, declrs, &mut ct, &mut code)?;
println!("{:#?}", code); prog.procs
.insert(declrs[x].uuid(), create_proc(&declrs[x], code));
prog.code.insert(declrs[x].uuid(), code);
} }
Ok(prog) Ok(prog)
} }
struct Runtimestack {
stack: Vec<Data>,
}
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<Data> {
self.stack.pop()
}
pub fn peek(&mut self, index: usize) -> Data {
self.stack[index]
}
}
fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result<Option<Data>, ()> {
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<i64, ()> { pub fn execute(prog: &Program) -> Result<i64, ()> {
// declaration of entry function // declaration of entry function
let main_fn_declr = crate::parser::data::Declr::main(); let main_fn_declr = crate::parser::data::Declr::main();
if let Some(main_fn) = prog.code.get(&main_fn_declr.uuid()) { if let Some(main_fn) = prog.procs.get(&main_fn_declr.uuid()) {
Ok(0) 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 { } 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(()); return Err(());
} }
} }

20
src/vmrt/output.rs Normal file
View File

@ -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() {
}
}