added loop and break keyword to vmrt
This commit is contained in:
parent
edcfbea81d
commit
ba0d6837f3
|
@ -1 +1,3 @@
|
|||
/target
|
||||
*.erpn
|
||||
*.vsasm
|
||||
|
|
18
prog.vsasm
18
prog.vsasm
|
@ -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
|
||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -26,12 +26,18 @@ fn main() {
|
|||
-- structs are tables
|
||||
|
||||
main() = int {
|
||||
|
||||
x:rat = 0.0;
|
||||
|
||||
unless 2 == 4 {
|
||||
yield 1;
|
||||
loop {
|
||||
x = x + 4
|
||||
|
||||
unless x < 16 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
yield 0;
|
||||
yield x;
|
||||
}
|
||||
";
|
||||
|
||||
|
|
|
@ -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 => (),
|
||||
|
|
|
@ -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",
|
||||
};
|
||||
|
|
|
@ -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!();
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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!();
|
||||
|
|
Loading…
Reference in New Issue