Created
June 30, 2013 05:34
-
-
Save hrkt/5893990 to your computer and use it in GitHub Desktop.
A brainf*ck language interpreter.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 | |
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 "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