added loop and break keyword to vmrt

This commit is contained in:
Sven Vogel 2022-12-06 22:48:52 +01:00
parent edcfbea81d
commit ba0d6837f3
8 changed files with 118 additions and 41 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
/target
*.erpn
*.vsasm

View File

@ -1,10 +1,16 @@
0xc8c7a99bb88e156b:
push int 0x2
push int 0x4
cmp eq int
jump-unless 0x6
push int 0x1
ret
push int 0x0
store 0x0
load 0x0
push int 0x4
add int
store 0x0
load 0x0
push int 0x10
cmp lt eq int
jump-unless 0xb
jump 0xc
jump 0x2
load 0x0
ret

View File

@ -27,11 +27,17 @@ fn main() {
main() = int {
unless 2 == 4 {
yield 1;
x:rat = 0.0;
loop {
x = x + 4
unless x < 16 {
break
}
}
yield 0;
yield x;
}
";

View File

@ -614,6 +614,7 @@ fn parse_term<'a>(
Token::Assign(_, _, _) => {
op_stack.push(token);
}
Token::Label(_, _) => output.push_back(token),
Token::Keyword(key, _) => {
match key {
Keyword::Unless => (),

View File

@ -200,3 +200,8 @@ pub const ERR74: &DebugMsg = &DebugMsg {
code: 74,
msg: "Missing operands",
};
pub const ERR75: &DebugMsg = &DebugMsg {
typ: crate::token::MessageType::Critical,
code: 75,
msg: "Unknown operation",
};

View File

@ -1,5 +1,5 @@
use colored::{ColoredString, Colorize};
use std::collections::VecDeque;
use std::{collections::VecDeque, fmt::format};
use crate::parser::data::Diagnostics;
@ -78,7 +78,8 @@ impl Operator {
"-" => Operator::Sub,
"*" => Operator::Mul,
"/" => Operator::Div,
"=" => Operator::Assign,
"=" => {
Operator::Assign },
_ => {
crate::message(MessageType::Critical, "Unknown operator");
@ -248,14 +249,15 @@ impl Operator {
}
}
_ => {
panic!("Unknown operator");
diagnostics.set_err(info, crate::msg::ERR75, format!("token {:?}", self));
return Err(());
}
}
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum Keyword {
pub enum Keyword<'a> {
Unless,
While,
/// while(true) loop
@ -265,10 +267,17 @@ pub enum Keyword {
Return,
Yield,
Please,
Goto(&'a str),
}
impl Keyword {
pub fn parse<'a>(text: &'a str) -> Keyword {
const GOTO_REGEX_SRC: &'static str = r"goto\s+([a-zA-Z0-9]+)";
lazy_static::lazy_static! {
static ref GOTO_REGEX: regex::Regex = regex::Regex::new(GOTO_REGEX_SRC).unwrap();
}
impl<'a> Keyword<'a> {
pub fn parse(text: &'a str) -> Keyword<'a> {
return match text {
"unless" => Keyword::Unless,
"while" => Keyword::While,
@ -279,6 +288,11 @@ impl Keyword {
"yield" => Keyword::Yield,
"please" => Keyword::Please,
_ => {
for cap in GOTO_REGEX.captures_iter(text) {
return Keyword::Goto(cap.get(1).unwrap().as_str());
}
crate::message(
MessageType::Critical,
format!("not a known keyword: {}", text),
@ -496,15 +510,17 @@ pub enum Token<'a> {
Decl(&'a str, Prim, DebugInfo),
Bool(bool, DebugInfo),
/// Keywords like ```if```,```break```,```while```
Keyword(Keyword, DebugInfo),
Keyword(Keyword<'a>, DebugInfo),
Type(Prim, DebugInfo),
/// Semicolon
Terminator(DebugInfo)
Terminator(DebugInfo),
Label(&'a str, DebugInfo)
}
impl<'a> std::fmt::Display for Token<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Token::Label(name, _) => f.write_fmt(format_args!(" {}:", name)),
Token::Type(t, _) => f.write_fmt(format_args!("__Type {:?}", t)),
Token::Word(w, _) => f.write_fmt(format_args!("__Word {:?}", w)),
Token::Delemiter(d, _) => f.write_fmt(format_args!("__Delemiter {:?}", d)),
@ -540,11 +556,12 @@ impl<'a> Into<DebugInfo> for Token<'a> {
Token::Bool(_, d) => d,
Token::Keyword(_, d) => d,
Token::Terminator(d) => d,
Token::Label(_, d) => d,
}
}
}
const TOKEN_REGEX_SRC: &'static str = r"(#.*|--.*)|(unless|while|loop|break|cont|ret|yield|please)|(int|rat|bool)|(true|false|ye|no|maybe)|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9]+))?\s*=|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9]+))|([A-Za-z_]+)|(\d*\.?\d+)|(!=|==|<=|<=|[&|+\-*/<>=])|([(){}])|(\n)|(;)";
const TOKEN_REGEX_SRC: &'static str = r"(#.*|--.*)|'([a-zA-Z0-9]+)|(goto\s+[a-zA-Z0-9]+|unless|while|loop|break|cont|ret|yield|please)|(int|rat|bool)|(true|false|ye|no|maybe)|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9]+))?\s*=[^=]|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9]+))|([A-Za-z_]+)|(\d*\.?\d+)|(!=|==|<=|<=|[&|+\-*/<>=])|([(){}])|(\n)|(;)";
lazy_static::lazy_static! {
static ref TOKEN_REGEX: regex::Regex = regex::Regex::new(TOKEN_REGEX_SRC).unwrap();
@ -582,10 +599,11 @@ pub fn tokenize<'a>(source: &'a str, diagnostics: &mut Diagnostics) -> Result<Ve
};
tokens.push_back(match i {
2 => Token::Keyword(Keyword::parse(mat.as_str()), debug_info),
3 => Token::Type(Prim::from(mat.as_str(), &debug_info, diagnostics)?, debug_info),
4 => Token::Bool(parse_bool(mat.as_str()), debug_info),
5 => {
2 => Token::Label(mat.as_str(), debug_info),
3 => Token::Keyword(Keyword::parse(mat.as_str()), debug_info),
4 => Token::Type(Prim::from(mat.as_str(), &debug_info, diagnostics)?, debug_info),
5 => Token::Bool(parse_bool(mat.as_str()), debug_info),
6 => {
let var_type = if let Some(mat) = enumerator.next().unwrap().1 {
Some(Prim::from(mat.as_str(), &debug_info, diagnostics)?)
} else {
@ -593,21 +611,21 @@ pub fn tokenize<'a>(source: &'a str, diagnostics: &mut Diagnostics) -> Result<Ve
};
Token::Assign(mat.as_str(), var_type, debug_info)
}
7 => {
8 => {
let var_type =
Prim::from(enumerator.next().unwrap().1.unwrap().as_str(), &debug_info, diagnostics)?;
Token::Decl(mat.as_str(), var_type, debug_info)
}
9 => Token::Word(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()), None, debug_info),
12 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info),
13 => {
10 => Token::Word(mat.as_str(), debug_info),
11 => Token::Number(mat.as_str(), NumHint::from(mat.as_str()), debug_info),
12 => Token::Operator(Operator::parse(mat.as_str()), None, debug_info),
13 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info),
14 => {
line_count += 1;
line_start = mat.start();
Token::LineBreak(debug_info)
}
14 => Token::Terminator(debug_info),
15 => Token::Terminator(debug_info),
_ => {
diagnostics.set_err(&debug_info, crate::msg::ERR71, format!("token: {}", mat.as_str()));
@ -628,7 +646,7 @@ fn parse_bool(text: &str) -> bool {
"false" | "no" => false,
"maybe" => rand::random(),
_ => {
crate::message(MessageType::Critical, format!("token: {}", text));
crate::message(MessageType::Critical, format!("token is not a boolean value: {}", text));
panic!();
},
};

View File

@ -201,6 +201,7 @@ pub struct Program {
enum LabelType {
Unless(usize),
Loop(usize),
Break(usize),
Pad
}
@ -208,6 +209,8 @@ enum LabelType {
struct Compiletime<'a> {
vartable: HashMap<&'a str, usize>,
labels: Vec<LabelType>,
lopctl: Vec<LabelType>,
marker: HashMap<&'a str, usize>,
stacksize: usize,
}
@ -238,13 +241,20 @@ fn parse_term<'a>(
ct.stacksize += 1;
}
Token::Assign(name, _, _) => {
ct.vartable.insert(name.clone(), ct.stacksize - 1);
code.push(Instr::Store(ct.stacksize - 1));
if ct.vartable.get(name).is_none() {
ct.vartable.insert(name.clone(), ct.stacksize - 1);
code.push(Instr::Store(ct.stacksize - 1));
} else {
code.push(Instr::Store(*ct.vartable.get(name).unwrap()));
}
}
Token::Var(name, _) => {
code.push(Instr::Load(*ct.vartable.get(name).unwrap()));
ct.stacksize += 1;
}
},
Token::Label(name, _) => {
ct.marker.insert(name, ct.stacksize + 1);
},
Token::Operator(op, hint, _) => {
code.push(match op {
crate::token::Operator::Or => Instr::Operation(Operation::Bool(BoolOp::Or)),
@ -331,9 +341,20 @@ fn parse_term<'a>(
crate::token::Keyword::Yield | crate::token::Keyword::Return => {
code.push(Instr::Return)
},
crate::token::Keyword::Loop => {
ct.labels.push(LabelType::Loop(code.len()));
},
crate::token::Keyword::Unless => {
ct.labels.push(LabelType::Unless(code.len()));
code.push(Instr::JumpUnless(0));
},
crate::token::Keyword::Goto(label) => {
let index = ct.marker.get(label).unwrap();
code.push(Instr::Jump(*index));
},
crate::token::Keyword::Break => {
ct.lopctl.push(LabelType::Break(code.len()));
code.push(Instr::Jump(0));
}
_ => (),
},
@ -364,6 +385,18 @@ fn parse_block<'a>(
LabelType::Unless(line) => {
prog[line] = Instr::JumpUnless(prog.len());
},
LabelType::Loop(line) => {
prog.push(Instr::Jump(line));
if let Some(label) = ct.lopctl.pop() {
match label {
LabelType::Break(line) => {
prog[line] = Instr::Jump(prog.len());
},
_ => ()
}
}
},
_ => ()
}
}
@ -487,8 +520,8 @@ fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result<Option<Da
},
Instr::JumpUnless(addr) => {
match stack.pop() {
Some(Data::Bool(false)) => x = *addr - 1,
Some(Data::Bool(true)) => (),
Some(Data::Bool(true)) => x = *addr - 1,
Some(Data::Bool(false)) => (),
_ => {
crate::message(crate::token::MessageType::Critical, "no condition for unless on stack");
panic!();

View File

@ -1,10 +1,16 @@
main:
Load Int 2
Load Int 4
Eq Int
Unless
Load Int 1
Yield
Load Int 0
Store Int x
Loop
Load Var x
Load Int 4
Add Int
Store Int x
Load Var x
Load Int 16
Lt Int
Unless
Break
Load Var x
Yield