diff options
Diffstat (limited to 'tools/brainfuck/bf_debug.py')
-rwxr-xr-x | tools/brainfuck/bf_debug.py | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/tools/brainfuck/bf_debug.py b/tools/brainfuck/bf_debug.py new file mode 100755 index 0000000..eee13e3 --- /dev/null +++ b/tools/brainfuck/bf_debug.py @@ -0,0 +1,374 @@ +#!/usr/bin/env python +import sys + +if len(sys.argv) < 2: + print("Give me filename...") + exit() + +# Parameters +TAPE_LEN = 264 # from original interpreter +TAPE_CONTEXT = 14 +CODE_CONTEXT = 72 + +process_input = (sys.argv[2].encode() if len(sys.argv) > 2 else b"") +process_output = b"" + +# Colors +HEADER = '\033[95m' +OKBLUE = '\033[94m' +OKCYAN = '\033[96m' +OKGREEN = '\033[92m' +WARNING = '\033[93m' +FAIL = '\033[91m' +ENDC = '\033[0m' +BOLD = '\033[1m' +UNDERLINE = '\033[4m' + +code = open(sys.argv[1]).read().replace("\n", "").replace(" ", "") + +stack = [] # track loop execution +tape = [0]*TAPE_LEN # process memory +ptr = 0 # current tape position + +rip = 0 # next instruction to execute +lip = 0 # previous instruction (illustrate jumps) + +breakpoints = [] # stop exec at these rips +breakops = [] # stop exec at these codes +watchpoints = [] # stop exce on these ptrs + + +def display_status(): + global code + global stack + global tape + global ptr + global rip + global lip + print("") + print("") + print("Tape ptr: %i"%(ptr)) + print("Prog rip: %i"%(rip)) + print("Prog lip: %i"%(lip)) + print("") + + # stack + if len(stack) == 0: + print(f"{FAIL}No loops{ENDC}") + else: + for l in stack: + print("0x%05x"%(l), end=" ") + print("") + print("") + + # tape + addr = "" + hexa = "" + deci = "" + asci = "" + for i in range(ptr - TAPE_CONTEXT, ptr + TAPE_CONTEXT + 1): + oob = i < 0 or i >= TAPE_LEN + color = (OKGREEN if i == ptr else WARNING if i in watchpoints else OKCYAN if tape[i] != 0 else FAIL if oob else '') + value = (0 if oob else tape[i]) + char = (chr(value) if value >= 0x20 and value < 0x7f else "U") + + addr += f" {color}{UNDERLINE}0x%02x{ENDC}"%(i) + hexa += f" {color}0x%02x{ENDC}"%(value) + deci += f" {color}%4i{ENDC}"%(value) + asci += f" {color}%4s{ENDC}"%(char) + + print(addr) + print(hexa) + print(deci) + print(asci) + print("") + + # code + breaks = "" + ops = "" + for i in range(rip - CODE_CONTEXT, rip + CODE_CONTEXT + 1): + oob = i < 0 or i >= len(code) + color = (OKGREEN+BOLD+UNDERLINE if i == rip + else OKBLUE+BOLD if i == lip + else FAIL+BOLD if oob else '') + oper = (" " if oob else code[i]) + brek = (" " if oob else "P" if i in breakpoints else "O" if code[i] in breakops else " ") + + breaks += f"{FAIL}{brek}{ENDC}" + ops += f"{color}{oper}{ENDC}" + + print(breaks) + print(ops) + +def display_tape(): + global code + global stack + global tape + global ptr + global rip + global lip + print("") + print("") + for i, x in enumerate(tape): + color = (OKGREEN if i == ptr else WARNING if i in watchpoints else OKCYAN if x != 0 else '') + print(f"{color}0x%02x{ENDC} "%(x), end="") + if (i+1) % 16 == 0: + print("") + elif (i+1) % 8 == 0: + print(" ", end="") + print("") + +def display_tape_ascii(): + global code + global stack + global tape + global ptr + global rip + global lip + print("") + print("") + for i, x in enumerate(tape): + color = (OKGREEN if i == ptr else '') + char = (chr(x) if x >= 0x20 and x < 0x7f else '.') + print(f"{color}{char}{ENDC}", end="") + print("") + +def display_code(): + global code + global stack + global tape + global ptr + global rip + global lip + print("") + print("") + for i, x in enumerate(code): + color = (OKGREEN+BOLD+UNDERLINE if i == rip + else OKBLUE+BOLD if i == lip + else FAIL+BOLD if i in breakpoints + else FAIL+BOLD if code[i] in breakops else '') + print(f"{color}{x}{ENDC}", end="") + print("") + +def display_input(): + global code + global stack + global tape + global ptr + global rip + global lip + global process_input + print("") + print("") + print(f"Input (to-be-read): {process_input}") + +def display_output(): + global code + global stack + global tape + global ptr + global rip + global lip + global process_output + print("") + print("") + print(f"Output (cumulative): {process_output}") + +def jump_past_loop(): + global code + global stack + global tape + global ptr + global rip + global lip + i = 1 + for pos in range(rip, len(code)): + if code[pos] == '[': + i += 1 + elif code[pos] == ']': + i -= 1 + if i == 0: + rip = pos + 1 + break + if i != 0: + raise Exception("'[' has no paring ']'") + +def run_code(): + global code + global stack + global tape + global ptr + global rip + global lip + global process_input + global process_output + while True: + if step_forward() == True: + break + if rip in breakpoints: + break + if rip < len(code) and (code[rip] in breakops): + break + if ptr in watchpoints: + break + +def step_forward(): + global code + global stack + global tape + global ptr + global rip + global lip + global process_input + global process_output + if rip >= len(code): + print("Execution finished.") + return True + + op = code[rip] + lip = rip + rip += 1 + + if op == '<': + if ptr == 0: + raise Exception("Tape ptr out of bounds! (underflow)") + ptr -= 1 + elif op == '>': + if ptr == TAPE_LEN-1: + raise Exception("Tap ptr out of bounds! (overflow)") + ptr += 1 + elif op == '+': + if tape[ptr] == 255: + tape[ptr] = 0 + else: + tape[ptr] += 1 + elif op == '-': + if tape[ptr] == 0: + tape[ptr] = 255 + else: + tape[ptr] -= 1 + elif op == '.': + process_output += tape[ptr].to_bytes(1, 'big') + display_output() + elif op == ',': + if len(process_input) == 0: + raise Exception("Out of input!") + display_input() + tape[ptr] = process_input[0] + process_input = process_input[1:] + elif op == '[': + if tape[ptr] == 0: + jump_past_loop() + else: + stack.append(rip) # rip currently on first op after [ + elif op == ']': + if tape[ptr] == 0: + stack.pop() + else: + rip = stack[-1] + else: + raise Exception("Illegal instruction!") + +def manage_breakpoints(): + global breakpoints + while True: + print("Current breakpoints:") + for i, x in enumerate(breakpoints): + print(f" {i}: {x}") + print("") + + ip = input("[a]dd/[d]el/[f]inish <arg>: ") + cmd = ip.split()[0] + + if cmd == 'f': + break + if cmd == 'a': + breakpoints.append(int(ip.split()[1])) + elif cmd == 'd': + del breakpoints[int(ip.split()[1])] + +def manage_breakops(): + global breakops + while True: + print("Current breakops:") + for i, x in enumerate(breakops): + print(f" {i}: {x}") + print("") + + ip = input("[a]dd/[d]el/[f]inish <arg>: ") + cmd = ip.split()[0] + + if cmd == 'f': + break + if cmd == 'a': + breakops.append(ip.split()[1]) + elif cmd == 'd': + del breakops[int(ip.split()[1])] + +def manage_watchpoints(): + global watchpoints + while True: + print("Current watchpoints:") + for i, x in enumerate(watchpoints): + print(f" {i}: {x}") + print("") + + ip = input("[a]dd/[d]el/[f]inish <arg>: ") + cmd = ip.split()[0] + + if cmd == 'f': + break + if cmd == 'a': + watchpoints.append(int(ip.split()[1])) + elif cmd == 'd': + del watchpoints[int(ip.split()[1])] + +def write_tape(): + global tape + addr = int(input("Address: ")) + val = int(input("Value: ")) + tape[addr] = val + + +enter_is_step = False +print("Hints: j: step forward t: show tape a: show tape (ascii) c: show code i: show input o: show output") +print(" r: run p: manage breakpoints l: manage breakops w: manage watchpoints q: quit s: show status") +print(" m: edit tape memory") +display_status() +while True: + c = input("> ") + + if c == 'j' or (c == '' and enter_is_step): + enter_is_step = True + step_forward() + display_status() + else: + enter_is_step = False + if c == 's': + display_status() + elif c == 't': + display_tape() + elif c == 'a': + display_tape_ascii() + elif c == 'c': + display_code() + elif c == 'i': + display_input() + elif c == 'o': + display_output() + elif c == 'q': + break + elif c == 'r': + run_code() + display_status() + elif c == 'p': + manage_breakpoints() + display_status() + elif c == 'l': + manage_breakops() + display_status() + elif c == 'w': + manage_watchpoints() + display_status() + elif c == 'm': + write_tape() |