oakc 0.6.1

A portable programming language with a compact backend
Documentation
#[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();
}