Code: Alles auswählen
#!/usr/bin/env python
from collections import defaultdict
import Tkinter as tkinter
import sys
class Brainfuck(object):
def __init__(self, command="", text=""):
self.command_index = 0
self.command = command
self.text = list(text)
self.index = 0
self.work = defaultdict(int)
self.inter = {"," : self.get, "." : self.put, ">" : self.up,
"<" : self.down, "+" : self.add, "-" : self.sub,
"[" : self.right, "]" : self.left }
self.opened_brackets = self._brackets()
self.closed_brackets = self._brackets(True)
def _brackets(self, inverted=False):
brackets = {}
stack = []
for index, char in enumerate(self.command):
if char == "[":
stack.append(index)
elif char == "]":
if inverted:
brackets[index] = stack.pop()
else:
brackets[stack.pop()] = index
return brackets
def run(self):
while self.command_index < len(self.command):
output = self.step()
if output is not None:
sys.stdout.write(output)
def step(self):
output = None
if self.command_index < len(self.command):
char = self.command[self.command_index]
if char in self.inter:
output = self.inter[char]()
self.command_index += 1
return output
def get(self):
self.work[self.index] = ord(self.text.pop(0)) \
if len(self.text) > 0 else 0
def put(self):
return chr(self.work[self.index])
def right(self):
if self.work[self.index] == 0:
self.command_index = self.opened_brackets[self.command_index]
def left(self):
if self.work[self.index] != 0:
self.command_index = self.closed_brackets[self.command_index]
def add(self):
self.work[self.index] += 1
def sub(self):
self.work[self.index] -= 1
def up(self):
self.index += 1
def down(self):
self.index -= 1
class ListFrame(tkinter.Frame):
def __init__(self, master, cnf=()):
tkinter.Frame.__init__(self, master, cnf)
pack_style = {"expand":True, "fill":"both", "padx":2, "pady":3}
label = tkinter.Label(self, text="Array:", anchor="w")
label.pack(fill="both", pady=2)
vbar = tkinter.Scrollbar(self)
vbar.pack(fill="y", side="right")
self.listbox = tkinter.Listbox(self, yscrollcommand=vbar.set, width=10)
self.listbox.pack(pack_style)
vbar.config(command=self.listbox.yview)
def clear(self):
self.listbox.delete(0, "end")
def append(self, value):
self.listbox.insert("end", "{0:5}".format(value))
def select(self, index):
self.listbox.selection_clear(0, "end")
self.listbox.selection_set(index)
self.listbox.see(index)
class TaggedText(tkinter.Text):
def __init__(self, master, cnf=()):
tkinter.Text.__init__(self, master, cnf)
self.current_index = 0
self.selected = {"background":"#AA0000", "foreground":"#FFFFFF"}
self.deselected = {"background":"#FFFFFF", "foreground":"#000000"}
def create_tags(self):
width = self.cget("width")
to_index = lambda num: "{0}.{1}".format(*divmod(num+width, width))
for number in xrange(len(self.get(1.0, "end"))):
self.tag_add(number, to_index(number), to_index(number+1))
self.config(state="disable")
self.select(0)
def selection_clear(self):
for number in xrange(len(self.get(1.0, "end"))):
self.config(state="normal")
self.tag_config(number, self.deselected)
def select(self, index):
self.tag_config(str(self.current_index), self.deselected)
self.tag_config(str(index), self.selected)
self.current_index = index
class BrainfuckDebugger(tkinter.Frame):
def __init__(self, master, cnf=()):
tkinter.Frame.__init__(self, master, cnf)
self.command = None
self.text = None
self.output = None
self.listframe = None
self.brainfuck = None
self.run_refresh = tkinter.IntVar(None, 1000)
def update_list(self):
self.listframe.clear()
index = 0
for index in xrange(len(self.brainfuck.work)):
self.listframe.append(self.brainfuck.work[index])
if self.brainfuck.index > index:
self.listframe.append(0)
self.listframe.select(self.brainfuck.index)
def start(self):
self.command.create_tags()
self.text.create_tags()
c, t = self.command.get(1.0, "end"), self.text.get(1.0, "end")
self.brainfuck = Brainfuck(c, t)
def stop(self):
self.brainfuck = None
self.command.selection_clear()
self.text.selection_clear()
self.listframe.clear()
self.output.delete(1.0, "end")
self
def step(self):
if self.brainfuck is None:
return
output = self.brainfuck.step()
if output is not None:
self.output.insert("end", output)
self.command.select(self.brainfuck.command_index)
self.text.select(len(self.text.get(1.0, "end")) -
len(self.brainfuck.text))
self.update_list()
def run(self):
if self.brainfuck is None:
return
self.step()
self.after(self.run_refresh.get(), self.run)
def create(self, command="", text=""):
pack_style = {"expand":True, "fill":"both", "padx":2, "pady":3}
inputframe = tkinter.Frame(self)
label = tkinter.Label(inputframe, text="Brainfuck Command:",
anchor="w")
label.pack(pack_style)
text_options = {"width":40, "height":7, "cursor":"xterm"}
self.command = TaggedText(inputframe, text_options)
self.command.insert("end", command)
self.command.pack(pack_style)
label = tkinter.Label(inputframe, text="Brainfuck Input:", anchor="w")
label.pack(pack_style)
self.text = TaggedText(inputframe, text_options)
self.text.insert("end", text)
self.text.pack(pack_style)
label = tkinter.Label(inputframe, text="Brainfuck Output:", anchor="w")
label.pack(pack_style)
self.output = TaggedText(inputframe, text_options)
self.output.pack(pack_style)
start = tkinter.Button(inputframe, text="Start", command=self.start,
cursor="hand2")
start.pack(pack_style, side="left")
stop = tkinter.Button(inputframe, text="Stop", command=self.stop,
cursor="hand2")
stop.pack(pack_style, side="left")
step = tkinter.Button(inputframe, text="Step", command=self.step,
cursor="hand2")
step.pack(pack_style, side="left")
run = tkinter.Button(inputframe, text="Run", command=self.run,
cursor="hand2")
run.pack(pack_style, side="left")
options = {"label":"Speed: ", "from_":1, "to":3000, "resolution":1,
"orient":"horizontal", "variable":self.run_refresh}
speed = tkinter.Scale(inputframe, options)
speed.pack(pack_style)
inputframe.pack(pack_style, side="left")
self.listframe = ListFrame(self)
self.listframe.pack(pack_style, side="left")
if __name__ == "__main__":
brainfuck_command = ",.,[>+[>+>+<<-]>>[<<+>>-]<[<<+>>-]<<.,]"
brainfuck_input = "Hello World"
#Brainfuck(string, text).run()
root = tkinter.Tk()
root.title("Brainfuck Debugger")
bd = BrainfuckDebugger(root)
bd.create(brainfuck_command, brainfuck_input)
bd.pack(expand=True, fill="both")
root.mainloop()
- die Liste scrollt jetzt selbstständig nach unten
- die Überprüfung der länge findet jetzt in "step" direkt statt und nicht in der GUI
- das Output Fenster und die Liste werden bei "stop" geleert
- die Laufgeschwindigkeit kann geändert werden
- das Aktualisieren der Liste in eine extra Methode gepackt.