mirror of
https://github.com/Noratrieb/brainfuck.git
synced 2026-01-16 06:15:02 +01:00
o2 start
This commit is contained in:
parent
81c0decd48
commit
7b6046745c
4 changed files with 358 additions and 351 deletions
207
bfi-rust/bf.b
207
bfi-rust/bf.b
|
|
@ -1,163 +1,44 @@
|
||||||
* factor an arbitrarily large positive integer
|
>+++++++++[<+++++++++++>-]<[>[-]>[-]<<[>+>+<<-]>>[<<+>>-]>>>
|
||||||
*
|
[-]<<<+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>>+<
|
||||||
* Copyright (C) 1999 by Brian Raiter
|
-]<<-<-]+++++++++>[<->-]>>+>[<[-]<<+>>>-]>[-]+<<[>+>-<<-]<<<
|
||||||
* under the GNU General Public License
|
[>>+>+<<<-]>>>[<<<+>>>-]>[<+>-]<<-[>[-]<[-]]>>+<[>[-]<-]<+++
|
||||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-
|
+++++[<++++++<++++++>>-]>>>[>+>+<<-]>>[<<+>>-]<[<<<<<.>>>>>-
|
||||||
*
|
]<<<<<<.>>[-]>[-]++++[<++++++++>-]<.>++++[<++++++++>-]<++.>+
|
||||||
* read in the number
|
++++[<+++++++++>-]<.><+++++..--------.-------.>>[>>+>+<<<-]>
|
||||||
*
|
>>[<<<+>>>-]<[<<<<++++++++++++++.>>>>-]<<<<[-]>++++[<+++++++
|
||||||
<<<<<<<<<+
|
+>-]<.>+++++++++[<+++++++++>-]<--.---------.>+++++++[<------
|
||||||
[-[>>>>>>>>>>][-]<<<<<<<<<<[[->>>>>>>>>>+<<<<<<<<<<]<<<<<<<<<<]
|
---->-]<.>++++++[<+++++++++++>-]<.+++..+++++++++++++.>++++++
|
||||||
>>>>>>>>>>,----------]
|
++[<---------->-]<--.>+++++++++[<+++++++++>-]<--.-.>++++++++
|
||||||
>>>>>>>>>>[------------------------------------->>>>>>>>>->]
|
[<---------->-]<++.>++++++++[<++++++++++>-]<++++.-----------
|
||||||
<[+>[>>>>>>>>>+>]<-<<<<<<<<<<]-
|
-.---.>+++++++[<---------->-]<+.>++++++++[<+++++++++++>-]<-.
|
||||||
*
|
>++[<----------->-]<.+++++++++++..>+++++++++[<---------->-]<
|
||||||
* display the number and initialize the loop variable to two
|
-----.---.>>>[>+>+<<-]>>[<<+>>-]<[<<<<<.>>>>>-]<<<<<<.>>>+++
|
||||||
*
|
+[<++++++>-]<--.>++++[<++++++++>-]<++.>+++++[<+++++++++>-]<.
|
||||||
[>++++++++++++++++++++++++++++++++++++++++++++++++.
|
><+++++..--------.-------.>>[>>+>+<<<-]>>>[<<<+>>>-]<[<<<<++
|
||||||
------------------------------------------------<<<<<<<<<<<]
|
++++++++++++.>>>>-]<<<<[-]>++++[<++++++++>-]<.>+++++++++[<++
|
||||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.
|
+++++++>-]<--.---------.>+++++++[<---------->-]<.>++++++[<++
|
||||||
--------------------------.[-]
|
+++++++++>-]<.+++..+++++++++++++.>++++++++++[<---------->-]<
|
||||||
>>>>>>>>>>>>++<<<<+
|
-.---.>+++++++[<++++++++++>-]<++++.+++++++++++++.++++++++++.
|
||||||
*
|
------.>+++++++[<---------->-]<+.>++++++++[<++++++++++>-]<-.
|
||||||
* the main loop
|
-.---------.>+++++++[<---------->-]<+.>+++++++[<++++++++++>-
|
||||||
*
|
]<--.+++++++++++.++++++++.---------.>++++++++[<---------->-]
|
||||||
[ [-]>>
|
<++.>+++++[<+++++++++++++>-]<.+++++++++++++.----------.>++++
|
||||||
*
|
+++[<---------->-]<++.>++++++++[<++++++++++>-]<.>+++[<----->
|
||||||
* make copies of the number and the loop variable
|
-]<.>+++[<++++++>-]<..>+++++++++[<--------->-]<--.>+++++++[<
|
||||||
*
|
++++++++++>-]<+++.+++++++++++.>++++++++[<----------->-]<++++
|
||||||
[>>>>[-]>[-]>[-]>[-]
|
.>+++++[<+++++++++++++>-]<.>+++[<++++++>-]<-.---.++++++.----
|
||||||
>[-]>[-]
|
---.----------.>++++++++[<----------->-]<+.---.[-]<<<->[-]>[
|
||||||
<<<<<<<[->>>+>+<<<<]>>>>>>>>]
|
-]<<[>+>+<<-]>>[<<+>>-]>>>[-]<<<+++++++++<[>>>+<<[>+>[-]<<-]
|
||||||
<<<<<<<<<<[>>>>>>[-<<<<+>>>>]<<<<<<<<<<<<<<<<]>>>>>>>>>>
|
>[<+>-]>[<<++++++++++>>>+<-]<<-<-]+++++++++>[<->-]>>+>[<[-]<
|
||||||
[>[->>>+>>+<<<<<]>>>>>>>>>]
|
<+>>>-]>[-]+<<[>+>-<<-]<<<[>>+>+<<<-]>>>[<<<+>>>-]<>>[<+>-]<
|
||||||
<<<<<<<<<<[>>>>>>[-<<<<<+>>>>>]<<<<<<<<<<<<<<<<]>>>>>>>>>>
|
<-[>[-]<[-]]>>+<[>[-]<-]<++++++++[<++++++<++++++>>-]>>>[>+>+
|
||||||
*
|
<<-]>>[<<+>>-]<[<<<<<.>>>>>-]<<<<<<.>>[-]>[-]++++[<++++++++>
|
||||||
* divide the number by the loop variable
|
-]<.>++++[<++++++++>-]<++.>+++++[<+++++++++>-]<.><+++++..---
|
||||||
*
|
-----.-------.>>[>>+>+<<<-]>>>[<<<+>>>-]<[<<<<++++++++++++++
|
||||||
[>>>[-]>>>[-]>[-]>>>] initialize
|
.>>>>-]<<<<[-]>++++[<++++++++>-]<.>+++++++++[<+++++++++>-]<-
|
||||||
<<<<<<<<<<[<<<<<<<<<<]
|
-.---------.>+++++++[<---------->-]<.>++++++[<+++++++++++>-]
|
||||||
>>>>>>>>>[-]>>>>>>>+<<<<<<<<[+]+
|
<.+++..+++++++++++++.>++++++++[<---------->-]<--.>+++++++++[
|
||||||
[ ->> double divisor until above dividend
|
<+++++++++>-]<--.-.>++++++++[<---------->-]<++.>++++++++[<++
|
||||||
[>>>>>>[->++<]>>>>]<<<<<<<<<<
|
++++++++>-]<++++.------------.---.>+++++++[<---------->-]<+.
|
||||||
[>>>>>>>>[-]>[-]
|
>++++++++[<+++++++++++>-]<-.>++[<----------->-]<.+++++++++++
|
||||||
<<<<[->>>++<<<]<<<<<<<<<<<<<<<]>>>>>>>>>>
|
..>+++++++++[<---------->-]<-----.---.+++.---.[-]<<<]
|
||||||
[>>>>>>>>[->+<[->+<[->+<[->+<[->+<[->+<[->+<[->+<[->+<
|
|
||||||
[->--------->>>>>>>>>+<<<<<<<<<<[->+<]]]]]]]]]]]>>]
|
|
||||||
<<<<<<<<<<[>>>>>>>>>[-<+<<<+>>>>]<<<<<<<<<<<<<<<<<<<]>>>>>>>>>>
|
|
||||||
[>>>>>>>[-<+>[-<+>[-<+>[-<+>[-<+>[-<+>[-<+>[-<+>[-<+>
|
|
||||||
[-<--------->>>>>>>>>>>+<<<<<<<<<<[-<+>]]]]]]]]]]]>>>]
|
|
||||||
<<<<<<<<<<
|
|
||||||
[>>>>[->>>+>>+<<<<<]<<<<<<<<<<<<<<]
|
|
||||||
>>>>>>>>>>[>>>>>>>[-<<<+>>>]>>>]<<<<<<<<<<
|
|
||||||
[>>>>>>>>[->-<]>
|
|
||||||
[<<<<<<<<<[<[-]>>>>>>>>>>[-<<<<<<<<<<+>>>>>>>>>>]<<<<<<<<<<<<<<<<<<<]
|
|
||||||
>>>>>>>>>>>>>>>>>>>]
|
|
||||||
<<<<<<<<<<<<<<<<<<<]
|
|
||||||
>>>>>>>>>[+[+[+[+[+[+[+[+[+[+[[-]<+>]]]]]]]]]]]<
|
|
||||||
]
|
|
||||||
>>>>>>>>
|
|
||||||
[ subtract divisor from dividend
|
|
||||||
<<<<<<
|
|
||||||
[>>>>>>>>[-]>[-]<<<<<[->>>+>+<<<<]>>>>>>]<<<<<<<<<<
|
|
||||||
[>>>>>>>>[-<<<<+>>>>]<<<[->>>+>+<<<<]<<<<<<<<<<<<<<<]>>>>>>>>>>
|
|
||||||
[>>>>>>>>>[-<<<<+>>>>]>]<<<<<<<<<<
|
|
||||||
[>>>>>>>>[-<->]<<<<<<<<<<<<<<<<<<]>>>>>>>>>>
|
|
||||||
[>>>>>>>[->+<[->+<[->+<[->+<[->+<[->+<[->+<[->+<[->+<[->+<
|
|
||||||
[++++++++++[+>-<]>>>>>>>>>>-<<<<<<<<<<]]]]]]]]]]]>>>]
|
|
||||||
>>>>>>>+
|
|
||||||
[ if difference is nonnegative then
|
|
||||||
[-]<<<<<<<<<<<<<<<<< replace dividend and increment quotient
|
|
||||||
[>>>>[-]>>>>[-<<<<+>>>>]<<[->>+<<]<<<<<<<<<<<<<<<<]>>>>>>>>>>
|
|
||||||
[>>>>>>>>[->+<<<+>>]>>]<<<<<<<<<<
|
|
||||||
[>>>[->>>>>>+<<<<<<]<<<<<<<<<<<<<]>>>>>>>>>>
|
|
||||||
[>>>>>>>>>[-<<<<<<+>>>>>>[-<<<<<<+>>>>>>
|
|
||||||
[-<<<<<<+>>>>>>[-<<<<<<+>>>>>>
|
|
||||||
[-<<<<<<+>>>>>>[-<<<<<<+>>>>>>
|
|
||||||
[-<<<<<<+>>>>>>[-<<<<<<+>>>>>>
|
|
||||||
[-<<<<<<+>>>>>>[-<<<<<<--------->>>>>>>>>>>>>>>>+<<<<<<<<<<
|
|
||||||
[-<<<<<<+>>>>>>]]]]]]]]]]]>]
|
|
||||||
>>>>>>>
|
|
||||||
] halve divisor and loop until zero
|
|
||||||
<<<<<<<<<<<<<<<<<[<<<<<<<<<<]>>>>>>>>>>
|
|
||||||
[>>>>>>>>[-]<<[->+<]<[->>>+<<<]>>>>>]<<<<<<<<<<
|
|
||||||
[+>>>>>>>[-<<<<<<<+>>>>>>>[-<<<<<<<->>>>>>+>
|
|
||||||
[-<<<<<<<+>>>>>>>[-<<<<<<<->>>>>>+>
|
|
||||||
[-<<<<<<<+>>>>>>>[-<<<<<<<->>>>>>+>
|
|
||||||
[-<<<<<<<+>>>>>>>[-<<<<<<<->>>>>>+>
|
|
||||||
[-<<<<<<<+>>>>>>>]]]]]]]]]<<<<<<<
|
|
||||||
[->>>>>>>+<<<<<<<]-<<<<<<<<<<]
|
|
||||||
>>>>>>>
|
|
||||||
[-<<<<<<<<<<<+>>>>>>>>>>>]
|
|
||||||
>>>[>>>>>>>[-<<<<<<<<<<<+++++>>>>>>>>>>>]>>>]<<<<<<<<<<
|
|
||||||
[+>>>>>>>>[-<<<<<<<<+>>>>>>>>[-<<<<<<<<->>>>>+>>>
|
|
||||||
[-<<<<<<<<+>>>>>>>>[-<<<<<<<<->>>>>+>>>
|
|
||||||
[-<<<<<<<<+>>>>>>>>[-<<<<<<<<->>>>>+>>>
|
|
||||||
[-<<<<<<<<+>>>>>>>>[-<<<<<<<<->>>>>+>>>
|
|
||||||
[-<<<<<<<<+>>>>>>>>]]]]]]]]]<<<<<<<<
|
|
||||||
[->>>>>>>>+<<<<<<<<]-<<<<<<<<<<]
|
|
||||||
>>>>>>>>[-<<<<<<<<<<<<<+>>>>>>>>>>>>>]>>
|
|
||||||
[>>>>>>>>[-<<<<<<<<<<<<<+++++>>>>>>>>>>>>>]>>]<<<<<<<<<<
|
|
||||||
[<<<<<<<<<<]>>>>>>>>>>
|
|
||||||
>>>>>>
|
|
||||||
]
|
|
||||||
<<<<<<
|
|
||||||
*
|
|
||||||
* make copies of the loop variable and the quotient
|
|
||||||
*
|
|
||||||
[>>>[->>>>+>+<<<<<]>>>>>>>]
|
|
||||||
<<<<<<<<<<
|
|
||||||
[>>>>>>>[-<<<<+>>>>]<<<<<[->>>>>+>>+<<<<<<<]<<<<<<<<<<<<]
|
|
||||||
>>>>>>>>>>[>>>>>>>[-<<<<<+>>>>>]>>>]<<<<<<<<<<
|
|
||||||
*
|
|
||||||
* break out of the loop if the quotient is larger than the loop variable
|
|
||||||
*
|
|
||||||
[>>>>>>>>>[-<->]<
|
|
||||||
[<<<<<<<<
|
|
||||||
[<<[-]>>>>>>>>>>[-<<<<<<<<<<+>>>>>>>>>>]<<<<<<<<<<<<<<<<<<]
|
|
||||||
>>>>>>>>>>>>>>>>>>]<<<<<<<<<<<<<<<<<<]
|
|
||||||
>>>>>>>>[>-<[+[+[+[+[+[+[+[+[+[[-]>+<]]]]]]]]]]]>+
|
|
||||||
[ [-]
|
|
||||||
*
|
|
||||||
* partially increment the loop variable
|
|
||||||
*
|
|
||||||
<[-]+>>>>+>>>>>>>>[>>>>>>>>>>]<<<<<<<<<<
|
|
||||||
*
|
|
||||||
* examine the remainder for nonzero digits
|
|
||||||
*
|
|
||||||
[<<<<<<[<<<<[<<<<<<<<<<]>>>>+<<<<<<<<<<]<<<<]
|
|
||||||
>>>>>>>>>>>>>>>>>>>>[>>>>>>>>>>]<<<<<<<<<<[<<<<<<<<<<]
|
|
||||||
>>>>-
|
|
||||||
[ [+]
|
|
||||||
*
|
|
||||||
* decrement the loop variable and replace the number with the quotient
|
|
||||||
*
|
|
||||||
>>>>>>>>-<<[>[-]>>[-<<+>>]>>>>>>>]<<<<<<<<<<
|
|
||||||
*
|
|
||||||
* display the loop variable
|
|
||||||
*
|
|
||||||
[+>>[>>>>>>>>+>>]<<-<<<<<<<<<<]-
|
|
||||||
[>>++++++++++++++++++++++++++++++++++++++++++++++++.
|
|
||||||
------------------------------------------------<<<<<<<<<<<<]
|
|
||||||
++++++++++++++++++++++++++++++++.[-]>>>>
|
|
||||||
]
|
|
||||||
*
|
|
||||||
* normalize the loop variable
|
|
||||||
*
|
|
||||||
>>>>>>
|
|
||||||
[>>[->>>>>+<<<<<[->>>>>+<<<<<
|
|
||||||
[->>>>>+<<<<<[->>>>>+<<<<<
|
|
||||||
[->>>>>+<<<<<[->>>>>+<<<<<
|
|
||||||
[->>>>>+<<<<<[->>>>>+<<<<<
|
|
||||||
[->>>>>+<<<<<[->>>>>--------->>>>>+<<<<<<<<<<
|
|
||||||
[->>>>>+<<<<<]]]]]]]]]]]>>>>>>>>]
|
|
||||||
<<<<<<<<<<[>>>>>>>[-<<<<<+>>>>>]<<<<<<<<<<<<<<<<<]
|
|
||||||
>>>>>>>>>
|
|
||||||
]<
|
|
||||||
]>>
|
|
||||||
*
|
|
||||||
* display the number and end
|
|
||||||
*
|
|
||||||
[>>>>>>>>>>]<<<<<<<<<<[+>[>>>>>>>>>+>]<-<<<<<<<<<<]-
|
|
||||||
[>++++++++++++++++++++++++++++++++++++++++++++++++.<<<<<<<<<<<]
|
|
||||||
++++++++++.
|
|
||||||
303
bfi-rust/src/interpreter/mod.rs
Normal file
303
bfi-rust/src/interpreter/mod.rs
Normal file
|
|
@ -0,0 +1,303 @@
|
||||||
|
const MEM_SIZE: usize = 0xFFFF;
|
||||||
|
|
||||||
|
type Memory = [u8; MEM_SIZE];
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, PartialOrd, PartialEq, Clone)]
|
||||||
|
enum SimpleStatement {
|
||||||
|
Inc,
|
||||||
|
Dec,
|
||||||
|
R,
|
||||||
|
L,
|
||||||
|
Out,
|
||||||
|
In,
|
||||||
|
Loop(Vec<SimpleStatement>),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn minify(code: &str) -> String {
|
||||||
|
let allowed: Vec<char> = vec!['>', '<', '+', '-', '.', ',', '[', ']'];
|
||||||
|
code.chars().filter(|c| allowed.contains(c)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(chars: Vec<char>) -> Vec<SimpleStatement> {
|
||||||
|
let mut loop_stack = vec![vec![]];
|
||||||
|
|
||||||
|
for c in chars {
|
||||||
|
match c {
|
||||||
|
'+' => loop_stack.last_mut().unwrap().push(SimpleStatement::Inc),
|
||||||
|
'-' => loop_stack.last_mut().unwrap().push(SimpleStatement::Dec),
|
||||||
|
'>' => loop_stack.last_mut().unwrap().push(SimpleStatement::R),
|
||||||
|
'<' => loop_stack.last_mut().unwrap().push(SimpleStatement::L),
|
||||||
|
'.' => loop_stack.last_mut().unwrap().push(SimpleStatement::Out),
|
||||||
|
',' => loop_stack.last_mut().unwrap().push(SimpleStatement::In),
|
||||||
|
'[' => loop_stack.push(vec![]),
|
||||||
|
']' => {
|
||||||
|
let statement = SimpleStatement::Loop(loop_stack.pop().unwrap());
|
||||||
|
loop_stack.last_mut().unwrap().push(statement);
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return loop_stack.pop().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// # optimization time
|
||||||
|
///
|
||||||
|
/// first parse the bf so that it can be executed faster
|
||||||
|
/// most importantly: loop jumps should be immediate
|
||||||
|
///
|
||||||
|
pub(crate) mod o1 {
|
||||||
|
use std::io::{Read, stdin};
|
||||||
|
|
||||||
|
use crate::interpreter::{MEM_SIZE, Memory, minify, parse, SimpleStatement};
|
||||||
|
|
||||||
|
pub fn run(pgm: &str) -> String {
|
||||||
|
let pgm = minify(pgm);
|
||||||
|
let pgm = parse(pgm.chars().collect());
|
||||||
|
let out = interpret(&pgm);
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interpret(pgm: &Vec<SimpleStatement>) -> String {
|
||||||
|
let mut out = String::new();
|
||||||
|
let mut pointer: usize = 0;
|
||||||
|
let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE];
|
||||||
|
|
||||||
|
for s in pgm {
|
||||||
|
execute(s, &mut mem, &mut pointer, &mut out)
|
||||||
|
}
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute(statement: &SimpleStatement, mem: &mut Memory, pointer: &mut usize, out: &mut String) {
|
||||||
|
match statement {
|
||||||
|
SimpleStatement::R => if *pointer == MEM_SIZE - 1 { *pointer = 0 } else { *pointer += 1 },
|
||||||
|
SimpleStatement::L => if *pointer == 0 { *pointer = MEM_SIZE - 1 } else { *pointer -= 1 },
|
||||||
|
SimpleStatement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(1),
|
||||||
|
SimpleStatement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(1),
|
||||||
|
SimpleStatement::Out => out.push(mem[*pointer] as u8 as char),
|
||||||
|
SimpleStatement::In => {
|
||||||
|
let mut in_buffer = [0, 1];
|
||||||
|
stdin().read(&mut in_buffer).unwrap();
|
||||||
|
mem[*pointer] = in_buffer[0] as u8;
|
||||||
|
}
|
||||||
|
SimpleStatement::Loop(vec) => {
|
||||||
|
while mem[*pointer] != 0 {
|
||||||
|
for s in vec {
|
||||||
|
execute(&s, mem, pointer, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::interpreter::o1::{execute, run, Statement};
|
||||||
|
use crate::interpreter::o1::Statement::{Dec, In, Inc, L, Loop, Out, R};
|
||||||
|
use crate::interpreter::parse;
|
||||||
|
use crate::o1::{execute, parse, run, Statement::{self, Dec, In, Inc, L, Loop, Out, R}};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn execute_simple() {
|
||||||
|
let mut pointer: usize = 0;
|
||||||
|
let mut mem: [u8; 65535] = [0; 65535];
|
||||||
|
let mut out = String::new();
|
||||||
|
|
||||||
|
execute(&Statement::R, &mut mem, &mut pointer, &mut out);
|
||||||
|
assert_eq!(pointer, 1);
|
||||||
|
execute(&Statement::L, &mut mem, &mut pointer, &mut out);
|
||||||
|
assert_eq!(pointer, 0);
|
||||||
|
execute(&Statement::Inc, &mut mem, &mut pointer, &mut out);
|
||||||
|
assert_eq!(mem[pointer], 1);
|
||||||
|
execute(&Statement::Dec, &mut mem, &mut pointer, &mut out);
|
||||||
|
assert_eq!(mem[pointer], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn execute_false_loop() {
|
||||||
|
let statement = Statement::Loop(vec![Statement::Inc, Statement::Inc, Statement::R]);
|
||||||
|
let mut pointer: usize = 0;
|
||||||
|
let mut mem: [u8; 65535] = [0; 65535];
|
||||||
|
|
||||||
|
execute(&statement, &mut mem, &mut pointer, &mut String::new());
|
||||||
|
assert_eq!(mem[0], 0);
|
||||||
|
assert_eq!(mem[1], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn execute_loop() {
|
||||||
|
let statement = Statement::Loop(vec![Statement::Inc, Statement::Inc, Statement::R]);
|
||||||
|
let mut pointer: usize = 0;
|
||||||
|
let mut mem: [u8; 65535] = [0; 65535];
|
||||||
|
mem[0] = 1;
|
||||||
|
|
||||||
|
execute(&statement, &mut mem, &mut pointer, &mut String::new());
|
||||||
|
assert_eq!(mem[0], 3);
|
||||||
|
assert_eq!(mem[1], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn run_loop() {
|
||||||
|
let program = "++++++++++[>++++++++++<-]>.";
|
||||||
|
let out = run(program);
|
||||||
|
assert_eq!(out, String::from("d"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hello_world() {
|
||||||
|
let program = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";
|
||||||
|
let out = run(program);
|
||||||
|
assert_eq!(out, String::from("Hello World!\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// # optimization time
|
||||||
|
/// some better optimizations like set null, repeating and doing more stuff with simplifying stuff
|
||||||
|
pub(crate) mod o2 {
|
||||||
|
use std::io::{Read, stdin};
|
||||||
|
|
||||||
|
use crate::interpreter::{minify, parse, SimpleStatement};
|
||||||
|
|
||||||
|
const MEM_SIZE: usize = 0xFFFF;
|
||||||
|
|
||||||
|
type Memory = [u8; MEM_SIZE];
|
||||||
|
|
||||||
|
enum Statement {
|
||||||
|
Inc,
|
||||||
|
Dec,
|
||||||
|
R,
|
||||||
|
L,
|
||||||
|
Out,
|
||||||
|
In,
|
||||||
|
Loop(Vec<Statement>),
|
||||||
|
SetNull,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn run(pgm: &str) -> String {
|
||||||
|
let pgm = minify(pgm);
|
||||||
|
let pgm = parse(pgm.chars().collect());
|
||||||
|
let pgm = optimize(&pgm);
|
||||||
|
let out = interpret(&pgm);
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn optimize(code: &Vec<SimpleStatement>) -> Vec<Statement> {
|
||||||
|
code.iter().map(|s| {
|
||||||
|
match s {
|
||||||
|
SimpleStatement::Loop(v) => {
|
||||||
|
if let [SimpleStatement::Dec] = v[..] {
|
||||||
|
Statement::SetNull
|
||||||
|
} else {
|
||||||
|
Statement::Loop(optimize(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SimpleStatement::Inc => Statement::Inc,
|
||||||
|
SimpleStatement::Dec => Statement::Dec,
|
||||||
|
SimpleStatement::R => Statement::R,
|
||||||
|
SimpleStatement::L => Statement::L,
|
||||||
|
SimpleStatement::Out => Statement::Out,
|
||||||
|
SimpleStatement::In => Statement::In,
|
||||||
|
}
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interpret(pgm: &Vec<Statement>) -> String {
|
||||||
|
let mut out = String::new();
|
||||||
|
let mut pointer: usize = 0;
|
||||||
|
let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE];
|
||||||
|
|
||||||
|
for s in pgm {
|
||||||
|
execute(s, &mut mem, &mut pointer, &mut out)
|
||||||
|
}
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
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 },
|
||||||
|
Statement::L => if *pointer == 0 { *pointer = MEM_SIZE - 1 } else { *pointer -= 1 },
|
||||||
|
Statement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(1),
|
||||||
|
Statement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(1),
|
||||||
|
Statement::SetNull => mem[*pointer] = 0,
|
||||||
|
Statement::Out => out.push(mem[*pointer] as u8 as char),
|
||||||
|
Statement::In => {
|
||||||
|
let mut in_buffer = [0, 1];
|
||||||
|
stdin().read(&mut in_buffer).unwrap();
|
||||||
|
mem[*pointer] = in_buffer[0] as u8;
|
||||||
|
}
|
||||||
|
Statement::Loop(vec) => {
|
||||||
|
while mem[*pointer] != 0 {
|
||||||
|
for s in vec {
|
||||||
|
execute(&s, mem, pointer, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::interpreter::o2::{execute, run};
|
||||||
|
use crate::interpreter::parse;
|
||||||
|
use crate::interpreter::SimpleStatement::{Dec, In, Inc, L, Loop, Out, R};
|
||||||
|
use crate::o2::{execute, parse, run};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn run_loop() {
|
||||||
|
let program = "++++++++++[>++++++++++<-]>.";
|
||||||
|
let out = run(program);
|
||||||
|
assert_eq!(out, String::from("d"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hello_world() {
|
||||||
|
let program = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";
|
||||||
|
let out = run(program);
|
||||||
|
assert_eq!(out, String::from("Hello World!\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::interpreter::parse;
|
||||||
|
use crate::interpreter::SimpleStatement::{Dec, In, Inc, L, Loop, Out, R};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_no_loop() {
|
||||||
|
let program = "+-<>,.";
|
||||||
|
let statements = vec![Inc, Dec, L, R, In, Out];
|
||||||
|
let result = parse(program.chars().collect());
|
||||||
|
|
||||||
|
assert_eq!(statements, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_simple_loop() {
|
||||||
|
let program = "+[<<]-";
|
||||||
|
let statements = vec![Inc, Loop(vec![L, L]), Dec];
|
||||||
|
let result = parse(program.chars().collect());
|
||||||
|
|
||||||
|
assert_eq!(statements, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
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());
|
||||||
|
|
||||||
|
assert_eq!(statements, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
|
mod interpreter;
|
||||||
|
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
use std::io::{Read, stdin};
|
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let path = env::args().skip(1).next();
|
let path = env::args().skip(1).next();
|
||||||
let path = match path {
|
let path = match path {
|
||||||
|
|
@ -18,191 +20,12 @@ fn main() {
|
||||||
fn run(path: String) {
|
fn run(path: String) {
|
||||||
println!("Path: {}", path);
|
println!("Path: {}", path);
|
||||||
let program = fs::read_to_string(path).unwrap();
|
let program = fs::read_to_string(path).unwrap();
|
||||||
let start = SystemTime::now();
|
let start1 = SystemTime::now();
|
||||||
let out = o1::run(&*program);
|
let out = interpreter::o1::run(&*program);
|
||||||
println!("{}\nFinished execution in {}ms", out, start.elapsed().unwrap().as_millis());
|
let end1 = start1.elapsed().unwrap();
|
||||||
}
|
let start2 = SystemTime::now();
|
||||||
|
let out2 = interpreter::o2::run(&*program);
|
||||||
///
|
let end2 = start2.elapsed().unwrap();
|
||||||
/// # optimization time
|
assert_eq!(out, out2);
|
||||||
///
|
println!("{}\nFinished execution. Took o1: {}ms, o2: {}ms", out, end1.as_millis(), end2.as_millis());
|
||||||
/// first parse the bf so that it can be executed faster
|
|
||||||
/// most importantly: loop jumps should be immediate
|
|
||||||
///
|
|
||||||
mod o1 {
|
|
||||||
use std::io::{stdin, Read, stdout, Write};
|
|
||||||
|
|
||||||
const MEM_SIZE: usize = 0xFFFF;
|
|
||||||
|
|
||||||
type Memory = [u8; MEM_SIZE];
|
|
||||||
|
|
||||||
|
|
||||||
pub fn run(pgm: &str) -> String {
|
|
||||||
let pgm = minify(pgm);
|
|
||||||
let pgm = parse(pgm.chars().collect());
|
|
||||||
let out = interpret(&pgm);
|
|
||||||
out
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// A single Statement, can be an instruction or a nestable loop
|
|
||||||
#[derive(Debug, PartialOrd, PartialEq)]
|
|
||||||
enum Statement {
|
|
||||||
Inc,
|
|
||||||
Dec,
|
|
||||||
R,
|
|
||||||
L,
|
|
||||||
Out,
|
|
||||||
In,
|
|
||||||
Loop(Vec<Statement>),
|
|
||||||
}
|
|
||||||
|
|
||||||
fn minify(code: &str) -> String {
|
|
||||||
let allowed: Vec<char> = vec!['>', '<', '+', '-', '.', ',', '[', ']'];
|
|
||||||
code.chars().filter(|c| allowed.contains(c)).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse(chars: Vec<char>) -> Vec<Statement> {
|
|
||||||
let mut loop_stack = vec![vec![]];
|
|
||||||
|
|
||||||
for c in chars {
|
|
||||||
match c {
|
|
||||||
'+' => loop_stack.last_mut().unwrap().push(Statement::Inc),
|
|
||||||
'-' => 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),
|
|
||||||
',' => loop_stack.last_mut().unwrap().push(Statement::In),
|
|
||||||
'[' => loop_stack.push(vec![]),
|
|
||||||
']' => {
|
|
||||||
let statement = Statement::Loop(loop_stack.pop().unwrap());
|
|
||||||
loop_stack.last_mut().unwrap().push(statement);
|
|
||||||
}
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return loop_stack.pop().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn interpret(pgm: &Vec<Statement>) -> String {
|
|
||||||
let mut out = String::new();
|
|
||||||
let mut pointer: usize = 0;
|
|
||||||
let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE];
|
|
||||||
|
|
||||||
for s in pgm {
|
|
||||||
execute(s, &mut mem, &mut pointer, &mut out)
|
|
||||||
}
|
|
||||||
|
|
||||||
out
|
|
||||||
}
|
|
||||||
|
|
||||||
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 },
|
|
||||||
Statement::L => if *pointer == 0 { *pointer = MEM_SIZE - 1 } else { *pointer -= 1 },
|
|
||||||
Statement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(1),
|
|
||||||
Statement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(1),
|
|
||||||
Statement::Out => out.push(mem[*pointer] as u8 as char),
|
|
||||||
Statement::In => {
|
|
||||||
let mut in_buffer = [0, 1];
|
|
||||||
stdin().read(&mut in_buffer).unwrap();
|
|
||||||
mem[*pointer] = in_buffer[0] as u8;
|
|
||||||
}
|
|
||||||
Statement::Loop(vec) => {
|
|
||||||
while mem[*pointer] != 0 {
|
|
||||||
for s in vec {
|
|
||||||
execute(&s, mem, pointer, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use crate::o1::{parse, Statement::{self, Inc, Dec, R, L, In, Out, Loop}, execute, run};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parse_no_loop() {
|
|
||||||
let program = "+-<>,.";
|
|
||||||
let statements = vec![Inc, Dec, L, R, In, Out];
|
|
||||||
let result = parse(program.chars().collect());
|
|
||||||
|
|
||||||
assert_eq!(statements, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn parse_simple_loop() {
|
|
||||||
let program = "+[<<]-";
|
|
||||||
let statements = vec![Inc, Loop(vec![L, L]), Dec];
|
|
||||||
let result = parse(program.chars().collect());
|
|
||||||
|
|
||||||
assert_eq!(statements, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
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());
|
|
||||||
|
|
||||||
assert_eq!(statements, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn execute_simple() {
|
|
||||||
let mut pointer: usize = 0;
|
|
||||||
let mut mem: [u8; 65535] = [0; 65535];
|
|
||||||
let mut out = String::new();
|
|
||||||
|
|
||||||
execute(&Statement::R, &mut mem, &mut pointer, &mut out);
|
|
||||||
assert_eq!(pointer, 1);
|
|
||||||
execute(&Statement::L, &mut mem, &mut pointer, &mut out);
|
|
||||||
assert_eq!(pointer, 0);
|
|
||||||
execute(&Statement::Inc, &mut mem, &mut pointer, &mut out);
|
|
||||||
assert_eq!(mem[pointer], 1);
|
|
||||||
execute(&Statement::Dec, &mut mem, &mut pointer, &mut out);
|
|
||||||
assert_eq!(mem[pointer], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn execute_false_loop() {
|
|
||||||
let statement = Statement::Loop(vec![Statement::Inc, Statement::Inc, Statement::R]);
|
|
||||||
let mut pointer: usize = 0;
|
|
||||||
let mut mem: [u8; 65535] = [0; 65535];
|
|
||||||
|
|
||||||
execute(&statement, &mut mem, &mut pointer, &mut String::new());
|
|
||||||
assert_eq!(mem[0], 0);
|
|
||||||
assert_eq!(mem[1], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn execute_loop() {
|
|
||||||
let statement = Statement::Loop(vec![Statement::Inc, Statement::Inc, Statement::R]);
|
|
||||||
let mut pointer: usize = 0;
|
|
||||||
let mut mem: [u8; 65535] = [0; 65535];
|
|
||||||
mem[0] = 1;
|
|
||||||
|
|
||||||
execute(&statement, &mut mem, &mut pointer, &mut String::new());
|
|
||||||
assert_eq!(mem[0], 3);
|
|
||||||
assert_eq!(mem[1], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn run_loop() {
|
|
||||||
let program = "++++++++++[>++++++++++<-]>.";
|
|
||||||
let out = run(program);
|
|
||||||
assert_eq!(out, String::from("d"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn hello_world() {
|
|
||||||
let program = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";
|
|
||||||
let out = run(program);
|
|
||||||
assert_eq!(out, String::from("Hello World!\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
0
bfi-rust/src/o2.rs
Normal file
0
bfi-rust/src/o2.rs
Normal file
Loading…
Add table
Add a link
Reference in a new issue