User:Marinus/Pirandello interpreter

Pirandello interpreter (escape (Interaction-/) does not work because there's no definition of what it should do.)


 * 1) !/usr/bin/env python

import sys

class Tape(object): def __init__(self): self.data = [0] * 100 self.idx = 3

def prev(self): if self.idx == 0: raise IndexError("The program went past the left end of the tape.") else: self.idx -= 1 def next(self): self.idx += 1 if self.idx >= len(self.data): self.data += [0] * 100

def get(self): return self.data[self.idx] def set(self, value): self.data[self.idx] = value def __getitem__(self, n): if n<0: raise IndexError("The program went past the left end of the tape.") try: return self.data[n] except IndexError: return 0 def __setitem__(self, n, v): if n<0: raise IndexError("The program went past the left end of the tape.") elif n>=len(self.data): self.data += [0] * (n - len(self.data) + 100) self.data[n] = v

class Field(object): UP, DOWN, LEFT, RIGHT = (0,-1), (0,1), (-1,0), (1,0)

def __init__(self, stream): lines = [x[:-1] for x in stream.readlines] self.llen = maxlen = max(map(len, lines)) self.lines = [ x + ' ' * (maxlen - len(x)) for x in lines ] def __getitem__(self, (x, y)): return self.lines[y%len(self.lines)][x%self.llen]

@staticmethod def addVectors((x1, y1), (x2, y2)): return (x1+x2, y1+y2)

class Mode(object): def equals(self): pass def percent(self): self.interpreter.cycle def do(self, char): try: { '+': self.plus, '-': self.minus, '/': self.slash, '*': self.star, '%': self.percent, '=': self.equals } [char] except KeyError: raise KeyError("no such command: " + char) def __init__(self, interp): self.interpreter = interp class Flow(Mode): def star(self): self.interpreter.skip def slash(self): self.interpreter.condturn def plus(self): self.interpreter.left def minus(self): self.interpreter.right class Data(Mode): def plus(self): self.interpreter.advance def minus(self): self.interpreter.retreat def star(self): self.interpreter.increment def slash(self): self.interpreter.decrement

class Interaction(Mode): def plus(self): self.interpreter.input def minus(self): self.interpreter.output def slash(self): self.interpreter.escape def star(self): self.interpreter.exit

class Register(Mode): def plus(self): self.interpreter.store def minus(self): self.interpreter.load def slash(self): self.interpreter.regskip def star(self): self.interpreter.add

class Cycle(object): def __init__(self, items): self.items = items self.current = 0 def next(self): self.current += 1 self.current %= len(self.items)

def prev(self): self.current -= 1 self.current %= len(self.items) def get(self): return self.items[self.current]

class Interpreter(object): def __init__(self, field, tape): self.field, self.tape = field, tape self.reg = 0 self.coords = (0, 0) self.mode = Cycle([x(self) for x in [Flow, Data, Interaction, Register]]) self.direction = Cycle([Field.DOWN, Field.LEFT, Field.UP, Field.RIGHT]) def cycle(self): self.mode.next def skip(self): self.coords = Field.addVectors(self.coords, self.direction.get) def condturn(self): self.left if self.tape.get > 0 else self.right def left(self): self.direction.prev def right(self): self.direction.next def advance(self): self.tape.next def retreat(self): try: self.tape.prev except: pass def increment(self): self.tape.set(self.tape.get + 1 % 256) def decrement(self): self.tape.set(self.tape.get - 1 % 256) def input(self): ch = sys.stdin.read(1) if ch: self.tape[1] = ord(ch) else: self.tape[2] = 1 def output(self): sys.stdout.write(chr(self.tape[1])) def escape(self): raise NotImplementedError("found an escape: spec is unclear, so escape is not implemented") def exit(self): sys.exit def store(self): self.reg = self.tape.get def load(self): self.tape.set(self.reg) def regskip(self): if self.reg: self.skip def add(self): self.tape.set(self.tape.get + self.reg % 256) def step(self): self.mode.get.do(self.field[self.coords]) self.coords = Field.addVectors(self.coords, self.direction.get)

def main(argv): if len(argv) != 2: print "usage: pirandello.py filename" sys.exit interp = None try: interp = Interpreter(Field(file(argv[1])), Tape) while True: interp.step except Exception, e:      if interp: at = " at (%d, %d)" % interp.coords else: at = "" print "error%s: %s" % (at, str(e))

if __name__=='__main__': main(sys.argv)