Skip to content

Instantly share code, notes, and snippets.

@kates
Created October 16, 2014 00:59
Show Gist options
  • Save kates/9c8a9406fc4c43e3ab1a to your computer and use it in GitHub Desktop.
Save kates/9c8a9406fc4c43e3ab1a to your computer and use it in GitHub Desktop.
toy vm bytecode compiler
use std::os;
use std::io;
use std::fmt;
struct Compiler {
source: String
//bytecode: String
}
enum Instruction {
InsHalt,
InsLoad(uint, uint),
InsMov(uint, uint),
InsAdd(uint, uint, uint),
InsSub(uint, uint, uint)
}
impl fmt::Show for Instruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
InsLoad(op1, op2) => {
write!(f, "1{}{:0x}", op1, op2)
},
InsMov(op1, op2) => {
write!(f, "2{}{}0", op1, op2)
},
InsAdd(op1, op2, op3) => {
write!(f, "3{}{}{}", op1, op2, op3)
},
InsSub(op1, op2, op3) => {
write!(f, "4{}{}{}", op1, op2, op3)
},
InsHalt => {
f.write(b"0000")
}
}
}
}
impl Compiler {
pub fn compile(filename: &str) -> Compiler {
let source_stream = io::File::open(&Path::new(filename)).read_to_string();
let source = match source_stream {
Ok(content) => content,
Err(why) => fail!("Error {}", why)
};
let compiler = Compiler {
source: source
//bytecode: "".to_string()
};
compiler.parse();
compiler
}
fn reg(&self, name: &str) -> uint {
match name {
"r0" => 0,
"r1" => 1,
"r2" => 2,
_ => 3
}
}
fn val(&self, name: &str) -> uint {
match from_str(name.as_slice()) {
Some(i) => i,
_ => 0
}
}
fn parse(&self) {
println!("{}", self.source);
let mut instructions : Vec<Instruction> = Vec::new();
for line in self.source.as_slice().split('\n') {
let tok : Vec<&str> = line.split(' ').collect();
match tok.as_slice() {
[opcode, op1, op2, op3] => {
match opcode {
"add" => {
instructions.push(InsAdd(self.reg(op1), self.reg(op2), self.reg(op3)));
},
"sub" => {
instructions.push(InsSub(self.reg(op1), self.reg(op2), self.reg(op3)));
}
_ => {}
}
},
[opcode, op1, op2] => {
match opcode {
"load" => {
instructions.push(InsLoad(self.reg(op1), self.val(op2)));
},
"mov" => {
instructions.push(InsMov(self.reg(op1), self.reg(op2)));
},
_ => {}
}
},
["halt"] => {
instructions.push(InsHalt)
},
_ => {
instructions.push(InsHalt)
}
}
}
println!("{}", instructions);
}
}
fn main() {
let args = os::args();
if args.len() < 2 {
fail!("Usage: tlc <source>");
}
Compiler::compile(args[1].as_slice());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment