diff --git a/plus1100.gmh.source b/plus1100.gmh.source new file mode 100644 index 0000000..b17e31b --- /dev/null +++ b/plus1100.gmh.source @@ -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 diff --git a/src/compiler.rs b/src/compiler.rs new file mode 100644 index 0000000..d5ac2b4 --- /dev/null +++ b/src/compiler.rs @@ -0,0 +1,62 @@ +use super::err::CompileError; + +pub fn compile_lang(s: &str) -> Result { + 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 { + 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 { + let i = match n.chars().skip(skip_chars).collect::().trim().parse::() { + 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::()); + ret.push('马'); + Ok(ret) +} diff --git a/src/err.rs b/src/err.rs index 9b7816d..dbd6e86 100644 --- a/src/err.rs +++ b/src/err.rs @@ -16,4 +16,11 @@ pub enum RuntimeError { #[error(display = "not implemented: {:?}", _0)] NotImplemented(String), -} \ No newline at end of file +} + +#[derive(Debug, Error)] +pub enum CompileError { + + #[error(display = "syntax syntax: {:?}", _0)] + SyntaxError(String), +} diff --git a/src/main.rs b/src/main.rs index 763909c..422b793 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ mod err; mod ins; mod parser; +mod compiler; mod context; mod vm; @@ -10,6 +11,7 @@ use std::{ }; use err::*; use parser::*; +use compiler::*; use context::*; use vm::*; @@ -19,6 +21,7 @@ use vm::*; fn main() { let is_help = env::args().any(|a| a == "-h" || a == "--help"); 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); 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) { Ok(i) => i, Err(err) => { println!("Parse error: {}", err); diff --git a/src/vm.rs b/src/vm.rs index 2445022..1a9ae9b 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -19,8 +19,8 @@ impl Instruction { let a = context.pop(); let b = context.pop(); if let (Some(a), Some(b)) = (a, b) { - context.push(b); context.push(a); + context.push(b); } else { return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call swap!"))); } @@ -85,7 +85,7 @@ impl Instruction { let addr = context.pop(); if let Some(addr) = 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))), } } else { @@ -165,6 +165,7 @@ impl Vm { if context.is_debug() { let is_define_label = if let Instruction::DefineLabel(_) = ins { true } else { false }; if !is_define_label { + println!("[DEBUG] Context: {:?}", context); println!("[DEBUG] Execute instruction: {:?}", ins); } }