mirror of
https://github.com/Noratrieb/brainfuck.git
synced 2026-01-14 13:35:00 +01:00
module restructuring
This commit is contained in:
parent
6d7205bc4b
commit
42fc197341
6 changed files with 53 additions and 30 deletions
|
|
@ -1,6 +1,6 @@
|
|||
pub mod o0;
|
||||
pub mod o1;
|
||||
pub mod o2;
|
||||
pub mod simple;
|
||||
pub mod parsed;
|
||||
pub mod optimized;
|
||||
|
||||
const MEM_SIZE: usize = 0xFFFF;
|
||||
|
||||
|
|
@ -13,6 +13,7 @@ enum Statement {
|
|||
R,
|
||||
L,
|
||||
Out,
|
||||
DOut,
|
||||
In,
|
||||
Loop(Vec<Statement>),
|
||||
}
|
||||
|
|
@ -23,7 +24,7 @@ fn minify(code: &str) -> String {
|
|||
code.chars().filter(|c| ALLOWED_CHARS.contains(c)).collect()
|
||||
}
|
||||
|
||||
fn parse(chars: Vec<char>) -> Vec<Statement> {
|
||||
fn parse(chars: Vec<char>, direct_print: bool) -> Vec<Statement> {
|
||||
let mut loop_stack = vec![vec![]];
|
||||
|
||||
for c in chars {
|
||||
|
|
@ -32,7 +33,13 @@ fn parse(chars: Vec<char>) -> Vec<Statement> {
|
|||
'-' => loop_stack.last_mut().unwrap().push(Statement::Dec),
|
||||
'>' => loop_stack.last_mut().unwrap().push(Statement::R),
|
||||
'<' => loop_stack.last_mut().unwrap().push(Statement::L),
|
||||
'.' => loop_stack.last_mut().unwrap().push(Statement::Out),
|
||||
'.' => {
|
||||
if direct_print {
|
||||
loop_stack.last_mut().unwrap().push(Statement::DOut)
|
||||
} else {
|
||||
loop_stack.last_mut().unwrap().push(Statement::Out)
|
||||
}
|
||||
}
|
||||
',' => loop_stack.last_mut().unwrap().push(Statement::In),
|
||||
'[' => loop_stack.push(vec![]),
|
||||
']' => {
|
||||
|
|
@ -62,7 +69,7 @@ mod tests {
|
|||
fn parse_no_loop() {
|
||||
let program = "+-<>,.";
|
||||
let statements = vec![Inc, Dec, L, R, In, Out];
|
||||
let result = parse(program.chars().collect());
|
||||
let result = parse(program.chars().collect(), false);
|
||||
|
||||
assert_eq!(statements, result);
|
||||
}
|
||||
|
|
@ -71,7 +78,7 @@ mod tests {
|
|||
fn parse_simple_loop() {
|
||||
let program = "+[<<]-";
|
||||
let statements = vec![Inc, Loop(vec![L, L]), Dec];
|
||||
let result = parse(program.chars().collect());
|
||||
let result = parse(program.chars().collect(), false);
|
||||
|
||||
assert_eq!(statements, result);
|
||||
}
|
||||
|
|
@ -80,7 +87,7 @@ mod tests {
|
|||
fn parse_complex_loops() {
|
||||
let program = ">[<[][<[<]>]>[>]]";
|
||||
let statements = vec![R, Loop(vec![L, Loop(vec![]), Loop(vec![L, Loop(vec![L]), R]), R, Loop(vec![R])])];
|
||||
let result = parse(program.chars().collect());
|
||||
let result = parse(program.chars().collect(), false);
|
||||
|
||||
assert_eq!(statements, result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
//! some better optimizations like set null, repeating and doing more stuff with simplifying stuff
|
||||
//!
|
||||
|
||||
use std::io::{Read, stdin};
|
||||
mod patterns;
|
||||
|
||||
use std::io::{Read, stdin, Write};
|
||||
|
||||
use crate::interpreter::{minify, parse, Statement, Memory, MEM_SIZE};
|
||||
use std::error::Error;
|
||||
|
|
@ -17,6 +19,7 @@ enum ExStatement {
|
|||
R,
|
||||
L,
|
||||
Out,
|
||||
DOut,
|
||||
In,
|
||||
Loop(Vec<ExStatement>),
|
||||
SetNull,
|
||||
|
|
@ -35,6 +38,7 @@ impl From<Statement> for ExStatement {
|
|||
Statement::Loop(v) => ExStatement::Loop(
|
||||
v.into_iter().map(|s| ExStatement::from(s)).collect()
|
||||
),
|
||||
Statement::DOut => ExStatement::DOut
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -59,10 +63,10 @@ impl Display for BfErr {
|
|||
impl Error for BfErr {}
|
||||
|
||||
|
||||
pub fn run(pgm: &str) -> Result<String, BfErr> {
|
||||
pub fn run(pgm: &str, direct_print: bool) -> Result<String, BfErr> {
|
||||
let pgm = minify(pgm);
|
||||
if pgm.len() < 1 { return Err(BfErr::new("no program found")); };
|
||||
let pgm = parse(pgm.chars().collect());
|
||||
let pgm = parse(pgm.chars().collect(), direct_print);
|
||||
let pgm = optimize(&pgm);
|
||||
let out = interpret(&pgm);
|
||||
Ok(out)
|
||||
|
|
@ -89,6 +93,7 @@ fn o_set_null(code: &Vec<Statement>) -> Vec<ExStatement> {
|
|||
Statement::R => ExStatement::R,
|
||||
Statement::L => ExStatement::L,
|
||||
Statement::Out => ExStatement::Out,
|
||||
Statement::DOut => ExStatement::DOut,
|
||||
Statement::In => ExStatement::In,
|
||||
}
|
||||
}).collect()
|
||||
|
|
@ -133,6 +138,10 @@ fn execute(statement: &ExStatement, mem: &mut Memory, pointer: &mut usize, out:
|
|||
ExStatement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(1),
|
||||
ExStatement::SetNull => mem[*pointer] = 0,
|
||||
ExStatement::Out => out.push(mem[*pointer] as u8 as char),
|
||||
ExStatement::DOut => {
|
||||
print!("{}", mem[*pointer] as u8 as char);
|
||||
std::io::stdout().flush().unwrap();
|
||||
}
|
||||
ExStatement::In => {
|
||||
let mut in_buffer = [0, 1];
|
||||
stdin().read(&mut in_buffer).unwrap();
|
||||
|
|
@ -156,22 +165,16 @@ fn execute(statement: &ExStatement, mem: &mut Memory, pointer: &mut usize, out:
|
|||
ExStatement::L => *pointer = (*pointer).wrapping_sub(*amount),
|
||||
ExStatement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(*amount as u8),
|
||||
ExStatement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(*amount as u8),
|
||||
ExStatement::Out => {
|
||||
for _ in 0..*amount {
|
||||
execute(&ExStatement::Out, mem, pointer, out)
|
||||
}
|
||||
}
|
||||
ExStatement::In => {
|
||||
for _ in 0..*amount {
|
||||
execute(&ExStatement::In, mem, pointer, out)
|
||||
}
|
||||
}
|
||||
ExStatement::Loop(v) => {
|
||||
for _ in 0..*amount {
|
||||
execute(&ExStatement::Loop(v.clone()), mem, pointer, out)
|
||||
}
|
||||
}
|
||||
_ => panic!("Invalid statement in repeat: {:?}", *statement)
|
||||
s => {
|
||||
for _ in 0..*amount {
|
||||
execute(s, mem, pointer, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -180,20 +183,21 @@ fn execute(statement: &ExStatement, mem: &mut Memory, pointer: &mut usize, out:
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::interpreter::o2::{run, o_repeat};
|
||||
use crate::interpreter::o2::ExStatement::{L, R, Inc, Dec, Repeat};
|
||||
use crate::interpreter::optimized::{run, o_repeat};
|
||||
use crate::interpreter::optimized::ExStatement::{Inc, Repeat, R, L};
|
||||
use crate::interpreter::Statement::Dec;
|
||||
|
||||
#[test]
|
||||
fn run_loop() {
|
||||
let program = "++++++++++[>++++++++++<-]>.";
|
||||
let out = run(program).unwrap();
|
||||
let out = run(program, false).unwrap();
|
||||
assert_eq!(out, String::from("d"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hello_world() {
|
||||
let program = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";
|
||||
let out = run(program).unwrap();
|
||||
let out = run(program, false).unwrap();
|
||||
assert_eq!(out, String::from("Hello World!\n"));
|
||||
}
|
||||
|
||||
8
bfi-rust/src/interpreter/optimized/patterns.rs
Normal file
8
bfi-rust/src/interpreter/optimized/patterns.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
//!
|
||||
//! # Patterns find and replace
|
||||
//! Pattern-match ExStatements and replace them with optimizations like add, multiply etc
|
||||
//!
|
||||
//! A pattern might look a bit like this: `Loop(Dec)` -> `SetNull`
|
||||
|
||||
|
||||
struct Pattern {}
|
||||
|
|
@ -5,13 +5,13 @@
|
|||
//! most importantly: loop jumps should be immediate
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::io::{Read, stdin};
|
||||
use std::io::{Read, stdin, Write};
|
||||
|
||||
use crate::interpreter::{MEM_SIZE, Memory, minify, parse, Statement};
|
||||
|
||||
pub fn run(pgm: &str) -> String {
|
||||
let pgm = minify(pgm);
|
||||
let pgm = parse(pgm.chars().collect());
|
||||
let pgm = parse(pgm.chars().collect(), false);
|
||||
let out = interpret(&pgm);
|
||||
out
|
||||
}
|
||||
|
|
@ -47,13 +47,17 @@ fn execute(statement: &Statement, mem: &mut Memory, pointer: &mut usize, out: &m
|
|||
}
|
||||
}
|
||||
}
|
||||
Statement::DOut => {
|
||||
print!("{}", mem[*pointer] as u8 as char);
|
||||
std::io::stdout().flush().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::interpreter::o1::{execute, run, Statement};
|
||||
use crate::interpreter::parsed::{execute, run, Statement};
|
||||
|
||||
#[test]
|
||||
fn execute_simple() {
|
||||
|
|
@ -30,7 +30,7 @@ fn run(program: String) {
|
|||
let out = interpreter::o1::run(&*program);
|
||||
let end1 = start1.elapsed().unwrap();*/
|
||||
let start2 = SystemTime::now();
|
||||
let out2 = interpreter::o2::run(&*program).unwrap();
|
||||
let out2 = interpreter::o2::run(&*program, false).unwrap();
|
||||
let end2 = start2.elapsed().unwrap();
|
||||
//assert_eq!(out, out2);
|
||||
//println!("{}\nFinished execution. Took o1: 18008ms (for hanoi), o2: {}ms", out2/*, end1.as_millis()*/, end2.as_millis());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue