Skip to content

Instantly share code, notes, and snippets.

@KeenS
Created February 24, 2018 03:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KeenS/96d69c44e4179fc2b34e257e3798761e to your computer and use it in GitHub Desktop.
Save KeenS/96d69c44e4179fc2b34e257e3798761e to your computer and use it in GitHub Desktop.
type Ip = usize;
type Var = usize;
#[derive(Debug)]
enum Instr {
Const(i32),
Add,
Sub,
Get(Var),
Set(Var),
Jz(Ip),
Jump(Ip),
Call(Ip),
Swap,
Ret,
End,
}
#[derive(Debug, PartialEq, Eq)]
enum Error {
InvalidIp,
StackUnderflow(Ip),
}
fn run(ins: &[Instr]) -> Result<i32, Error> {
use self::Instr::*;
let mut stack = Vec::new();
let mut calls = Vec::new();
let mut vars = [0; 32];
let mut ip = 0;
macro_rules! ignore {
($tt: tt) => {}
}
macro_rules! get_args {
($($arg: pat),*) => {
let ($($arg,)*) = ($({ignore!($arg);
stack.pop().ok_or(Error::StackUnderflow(ip))?},)*);
}
}
macro_rules! ret {
($expr: expr) => {stack.push($expr)}
}
loop {
match ins.get(ip).ok_or(Error::InvalidIp)? {
&Const(ref i) => ret!(*i),
&Add => {
get_args!(a, b);
ret!(a + b);
}
&Sub => {
get_args!(a, b);
ret!(a - b);
}
&Get(ref var) => {
ret!(vars[*var]);
}
&Set(ref var) => {
get_args!(a);
vars[*var] = a;
}
&Jz(ref target) => {
get_args!(a);
if a == 0 {
ip = *target - 1
}
}
&Jump(ref target) => ip = *target - 1,
&Call(ref target) => {
calls.push(ip);
ip = *target - 1;
}
&Swap => {
get_args!(a, b);
ret!(a);
ret!(b);
}
&Ret => ip = calls.pop().ok_or(Error::StackUnderflow(ip))?,
&End => return stack.pop().ok_or(Error::StackUnderflow(ip)),
}
ip += 1
}
}
fn main() {
use self::Instr::*;
let insts = [
/* 0 */ Const(36),
/* 1 */ Call(3),
/* 2 */ End,
/* 3 */ Set(0), // Fib:
/* 4 */ Get(0),
/* 5 */ Jz(11),
/* 6 */ Const(1),
/* 7 */ Get(0),
/* 8 */ Sub,
/* 9 */ Jz(11),
/* 10 */ Jump(13),
/* 11 */ Const(1), // If n <= 1
/* 12 */ Ret,
/* 14 */ Get(0), // If 1 < n
/* 17 */ Get(0), // a bit tricky. For saving locals
/* 13 */ Const(1),
/* 14 */ Swap,
/* 15 */ Sub,
/* 16 */ Call(3),
/* 17 */ Swap,
/* 18 */ Const(2),
/* 19 */ Swap,
/* 20 */ Sub,
/* 21 */ Call(3),
/* 22 */ Add,
/* 23 */ Ret,
];
let ret = run(&insts);
assert_eq!(ret, Ok(24157817));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment