From 0f9d904c71062cc12362c5d883e67022f3f2c0a8 Mon Sep 17 00:00:00 2001 From: Valentin Gehrke Date: Wed, 30 Nov 2016 15:58:48 +0100 Subject: [PATCH] Brainfuck interpreter with lexer and parser slr(1) --- brainfuck.py | 308 ++++++++++++++++++++++++++++++++++++++++++++++++++ helloworld.bf | 19 ++++ 2 files changed, 327 insertions(+) create mode 100644 brainfuck.py create mode 100644 helloworld.bf diff --git a/brainfuck.py b/brainfuck.py new file mode 100644 index 0000000..a28c2e7 --- /dev/null +++ b/brainfuck.py @@ -0,0 +1,308 @@ +#!/usr/bin/env python +from sys import stdout,stdin,argv + +class State: + def __init__(self): + self.data = [0] + self.ptr = 0 + + def prev(self): + if self.ptr == 0: + self.data.insert(0,0) + else: + self.ptr-=1 + + def next(self): + if self.ptr == len(self.data)-1: + self.data.append(0) + self.ptr+=1 + + def get(self): + return self.data[self.ptr] + + def set(self,val): + self.data[self.ptr] = val + + +class Instruction: + def run(self,state): + raise NotImplementedError + + def __repr__(self): + return self.__class__.__name__ + +class NextInstruction(Instruction): + def run(self,state): + state.next() + +class PrevInstruction(Instruction): + def run(self,state): + state.prev() + +class IncInstruction(Instruction): + def run(self,state): + state.set(state.get() + 1) + +class DecInstruction(Instruction): + def run(self,state): + state.set(state.get() - 1) + +class PutInstruction(Instruction): + def run(self,state): + stdout.write(chr(state.get())) + stdout.flush() + +class GetInstruction(Instruction): + def run(self,state): + state.set(ord(stdin.read(1))) + +class BlockInstruction(Instruction): + def __init__(self): + self.instructions = [] + + def prepend(self, inst): + self.instructions.insert(0, inst) + + def run(self,state): + for inst in self.instructions: + inst.run(state) + + def __repr__(self): + return ", ".join(map(repr,self.instructions)) + +class LoopInstruction(Instruction): + def __init__(self,block): + self.block = block + + def run(self,state): + while state.get() != 0: + self.block.run(state) + + def __repr__(self): + return "[ %s ]" % (repr(self.block)) + +Inext = NextInstruction() +Iprev = PrevInstruction() +Iinc = IncInstruction() +Idec = DecInstruction() +Iput = PutInstruction() +Iget = GetInstruction() + +class Token: + NEXT = "T_NEXT" + PREV = "T_PREV" + INC = "T_INC" + DEC = "T_DEC" + PUT = "T_PUT" + GET = "T_GET" + LOOP_START = "T_LOOP_START" + LOOP_END = "T_LOOP_END" + EOF = "T_EOF" + +def lex(it): + if type(it) == str: + it = iter(it) + END = object() + c = next(it,END) + + while c != END: + if c == ">": + yield Token.NEXT + elif c == "<": + yield Token.PREV + elif c == "+": + yield Token.INC + elif c == "-": + yield Token.DEC + elif c == ".": + yield Token.PUT + elif c == ",": + yield Token.GET + elif c == "[": + yield Token.LOOP_START + elif c == "]": + yield Token.LOOP_END + + c = next(it,END) + + yield Token.EOF + +class DefaultDict: + def __init__(self,value): + self.value = value + + def __contains__(self,key): + return True + + def __getitem__(self,key): + return self.value + +def parse(it): + NTS_S = object() + NTS_B = object() + + r = object() + s = object() + a = object() + + table = [ + { + Token.NEXT: (s,5), + Token.PREV: (s,6), + Token.INC: (s,7), + Token.DEC: (s,8), + Token.PUT: (s,9), + Token.GET: (s,10), + Token.LOOP_START: (s,2) + }, + { + Token.NEXT: (s,5), + Token.PREV: (s,6), + Token.INC: (s,7), + Token.DEC: (s,8), + Token.PUT: (s,9), + Token.GET: (s,10), + Token.LOOP_START: (s,2), + Token.LOOP_END: (r,3), + Token.EOF: (r,3) + }, + { + Token.NEXT: (s,5), + Token.PREV: (s,6), + Token.INC: (s,7), + Token.DEC: (s,8), + Token.PUT: (s,9), + Token.GET: (s,10), + Token.LOOP_START: (s,2) + }, + { + Token.LOOP_END: (s,4) + }, + DefaultDict( (r,10) ), + DefaultDict( (r,4) ), + DefaultDict( (r,5) ), + DefaultDict( (r,6) ), + DefaultDict( (r,7) ), + DefaultDict( (r,8) ), + DefaultDict( (r,9) ), + DefaultDict( (r,2) ), + DefaultDict( (a,0) ) + ] + + goto = [ + { NTS_S: 12, NTS_B: 1 }, + { NTS_S: 11, NTS_B: 1 }, + { NTS_S: 3, NTS_B: 1 }, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + ] + + state = [0] + data = [] + c = next(it) + + while True: + op, dat = table[state[-1]][c] + if op == s: + data.append(c) + c = next(it) + state.append(dat) + elif op == a: + return data[0] + elif op == r: + if dat == 2: + S = data.pop() + B = data.pop() + state.pop() + state.pop() + + S.prepend(B) + data.append(S) + + state.append( goto[state[-1]][NTS_S] ) + elif dat == 3: + B = data.pop() + state.pop() + + S = BlockInstruction() + S.prepend(B) + data.append(S) + + state.append( goto[state[-1]][NTS_S] ) + elif dat == 4: + data.pop() + state.pop() + + data.append( Inext ) + + state.append( goto[state[-1]][NTS_B] ) + elif dat == 5: + data.pop() + state.pop() + + data.append( Iprev ) + + state.append( goto[state[-1]][NTS_B] ) + elif dat == 6: + data.pop() + state.pop() + + data.append( Iinc ) + + state.append( goto[state[-1]][NTS_B] ) + elif dat == 7: + data.pop() + state.pop() + + data.append( Idec ) + + state.append( goto[state[-1]][NTS_B] ) + elif dat == 8: + data.pop() + state.pop() + + data.append( Iput ) + + state.append( goto[state[-1]][NTS_B] ) + elif dat == 9: + data.pop() + state.pop() + + data.append( Iget ) + + state.append( goto[state[-1]][NTS_B] ) + elif dat == 10: + data.pop() + S = data.pop() + data.pop() + state.pop() + state.pop() + state.pop() + + B = LoopInstruction(S) + data.append(B) + + state.append( goto[state[-1]][NTS_B] ) + + +if __name__ == '__main__': + + if len(argv) > 1: + fd = open(argv[1],"r") + contents = fd.read() + fd.close() + else: + contents = ",[.,]" + + ast = parse(lex(contents)) + + state = State() + ast.run(state) diff --git a/helloworld.bf b/helloworld.bf new file mode 100644 index 0000000..d18dfe7 --- /dev/null +++ b/helloworld.bf @@ -0,0 +1,19 @@ +++++++++++ + [ + >+++++++>++++++++++>+++>+<<<<- + ] Schleife zur Vorbereitung der Textausgabe + >++. Ausgabe von 'H' + >+. Ausgabe von 'e' + +++++++. 'l' + . 'l' + +++. 'o' + >++. Leerzeichen + <<+++++++++++++++. 'W' + >. 'o' + +++. 'r' + ------. 'l' + --------. 'd' + >+. '!' + >. Zeilenvorschub + +++. Wagenrücklauf +