Skip to content

Instantly share code, notes, and snippets.

@bellbind
Created July 9, 2009 11:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bellbind/143597 to your computer and use it in GitHub Desktop.
Save bellbind/143597 to your computer and use it in GitHub Desktop.
[Python] brainf**k interpreter with AST
import sys
class Engine(object):
"""Brainf**k interpreter.
usage:
bf = Engine()
bf("++++++++++++++.")
"""
def __init__(self):
pass
def __call__(self, code="",
input=sys.stdin, output=sys.stdout, bufsize=30000):
inst = _parse(code)
env = _Env(code, input, output, bufsize)
while inst is not None:
inst = inst(env)
pass
return env
pass
class _Env(object):
def __init__(self, code, input, output, bufsize):
self.code = code
self.input = input
self.output = output
self.buf = [0] * bufsize
self.index = 0
pass
def value(self):
return self.buf[self.index]
def pinc(self): self.index += 1
def pdec(self): self.index -= 1
def vinc(self): self.buf[self.index] += 1
def vdec(self): self.buf[self.index] -= 1
def putc(self): self.output.write(chr(self.buf[self.index]))
def getc(self): self.buf[self.index] = ord(self.input.read(1))
pass
def _parse(code):
root = _Block()
curr = root
for ch in code:
if ch == ">": curr.append(_cmd("pinc"))
elif ch == "<": curr.append(_cmd("pdec"))
elif ch == "+": curr.append(_cmd("vinc"))
elif ch == "-": curr.append(_cmd("vdec"))
elif ch == ".": curr.append(_cmd("putc"))
elif ch == ",": curr.append(_cmd("getc"))
elif ch == "[": curr = curr.append(_LoopBlock)
elif ch == "]": curr = curr.parent
pass
return root
class _Inst(object):
def __init__(self, parent):
self.parent = parent
self.brother = None
pass
def __call__(self, env):
return self.brother
pass
class _Noop(_Inst): pass
class _Quit(_Inst):
def __call__(self, env):
return self.parent.brother
pass
class _Block(_Inst):
"""
normal block chidren: Noop, ..., Quit
loop block children: Jump, ..., Loop
"""
def __init__(self, parent=None, eldest=_Noop, youngest=_Quit):
super(_Block, self).__init__(parent)
self.eldest = eldest(self)
self.youngest = youngest(self)
self.eldest.brother = self.youngest
pass
def __call__(self, env):
return self.eldest
def append(self, child_inst):
curr = self.eldest
while curr.brother is not self.youngest: curr = curr.brother
child = child_inst(self)
curr.brother = child
child.brother = self.youngest
return child
pass
class _Jump(_Inst):
def __call__(self, env):
if env.value() != 0: return self.brother
return self.parent.brother
pass
class _Loop(_Inst):
def __call__(self, env):
return self.parent.eldest
pass
class _LoopBlock(_Block):
def __init__(self, parent):
super(_LoopBlock, self).__init__(parent, _Jump, _Loop)
pass
pass
class _Cmd(_Inst):
def __init__(self, cmd, parent):
super(_Cmd, self).__init__(parent)
self.cmd = cmd
pass
def __call__(self, env):
getattr(env, self.cmd)()
return self.brother
pass
def _cmd(cmd):
return lambda parent: _Cmd(cmd, parent)
if __name__ == "__main__":
code = """
+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.
------------.<++++++++.--------.+++.------.--------.>+.
>++++++++++.
""" # "Hello, world!\n" from Wikipedia
if len(sys.argv) > 1: code = sys.argv[1]
engine = Engine()
engine(code)
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment