blob: eee13e3d853d95f65acaab3b2c0f9e314f403fa7 (
plain) (
tree)
|
|
#!/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()
|