User:Marinus/Minimal-2D interpreter
Jump to navigation
Jump to search
#!/usr/bin/env python # Minimal-2D interpreter import sys def addvec((x1,y1),(x2,y2)): return (x1+x2, y1+y2) def mulvec((x,y),m): return (x*m, y*m) # bidirectional infinite tape class Tape: def __init__(self): self.tape = [0] self.offset = 0 self.pos = 0 def left(self): self.pos -= 1 if self.pos == -1: self.offset += 1 self.pos = 0 self.tape.insert(0, 0) def right(self): self.pos += 1 if len(self.tape) >= self.pos + self.offset: self.tape.append(0) def get(self): return self.tape[self.pos+self.offset] def set(self, v): self.tape[self.pos+self.offset] = v # program field class Field: def __init__(self, f, emptychar=' '): self.lines = [line[:-1] for line in f.readlines()] self.ybound = len(self.lines) self.xbound = max([len(line) for line in self.lines]) self.emptychar = emptychar def __getitem__(self, (x, y)): if 0<=x<self.xbound and 0<=y<self.ybound: try: return self.lines[y][x] except IndexError: return self.emptychar else: raise IndexError("coordinates are outside field") # program head class Head: U,D,L,R = (0,-1), (0,1), (-1,0), (1,0) def __init__(self, tape, field): self.tape=tape self.field=field self.ip=[0,0] self.dir=self.R self.cmds = { '<': self.tape.left, '>': self.tape.right, '+': self.inc, '-': self.dec, '.': self.out, ',': self.inp, '/': self.skip, 'U': self.sdir(self.U), 'D': self.sdir(self.D), 'L': self.sdir(self.L), 'R': self.sdir(self.R) } def inc(self): self.tape.set(self.tape.get()+1) def dec(self): self.tape.set(self.tape.get()-1) def out(self): sys.stdout.write(chr(self.tape.get()%256)) def inp(self): ch = sys.stdin.read(1) self.tape.set(ch and ord(ch) or -1) def skip(self): self.ip = addvec(self.ip, mulvec(self.dir, not self.tape.get())) def sdir(self, d): def f(): self.dir=d return f def step(self): try: if self.field[self.ip] in self.cmds.keys(): self.cmds[self.field[self.ip]]() self.ip = addvec(self.ip, self.dir) return True except IndexError: # end program, we've left the field return False def main(argv): if len(argv) != 2: print "usage: %s program" % argv[0] sys.exit() try: h = Head(Tape(), Field(file(argv[1]))) while h.step(): pass except IOError, e: print "error: can't read %s: %s" % (argv[1], e) if __name__=='__main__': main(sys.argv)