User:Marinus/96 interpreter

From Esolang
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)