Brainfuck interpreter with lexer and parser slr(1)

This commit is contained in:
madmaurice 2016-11-30 15:58:48 +01:00
parent e1897e2a8c
commit 0f9d904c71
2 changed files with 327 additions and 0 deletions

308
brainfuck.py Normal file
View File

@ -0,0 +1,308 @@
#!/usr/bin/env python
from sys import stdout,stdin,argv
class State:
def __init__(self):
self.data = [0]
self.ptr = 0
def prev(self):
if self.ptr == 0:
self.data.insert(0,0)
else:
self.ptr-=1
def next(self):
if self.ptr == len(self.data)-1:
self.data.append(0)
self.ptr+=1
def get(self):
return self.data[self.ptr]
def set(self,val):
self.data[self.ptr] = val
class Instruction:
def run(self,state):
raise NotImplementedError
def __repr__(self):
return self.__class__.__name__
class NextInstruction(Instruction):
def run(self,state):
state.next()
class PrevInstruction(Instruction):
def run(self,state):
state.prev()
class IncInstruction(Instruction):
def run(self,state):
state.set(state.get() + 1)
class DecInstruction(Instruction):
def run(self,state):
state.set(state.get() - 1)
class PutInstruction(Instruction):
def run(self,state):
stdout.write(chr(state.get()))
stdout.flush()
class GetInstruction(Instruction):
def run(self,state):
state.set(ord(stdin.read(1)))
class BlockInstruction(Instruction):
def __init__(self):
self.instructions = []
def prepend(self, inst):
self.instructions.insert(0, inst)
def run(self,state):
for inst in self.instructions:
inst.run(state)
def __repr__(self):
return ", ".join(map(repr,self.instructions))
class LoopInstruction(Instruction):
def __init__(self,block):
self.block = block
def run(self,state):
while state.get() != 0:
self.block.run(state)
def __repr__(self):
return "[ %s ]" % (repr(self.block))
Inext = NextInstruction()
Iprev = PrevInstruction()
Iinc = IncInstruction()
Idec = DecInstruction()
Iput = PutInstruction()
Iget = GetInstruction()
class Token:
NEXT = "T_NEXT"
PREV = "T_PREV"
INC = "T_INC"
DEC = "T_DEC"
PUT = "T_PUT"
GET = "T_GET"
LOOP_START = "T_LOOP_START"
LOOP_END = "T_LOOP_END"
EOF = "T_EOF"
def lex(it):
if type(it) == str:
it = iter(it)
END = object()
c = next(it,END)
while c != END:
if c == ">":
yield Token.NEXT
elif c == "<":
yield Token.PREV
elif c == "+":
yield Token.INC
elif c == "-":
yield Token.DEC
elif c == ".":
yield Token.PUT
elif c == ",":
yield Token.GET
elif c == "[":
yield Token.LOOP_START
elif c == "]":
yield Token.LOOP_END
c = next(it,END)
yield Token.EOF
class DefaultDict:
def __init__(self,value):
self.value = value
def __contains__(self,key):
return True
def __getitem__(self,key):
return self.value
def parse(it):
NTS_S = object()
NTS_B = object()
r = object()
s = object()
a = object()
table = [
{
Token.NEXT: (s,5),
Token.PREV: (s,6),
Token.INC: (s,7),
Token.DEC: (s,8),
Token.PUT: (s,9),
Token.GET: (s,10),
Token.LOOP_START: (s,2)
},
{
Token.NEXT: (s,5),
Token.PREV: (s,6),
Token.INC: (s,7),
Token.DEC: (s,8),
Token.PUT: (s,9),
Token.GET: (s,10),
Token.LOOP_START: (s,2),
Token.LOOP_END: (r,3),
Token.EOF: (r,3)
},
{
Token.NEXT: (s,5),
Token.PREV: (s,6),
Token.INC: (s,7),
Token.DEC: (s,8),
Token.PUT: (s,9),
Token.GET: (s,10),
Token.LOOP_START: (s,2)
},
{
Token.LOOP_END: (s,4)
},
DefaultDict( (r,10) ),
DefaultDict( (r,4) ),
DefaultDict( (r,5) ),
DefaultDict( (r,6) ),
DefaultDict( (r,7) ),
DefaultDict( (r,8) ),
DefaultDict( (r,9) ),
DefaultDict( (r,2) ),
DefaultDict( (a,0) )
]
goto = [
{ NTS_S: 12, NTS_B: 1 },
{ NTS_S: 11, NTS_B: 1 },
{ NTS_S: 3, NTS_B: 1 },
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
]
state = [0]
data = []
c = next(it)
while True:
op, dat = table[state[-1]][c]
if op == s:
data.append(c)
c = next(it)
state.append(dat)
elif op == a:
return data[0]
elif op == r:
if dat == 2:
S = data.pop()
B = data.pop()
state.pop()
state.pop()
S.prepend(B)
data.append(S)
state.append( goto[state[-1]][NTS_S] )
elif dat == 3:
B = data.pop()
state.pop()
S = BlockInstruction()
S.prepend(B)
data.append(S)
state.append( goto[state[-1]][NTS_S] )
elif dat == 4:
data.pop()
state.pop()
data.append( Inext )
state.append( goto[state[-1]][NTS_B] )
elif dat == 5:
data.pop()
state.pop()
data.append( Iprev )
state.append( goto[state[-1]][NTS_B] )
elif dat == 6:
data.pop()
state.pop()
data.append( Iinc )
state.append( goto[state[-1]][NTS_B] )
elif dat == 7:
data.pop()
state.pop()
data.append( Idec )
state.append( goto[state[-1]][NTS_B] )
elif dat == 8:
data.pop()
state.pop()
data.append( Iput )
state.append( goto[state[-1]][NTS_B] )
elif dat == 9:
data.pop()
state.pop()
data.append( Iget )
state.append( goto[state[-1]][NTS_B] )
elif dat == 10:
data.pop()
S = data.pop()
data.pop()
state.pop()
state.pop()
state.pop()
B = LoopInstruction(S)
data.append(B)
state.append( goto[state[-1]][NTS_B] )
if __name__ == '__main__':
if len(argv) > 1:
fd = open(argv[1],"r")
contents = fd.read()
fd.close()
else:
contents = ",[.,]"
ast = parse(lex(contents))
state = State()
ast.run(state)

19
helloworld.bf Normal file
View File

@ -0,0 +1,19 @@
++++++++++
[
>+++++++>++++++++++>+++>+<<<<-
] Schleife zur Vorbereitung der Textausgabe
>++. Ausgabe von 'H'
>+. Ausgabe von 'e'
+++++++. 'l'
. 'l'
+++. 'o'
>++. Leerzeichen
<<+++++++++++++++. 'W'
>. 'o'
+++. 'r'
------. 'l'
--------. 'd'
>+. '!'
>. Zeilenvorschub
+++. Wagenrücklauf