-
-
Save emberian/6194862 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::uint; | |
use std::io; | |
use std::str; | |
enum Token { | |
Add, | |
Sub, | |
Inc, | |
Dec, | |
Out, | |
In, | |
Begin (uint), | |
End (uint), | |
Nil | |
} | |
struct Context { | |
program: ~[Token], | |
pc: uint, | |
cell: int, | |
stack: ~[uint], | |
sp: uint, | |
heap_forward: ~[u8], | |
heap_backward: ~[u8] | |
} | |
fn heap_get(ctx: &Context, addr: int) -> u8 { | |
let flen = ctx.heap_forward.len() as int; | |
let blen = ctx.heap_backward.len() as int; | |
match addr { | |
i if i >= 0 && i < flen => ctx.heap_forward[i], | |
i if i > -blen && i < 0 => ctx.heap_backward[-i-1], | |
_ => 0 | |
} | |
} | |
fn append_zeros_and_set(arr: &mut ~[u8], numzeros: uint, val: u8) { | |
for _ in range(0, numzeros) { | |
arr.push(0); | |
} | |
arr.push(val); | |
} | |
fn heap_set(ctx: &mut Context, addr: int, val: u8) { | |
let flen = ctx.heap_forward.len() as int; | |
let blen = ctx.heap_backward.len() as int; | |
match addr { | |
i if i >= 0 && i < flen => ctx.heap_forward[i] = val, | |
i if i >= flen => append_zeros_and_set(&mut ctx.heap_forward, (i - flen) as uint, val), | |
_ => () | |
} | |
match addr { | |
i if i < 0 && i > -blen => ctx.heap_backward[-i - blen] = val, | |
i if i <= -blen => append_zeros_and_set(&mut ctx.heap_backward, (blen - i) as uint, val), | |
_ => () | |
} | |
} | |
fn push(ctx: &mut Context, start: uint) -> uint { | |
ctx.stack.push(start); | |
0 | |
} | |
fn pop(ctx: &mut Context, end: uint) -> uint { | |
let start = ctx.stack.pop(); | |
match ctx.program[start] { | |
Begin(_) => ctx.program[start] = Begin(end), | |
_ => () | |
} | |
start | |
} | |
fn parse_token(ctx: &mut Context, symbol: char) -> Token { | |
match symbol { | |
'+' => Add, | |
'-' => Sub, | |
'>' => Inc, | |
'<' => Dec, | |
'.' => Out, | |
',' => In, | |
'[' => Begin(push(ctx, ctx.pc)), | |
']' => End(pop(ctx, ctx.pc)), | |
_ => Nil | |
} | |
} | |
fn parse_program(ctx: &mut Context, source: &str) { | |
for ch in source.iter() { | |
let tok = parse_token(ctx, ch); | |
ctx.program.push(tok); | |
ctx.pc += 1; | |
} | |
} | |
fn exec_program(ctx: &mut Context) { | |
ctx.pc = 0; | |
loop { | |
if ctx.pc >= ctx.program.len() { | |
break; | |
} | |
let tok = ctx.program[ctx.pc]; | |
//println(fmt!("pc: %u, cl: %i, sp: %u, in: %?", ctx.pc, ctx.cell, ctx.sp, tok)); | |
match tok { | |
Add => { | |
let val = heap_get(ctx, ctx.cell) + 1; | |
heap_set(ctx, ctx.cell, val) | |
}, | |
Sub => { | |
let val = heap_get(ctx, ctx.cell) - 1; | |
heap_set(ctx, ctx.cell, val) | |
}, | |
Inc => ctx.cell += 1, | |
Dec => ctx.cell -= 1, | |
Out => io::stdout().write_u8(heap_get(ctx, ctx.cell)), | |
In => heap_set(ctx, ctx.cell, io::stdin().read_u8()), | |
Begin(x) => if heap_get(ctx, ctx.cell) == 0 {ctx.pc = x;}, | |
End(x) => if heap_get(ctx, ctx.cell) != 0 {ctx.pc = x;}, | |
_ => () | |
} | |
ctx.pc += 1; | |
} | |
} | |
fn main() { | |
let prog = str::from_bytes(io::stdin().read_whole_stream()); | |
let mut ctx = Context {program: ~[], pc: 0, cell: 0, stack: ~[], sp: 0, heap_forward: ~[], heap_backward: ~[]}; | |
parse_program(&mut ctx, prog); | |
exec_program(&mut ctx); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment