128 lines
3.8 KiB
Rust
128 lines
3.8 KiB
Rust
|
|
#[derive(Clone, Copy, Debug)]
|
||
|
|
enum Instruction {
|
||
|
|
LoadInt { dst: u8, value: i16 },
|
||
|
|
Copy { dst: u8, src: u8 },
|
||
|
|
Add { dst: u8, src1: u8, src2: u8 },
|
||
|
|
Sub { dst: u8, src1: u8, src2: u8 },
|
||
|
|
Call { func: u8, arg: u8, dst: u8 },
|
||
|
|
Return { src: u8 },
|
||
|
|
JumpNotLess { target: u8, src1: u8, src2: u8 },
|
||
|
|
}
|
||
|
|
|
||
|
|
struct Function {
|
||
|
|
code: Vec<Instruction>,
|
||
|
|
num_registers: usize,
|
||
|
|
}
|
||
|
|
|
||
|
|
struct Vm {
|
||
|
|
functions: Vec<Function>,
|
||
|
|
stack: Vec<i64>,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Vm {
|
||
|
|
pub fn new() -> Vm {
|
||
|
|
Vm {
|
||
|
|
functions: vec![],
|
||
|
|
stack: vec![],
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn call(&mut self, func: u8, arg: i64) -> i64 {
|
||
|
|
let func = func as usize;
|
||
|
|
|
||
|
|
let base_pointer = self.stack.len();
|
||
|
|
{
|
||
|
|
let function = &self.functions[func];
|
||
|
|
let stack_top = base_pointer + function.num_registers;
|
||
|
|
self.stack.resize(stack_top, 0);
|
||
|
|
self.stack[base_pointer] = arg;
|
||
|
|
}
|
||
|
|
|
||
|
|
let bp = base_pointer;
|
||
|
|
let mut program_counter = 0;
|
||
|
|
|
||
|
|
loop {
|
||
|
|
let func = &self.functions[func];
|
||
|
|
let instr = func.code[program_counter];
|
||
|
|
program_counter += 1;
|
||
|
|
|
||
|
|
match instr {
|
||
|
|
Instruction::LoadInt { dst, value } => {
|
||
|
|
*self.reg(bp, dst) = value as i64;
|
||
|
|
}
|
||
|
|
|
||
|
|
Instruction::Copy { dst, src } => {
|
||
|
|
*self.reg(bp, dst) = *self.reg(bp, src);
|
||
|
|
}
|
||
|
|
|
||
|
|
Instruction::Add { dst, src1, src2 } => {
|
||
|
|
*self.reg(bp, dst) = *self.reg(bp, src1) + *self.reg(bp, src2);
|
||
|
|
}
|
||
|
|
|
||
|
|
Instruction::Sub { dst, src1, src2 } => {
|
||
|
|
*self.reg(bp, dst) = *self.reg(bp, src1) - *self.reg(bp, src2);
|
||
|
|
}
|
||
|
|
|
||
|
|
Instruction::Call { func, arg, dst } => {
|
||
|
|
let arg = *self.reg(bp, arg);
|
||
|
|
let result = self.call(func, arg);
|
||
|
|
*self.reg(bp, dst) = result;
|
||
|
|
}
|
||
|
|
|
||
|
|
Instruction::Return { src } => {
|
||
|
|
let result = *self.reg(bp, src);
|
||
|
|
self.stack.truncate(base_pointer);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
Instruction::JumpNotLess { target, src1, src2 } => {
|
||
|
|
let src1 = *self.reg(bp, src1);
|
||
|
|
let src2 = *self.reg(bp, src2);
|
||
|
|
if !(src1 < src2) {
|
||
|
|
program_counter = target as usize;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fn reg(&mut self, base_pointer: usize, index: u8) -> &mut i64 {
|
||
|
|
&mut self.stack[base_pointer + index as usize]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
fn main() {
|
||
|
|
let mut vm = Vm::new();
|
||
|
|
|
||
|
|
let fib = 0;
|
||
|
|
vm.functions.push(Function {
|
||
|
|
code: {
|
||
|
|
let n = 0;
|
||
|
|
let two = 1;
|
||
|
|
let one = 2;
|
||
|
|
let temp = 3;
|
||
|
|
let recursive_1 = 4;
|
||
|
|
let recursive_2 = 5;
|
||
|
|
let result = 6;
|
||
|
|
|
||
|
|
vec![
|
||
|
|
Instruction::LoadInt { dst: two, value: 2 },
|
||
|
|
Instruction::JumpNotLess { target: 3, src1: n, src2: two },
|
||
|
|
Instruction::Return { src: n },
|
||
|
|
Instruction::Sub { dst: temp, src1: n, src2: two },
|
||
|
|
Instruction::Call { func: fib, arg: temp, dst: recursive_1 },
|
||
|
|
Instruction::LoadInt { dst: one, value: 1 },
|
||
|
|
Instruction::Sub { dst: temp, src1: n, src2: one },
|
||
|
|
Instruction::Call { func: fib, arg: temp, dst: recursive_2 },
|
||
|
|
Instruction::Add { dst: result, src1: recursive_1, src2: recursive_2 },
|
||
|
|
Instruction::Return { src: result },
|
||
|
|
]
|
||
|
|
},
|
||
|
|
num_registers: 7,
|
||
|
|
});
|
||
|
|
|
||
|
|
for i in 0..10 {
|
||
|
|
println!("fib({}) = {}", i, vm.call(fib, i));
|
||
|
|
}
|
||
|
|
}
|