Ich habe einen Brainfuck Interpreter geschrieben, beziehungsweise viel mehr eine Klasse dafür, eine richtige GUI kommt vielleicht noch irgendwann.
Nach dem Thread in dem es um einen kleinen Bug in meinem Code ging, ist er jetzt auch mal fertig.
Ich würde mich freuen, wenn ihr mir ein paar Dinge zu meinem Code sagen könntet.
Ich habe bestimmt einige Dinge gemacht, die man besser machen könnte/sollte.
Achja, wer nicht mit Brainfuck vertraut ist, sich aber trotzdem mit dem Code befassen will (wovon ich zwar nicht ausgehe), sollte sich mal den Brainfuck Artikel auf Wikipedia anschaun. Da steht eigentlich alles wichtige drin und es ist wirklich nicht schwer zu verstehen.
Code: Alles auswählen
class NumError(Exception):
def __init__(self, description = ""):
self.description = description
def __str__(self):
print self.description
return self.description
class BFSyntaxError(Exception):
def __init__(self, description = ""):
self.description = description
def __str__(self):
print self.description
return self.description
class Brainfuck():
"""
This class can run Brainfuck code
"""
def __init__(self, arraysize=30000, fieldsize=256):
"""
arraysize: The number of fields that the array consists of.
Usually this is 30000 but if you want to display
self.array for example you should set it as low as
you need it
"""
self.arraysize = arraysize
self.fieldsize = fieldsize # Should be a byte or a multiple of it
self.loops = [] # Used to store the informations about the loops
self.code = ""
self.set_chars()
self.array = []
self.pointer = 0
self.reset()
def check_syntax(self):
"""
Checks the Brainfuck code for the correct using of '[' and ']'
"""
i = 0
x = 0
for i in xrange(len(self.code)):
# this will find the matching loop-end for this loop-begin
if self.code[i] == self.chars[4]: # char 4 = [
x += 1
elif self.code[i] == self.chars[5]: # char 5 = ]
x -= 1
i += 1
if x == 0:
return True
else:
raise BFSyntaxError()
def set_chars(self, chars=["+", "-", ">", "<", "[", "]", ".", ","]):
"""
With this Method you can rename the standard Brainfuck characters with
other characters.
The code will always interpret the characters in this order:
+ - > < [ ] . ,
"""
self.chars = chars
print self.chars
self.char_handler = {self.chars[0]:self.increase_field,
self.chars[1]:self.decrease_field,
self.chars[2]:self.increase_pointer,
self.chars[3]:self.decrease_pointer,
self.chars[4]:self.loop_begin,
self.chars[5]:self.loop_end,
self.chars[6]:self.printchar,
self.chars[7]:self.readchar}
def reset(self):
"""
This method resets all variables that have to be resetted to work
corretly with any other Brainfuck-Code
"""
self.array = [0] * self.arraysize
self.pointer = 0
def readchar(self, num):
"""
This method reads the character from the input and checks if it is
a valid value.
Brainfuck character: ,
"""
if int(num) < self.fieldsize and int(num) >= 0:
self.array[self.pointer] = int(num)
return True
else:
raise NumError()
def printchar(self):
"""
Prints the ASCII-Code for the field of self.array that self.pointer
points at.
Brainfuck character: .
"""
return chr(self.array[self.pointer])
def increase_field(self):
"""
Increases the field of self.array that self.pointer points at by one.
Brainfuck character: +
"""
if self.array[self.pointer] < self.fieldsize - 1:
self.array[self.pointer] += 1
else:
self.array[self.pointer] = 0
def decrease_field(self):
"""
Decreases the field of self.array that self.pointer points at by one.
Brainfuck character: -
"""
if self.array[self.pointer] > 0:
self.array[self.pointer] -= 1
else:
self.array[self.pointer] = self.fieldsize - 1
def increase_pointer(self):
"""
Increases selt.pointer by one.
Brainfuck character: >
"""
if self.pointer < self.arraysize - 1:
self.pointer += 1
else:
self.pointer = 0
def decrease_pointer(self):
"""
Decreases selt.pointer by one.
Brainfuck character: <
"""
if self.pointer > 0:
self.pointer -= 1
else:
self.pointer = self.arraysize - 1
def loop_begin(self, i):
"""
This is called when a loop is starting (or not if the field is 0)
Brainfuck character: [
"""
if self.array[self.pointer] == 0:
# this will find the matching loop-end for this loop-begin
x = 0
while i <= (len(self.code)):
if self.code[i] == self.chars[4]: # char 4 = [
x += 1
elif self.code[i] == self.chars[5]: # char 5 = ]
x -= 1
if x <= 0:
return i
i += 1
else:
self.loops.append(i)
return i
def loop_end(self, i):
"""
This is called when the endloop-character is found
Brainfuck character: ]
"""
if self.array[self.pointer] == 0:
self.loops.pop()
return i
else:
x = self.loops.pop()
self.loops.append(x)
return x
def run(self):
"""
This runs the Brainfuck-Code and returns it's output
"""
output = ""
i = 0
while i < len(self.code):
character = self.code[i]
if character in self.char_handler:
if character == self.chars[4]:
i = self.char_handler[self.chars[4]](i)
elif character == self.chars[5]:
i = self.char_handler[self.chars[5]](i)
elif character == self.chars[6]:
output += self.char_handler[self.chars[6]]()
elif character == self.chars[7]:
while True:
try:
print "Input required"
self.char_handler[self.chars[7]](int(raw_input()))
break
except ValueError:
print "Please, enter a number!"
except NumError:
print "Number has to be between including 0 and " + str(self.fieldsize-1)
else:
self.char_handler[character]()
i += 1
if output != "":
print output
# Beispiel
if __name__ == '__main__':
bf = Brainfuck(30)
while True:
try:
code = ""
read = ""
print "Enter brainfuck code"
while not read == "/code":
read = raw_input()
code += read
bf.code = code
bf.check_syntax()
break
except BFSyntaxError:
print "Your Code is incorrect, check the syntax"
bf.run()
Sobald ihr eine neue Zeile mit /code eingebt, ist die Codeeingabe beendet und der Code wird ausgeführt.
Edit: Code nach dem Vorschlag, ein Dictionary (self.handle_chars) für die Funktionsaufrufe in run() zu benutzen