#![no_std]
use core::mem::size_of;
const TAPE_SIZE: usize = 65535;
const NESTED_LOOP_LIMIT: usize = 1024;
type Cell = u8;
const MAX_SIZE: Cell = ((1 << (size_of::<Cell>() * 8)) - 1) as Cell;
pub trait Input {
fn input(&mut self) -> char {
'\0'
}
}
pub trait Output {
fn output(&mut self, _: char) {}
}
pub struct Interpreter<'a, I, O>
where
I: Input,
O: Output,
{
input: &'a mut I,
output: &'a mut O,
data_ptr: usize,
data_tape: [Cell; TAPE_SIZE],
instruction_ptr: usize,
instruction_tape: [Cell; TAPE_SIZE],
nested_loop_counter: usize,
nested_loop_stack: [usize; NESTED_LOOP_LIMIT],
}
fn instruction_tape_from_str(s: &str) -> [Cell; TAPE_SIZE] {
let mut tape = [0; TAPE_SIZE];
for (i, ch) in s.chars().enumerate() {
tape[i] = ch as Cell;
}
tape
}
impl<'a, I, O> Interpreter<'a, I, O>
where
I: Input,
O: Output,
{
pub fn new(program: &str, input: &'a mut I, output: &'a mut O) -> Self {
Self {
input,
output,
data_ptr: 0,
data_tape: [0; TAPE_SIZE],
instruction_ptr: 0,
instruction_tape: instruction_tape_from_str(program),
nested_loop_counter: 0,
nested_loop_stack: [0; NESTED_LOOP_LIMIT],
}
}
fn reset(&mut self) {
self.data_ptr = 0;
self.data_tape = [0; TAPE_SIZE];
self.instruction_ptr = 0;
self.nested_loop_counter = 0;
self.nested_loop_stack = [0; NESTED_LOOP_LIMIT];
}
pub fn run(&mut self) {
self.reset();
while self.instruction_tape[self.instruction_ptr] != 0 {
let ins = self.instruction_tape[self.instruction_ptr] as u8 as char;
match ins {
'[' => self.enter_loop(),
']' => self.exit_loop(),
'+' => self.increment(),
'-' => self.decrement(),
'>' => self.right(),
'<' => self.left(),
'.' => self.output(),
',' => self.input(),
_ => {}
}
self.instruction_ptr += 1;
}
}
fn increment(&mut self) {
self.data_tape[self.data_ptr] = if self.data_tape[self.data_ptr] == MAX_SIZE {
0
}
else {
self.data_tape[self.data_ptr] + 1
} }
fn decrement(&mut self) {
self.data_tape[self.data_ptr] = if self.data_tape[self.data_ptr] == 0 {
MAX_SIZE
}
else {
self.data_tape[self.data_ptr] - 1
} }
fn left(&mut self) {
if self.data_ptr == 0 {
self.data_ptr = TAPE_SIZE - 1;
} else {
self.data_ptr -= 1;
}
}
fn right(&mut self) {
if self.data_ptr == TAPE_SIZE - 1 {
self.data_ptr = 0;
} else {
self.data_ptr += 1;
}
}
fn output(&mut self) {
self.output
.output(self.data_tape[self.data_ptr] as u8 as char)
}
fn input(&mut self) {
self.data_tape[self.data_ptr] = self.input.input() as Cell
}
fn goto_topmost_loop(&mut self) {
self.instruction_ptr = self.nested_loop_stack[self.nested_loop_counter - 1];
}
fn enter_loop(&mut self) {
if self.data_tape[self.data_ptr] != 0 {
self.nested_loop_stack[self.nested_loop_counter] = self.instruction_ptr;
self.nested_loop_counter += 1;
} else {
let mut loop_counter = 1;
for (i, ins) in self.instruction_tape[self.instruction_ptr + 1..]
.iter()
.enumerate()
{
match *ins as u8 as char {
'[' => loop_counter += 1,
']' => loop_counter -= 1,
_ => {}
}
if loop_counter == 0 {
self.instruction_ptr = i + self.instruction_ptr + 1;
break;
}
}
}
}
fn exit_loop(&mut self) {
if self.data_tape[self.data_ptr] != 0 {
self.goto_topmost_loop()
} else {
self.nested_loop_counter -= 1;
self.nested_loop_stack[self.nested_loop_counter] = 0;
}
}
}