one-file-projects/bfcompiler.py

320 lines
8.3 KiB
Python
Raw Normal View History

class CompileState(object):
def __init__(self):
self.vars = {}
self.cells = set()
self.currentCell = 0
def requestVar(self,name):
try:
return self.vars[name]
except:
cell = 0
while cell in self.cells:
cell+=1
self.vars[name] = cell
self.cells.add(cell)
return cell
def releaseVar(self,name):
try:
cell = self.vars[name]
except KeyError:
return False
2015-11-01 14:36:52 +01:00
del self.vars[name]
self.cells.remove(cell)
def requestTempVar(self):
vid = object()
cell = self.requestVar(vid)
return vid, cell
def incrementCell(self):
self.currentCell += 1
def decrementCell(self):
self.currentCell -= 1
class Command(object):
def __str__(self):
return self.__class__.__name__
def compile(self,state):
raise NotImplementedError
class SimpleRepeatedCommand(Command):
def __init__(self,repeats,command):
self.repeats = repeats
self.command = command
def compile(self,state):
s = ""
for i in range(self.repeats):
s += self.command.compile(state)
return s
def __str__(self):
return "Repeat(%d)(%s)" % (self.repeats, str(self.command))
class CompositeCommand(Command):
def __init__(self,commands):
self.commands = commands
def compile(self,state):
s=""
for command in self.commands:
s+=command.compile(state)
return s
def __str__(self):
return "[" + ",".join([ str(command) for command in self.commands]) + "]"
class SimpleIncrement(Command):
def compile(self,state):
return '+'
class SimpleDecrement(Command):
def compile(self,state):
return '-'
class SimpleNextCell(Command):
def compile(self,state):
state.incrementCell()
return '>'
class SimplePrevCell(Command):
def compile(self,state):
state.decrementCell()
return '<'
class SimpleOutput(Command):
def compile(self,state):
return '.'
class SimpleInput(Command):
def compile(self,state):
return ','
class SimpleLoopBegin(Command):
def compile(self,state):
return '['
class SimpleLoopEnd(Command):
def compile(self,state):
return ']'
class SimpleLoop(Command):
def __init__(self,command):
self.command = command
def compile(self,state):
return CompositeCommand([SimpleLoopBegin(), self.command, SimpleLoopEnd()]).compile(state)
class SelectVariable(Command):
def __init__(self,variable):
self.variable = variable
def compile(self,state):
d = state.requestVar(self.variable) - state.currentCell
if d < 0:
return SimpleRepeatedCommand(-d,SimplePrevCell()).compile(state)
elif d > 0:
return SimpleRepeatedCommand(d,SimpleNextCell()).compile(state)
else:
return ""
class ClearCell(Command):
def compile(self,state):
return SimpleLoop(SimpleDecrement()).compile(state)
class WriteConstant(Command):
def __init__(self,const):
self.const = const
def compile(self,state):
return CompositeCommand([ClearCell(),SimpleRepeatedCommand(self.const, SimpleIncrement())]).compile(state)
class SetConstant(Command):
def __init__(self,variable,const):
self.variable = variable
self.const = const
def compile(self,state):
return CompositeCommand([SelectVariable(self.variable),WriteConstant(self.const)]).compile(state)
SetVariable = SetConstant
class Move(Command):
def __init__(self, source, dest):
self.source = source
self.dest = dest
def compile(self,state):
return CompositeCommand([
SelectVariable(self.dest),
ClearCell(),
SimpleAddition(self.source,self.dest)
]).compile(state)
class Copy(Command):
def __init__(self,source,dest):
self.source = source
self.dest = dest
def compile(self,state):
tmp, _ = state.requestTempVar()
s = CompositeCommand([
SelectVariable(self.dest),
ClearCell(),
SelectVariable(tmp),
ClearCell(),
SelectVariable(self.source),
SimpleLoop(CompositeCommand([
SelectVariable(self.dest),
SimpleIncrement(),
SelectVariable(tmp),
SimpleIncrement(),
SelectVariable(self.source),
SimpleDecrement()
])),
Move(tmp,self.source)
]).compile(state)
state.releaseVar(tmp)
return s
class SimpleAddition(Command):
def __init__(self, source, dest):
self.source = source
self.dest = dest
def compile(self,state):
return CompositeCommand([
SelectVariable(self.source),
SimpleLoop(CompositeCommand([
SelectVariable(self.dest),
SimpleIncrement(),
SelectVariable(self.source),
SimpleDecrement(),
]))
]).compile(state)
class Addition2(Command):
def __init__(self,source,dest):
self.source = source
self.dest = dest
def compile(self,state):
tmp, _ = state.requestTempVar()
s = CompositeCommand([
Copy(self.source,tmp),
SimpleAddition(tmp,self.dest)
]).compile(state)
state.releaseVar(tmp)
return s
class Condition(Command):
def __init__(self,condition,command):
self.condition = condition
self.command = command
def compile(self,state):
return CompositeCommand([
SelectVariable(self.condition),
SimpleLoop(CompositeCommand([
self.command,
SelectVariable(self.condition),
ClearCell(),
])),
]).compile(state)
class ConditionKeep(Command):
def __init__(self,condition,command):
self.condition = condition
self.command = command
def compile(self,state):
tmp, _ = state.requestTempVar()
s = CompositeCommand([
Copy(self.condition,tmp),
Condition(tmp,self.command)
]).compile(state)
state.releaseVar(tmp)
return s
class Booleanize(Command):
def __init__(self,variable):
self.variable = variable
def compile(self,state):
tmp, _ = state.requestTempVar()
s = CompositeCommand([
SelectVariable(tmp),
ClearCell(),
Condition(self.variable,CompositeCommand([
SelectVariable(tmp),
SimpleIncrement()
])),
Move(tmp,self.variable)
]).compile(state)
state.releaseVar(tmp)
return s
class Not(Command):
def __init__(self,variable):
self.variable = variable
def compile(self,state):
tmp, _ = state.requestTempVar()
s = CompositeCommand([
SelectVariable(tmp),
WriteConstant(1),
Condition(self.variable,CompositeCommand([
SelectVariable(tmp),
SimpleDecrement()
])),
Move(tmp,self.variable)
]).compile(state)
state.releaseVar(tmp)
return s
class And(Command):
def __init__(self,source,dest):
self.source = source
self.dest = dest
def compile(self,state):
return ConditionKeep(self.dest, Move(self.source,self.dest)).compile(state)
class Or(Command):
def __init__(self,source,dest):
self.source = source
self.dest = dest
def compile(self,state):
return CompositeCommand([
SimpleAddition(self.source, self.dest),
SelectVariable(self.dest),
Booleanize(self.dest)
]).compile(state)
if __name__ == "__main__":
c = CompositeCommand([
SetVariable("a",2),
SetVariable("b",5),
Addition2("b","a"),
Copy("a","tmp"),
Or("tmp","b"),
ConditionKeep("tmp",CompositeCommand([
SelectVariable("b"),
SimpleIncrement()
])),
Not("tmp"),
Condition("tmp",CompositeCommand([
SelectVariable("b"),
SimpleDecrement()
]))
])
print(c.compile(CompileState()))