add compiler
This commit is contained in:
36
plus1100.gmh.source
Normal file
36
plus1100.gmh.source
Normal 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
62
src/compiler.rs
Normal 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)
|
||||
}
|
||||
@@ -17,3 +17,10 @@ pub enum RuntimeError {
|
||||
#[error(display = "not implemented: {:?}", _0)]
|
||||
NotImplemented(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CompileError {
|
||||
|
||||
#[error(display = "syntax syntax: {:?}", _0)]
|
||||
SyntaxError(String),
|
||||
}
|
||||
|
||||
11
src/main.rs
11
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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user