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}