1use std::io::{BufRead, BufReader, Bytes, 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 #[parser]
18 mod parse {
19 use super::Instr;
20
21 type Lexer = parse_it::CharLexer;
22
23 pub Brainfuck -> Vec<Instr> {
24 Primitive* => self,
25 }
26
27 Primitive -> Instr {
28 '<' => Instr::Left,
29 '>' => Instr::Right,
30 '+' => Instr::Incr,
31 '-' => Instr::Decr,
32 ',' => Instr::Read,
33 '.' => Instr::Write,
34 '[' Primitive+ ']' => Instr::Loop(self)
35 }
36 }
37}
38
39fn main() {
40 let parser = parse::Brainfuck::default();
41 let src = "--[>--->->->++>-<<<<<-------]>--.>---------.>--..+++.>----.>+++++++++.<<.+++.------.<-.>>+.";
42
43 match parser.parse(src) {
44 Ok(ast) => {
45 let mut stdin = BufReader::new(std::io::stdin().lock()).bytes();
46 execute(&ast, &mut 0, &mut [0; TAPE_LEN], &mut stdin)
47 }
48 Err(err) => println!("{err:?}"),
49 };
50}
51
52const TAPE_LEN: usize = 10_000;
53
54fn execute(
55 ast: &[Instr],
56 ptr: &mut usize,
57 tape: &mut [u8; TAPE_LEN],
58 stdin: &mut Bytes<impl BufRead>,
59) {
60 for symbol in ast {
61 match symbol {
62 Instr::Left => *ptr = (*ptr + TAPE_LEN - 1).rem_euclid(TAPE_LEN),
63 Instr::Right => *ptr = (*ptr + 1).rem_euclid(TAPE_LEN),
64 Instr::Incr => tape[*ptr] = tape[*ptr].wrapping_add(1),
65 Instr::Decr => tape[*ptr] = tape[*ptr].wrapping_sub(1),
66 Instr::Read => tape[*ptr] = stdin.next().unwrap().unwrap(),
67 Instr::Write => print!("{}", tape[*ptr] as char),
68 Instr::Loop(ast) => {
69 while tape[*ptr] != 0 {
70 execute(ast, ptr, tape, stdin)
71 }
72 }
73 }
74 }
75}