use std::{
io::{self, Read, Write},
};
const NUM_CELLS: usize = 30000;
pub struct Breakfast {
memory: [u8; NUM_CELLS],
program: Vec<u8>,
brackets: Vec<Option<usize>>,
pub config: Config,
}
impl Breakfast {
pub fn new(config: Config) -> Breakfast {
Breakfast {
memory: [0; NUM_CELLS],
program: vec![0],
brackets: vec![None],
config,
}
}
pub fn parse(program: &str) -> Vec<u8> {
program
.bytes()
.filter(|b| matches!(
b,
b'>' | b'<' | b'+' | b'-' |
b'.' | b',' | b'[' | b']' |
b'#')
)
.collect()
}
fn build_brackets(commands: &[u8]) ->
Result<Vec<Option<usize>>, &'static str>
{
let mut map = vec![None; commands.len()];
let mut stack = Vec::new();
for (i, cmd) in commands.iter().enumerate() {
match cmd {
b'[' => stack.push(i),
b']' => {
if let Some(start) = stack.pop() {
map[start] = Some(i);
map[i] = Some(start);
} else {
return Err("Unmatched ']'");
}
}
_ => (),
}
}
if !stack.is_empty() {
return Err("Unmatched '['");
}
Ok(map)
}
pub fn run(&mut self, program: Vec<u8>) -> io::Result<()> {
let brackets = match Self::build_brackets(&program) {
Ok(map) => map,
Err(e) => {
panic!("{}", e);
}
};
self.program = program;
self.brackets = brackets;
let mut ptr: usize = 0;
let mut loc: usize = 0;
while loc < self.program.len() {
let command = self.program[loc];
match command {
b'>' => ptr = (ptr + 1).min(29999),
b'<' => ptr = ptr.saturating_sub(1),
b'+' => self.memory[ptr] = self.memory[ptr].wrapping_add(1),
b'-' => self.memory[ptr] = self.memory[ptr].wrapping_sub(1),
b'.' => {
io::stdout().write_all(&[self.memory[ptr]]).unwrap();
io::stdout().flush().unwrap();
}
b',' => {
let mut buf = [0u8];
if io::stdin().read_exact(&mut buf).is_ok() {
self.memory[ptr] = buf[0];
} else {
match self.config.eof_behavior {
EofBehavior::Keep => {}
EofBehavior::Zero => self.memory[ptr] = 0,
EofBehavior::Max => self.memory[ptr] = 255,
}
}
}
b'[' => {
if self.memory[ptr] == 0 {
loc = self.brackets[loc].unwrap();
}
}
b']' => {
if self.memory[ptr] != 0 {
loc = self.brackets[loc].unwrap();
}
}
b'#' if self.config.dbg => {
println!(
"\n[DEBUG] commmand index: {}, pointer index: {}, cell value: {:?}\n",
loc, ptr, self.memory[ptr]
);
}
_ => {}
}
loc += 1;
}
println!();
Ok(())
}
}
pub enum EofBehavior {
Keep,
Zero,
Max,
}
impl Default for EofBehavior {
fn default() -> EofBehavior { EofBehavior::Keep }
}
#[derive(Default)]
pub struct Config {
pub eof_behavior: EofBehavior,
pub dbg: bool,
}