brainfuck/
brainfuck.rs

1use std::io::Read;
2
3use parse_it::ParseIt;
4
5#[derive(Debug, Clone)]
6pub enum Instr {
7    Left,
8    Right,
9    Incr,
10    Decr,
11    Read,
12    Write,
13    Loop(Vec<Self>),
14}
15
16parse_it::parse_it! {
17    mod parse {
18        use super::Instr;
19
20        pub Brainfuck -> Vec<Instr> {
21            Primitive* => self,
22        }
23
24        Primitive -> Instr {
25            '<' => Instr::Left,
26            '>' => Instr::Right,
27            '+' => Instr::Incr,
28            '-' => Instr::Decr,
29            ',' => Instr::Read,
30            '.' => Instr::Write,
31            '[' Primitive+ ']' => Instr::Loop(self)
32        }
33    }
34}
35
36fn main() {
37    let parser = parse::Brainfuck::default();
38    let src = "--[>--->->->++>-<<<<<-------]>--.>---------.>--..+++.>----.>+++++++++.<<.+++.------.<-.>>+.";
39
40    match parser.parse(src) {
41        Ok(ast) => execute(&ast, &mut 0, &mut [0; TAPE_LEN]),
42        Err(err) => println!("{:?}", err),
43    };
44}
45
46const TAPE_LEN: usize = 10_000;
47
48fn execute(ast: &[Instr], ptr: &mut usize, tape: &mut [u8; TAPE_LEN]) {
49    for symbol in ast {
50        match symbol {
51            Instr::Left => *ptr = (*ptr + TAPE_LEN - 1).rem_euclid(TAPE_LEN),
52            Instr::Right => *ptr = (*ptr + 1).rem_euclid(TAPE_LEN),
53            Instr::Incr => tape[*ptr] = tape[*ptr].wrapping_add(1),
54            Instr::Decr => tape[*ptr] = tape[*ptr].wrapping_sub(1),
55            Instr::Read => tape[*ptr] = std::io::stdin().bytes().next().unwrap().unwrap(),
56            Instr::Write => print!("{}", tape[*ptr] as char),
57            Instr::Loop(ast) => {
58                while tape[*ptr] != 0 {
59                    execute(ast, ptr, tape)
60                }
61            }
62        }
63    }
64}