Skip to content

Instantly share code, notes, and snippets.

@prologic
Created December 7, 2015 05:48
Show Gist options
  • Save prologic/10aac26b7d87e2e9cc92 to your computer and use it in GitHub Desktop.
Save prologic/10aac26b7d87e2e9cc92 to your computer and use it in GitHub Desktop.
A JIT optimized Brain Fuck interpreter writtein in RPython
#!/usr/bin/env python
"""BF Interpreter"""
import os
import sys
try:
from rpython.rlib.jit import purefunction, JitDriver
except ImportError:
def purefunction(fn):
return fn
class JitDriver(object):
"""Dummy JitDriver for when we're running under CPython"""
def __init__(self, *args, **kwargs):
pass
def jit_merge_point(self, *args, **kwargs):
pass
def can_enter_jit(self, *args, **kwargs):
pass
STDIN = sys.stdin.fileno()
STDOUT = sys.stdout.fileno()
def get_printable_location(pc, program, bmap):
return "%s_%s_%s" % (program[:pc], program[pc], program[pc+1:])
jitdriver = JitDriver(
greens=["pc", "program", "bmap"],
reds=["tape"],
get_printable_location=get_printable_location
)
class Tape(object):
def __init__(self):
self.thetape = [0]
self.position = 0
def get(self):
return self.thetape[self.position]
def set(self, val):
self.thetape[self.position] = val
def inc(self):
self.thetape[self.position] += 1
def dec(self):
self.thetape[self.position] -= 1
def advance(self):
self.position += 1
if len(self.thetape) <= self.position:
self.thetape.append(0)
def devance(self):
self.position -= 1
@purefunction
def get_matching_bracket(bmap, pc):
return bmap[pc]
def run(program, bmap):
pc = 0
tape = Tape()
while pc < len(program):
jitdriver.jit_merge_point(
pc=pc, tape=tape, program=program, bmap=bmap
)
code = program[pc]
if code == ">":
tape.advance()
elif code == "<":
tape.devance()
elif code == "+":
tape.inc()
elif code == "-":
tape.dec()
elif code == ".":
# print
os.write(STDOUT, chr(tape.get()))
elif code == ",":
# read from stdin
tape.set(ord(os.read(STDIN, 1)[0]))
elif code == "[" and tape.get() == 0:
# Skip forward to the matching ]
pc = get_matching_bracket(bmap, pc)
elif code == "]" and tape.get() != 0:
# Skip back to the matching [
pc = get_matching_bracket(bmap, pc)
pc += 1
return 0
def parse(program):
parsed = []
bmap = {}
leftstack = []
pc = 0
for char in program:
if char in ('[', ']', '<', '>', '+', '-', ',', '.'):
parsed.append(char)
if char == '[':
leftstack.append(pc)
elif char == ']':
left = leftstack.pop()
right = pc
bmap[left] = right
bmap[right] = left
pc += 1
return "".join(parsed), bmap
def main(argv):
source = open(argv[1], "rb")
program, bmap = parse(source.read())
return run(program, bmap)
def target(*args):
return main, None
def jitpolicy(driver):
from rpython.jit.codewriter.policy import JitPolicy
return JitPolicy()
if __name__ == "__main__":
raise SystemExit(main(sys.argv))
@prologic
Copy link
Author

prologic commented Dec 7, 2015

Getting Started

mkvirtualenv bf
pip install rpython
rpython --opt=jit --output=bf bf.py
./bf <(echo "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment