interactive brainfuck repl

This commit is contained in:
nora 2021-05-03 18:06:46 +02:00
parent 5cc058267b
commit c17bea08e0
7 changed files with 168 additions and 43 deletions

View file

@ -1,13 +1,16 @@
use crate::interpreter::optimized::PrintMode;
use std::str::Chars;
pub mod simple;
pub mod parsed;
pub mod optimized;
const MEM_SIZE: usize = 0xFFFF;
pub const MEM_SIZE: usize = 0xFFFF;
type Memory = [u8; MEM_SIZE];
pub type Memory = [u8; MEM_SIZE];
#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Clone)]
enum Statement {
pub enum Statement {
Inc,
Dec,
R,
@ -20,11 +23,11 @@ enum Statement {
const ALLOWED_CHARS: [char; 8] = ['>', '<', '+', '-', '.', ',', '[', ']'];
fn minify(code: &str) -> String {
pub fn minify(code: &str) -> String {
code.chars().filter(|c| ALLOWED_CHARS.contains(c)).collect()
}
fn parse(chars: Vec<char>, direct_print: bool) -> Vec<Statement> {
pub fn parse(chars: Chars, print_mode: PrintMode) -> Vec<Statement> {
let mut loop_stack = vec![vec![]];
for c in chars {
@ -34,10 +37,9 @@ fn parse(chars: Vec<char>, direct_print: bool) -> Vec<Statement> {
'>' => loop_stack.last_mut().unwrap().push(Statement::R),
'<' => loop_stack.last_mut().unwrap().push(Statement::L),
'.' => {
if direct_print {
loop_stack.last_mut().unwrap().push(Statement::DOut)
} else {
loop_stack.last_mut().unwrap().push(Statement::Out)
match print_mode {
PrintMode::ToString => loop_stack.last_mut().unwrap().push(Statement::Out),
PrintMode::DirectPrint => loop_stack.last_mut().unwrap().push(Statement::DOut)
}
}
',' => loop_stack.last_mut().unwrap().push(Statement::In),

View file

@ -24,7 +24,7 @@ enum ExStatement {
Loop(Vec<ExStatement>),
SetNull,
Repeat(Box<ExStatement>, usize),
ForLoop(usize, Box<ExStatement>),
_ForLoop(usize, Box<ExStatement>),
}
impl From<Statement> for ExStatement {
@ -46,7 +46,7 @@ impl From<Statement> for ExStatement {
#[derive(Debug)]
pub struct BfErr {
msg: &'static str
msg: &'static str,
}
impl BfErr {
@ -64,10 +64,15 @@ impl Display for BfErr {
impl Error for BfErr {}
pub fn run(pgm: &str, direct_print: bool) -> Result<String, BfErr> {
pub enum PrintMode {
ToString,
DirectPrint,
}
pub fn run(pgm: &str, print_mode: PrintMode) -> Result<String, BfErr> {
let pgm = minify(pgm);
if pgm.is_empty() { return Err(BfErr::new("no program found")); };
let pgm = parse(pgm.chars().collect(), direct_print);
let pgm = parse(pgm.chars(), print_mode);
let pgm = optimize(&pgm);
let out = interpret(&pgm);
Ok(out)
@ -177,7 +182,7 @@ fn execute(statement: &ExStatement, mem: &mut Memory, pointer: &mut usize, out:
}
}
}
ExStatement::ForLoop(offset, statement) => {
ExStatement::_ForLoop(offset, statement) => {
*pointer += offset;
while mem[*pointer - offset] != 0 {
execute(statement, mem, pointer, out);

View file

@ -7,12 +7,12 @@ use crate::interpreter::optimized::ExStatement;
///
/// Replace this: `[>>x<<-]` or `[->>x<<]` with `WhileAdd(2, x)`
fn for_loop(to_test: ExStatement) -> ExStatement {
fn _for_loop(to_test: ExStatement) -> ExStatement {
match to_test {
ExStatement::Loop(v) => {
match v[..] {
[ExStatement::R, ExStatement::Inc, ExStatement::L, ExStatement::Dec] => {
ExStatement::ForLoop(1, Box::from(ExStatement::Inc))
ExStatement::_ForLoop(1, Box::from(ExStatement::Inc))
}
_ => ExStatement::Loop(v)
}
@ -26,18 +26,18 @@ fn for_loop(to_test: ExStatement) -> ExStatement {
#[cfg(test)]
mod test {
use crate::interpreter::optimized::ExStatement::{Out, Loop, Inc, R, L, Dec, ForLoop};
use crate::interpreter::optimized::patterns::for_loop;
use crate::interpreter::optimized::ExStatement::{Out, Loop, Inc, R, L, Dec, _ForLoop};
use crate::interpreter::optimized::patterns::_for_loop;
#[test]
fn for_loop_false() {
let statement = Loop(vec![Out, Inc]);
assert_eq!(statement.clone(), for_loop(statement));
assert_eq!(statement.clone(), _for_loop(statement));
}
#[test]
fn for_loop_simplest() {
let statement = Loop(vec![R, Inc, L, Dec]);
assert_eq!(ForLoop(1, Box::from(Inc)), for_loop(statement));
assert_eq!(_ForLoop(1, Box::from(Inc)), _for_loop(statement));
}
}

View file

@ -8,13 +8,16 @@
use std::io::{Read, stdin, Write};
use crate::interpreter::{MEM_SIZE, Memory, minify, parse, Statement};
use crate::interpreter::optimized::PrintMode;
use crate::repl::BrainfuckState;
pub fn run(pgm: &str) -> String {
let pgm = minify(pgm);
let pgm = parse(pgm.chars().collect(), false);
let pgm = parse(pgm.chars(), PrintMode::ToString);
interpret(&pgm)
}
fn interpret(pgm: &[Statement]) -> String {
let mut out = String::new();
let mut pointer: usize = 0;
@ -27,6 +30,12 @@ fn interpret(pgm: &[Statement]) -> String {
out
}
pub fn interpret_with_state(pgm: &[Statement], state: &mut BrainfuckState) {
for s in pgm {
execute(s, &mut state.memory, &mut state.pointer, &mut String::new())
}
}
fn execute(statement: &Statement, mem: &mut Memory, pointer: &mut usize, out: &mut String) {
match statement {
Statement::R => if *pointer == MEM_SIZE - 1 { *pointer = 0 } else { *pointer += 1 },