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}