Skip to content

Instantly share code, notes, and snippets.

@rgngl
Created October 16, 2013 13:44
Show Gist options
  • Save rgngl/7007960 to your computer and use it in GitHub Desktop.
Save rgngl/7007960 to your computer and use it in GitHub Desktop.
Brainfuck interpreter in Python
#Wrote this to entertain myself, on a slow day at work.
#Üstün Ergenoglu
import sys
class Instructions:
SUBP = 0
INCP = 1
DECP = 2
INCV = 3
DECV = 4
OUTPUT = 5
INPUT = 6
RET = 7
class BFInterp:
def __init__(self, text):
self.programTree = list()
self.__parse(text)
def __parse(self, text):
stack = list()
stack.append(self.programTree)
for c in text:
if c == ">":
stack[-1].append((Instructions.INCP, 0))
elif c == "<":
stack[-1].append((Instructions.DECP, 0))
elif c == "+":
stack[-1].append((Instructions.INCV, 0))
elif c == "-":
stack[-1].append((Instructions.DECV, 0))
elif c == ".":
stack[-1].append((Instructions.OUTPUT, 0))
elif c == ",":
stack[-1].append((Instructions.INPUT, 0))
elif c == "[":
newList = list()
stack[-1].append((Instructions.SUBP, newList))
stack.append(newList)
elif c == "]":
stack[-1].append((Instructions.RET, 0))
stack.pop()
def run(self):
self.tape = [0] * (16 * 1024 * 1024)
self.pointer = 0
self.__runList(self.programTree)
def __runList(self, plist):
pc = 0
while pc < len(plist):
i = plist[pc]
instr = i[0]
param = i[1]
if instr == Instructions.INCP:
self.pointer += 1
elif instr == Instructions.DECP:
self.pointer -= 1
elif instr == Instructions.INCV:
self.tape[self.pointer] += 1
elif instr == Instructions.DECV:
self.tape[self.pointer] -= 1
elif instr == Instructions.OUTPUT:
print(chr(self.tape[self.pointer]), end="")
elif instr == Instructions.INPUT:
self.tape[self.pointer] = ord(sys.stdin.read(1)[0])
elif instr == Instructions.SUBP:
if self.tape[self.pointer] != 0:
self.__runList(param)
elif instr == Instructions.RET:
if self.tape[self.pointer] != 0:
pc = 0
continue
pc += 1
if __name__ == "__main__":
if len(sys.argv) < 2:
print("usage:", sys.argv[0], "<inputfile>")
sys.exit(-1)
sourcefilename = sys.argv[1]
sourcefile = open(sourcefilename, "rt")
programText = sourcefile.read()
sourcefile.close()
interp = BFInterp(programText)
interp.run()
>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.>>>++++++++[<++++>-]<
.>>>++++++++++[<+++++++++>-]<---.<<<<.+++.------.--------.>>+.
-,+[ Read first character and start outer character reading loop
-[ Skip forward if character is 0
>>++++[>++++++++<-] Set up divisor (32) for division loop
(MEMORY LAYOUT: dividend copy remainder divisor quotient zero zero)
<+<-[ Set up dividend (x minus 1) and enter division loop
>+>+>-[>>>] Increase copy and remainder / reduce divisor / Normal case: skip forward
<[[>+<-]>>+>] Special case: move remainder back to divisor and increase quotient
<<<<<- Decrement dividend
] End division loop
]>>>[-]+ End skip loop; zero former divisor and reuse space for a flag
>--[-[<->+++[-]]]<[ Zero that flag unless quotient was 2 or 3; zero quotient; check flag
++++++++++++<[ If flag then set up divisor (13) for second division loop
(MEMORY LAYOUT: zero copy dividend divisor remainder quotient zero zero)
>-[>+>>] Reduce divisor; Normal case: increase remainder
>[+[<+>-]>+>>] Special case: increase remainder / move it back to divisor / increase quotient
<<<<<- Decrease dividend
] End division loop
>>[<+>-] Add remainder back to divisor to get a useful 13
>[ Skip forward if quotient was 0
-[ Decrement quotient and skip forward if quotient was 1
-<<[-]>> Zero quotient and divisor if quotient was 2
]<<[<<->>-]>> Zero divisor and subtract 13 from copy if quotient was 1
]<<[<<+>>-] Zero divisor and add 13 to copy if quotient was 0
] End outer skip loop (jump to here if ((character minus 1)/32) was not 2 or 3)
<[-] Clear remainder from first division if second division was skipped
<.[-] Output ROT13ed character from copy and clear it
<-,+ Read next character
] End character reading loop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment