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)
|
||||||
|
}
|
||||||
@@ -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),
|
||||||
|
}
|
||||||
|
|||||||
11
src/main.rs
11
src/main.rs
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user