add compiler

This commit is contained in:
2020-05-10 01:39:48 +08:00
parent fe196b6507
commit bdc9eb543a
5 changed files with 120 additions and 3 deletions

36
plus1100.gmh.source Normal file
View File

@@ -0,0 +1,36 @@
// a = 0
push 10
push 0
store
// b = 0
push 0
definelabel 1111
// b += a
// a += 1
push 10
retrieve
push 1
add
dup
push 10
swap
store
add
// if a < 100 goto 1111
push 10
retrieve
push 100
sub
gotolabell0 1111
// print b
stdoutnum
// print \n
push 10
stdoutchar
end

62
src/compiler.rs Normal file
View File

@@ -0,0 +1,62 @@
use super::err::CompileError;
pub fn compile_lang(s: &str) -> Result<String, CompileError> {
let mut ret = Vec::with_capacity(1024);
// s.lines().for_each(|ln| ret.push(compile_line(ln)));
for ln in s.lines() {
ret.push(compile_line(ln)?);
}
Ok(ret.join("\n"))
}
fn compile_line(ln: &str) -> Result<String, CompileError> {
if ln.is_empty() {
return Ok("".into());
}
let lower_ln = &ln.trim().to_lowercase();
match lower_ln.as_str() {
push if push.starts_with("push") => Ok("草草".to_owned() + &compile_number(lower_ln, 4)?),
"dup" => Ok("草马草".into()),
copyn if copyn.starts_with("copyn") => Ok("草泥草".to_owned() + &compile_number(lower_ln, 5)?),
"swap" => Ok("草马泥".into()),
"pop" => Ok("草马马".into()),
popn if popn.starts_with("popn") => Ok("草泥马".to_owned() + &compile_number(lower_ln, 4)?),
"add" => Ok("泥草草草".into()),
"sub" => Ok("泥草草泥".into()),
"mul" => Ok("泥草草马".into()),
"div" => Ok("泥草泥草".into()),
"mod" => Ok("泥草泥泥".into()),
"store" => Ok("泥泥草".into()),
"retrieve" => Ok("泥泥泥".into()),
definelabel if definelabel.starts_with("definelabel") => Ok("马草草".to_owned() + &compile_number(lower_ln, 11)?),
callatlabel if callatlabel.starts_with("callatlabel") => Ok("马草泥".to_owned() + &compile_number(lower_ln, 11)?),
gotolabele0 if gotolabele0.starts_with("gotolabele0") => Ok("马泥草".to_owned() + &compile_number(lower_ln, 11)?),
gotolabell0 if gotolabell0.starts_with("gotolabell0") => Ok("马泥泥".to_owned() + &compile_number(lower_ln, 11)?),
gotolabel if gotolabel.starts_with("gotolabel") => Ok("马草马".to_owned() + &compile_number(lower_ln, 9)?),
"returncallat" => Ok("马泥马".into()),
"end" => Ok("马马马".into()),
"stdoutchar" => Ok("泥马草草".into()),
"stdoutnum" => Ok("泥马草泥".into()),
"stdinchar" => Ok("泥马泥草".into()),
"stdinnum" => Ok("泥马泥泥".into()),
comment if comment.starts_with("//") => Ok("".into()),
// unknown synatx
_ => Err(CompileError::SyntaxError(format!("syntax error: {}", lower_ln))),
}
}
fn compile_number(n: &str, skip_chars: usize) -> Result<String, CompileError> {
let i = match n.chars().skip(skip_chars).collect::<String>().trim().parse::<isize>() {
Ok(i) => i, Err(err) => {
return Err(CompileError::SyntaxError(format!("Parse number failed: {}", err)));
},
};
let mut ret = String::with_capacity(16);
ret.push(if i < 0 { '泥' } else { '草' });
let abs_i = if i < 0 { -i } else { i };
ret.push_str(&format!("{:b}", abs_i).chars().map(|c| if c == '1' { '泥' } else { '草' }).collect::<String>());
ret.push('马');
Ok(ret)
}

View File

@@ -16,4 +16,11 @@ pub enum RuntimeError {
#[error(display = "not implemented: {:?}", _0)] #[error(display = "not implemented: {:?}", _0)]
NotImplemented(String), NotImplemented(String),
} }
#[derive(Debug, Error)]
pub enum CompileError {
#[error(display = "syntax syntax: {:?}", _0)]
SyntaxError(String),
}

View File

@@ -1,6 +1,7 @@
mod err; mod err;
mod ins; mod ins;
mod parser; mod parser;
mod compiler;
mod context; mod context;
mod vm; mod vm;
@@ -10,6 +11,7 @@ use std::{
}; };
use err::*; use err::*;
use parser::*; use parser::*;
use compiler::*;
use context::*; use context::*;
use vm::*; use vm::*;
@@ -19,6 +21,7 @@ use vm::*;
fn main() { fn main() {
let is_help = env::args().any(|a| a == "-h" || a == "--help"); let is_help = env::args().any(|a| a == "-h" || a == "--help");
let is_debug = env::args().any(|a| a == "-d" || a == "--debug"); let is_debug = env::args().any(|a| a == "-d" || a == "--debug");
let is_compile = env::args().any(|a| a == "-c" || a == "--compile");
let arg_file = env::args().filter(|a| !a.starts_with("-")).nth(1); let arg_file = env::args().filter(|a| !a.starts_with("-")).nth(1);
if is_help { if is_help {
@@ -45,6 +48,14 @@ fn main() {
}, },
}; };
if is_compile {
match compile_lang(&input) {
Ok(compiled) => println!("{}", compiled),
Err(err) => println!("Compile error: {}", err),
}
return;
}
let instructions = match parse_lang(&input) { let instructions = match parse_lang(&input) {
Ok(i) => i, Err(err) => { Ok(i) => i, Err(err) => {
println!("Parse error: {}", err); println!("Parse error: {}", err);

View File

@@ -19,8 +19,8 @@ impl Instruction {
let a = context.pop(); let a = context.pop();
let b = context.pop(); let b = context.pop();
if let (Some(a), Some(b)) = (a, b) { if let (Some(a), Some(b)) = (a, b) {
context.push(b);
context.push(a); context.push(a);
context.push(b);
} else { } else {
return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call swap!"))); return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call swap!")));
} }
@@ -85,7 +85,7 @@ impl Instruction {
let addr = context.pop(); let addr = context.pop();
if let Some(addr) = addr { if let Some(addr) = addr {
match context.get_mem(addr) { match context.get_mem(addr) {
Some(val) => { context.put_mem(addr, val); }, Some(val) => { context.push(val); },
None => return Err(RuntimeError::ErrorVmState(format!("Memory addr not found: {}!", addr))), None => return Err(RuntimeError::ErrorVmState(format!("Memory addr not found: {}!", addr))),
} }
} else { } else {
@@ -165,6 +165,7 @@ impl Vm {
if context.is_debug() { if context.is_debug() {
let is_define_label = if let Instruction::DefineLabel(_) = ins { true } else { false }; let is_define_label = if let Instruction::DefineLabel(_) = ins { true } else { false };
if !is_define_label { if !is_define_label {
println!("[DEBUG] Context: {:?}", context);
println!("[DEBUG] Execute instruction: {:?}", ins); println!("[DEBUG] Execute instruction: {:?}", ins);
} }
} }