1 | import os |
2 | |
3 | fn main() { |
4 | if os.args.len < 2 { |
5 | eprintln('you need to supply a brainfuck program as a string argument') |
6 | exit(1) // exit with non-zero exit code if there is no program to run |
7 | } |
8 | program := os.args[1] // our program is fed in as a string |
9 | |
10 | mut memory := []u8{len: 256} // we have 256 bytes of memory |
11 | mut address := u8(0) // as well as an 8-bit address register |
12 | |
13 | mut stack := []int{} // our stack does not need a maximum length |
14 | |
15 | mut program_counter := 0 // program counter |
16 | |
17 | // interpreter starts here |
18 | for program_counter < program.len { |
19 | // we look at what the current character our program counter is seeing |
20 | match program[program_counter] { |
21 | `>` { |
22 | address++ // increment the address |
23 | } |
24 | `<` { |
25 | address-- // decrement the address |
26 | } |
27 | `+` { |
28 | memory[address]++ // increment the value at the address |
29 | } |
30 | `-` { |
31 | memory[address]-- // decrement the value at the address |
32 | } |
33 | `.` { |
34 | print(memory[address].ascii_str()) // print the value at the address |
35 | } |
36 | `,` { |
37 | input := os.input_opt('') or { '' } // read value and account for errors |
38 | memory[address] = input[0] // this is so we can ignore newlines |
39 | // because strings are 0-terminated, it also gives us a default value for free! |
40 | } |
41 | `[` { |
42 | stack << program_counter // add loop start address to the call stack |
43 | } |
44 | `]` { |
45 | if memory[address] != 0 { |
46 | // set the program counter to the last loop start |
47 | // so it jumps back and loops again |
48 | program_counter = stack[stack.len - 1] |
49 | } else { |
50 | // otherwise remove the address from the stack and continue |
51 | stack.pop() |
52 | } |
53 | } |
54 | else { |
55 | // the interpreter should ignore characters that are not part of the language |
56 | } |
57 | } |
58 | // increment the program counter to go to the next instruction |
59 | program_counter++ |
60 | // back to line 20! |
61 | } |
62 | |
63 | // print the state of the interpreter at the end |
64 | println('Address: ${address}') |
65 | println('Memory: ${memory}') |
66 | } |