brainfuck.gno
2.84 Kb ยท 97 lines
1// Package brainfuck implements a minimalist Brainfuck language interpreter.
2package brainfuck
3
4// Run executes a byte slice encoded Brainfuck program with the provided input and
5// returns the output. If no input is desired, use an empty string "". Memory is
6// dynamically allocated and grows rightward as needed. The pointer cannot go below
7// zero (does not wrap from the beginning to end). When input is exhausted, the ','
8// command writes 0 to the current cell. Program exits early if unmatched brackets
9// are encountered.
10func Run(code, input []byte) []byte {
11 memory := []byte{} // dynamic memory tape
12 output := []byte{} // collected output bytes
13 pointer := 0 // memory cell pointer
14 cursor := 0 // code instruction pointer
15 i := 0 // input index
16
17 for cursor < len(code) {
18 switch code[cursor] {
19 case '>': // Move pointer right
20 pointer++
21 if pointer <= 0 { // Guard against potential overflow
22 pointer = 0
23 }
24 ensureMemory(&memory, pointer)
25 case '<': // Move pointer left
26 pointer--
27 if pointer <= 0 { // Guard against below zero
28 pointer = 0
29 }
30 case '+': // Increment current cell (wraps: 255+1=0)
31 ensureMemory(&memory, pointer)
32 memory[pointer]++
33 case '-': // Decrement current cell (wraps: 0-1=255)
34 ensureMemory(&memory, pointer)
35 memory[pointer]--
36 case '.': // Output current cell
37 ensureMemory(&memory, pointer)
38 output = append(output, memory[pointer])
39 case ',': // Read one byte from input
40 ensureMemory(&memory, pointer)
41 if i < len(input) {
42 memory[pointer] = input[i]
43 i++
44 } else {
45 memory[pointer] = 0 // Write 0 when input is exhausted
46 }
47 case '[': // Jump forward to matching ] if current cell is 0
48 ensureMemory(&memory, pointer)
49 if memory[pointer] == 0 {
50 brackets := 1 // Track nesting level
51 for brackets > 0 {
52 cursor++
53 if cursor >= len(code) {
54 return output // Exit if unmatched bracket
55 }
56 if code[cursor] == '[' {
57 brackets++
58 } else if code[cursor] == ']' {
59 brackets--
60 }
61 }
62 }
63 case ']': // Jump back to matching [ if current cell is not 0
64 ensureMemory(&memory, pointer)
65 if memory[pointer] != 0 {
66 brackets := 1 // Track nesting level
67 for brackets > 0 {
68 cursor--
69 if cursor < 0 {
70 return output // Exit if unmatched bracket
71 }
72 if code[cursor] == ']' {
73 brackets++
74 } else if code[cursor] == '[' {
75 brackets--
76 }
77 }
78 }
79 }
80 cursor++
81 if cursor < 0 { // Guard cursor against potential overflow
82 cursor = 0
83 }
84 if i < 0 { // Guard input index against potential overflow
85 i = 0
86 }
87 }
88 return output
89}
90
91// ensureMemory grows the memory slice if needed to accommodate the specified
92// pointer position. New cells are initialized to zero.
93func ensureMemory(memory *[]byte, pointer int) {
94 for pointer >= len(*memory) {
95 *memory = append(*memory, 0)
96 }
97}