Brainfuck interpreter with lexer and parser slr(1)
This commit is contained in:
parent
e1897e2a8c
commit
0f9d904c71
2 changed files with 327 additions and 0 deletions
308
brainfuck.py
Normal file
308
brainfuck.py
Normal 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
19
helloworld.bf
Normal 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
|
||||
|
Loading…
Reference in a new issue