import os fn main() { if os.args.len < 2 { eprintln('you need to supply a brainfuck program as a string argument') exit(1) // exit with non-zero exit code if there is no program to run } program := os.args[1] // our program is fed in as a string mut memory := []u8{len: 256} // we have 256 bytes of memory mut address := u8(0) // as well as an 8-bit address register mut stack := []int{} // our stack does not need a maximum length mut program_counter := 0 // program counter // interpreter starts here for program_counter < program.len { // we look at what the current character our program counter is seeing match program[program_counter] { `>` { address++ // increment the address } `<` { address-- // decrement the address } `+` { memory[address]++ // increment the value at the address } `-` { memory[address]-- // decrement the value at the address } `.` { print(memory[address].ascii_str()) // print the value at the address } `,` { input := os.input_opt('') or { '' } // read value and account for errors memory[address] = input[0] // this is so we can ignore newlines // because strings are 0-terminated, it also gives us a default value for free! } `[` { stack << program_counter // add loop start address to the call stack } `]` { if memory[address] != 0 { // set the program counter to the last loop start // so it jumps back and loops again program_counter = stack[stack.len - 1] } else { // otherwise remove the address from the stack and continue stack.pop() } } else { // the interpreter should ignore characters that are not part of the language } } // increment the program counter to go to the next instruction program_counter++ // back to line 20! } // print the state of the interpreter at the end println('Address: ${address}') println('Memory: ${memory}') }