Skip to content

Instantly share code, notes, and snippets.

@hrkt
Created June 30, 2013 05:34
Show Gist options
  • Save hrkt/5893990 to your computer and use it in GitHub Desktop.
Save hrkt/5893990 to your computer and use it in GitHub Desktop.
A brainf*ck language interpreter.
#!/usr/bin/python
import sys
write = sys.stdout.write
# debug mode flag (True/False)
DEBUG_MODE = False
def dp(str):
if(DEBUG_MODE):
print str
class BFError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class BF:
""" Brainf*ck intereter """
""" version 0.1 2010.06.29 """
""" - Hello world """
""" """
""" specification of Brainf*ck language, see """
""" http://ja.wikipedia.org/wiki/Brainfuck """
""" """
""" TODO: """
""" - support for nested brankets """
code = []
code_ptr = 0
tape = []
tape_ptr = 0
bracket_depth = 0
def __init__(self):
self.tape_ptr = 0
for i in range(0, 30000):
self.tape.append(0)
def greater_than(self):
self.tape_ptr += 1
self.code_ptr += 1
def less_than(self):
self.tape_ptr -= 1
self.code_ptr += 1
def plus(self):
if(self.tape[self.tape_ptr] == sys.maxint):
raise BFError("overflow.")
self.tape[self.tape_ptr] += 1
self.code_ptr += 1
def minus(self):
if(self.tape[self.tape_ptr] == (-sys.maxint - 1)):
raise BFError("overflow.")
self.tape[self.tape_ptr] -= 1
self.code_ptr += 1
def period(self):
write(chr((self.tape[self.tape_ptr])))
self.code_ptr += 1
def comma(self):
self.code_ptr += 1
pass
def bracket_open(self):
"""TODO: must parse multiple brckets."""
if(self.tape[self.tape_ptr] == 0):
while(self.code[self.code_ptr] != ']'):
self.code_ptr += 1
if(self.code_ptr == len(self.code)):
raise BFError("error. pointer is out of lange. at " + str(self.code_ptr))
else:
self.code_ptr += 1
def bracket_close(self):
"""TODO: must parse multiple brckets."""
if(self.tape[self.tape_ptr] != 0):
while(self.code[self.code_ptr] != '['):
self.code_ptr -= 1
if(self.code_ptr < 0):
raise BFError("error. pointer is out of lange. at " + str(self.code_ptr))
else:
self.code_ptr += 1
def execute(self, message):
""" parse and execute code. """
""" when something odd happens, this method raise BFError. """
for s in range(0, len(message)):
self.code.append(message[s])
dp("length of code = " + str(len(message)))
loop_flg = True
step = 0 # to stop the program, when it's out of control. debug purpose.
max_step = sys.maxint
while(step < max_step and True):
if(self.code_ptr == len(self.code)):
dp("done.")
loop_flg = False
print
break
dp("step=%d code_ptr=%d code=%s tape_ptr=%d tape=%d" % (step, self.code_ptr, self.code[self.code_ptr], self.tape_ptr, self.tape[self.tape_ptr]))
if(self.code[self.code_ptr] == '>'):
self.greater_than()
elif(self.code[self.code_ptr] == '<'):
self.less_than()
elif(self.code[self.code_ptr] == '+'):
self.plus()
elif(self.code[self.code_ptr] == '-'):
self.minus()
elif(self.code[self.code_ptr] == '.'):
self.period()
elif(self.code[self.code_ptr] == ','):
self.comma()
elif(self.code[self.code_ptr] == '['):
self.bracket_open()
elif(self.code[self.code_ptr] == ']'):
self.bracket_close()
else:
raise BFError("unknown token %s at position %d"
% (self.code[self.code_ptr], self.code_ptr))
step += 1
def main():
argc = len(sys.argv)
if(argc == 2):
buf = ""
for line in open(sys.argv[1], 'r'):
if(len(line) == 0 or line[0] == '#'):
continue
line = line.strip()
line = line.strip('\r\n\r')
buf = buf + line
code = buf
else:
print("usage: ./brainfuck.py your_code")
sys.exit(0)
print "the code is"
print '#' * 80
print code
print '#' * 80
print
print "interpret!"
try:
bf = BF()
bf.execute(code)
except BFError, e:
print e
sys.exit(1)
if __name__=='__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment