User:Marinus/96 interpreter
Jump to navigation
Jump to search
This is a 96 interpreter.
#!/usr/bin/env python
# 96.py - 96 interpreter
import sys
# array that resizes automatically
class Array:
def __init__(self):
self.arr = []
self.curpos = 0
def __getitem__(self, i):
if i < len(self.arr):
return self.arr[i]
else:
return 0
def __setitem__(self, i, v):
# grow array if necessary
if i >= len(self.arr):
self.arr += [0] * (i - len(self.arr) + 1)
self.arr[i] = v
class PgmError(Exception): pass;
class Interpreter:
def __init__(self, code):
self.code = code[:]
self.acc = 0
self.markstack = []
self.ip = 0
# make memory arrays
self.arrs = {}
for arr in 'abcdefghijklmnopqrstuvwxyz':
self.arrs[arr] = Array()
self.curarr = self.arrs['a']
self.mp = 0
def run(self):
while self.ip < len(self.code):
try:
self.docmd(self.code[self.ip])
self.ip += 1
except (PgmError, ZeroDivisionError):
# error mode
pc = 0
while self.ip < len(self.code)-1:
self.ip += 1
c = self.code[self.ip]
if c == '(':
pc += 1
elif c == ';':
if pc == 0:
self.ip += 1
break
elif c == ')':
if pc == 0:
self.ip += 1
break
else:
pc -= 1
elif c == ']':
try:self.markstack.pop()
except:pass
def docmd(self, c):
## modify current element ####
if c == '+': self.curarr[self.mp] += 1
elif c == '-':
if self.curarr[self.mp] == 0:
raise PgmError()
else:
self.curarr[self.mp] -= 1
elif c == '.': self.curarr[self.mp] = 0
elif c in '0123456789':
self.curarr[self.mp] *= 10
self.curarr[self.mp] += ord(c) - ord('0')
elif c == '@': self.curarr[self.mp] = self.acc
## memory pointer control ####
elif c in 'abcdefghijklmnopqrstuvwxyz':
self.mp = 0
self.curarr = self.arrs[c]
elif c == ',': self.mp += 1
elif c == "'":
if self.mp == 0: raise PgmError()
else: self.mp -= 1
elif c == '#':
self.mp = self.curarr[self.mp]
elif c == '_':
self.mp = 0
while self.curarr[self.mp] != 0:
self.mp += 1
## unary operators ####
elif c == '^':
self.acc += 1
elif c == '|':
if self.acc == 0: raise PgmError()
else: self.acc -= 1
elif c == ' ':
self.acc = 0
elif c == ':':
self.acc = self.curarr[self.mp]
## binary operators ####
elif c == '&': self.acc += self.curarr[self.mp]
elif c == '=': self.acc = abs(self.acc - self.curarr[self.mp])
elif c == '*': self.acc *= self.curarr[self.mp]
elif c == '/': self.acc /= self.curarr[self.mp]
elif c == '%': self.acc %= self.curarr[self.mp]
elif c == '\\': self.acc = self.curarr[self.mp] / self.acc
elif c == '`': self.acc = self.curarr[self.mp] % self.acc
## test operators ####
elif c == '<': self.acc = [1,0][self.acc < self.curarr[self.mp]]
elif c == '>': self.acc = [1,0][self.acc > self.curarr[self.mp]]
## i/o ####
elif c == '?':
line = sys.stdin.readline()
if line=='':
pass # eof -> no effect
elif line.replace('\n','').isdigit() and line[0] != '0':
self.acc = int(line) # number input
else:
# string input
i = 0
for ch in line:
self.curarr[i] = ord(ch)
i += 1
self.curarr[i] = 0
elif c == '"':
# string output
i = 0
while self.curarr[i] != 0:
sys.stdout.write(chr(self.curarr[i]%256))
i += 1
elif c == '$':
# int output
sys.stdout.write(str(self.acc) + ' ')
## advanced (ooh...) ####
elif c == '~':
foo = self.acc
self.acc = self.curarr[self.mp]
self.curarr[self.mp] = foo
elif c == '!':
self.docmd(chr(self.acc)%256)
## marks ####
elif c == '[':
self.markstack.append(self.ip + 1)
elif c == ']':
if len(self.markstack) > 0:
self.ip = self.markstack[-1]-1
# -1 because ip is incremented after command is done
## error causing / functions #
elif c == '(':
if self.acc: raise PgmError()
elif c == ';':
raise PgmError()
elif c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
self.markstack.append(self.ip + 1)
self.ip = self.code.index(c)
elif c == '\n':
if len(self.markstack) > 0:
self.ip = self.markstack.pop()-1
def main(argv):
if len(argv) != 2:
print "Usage: 96.py <programfile>"
sys.exit()
try: code = file(argv[1]).read()
except IOError, e:
print "Can't open file:", e
sys.exit()
Interpreter(code).run()
if __name__=='__main__': main(sys.argv)