added loop and break keyword to vmrt
This commit is contained in:
parent
edcfbea81d
commit
ba0d6837f3
|
@ -1 +1,3 @@
|
||||||
/target
|
/target
|
||||||
|
*.erpn
|
||||||
|
*.vsasm
|
||||||
|
|
18
prog.vsasm
18
prog.vsasm
|
@ -1,10 +1,16 @@
|
||||||
|
|
||||||
0xc8c7a99bb88e156b:
|
0xc8c7a99bb88e156b:
|
||||||
push int 0x2
|
|
||||||
push int 0x4
|
|
||||||
cmp eq int
|
|
||||||
jump-unless 0x6
|
|
||||||
push int 0x1
|
|
||||||
ret
|
|
||||||
push int 0x0
|
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
|
ret
|
||||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -26,12 +26,18 @@ fn main() {
|
||||||
-- structs are tables
|
-- structs are tables
|
||||||
|
|
||||||
main() = int {
|
main() = int {
|
||||||
|
|
||||||
|
x:rat = 0.0;
|
||||||
|
|
||||||
unless 2 == 4 {
|
loop {
|
||||||
yield 1;
|
x = x + 4
|
||||||
|
|
||||||
|
unless x < 16 {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
yield 0;
|
yield x;
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
|
|
||||||
|
|
|
@ -614,6 +614,7 @@ fn parse_term<'a>(
|
||||||
Token::Assign(_, _, _) => {
|
Token::Assign(_, _, _) => {
|
||||||
op_stack.push(token);
|
op_stack.push(token);
|
||||||
}
|
}
|
||||||
|
Token::Label(_, _) => output.push_back(token),
|
||||||
Token::Keyword(key, _) => {
|
Token::Keyword(key, _) => {
|
||||||
match key {
|
match key {
|
||||||
Keyword::Unless => (),
|
Keyword::Unless => (),
|
||||||
|
|
|
@ -200,3 +200,8 @@ pub const ERR74: &DebugMsg = &DebugMsg {
|
||||||
code: 74,
|
code: 74,
|
||||||
msg: "Missing operands",
|
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 colored::{ColoredString, Colorize};
|
||||||
use std::collections::VecDeque;
|
use std::{collections::VecDeque, fmt::format};
|
||||||
|
|
||||||
use crate::parser::data::Diagnostics;
|
use crate::parser::data::Diagnostics;
|
||||||
|
|
||||||
|
@ -78,7 +78,8 @@ impl Operator {
|
||||||
"-" => Operator::Sub,
|
"-" => Operator::Sub,
|
||||||
"*" => Operator::Mul,
|
"*" => Operator::Mul,
|
||||||
"/" => Operator::Div,
|
"/" => Operator::Div,
|
||||||
"=" => Operator::Assign,
|
"=" => {
|
||||||
|
Operator::Assign },
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
crate::message(MessageType::Critical, "Unknown operator");
|
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)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub enum Keyword {
|
pub enum Keyword<'a> {
|
||||||
Unless,
|
Unless,
|
||||||
While,
|
While,
|
||||||
/// while(true) loop
|
/// while(true) loop
|
||||||
|
@ -265,10 +267,17 @@ pub enum Keyword {
|
||||||
Return,
|
Return,
|
||||||
Yield,
|
Yield,
|
||||||
Please,
|
Please,
|
||||||
|
Goto(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Keyword {
|
const GOTO_REGEX_SRC: &'static str = r"goto\s+([a-zA-Z0-9]+)";
|
||||||
pub fn parse<'a>(text: &'a str) -> Keyword {
|
|
||||||
|
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 {
|
return match text {
|
||||||
"unless" => Keyword::Unless,
|
"unless" => Keyword::Unless,
|
||||||
"while" => Keyword::While,
|
"while" => Keyword::While,
|
||||||
|
@ -279,6 +288,11 @@ impl Keyword {
|
||||||
"yield" => Keyword::Yield,
|
"yield" => Keyword::Yield,
|
||||||
"please" => Keyword::Please,
|
"please" => Keyword::Please,
|
||||||
_ => {
|
_ => {
|
||||||
|
|
||||||
|
for cap in GOTO_REGEX.captures_iter(text) {
|
||||||
|
return Keyword::Goto(cap.get(1).unwrap().as_str());
|
||||||
|
}
|
||||||
|
|
||||||
crate::message(
|
crate::message(
|
||||||
MessageType::Critical,
|
MessageType::Critical,
|
||||||
format!("not a known keyword: {}", text),
|
format!("not a known keyword: {}", text),
|
||||||
|
@ -496,15 +510,17 @@ pub enum Token<'a> {
|
||||||
Decl(&'a str, Prim, DebugInfo),
|
Decl(&'a str, Prim, DebugInfo),
|
||||||
Bool(bool, DebugInfo),
|
Bool(bool, DebugInfo),
|
||||||
/// Keywords like ```if```,```break```,```while```
|
/// Keywords like ```if```,```break```,```while```
|
||||||
Keyword(Keyword, DebugInfo),
|
Keyword(Keyword<'a>, DebugInfo),
|
||||||
Type(Prim, DebugInfo),
|
Type(Prim, DebugInfo),
|
||||||
/// Semicolon
|
/// Semicolon
|
||||||
Terminator(DebugInfo)
|
Terminator(DebugInfo),
|
||||||
|
Label(&'a str, DebugInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> std::fmt::Display for Token<'a> {
|
impl<'a> std::fmt::Display for Token<'a> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
Token::Label(name, _) => f.write_fmt(format_args!(" {}:", name)),
|
||||||
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)),
|
||||||
|
@ -540,11 +556,12 @@ impl<'a> Into<DebugInfo> for Token<'a> {
|
||||||
Token::Bool(_, d) => d,
|
Token::Bool(_, d) => d,
|
||||||
Token::Keyword(_, d) => d,
|
Token::Keyword(_, d) => d,
|
||||||
Token::Terminator(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! {
|
lazy_static::lazy_static! {
|
||||||
static ref TOKEN_REGEX: regex::Regex = regex::Regex::new(TOKEN_REGEX_SRC).unwrap();
|
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 {
|
tokens.push_back(match i {
|
||||||
2 => Token::Keyword(Keyword::parse(mat.as_str()), debug_info),
|
2 => Token::Label(mat.as_str(), debug_info),
|
||||||
3 => Token::Type(Prim::from(mat.as_str(), &debug_info, diagnostics)?, debug_info),
|
3 => Token::Keyword(Keyword::parse(mat.as_str()), debug_info),
|
||||||
4 => Token::Bool(parse_bool(mat.as_str()), debug_info),
|
4 => Token::Type(Prim::from(mat.as_str(), &debug_info, diagnostics)?, debug_info),
|
||||||
5 => {
|
5 => Token::Bool(parse_bool(mat.as_str()), debug_info),
|
||||||
|
6 => {
|
||||||
let var_type = if let Some(mat) = enumerator.next().unwrap().1 {
|
let var_type = if let Some(mat) = enumerator.next().unwrap().1 {
|
||||||
Some(Prim::from(mat.as_str(), &debug_info, diagnostics)?)
|
Some(Prim::from(mat.as_str(), &debug_info, diagnostics)?)
|
||||||
} else {
|
} 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)
|
Token::Assign(mat.as_str(), var_type, debug_info)
|
||||||
}
|
}
|
||||||
7 => {
|
8 => {
|
||||||
let var_type =
|
let var_type =
|
||||||
Prim::from(enumerator.next().unwrap().1.unwrap().as_str(), &debug_info, diagnostics)?;
|
Prim::from(enumerator.next().unwrap().1.unwrap().as_str(), &debug_info, diagnostics)?;
|
||||||
Token::Decl(mat.as_str(), var_type, debug_info)
|
Token::Decl(mat.as_str(), var_type, debug_info)
|
||||||
}
|
}
|
||||||
9 => Token::Word(mat.as_str(), debug_info),
|
10 => Token::Word(mat.as_str(), debug_info),
|
||||||
10 => Token::Number(mat.as_str(), NumHint::from(mat.as_str()), debug_info),
|
11 => 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::Operator(Operator::parse(mat.as_str()), None, debug_info),
|
||||||
12 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info),
|
13 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info),
|
||||||
13 => {
|
14 => {
|
||||||
line_count += 1;
|
line_count += 1;
|
||||||
line_start = mat.start();
|
line_start = mat.start();
|
||||||
Token::LineBreak(debug_info)
|
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()));
|
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,
|
"false" | "no" => false,
|
||||||
"maybe" => rand::random(),
|
"maybe" => rand::random(),
|
||||||
_ => {
|
_ => {
|
||||||
crate::message(MessageType::Critical, format!("token: {}", text));
|
crate::message(MessageType::Critical, format!("token is not a boolean value: {}", text));
|
||||||
panic!();
|
panic!();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -201,6 +201,7 @@ pub struct Program {
|
||||||
enum LabelType {
|
enum LabelType {
|
||||||
Unless(usize),
|
Unless(usize),
|
||||||
Loop(usize),
|
Loop(usize),
|
||||||
|
Break(usize),
|
||||||
Pad
|
Pad
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,6 +209,8 @@ enum LabelType {
|
||||||
struct Compiletime<'a> {
|
struct Compiletime<'a> {
|
||||||
vartable: HashMap<&'a str, usize>,
|
vartable: HashMap<&'a str, usize>,
|
||||||
labels: Vec<LabelType>,
|
labels: Vec<LabelType>,
|
||||||
|
lopctl: Vec<LabelType>,
|
||||||
|
marker: HashMap<&'a str, usize>,
|
||||||
stacksize: usize,
|
stacksize: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,13 +241,20 @@ fn parse_term<'a>(
|
||||||
ct.stacksize += 1;
|
ct.stacksize += 1;
|
||||||
}
|
}
|
||||||
Token::Assign(name, _, _) => {
|
Token::Assign(name, _, _) => {
|
||||||
ct.vartable.insert(name.clone(), ct.stacksize - 1);
|
if ct.vartable.get(name).is_none() {
|
||||||
code.push(Instr::Store(ct.stacksize - 1));
|
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, _) => {
|
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::Label(name, _) => {
|
||||||
|
ct.marker.insert(name, 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)),
|
||||||
|
@ -331,9 +341,20 @@ fn parse_term<'a>(
|
||||||
crate::token::Keyword::Yield | crate::token::Keyword::Return => {
|
crate::token::Keyword::Yield | crate::token::Keyword::Return => {
|
||||||
code.push(Instr::Return)
|
code.push(Instr::Return)
|
||||||
},
|
},
|
||||||
|
crate::token::Keyword::Loop => {
|
||||||
|
ct.labels.push(LabelType::Loop(code.len()));
|
||||||
|
},
|
||||||
crate::token::Keyword::Unless => {
|
crate::token::Keyword::Unless => {
|
||||||
ct.labels.push(LabelType::Unless(code.len()));
|
ct.labels.push(LabelType::Unless(code.len()));
|
||||||
code.push(Instr::JumpUnless(0));
|
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) => {
|
LabelType::Unless(line) => {
|
||||||
prog[line] = Instr::JumpUnless(prog.len());
|
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) => {
|
Instr::JumpUnless(addr) => {
|
||||||
match stack.pop() {
|
match stack.pop() {
|
||||||
Some(Data::Bool(false)) => x = *addr - 1,
|
Some(Data::Bool(true)) => x = *addr - 1,
|
||||||
Some(Data::Bool(true)) => (),
|
Some(Data::Bool(false)) => (),
|
||||||
_ => {
|
_ => {
|
||||||
crate::message(crate::token::MessageType::Critical, "no condition for unless on stack");
|
crate::message(crate::token::MessageType::Critical, "no condition for unless on stack");
|
||||||
panic!();
|
panic!();
|
||||||
|
|
Loading…
Reference in New Issue