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() {
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 = foo(4)
a = 4
b = pi
c = true
r = foo(3, 4.0)
h = foo(3,5.0)
b:int = 4
9
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));
}
}
}
}

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)]
enum Data {
@ -10,6 +15,29 @@ enum Data {
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)]
enum IntOp {
CmpEq,
@ -22,7 +50,7 @@ enum IntOp {
Add,
Sub,
Mul,
Div
Div,
}
#[derive(Debug)]
@ -37,7 +65,7 @@ enum RatOp {
Add,
Sub,
Mul,
Div
Div,
}
#[derive(Debug)]
@ -47,14 +75,14 @@ enum BoolOp {
And,
Or,
Xor
Xor,
}
#[derive(Debug)]
enum Operation {
Int(IntOp),
Rat(RatOp),
Bool(BoolOp)
Bool(BoolOp),
}
#[derive(Debug)]
@ -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<Instr>,
// number of expected arguments
args: usize,
// hashed declaration is used as "address"
addr: u64,
}
#[derive(Default)]
pub struct Program {
code: HashMap<u64, Proc>
procs: HashMap<u64, Proc>,
}
#[derive(Default)]
@ -108,7 +136,13 @@ struct Compiletime<'a> {
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() {
let instr = match token {
Token::Number(value, hint, _) => {
@ -117,26 +151,25 @@ fn parse_term<'a>(term: &VecDeque<Token<'a>>, x: usize, declr: &Vec<Declr<'a>>,
NumHint::Rat => Data::Rat(value.parse::<f64>().unwrap()),
}));
ct.stacksize += 1;
},
}
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<Token<'a>>, x: usize, declr: &Vec<Declr<'a>>,
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()))
}
}
}
Token::Keyword(keyword, _) => {
match keyword {
crate::token::Keyword::Yield | crate::token::Keyword::Return => code.push(Instr::Return),
_ => ()
}
}
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)
}
_ => (),
},
_ => ()
_ => (),
};
}
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() {
compile_expr(expr, x, declr, ct, prog)?;
}
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 {
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<Declr<'a>>, ct: &mut
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();
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<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, ()> {
// 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()) {
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 {
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(());
}
}

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