#[std]
#[memory(1024)]
//
// A brainfuck interpreter written in Oak
//
// Copy a char array
fn strcpy(dst: &char, src: &char) {
for (let i=0; src[i] != '\0'; i=i+1) {
dst[i] = src[i];
}
dst[i] = 0;
}
// Get the length of a char array
fn strlen(str: &char) -> num {
for (let i=0; str[i] != '\0'; i=i+1) {}
return i
}
const EOF = -1;
const MAX_LOOP_DEPTH = 32;
const TAPE_SIZE = 128;
const MACHINE = 6;
struct Machine {
let jmp_stack: &num,
jmp_counter: num,
val_ptr: num,
ins_ptr: num,
tape: &num,
code: &char;
fn new(source_code: &char) -> Machine {
let jmp_stack = alloc(MAX_LOOP_DEPTH) as #
let jmp_counter = 0;
let val_ptr = 0;
let ins_ptr = 0;
let code = alloc(strlen(source_code)) as &char;
strcpy(code, source_code);
let tape = alloc(TAPE_SIZE) as #
return [
jmp_stack,
jmp_counter,
val_ptr,
ins_ptr,
tape,
code
];
}
fn token(self: &Machine) -> &char { return self->code + self->ins_ptr }
fn plus(self: &Machine) { self->val = self->val + 1 }
fn minus(self: &Machine) { self->val = self->val - 1 }
fn left(self: &Machine) { self->val_ptr = self->val_ptr - 1 }
fn right(self: &Machine) { self->val_ptr = self->val_ptr + 1 }
fn input(self: &Machine) { self->val = get_char() }
fn out(self: &Machine) {
if self->val != EOF {
putchar((self->val) as char)
}
}
fn val(self: &Machine) -> &num { return self->tape + self->val_ptr }
fn loop(self: &Machine) {
(self->jmp_stack)[self->jmp_counter] = self->ins_ptr;
self->jmp_counter = self->jmp_counter + 1;
}
fn end(self: &Machine) {
if self->val != 0.0 {
self->jmp_counter = self->jmp_counter - 1;
self->ins_ptr = (self->jmp_stack)[self->jmp_counter];
(self->jmp_stack)[self->jmp_counter] = 0;
} else {
self->jmp_counter = self->jmp_counter - 1;
(self->jmp_stack)[self->jmp_counter] = 0;
self->ins_ptr = self->ins_ptr + 1;
}
}
fn dump(self: &Machine) {
putstrln(self->code);
for i in 0..self->ins_ptr {
putchar(' ');
}
putcharln('^');
putchar('[');
for i in 0..TAPE_SIZE {
putchar(' '); putnum((self->tape)[i]);
}
putstr(" ]\n ");
for i in 0..self->val_ptr {
putstr(" ");
}
putcharln('^');
}
fn run(self: &Machine) {
while self->ins_ptr != strlen(self->code) {
if self->token == '+' { self.plus() }
if self->token == '-' { self.minus() }
if self->token == '<' { self.left() }
if self->token == '>' { self.right() }
if self->token == ',' { self.input() }
if self->token == '.' { self.out() }
if self->token == '[' { self.loop() }
if self->token == ']' { self.end() }
else {
self->ins_ptr = self->ins_ptr + 1;
}
}
}
fn drop(self: &Machine) {
free self->jmp_stack: MAX_LOOP_DEPTH;
free self->code: strlen(self->code);
free self->tape: TAPE_SIZE;
}
}
fn main() {
let m: Machine = Machine::new(
"++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."
);
m.run();
m.dump();
m.drop();
}