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] +[-->-[>>+>-----<<]<--<---]>-.>>>+.>>..+++[.>]<<<<.+++.------.<<-.>>>>+.