Published .
mod parser; mod interpreter; fn main() { let source = std::fs::read_to_string("helloworld.bf").expect("Missing file: helloworld.bf"); let parsed = parser::parse(&source); let mut interpreter = interpreter::Interpreter::new(); interpreter.run(&parsed); }
#[derive(Debug)] pub enum Instruction { IncrementPointer, DecrementPointer, IncrementValue, DecrementValue, OutputValue, ReadValue, Branch(Vec<Instruction>), } struct Input<'a> { source: &'a str, position: usize, } impl Input<'_> { fn read_all(&mut self) -> Vec<Instruction> { let mut result: Vec<Instruction> = vec!(); while !self.done_reading() { if let Some(next) = self.read_next() { result.push(next); } else { break; } } result } fn read_next(&mut self) -> Option<Instruction> { while !self.done_reading() && self.next_is_comment() { self.skip_next_char(); } if self.peek_char() == Some('[') { return self.read_branch(); } else { return self.read_instruction_char() } } fn read_branch(&mut self) -> Option<Instruction> { let mut branch: Vec<Instruction> = vec!(); self.skip_next_char(); // [ while self.peek_char() != Some(']') { if self.next_is_comment() { self.skip_next_char() } else if let Some(next) = self.read_next() { branch.push(next); } else { return None; } } self.skip_next_char(); // ] Some(Instruction::Branch(branch)) } fn peek_char(&self) -> Option<char> { self.source.chars().collect::<Vec<_>>().get(self.position).copied() } fn next_is_comment(&self) -> bool { if let Some(next) = self.peek_char() { !vec!['>', '<', '+', '-', '.', ',', '['].contains(&next) } else { false } } fn read_instruction_char(&mut self) -> Option<Instruction> { let c = self.peek_char(); self.skip_next_char(); match c { Some('>') => Some(Instruction::IncrementPointer), Some('<') => Some(Instruction::DecrementPointer), Some('+') => Some(Instruction::IncrementValue), Some('-') => Some(Instruction::DecrementValue), Some('.') => Some(Instruction::OutputValue), Some(',') => Some(Instruction::ReadValue), _ => None, } } fn done_reading(&self) -> bool { self.position >= self.source.chars().count() } fn skip_next_char(&mut self) { if !self.done_reading() { self.position += 1; } } } pub fn parse(source: &str) -> Vec<Instruction> { let mut input = Input { source, position: 0 }; input.read_all() }
use crate::parser::Instruction; pub struct Interpreter { pointer: isize, cells: std::collections::HashMap<isize, u8>, } impl Interpreter { pub fn new() -> Interpreter { Interpreter { pointer: 0, cells: std::collections::HashMap::new(), } } pub fn run(&mut self, instructions: &Vec<Instruction>) { for instruction in instructions { self.run_instruction(instruction); } } fn run_instruction(&mut self, instruction: &Instruction) { match instruction { Instruction::IncrementPointer => self.increment_pointer(), Instruction::DecrementPointer => self.decrement_pointer(), Instruction::IncrementValue => self.increment_value(), Instruction::DecrementValue => self.decrement_value(), Instruction::OutputValue => self.output_value(), Instruction::ReadValue => self.read_value(), Instruction::Branch(body) => self.branch(&body), } } fn increment_pointer(&mut self) { self.pointer += 1; } fn decrement_pointer(&mut self) { self.pointer -= 1; } fn increment_value(&mut self) { self.set_current_cell(self.current_cell().wrapping_add(1)) } fn decrement_value(&mut self) { self.set_current_cell(self.current_cell().wrapping_sub(1)) } fn output_value(&mut self) { print!("{}", self.current_cell() as char); } fn read_value(&mut self) { } fn branch(&mut self, body: &Vec<Instruction>) { while self.current_cell() != 0 { self.run(body); } } fn current_cell(&self) -> u8 { *self.cells.get(&self.pointer).unwrap_or(&0) } fn set_current_cell(&mut self, value: u8) { self.cells.insert(self.pointer, value); } }
Hello, world! Source: [https://codegolf.stackexchange.com/a/163590] +[-->-[>>+>-----<<]<--<---]>-.>>>+.>>..+++[.>]<<<<.+++.------.<<-.>>>>+.