added vmrt module

This commit is contained in:
Sven Vogel 2022-11-29 18:34:54 +01:00
parent fda09066c7
commit e80a69fb41
6 changed files with 276 additions and 29 deletions

View File

@ -6,6 +6,7 @@ mod parser;
// designed for a virtual stack machiene // designed for a virtual stack machiene
mod inter; mod inter;
mod conf; mod conf;
mod vmrt;
use colored::Colorize; use colored::Colorize;
use parser::*; use parser::*;
@ -47,10 +48,13 @@ foo(x:int, y:rat) = bool {
main() = int { main() = int {
a = 4 a = 4
b = 5.5 b = pi
c = true c = true
r = foo(3, ffalsee) r = foo(3, 4.0)
0 h = foo(3,5.0)
b:int = 4
9
} }
"; ";
@ -59,7 +63,9 @@ main() = int {
let settings = conf::parse_args(&mut diagnostics); let settings = conf::parse_args(&mut diagnostics);
if let Ok(mut tokens) = tokenize(source, &mut diagnostics) { if let Ok(mut tokens) = tokenize(source, &mut diagnostics) {
parse(&mut tokens, &mut diagnostics, &settings); if let Ok((fs, ds)) = parse(&mut tokens, &mut diagnostics, &settings) {
vmrt::compile(&fs, &ds);
}
} }
println!("{}", diagnostics); println!("{}", diagnostics);

View File

@ -2,6 +2,8 @@ use crate::token::{DebugInfo, DebugNotice, Token, MessageType};
use crate::Prim; use crate::Prim;
use core::panic; use core::panic;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum LogLvl { pub enum LogLvl {
@ -127,7 +129,9 @@ pub struct Declr<'a> {
pub result_typ: Option<Prim>, pub result_typ: Option<Prim>,
/// debug info /// debug info
pub info: Option<DebugInfo> pub info: Option<DebugInfo>,
uuid: u64
} }
impl<'a> Declr<'a> { impl<'a> Declr<'a> {
@ -138,8 +142,39 @@ impl<'a> Declr<'a> {
results: false, results: false,
result_typ: None, result_typ: None,
info: None, info: None,
uuid: 0,
} }
} }
pub fn get_arg_ord(&self, name: &str) -> usize {
if let Some(args) = self.args.as_ref() {
for (x, arg) in args.iter().enumerate() {
if arg.0 == name {
return x;
}
}
}
return 0;
}
pub fn gen_uuid(&mut self) {
let mut hasher = DefaultHasher::default();
self.name.unwrap().hash(&mut hasher);
if let Some(args) = self.args.as_ref() {
for arg in args.iter() {
arg.0.hash(&mut hasher);
arg.1.hash(&mut hasher);
}
}
self.uuid = hasher.finish()
}
pub fn uuid(&self) -> u64 {
self.uuid
}
} }
impl<'a> std::fmt::Display for Declr<'a> { impl<'a> std::fmt::Display for Declr<'a> {

View File

@ -44,6 +44,8 @@ fn discover_functions<'a>(
return Err(()); return Err(());
} }
declr.gen_uuid();
// store new function and its declaration // store new function and its declaration
funcs.push(func); funcs.push(func);
declrs.push(declr); declrs.push(declr);
@ -134,7 +136,7 @@ fn discover_functions<'a>(
if func.raw.is_none() { if func.raw.is_none() {
match &top { match &top {
Token::Operator(op, _) => match op { Token::Operator(op, _, _) => match op {
Operator::Assign => { Operator::Assign => {
// check if we already have an assign // check if we already have an assign
if declr.results { if declr.results {
@ -458,7 +460,7 @@ fn process_keyword(
if let Some(operand) = operands.pop() { if let Some(operand) = operands.pop() {
if let Some(typ) = scope.func_return_typ { if let Some(typ) = scope.func_return_typ {
if typ != operand { if !typ.is_equal(operand) {
diagnostics.set_err( diagnostics.set_err(
info, info,
crate::msg::ERR59, crate::msg::ERR59,
@ -491,7 +493,7 @@ fn collapse_operation(
) -> Result<(), ()> { ) -> Result<(), ()> {
match operation { match operation {
Token::Operator(op, dbginf) => op.operate(operands, &dbginf, diagnostics)?, Token::Operator(op, _, dbginf) => op.operate(operands, &dbginf, diagnostics)?,
Token::Assign(name, ref mut typ, dbginf) => { Token::Assign(name, ref mut typ, dbginf) => {
check_var_typ(typ, operands, &dbginf, diagnostics)?; check_var_typ(typ, operands, &dbginf, diagnostics)?;
scope.decl_var((*name).to_owned(), typ.clone()); scope.decl_var((*name).to_owned(), typ.clone());
@ -660,11 +662,11 @@ fn parse_term<'a>(
} }
}, },
Token::Operator(op, _) => { Token::Operator(op, _, _) => {
let prec0 = op.prec(); let prec0 = op.prec();
while let Some(mut top) = op_stack.last_mut() { while let Some(mut top) = op_stack.last_mut() {
match &top { match &top {
Token::Operator(op1, _) => { Token::Operator(op1, _, _) => {
let prec1 = op1.prec(); let prec1 = op1.prec();
if prec1 > prec0 || prec0 == prec1 && op.assoc() == Assoc::Left { if prec1 > prec0 || prec0 == prec1 && op.assoc() == Assoc::Left {
@ -712,7 +714,9 @@ fn parse_term<'a>(
scope.expr_yield = value_stack.len() == 1; scope.expr_yield = value_stack.len() == 1;
if scope.expr_yield { if scope.expr_yield {
let yielded = value_stack.pop().unwrap(); let yielded = value_stack.pop().unwrap();
if !yielded.is_equal(scope.func_return_typ.unwrap()) { if !yielded.is_equal(scope.func_return_typ.unwrap()) {
diagnostics.set_err( diagnostics.set_err(
&output[0], &output[0],
crate::msg::ERR59, crate::msg::ERR59,
@ -722,7 +726,7 @@ fn parse_term<'a>(
yielded yielded
), ),
); );
panic!(); return Err(());
} }
} }
@ -793,16 +797,16 @@ fn parse_exprs<'a>(
/// reorder and organize a listing of instructions to a RPN based format: /// reorder and organize a listing of instructions to a RPN based format:
/// any program is made out of functions. /// any program is made out of functions.
/// A function has a name followed by an optional parameter list, followed by an optional equal sign and block. /// A function has a name followed by an optional parameter list, followed by an optional equal sign and block.
pub fn parse<'a>(tokens: &mut VecDeque<crate::Token<'a>>, diagnostics: &mut data::Diagnostics, settings: &Settings) { pub fn parse<'a>(tokens: &mut VecDeque<crate::Token<'a>>, diagnostics: &mut data::Diagnostics, settings: &Settings) -> Result<(Vec<Func<'a>>, Vec<Declr<'a>>), ()> {
if let Ok((mut funcs, declrs)) = discover_functions(tokens, diagnostics) { let (mut funcs, declrs) = discover_functions(tokens, diagnostics)?;
if let Ok(()) = discover_exprs(&mut funcs, &declrs, diagnostics) {
if let Ok(()) = parse_exprs(&mut funcs, &declrs, diagnostics) {
if settings.gen_erpn() { discover_exprs(&mut funcs, &declrs, diagnostics)?;
crate::inter::convert_to_erpn(&mut funcs, &declrs); parse_exprs(&mut funcs, &declrs, diagnostics)?;
}
} if settings.gen_erpn() {
} crate::inter::convert_to_erpn(&mut funcs, &declrs);
} }
return Ok((funcs, declrs));
} }

View File

@ -163,6 +163,7 @@ impl Operator {
info: &DebugInfo, info: &DebugInfo,
diagnostics: &mut crate::parser::data::Diagnostics, diagnostics: &mut crate::parser::data::Diagnostics,
) -> Result<(),()> { ) -> Result<(),()> {
// TODO: insert type hint
match self { match self {
Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => { Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => {
let types_valid = let types_valid =
@ -459,7 +460,7 @@ pub enum Token<'a> {
Word(&'a str, DebugInfo), Word(&'a str, DebugInfo),
/// Single symbol delemiter like ```(```,```}``` /// Single symbol delemiter like ```(```,```}```
Delemiter(char, DebugInfo), Delemiter(char, DebugInfo),
Operator(Operator, DebugInfo), Operator(Operator, Option<Prim>, DebugInfo),
Number(&'a str, NumHint, DebugInfo), Number(&'a str, NumHint, DebugInfo),
LineBreak(DebugInfo), LineBreak(DebugInfo),
Func(&'a str, DebugInfo), Func(&'a str, DebugInfo),
@ -485,7 +486,7 @@ impl<'a> std::fmt::Display for Token<'a> {
Token::Type(t, _) => f.write_fmt(format_args!("__Type {:?}", t)), Token::Type(t, _) => f.write_fmt(format_args!("__Type {:?}", t)),
Token::Word(w, _) => f.write_fmt(format_args!("__Word {:?}", w)), Token::Word(w, _) => f.write_fmt(format_args!("__Word {:?}", w)),
Token::Delemiter(d, _) => f.write_fmt(format_args!("__Delemiter {:?}", d)), Token::Delemiter(d, _) => f.write_fmt(format_args!("__Delemiter {:?}", d)),
Token::Operator(o, _) => f.write_fmt(format_args!("{:?}", o)), Token::Operator(o, _, _) => f.write_fmt(format_args!("{:?}", o)),
Token::Number(n, hint, _) => f.write_fmt(format_args!("Load {:?} {}", hint, n)), Token::Number(n, hint, _) => f.write_fmt(format_args!("Load {:?} {}", hint, n)),
Token::LineBreak(_) => f.write_str("__Line-break"), Token::LineBreak(_) => f.write_str("__Line-break"),
Token::Func(name, _) => f.write_fmt(format_args!("Call {}", name)), Token::Func(name, _) => f.write_fmt(format_args!("Call {}", name)),
@ -506,7 +507,7 @@ impl<'a> Into<DebugInfo> for Token<'a> {
Token::Type(_, d) => d, Token::Type(_, d) => d,
Token::Word(_, d) => d, Token::Word(_, d) => d,
Token::Delemiter(_, d) => d, Token::Delemiter(_, d) => d,
Token::Operator(_, d) => d, Token::Operator(_, _, d) => d,
Token::Number(_, _, d) => d, Token::Number(_, _, d) => d,
Token::LineBreak(d) => d, Token::LineBreak(d) => d,
Token::Func(_, d) => d, Token::Func(_, d) => d,
@ -577,7 +578,7 @@ pub fn tokenize<'a>(source: &'a str, diagnostics: &mut Diagnostics) -> Result<Ve
} }
9 => Token::Word(mat.as_str(), debug_info), 9 => Token::Word(mat.as_str(), debug_info),
10 => Token::Number(mat.as_str(), NumHint::from(mat.as_str()), debug_info), 10 => Token::Number(mat.as_str(), NumHint::from(mat.as_str()), debug_info),
11 => Token::Operator(Operator::parse(mat.as_str()), debug_info), 11 => Token::Operator(Operator::parse(mat.as_str()), None, debug_info),
12 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info), 12 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info),
13 => { 13 => {
line_count += 1; line_count += 1;

195
src/vmrt/mod.rs Normal file
View File

@ -0,0 +1,195 @@
use std::collections::{VecDeque, HashMap};
use crate::{parser::data::*, token::{Token, NumHint}};
#[derive(Debug)]
enum Data {
Int(i64),
Rat(f64),
Bool(bool),
Off(usize),
}
#[derive(Debug)]
enum IntOp {
CmpEq,
CmpNEq,
CmpLt,
CmpGt,
CmpLtEq,
CmpGtEq,
Add,
Sub,
Mul,
Div
}
#[derive(Debug)]
enum RatOp {
CmpEq,
CmpNEq,
CmpLt,
CmpGt,
CmpLtEq,
CmpGtEq,
Add,
Sub,
Mul,
Div
}
#[derive(Debug)]
enum BoolOp {
CmpEq,
CmpNEq,
And,
Or,
Xor
}
#[derive(Debug)]
enum Operation {
Int(IntOp),
Rat(RatOp),
Bool(BoolOp)
}
#[derive(Debug)]
enum Instr {
/// load some data onto the stack
Push(Data),
/// delete the last value from stack
Pop,
/// push the value stored at offset onto the stack
Load(usize),
/// store the value stored at the stack[0](offset) stack[1](value) onto the stack
Store,
Call(u64),
Return,
Operation(Operation),
Exit
}
/// function stack layout
/// +----------------------------------+
/// | Return address |
/// +----------------------------------+
/// | Parameter (0) |
/// +----------------------------------+
/// | Parameter (1) |
/// +----------------------------------+
/// | Parameter (2) |
/// +----------------------------------+
/// | Parameter (n) |
/// +----------------------------------+
#[derive(Default)]
pub struct Program {
code: HashMap<u64, Vec<Instr>>
}
#[derive(Default)]
struct Compiletime<'a> {
vartable: HashMap<&'a str, 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>) {
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::<i64>().unwrap()),
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));
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, _, _) => {
code.push(match op {
crate::token::Operator::Or => Instr::Operation(Operation::Bool(BoolOp::Or)),
crate::token::Operator::And => Instr::Operation(Operation::Bool(BoolOp::And)),
crate::token::Operator::Xor => Instr::Operation(Operation::Bool(BoolOp::Xor)),
_ => panic!()
});
// 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),
_ => ()
}
}
_ => ()
};
}
}
fn parse_block<'a>(block: &VecDeque<Expr<'a>>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut Compiletime<'a>, prog: &mut Vec<Instr>) {
for expr in block.iter() {
compile_expr(expr, x, declr, ct, prog);
}
}
fn compile_expr<'a>(expr: &Expr<'a>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut Compiletime<'a>, prog: &mut Vec<Instr>) {
match expr {
Expr::Block(block) => parse_block(block, x, declr, ct, prog),
Expr::Term(term) => parse_term(term, x, declr, ct, prog),
}
}
pub fn compile<'a>(funcs: &Vec<Func<'a>>, declrs: &Vec<Declr<'a>>) {
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;
compile_expr(func.expr.as_ref().unwrap(), x, declrs, &mut ct, &mut code);
println!("{:#?}", code);
prog.code.insert(declrs[x].uuid(), code);
}
}

View File

@ -23,12 +23,18 @@ foo:
main: main:
Load Int 4 Load Int 4
Store Int a Store Int a
Load Rat 5.5 Call pi
Store Rat b Store Rat b
Load Bool true Load Bool true
Store Bool c Store Bool c
Load Int 3 Load Int 3
Load Rat 3.4 Load Rat 4.0
Call foo Call foo
Store Bool r Store Bool r
Load Int 0 Load Int 3
Load Rat 5.0
Call foo
Store Bool h
Load Int 4
Store Int b
Load Int 9