#!/usr/bin/env python3 import sys import argparse def create_jumps_dictionary(program): lbraces = list() res = dict() for index, command in enumerate(program): if command == '[': lbraces.append(index) elif command == ']': if len(lbraces) == 0: raise SyntaxError("Brainfuck: mismatched parentheses (at index: %s)" % index) lbrace_index = lbraces.pop() res[lbrace_index] = index res[index] = lbrace_index if len(lbraces) > 0: raise SyntaxError("Brainfuck: mismatched parentheses (at indexes: %s)" % str(lbraces)) return res def brainfuck(program, bits=8): jumps = create_jumps_dictionary(program) data = dict() data_pointer = 0 instruction_pointer = 0 while instruction_pointer < len(program): command = program[instruction_pointer] if command == '>': data_pointer += 1 elif command == '<': data_pointer -= 1 elif command == '+': data[data_pointer] = (data.get(data_pointer, 0) + 1) if data[data_pointer] == 2 ** bits: data[data_pointer] = 0 elif command == '-': data[data_pointer] = (data.get(data_pointer, 0) - 1) if data[data_pointer] == -1: data[data_pointer] = 2 ** bits - 1 elif command == ',': data[data_pointer] = ord(sys.stdin.read(1)) % 256 elif command == '.': print(chr(data.get(data_pointer, 0)), end='', flush=True) elif command == '[': if data.get(data_pointer, 0) == 0: instruction_pointer = jumps[instruction_pointer] elif command == ']': if data.get(data_pointer, 0) != 0: instruction_pointer = jumps[instruction_pointer] else: # everything else is comment pass instruction_pointer += 1 if data_pointer != 0: print("WARNING (interpreter) - at the end of the execution the data pointer is %s instead of 0 (possibly a compiler issue)" % str(data_pointer)) if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument("filepath") parser.add_argument("--bits", "-b", "--interpreter-bits", type=int, default=8, help="Amount of bits each cell uses") args = parser.parse_args() with open(args.filepath, 'r') as f: code = f.read() brainfuck(code, args.bits)