308 lines
6.6 KiB
Python
308 lines
6.6 KiB
Python
#!/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)
|