diff interps/linguine/linguine.py @ 996:859f9b4339e6

<Gregor> tar xf egobot.tar.xz
author HackBot
date Sun, 09 Dec 2012 19:30:08 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interps/linguine/linguine.py	Sun Dec 09 19:30:08 2012 +0000
@@ -0,0 +1,343 @@
+#! /usr/bin/env python
+
+"""
+Linguine programming language interpreter
+Copyright (c) 2005 by Jeffry Johnston
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation. See the file LICENSE
+for more details.
+
+Version History:
+1.00    November 24, 2005       Initial version
+1.10    November 25, 2005       Added jump dereferencing
+1.20    November 26, 2005       Added `>' instruction
+1.21    November 26, 2005       Fix negative y on `>' bug
+1.22    November 26, 2005       Fix >> big number bug
+1.30    November 27, 2005       Added `^' instruction  
+"""
+
+import sys
+import time
+from optparse import OptionParser
+
+VERSION = "1.10"
+glo_memory = {}
+
+
+
+
+def read(filename):
+   """
+   Reads and parses the program, checking for errors.
+   Returns:
+     (firstline, program)
+       firstline = line number of first program line
+       program = {linenum: (command_list, goto, deref_goto), ...}
+         linenum = line number 
+         command_list = [(instr, x, deref_x, y, deref_y, ifjump, deref_if), ...] 
+            instr = instruction, one of: =, +, -, |, ?, $, #, <, ~ 
+            x = x value
+            deref_x = number of times x value should be deref'd, or 0        
+            y = y value
+            deref_y = number of times y value should be deref'd, or 0       
+            ifjump = ifjump line number 
+            deref_if = number of times ifjump value should be deref'd, or 0       
+         goto = jump line number
+         deref_goto = number of times goto value should be deref'd, or 0       
+   """
+   fileline = 0
+   program = {}
+   firstline = None
+   goto_list = []
+   try: 
+      infile = open(filename)
+      while True:
+         # read line
+         line = infile.readline()
+         fileline += 1
+         if line == "":
+            break
+            
+         # strip comments
+         i = line.find("'")
+         if i >= 0:
+            line = line[0:i]
+         line = line.strip()   
+         
+         # ignore blank lines
+         if len(line) < 1:
+            continue
+            
+         # get line number
+         i = line.find("[")
+         if i < 0:
+            print >> sys.stderr, "Error [line " + str(fileline) + "]: missing `['"
+            sys.exit(1)
+         try:   
+            linenum = int(line[0:i].strip())
+            linenum = int(linenum)
+            if linenum == 0:
+               raise ValueError
+            if firstline == None or linenum < firstline: 
+               firstline = linenum
+         except ValueError:
+            print >> sys.stderr, "Error [line " + str(fileline) + "]: bad or missing line number `" + str(linenum) + "'"
+            sys.exit(1)
+         
+         # get command    
+         line = line[i:]
+         i = line.find("]")
+         if i < 0:
+            print >> sys.stderr, "Error [line " + str(fileline) + "]: missing `]'"
+            sys.exit(1)
+         command = line[1:i].strip()
+         if len(command) < 2:
+            print >> sys.stderr, "Error [line " + str(fileline) + "]: missing or invalid command"
+            sys.exit(1)
+         goto = line[i + 1:].strip()
+            
+         # parse commands
+         command_list = []  
+         commands = command.split(",")
+         for command in commands:
+            command = command.strip()
+
+            # get x deref 
+            deref_x = 0
+            while len(command) > 0 and command[0] == "*":
+               deref_x += 1
+               command = command[1:].strip()
+
+            # find instruction
+            for c in "=+|>?^#$<~-": 
+               i = command.find(c, 1)
+               if i >= 0:
+                  instr = c
+                  break
+            else:
+               print >> sys.stderr, "Error [line " + str(fileline) + "]: unrecognized command `" + command + "'"
+               sys.exit(1)
+            
+            # get x  
+            x = command[0:i].strip()
+            command = command[i + 1:].strip()
+            try:   
+               x = int(x)  
+            except ValueError:
+               print >> sys.stderr, "Error [line " + str(fileline) + "]: bad x value `" + str(x) + "'"
+               sys.exit(1)
+         
+            # get y deref 
+            deref_y = 0
+            while len(command) > 0 and command[0] == "*":
+               deref_y += 1
+               command = command[1:].strip()
+         
+            # get if jump 
+            deref_if = 0
+            if instr[0] == "<" or instr[0] == "~":
+               i = command.find(":")
+               if i < 0:
+                  print >> sys.stderr, "Error [line " + str(fileline) + "]: missing if jump line number"
+                  sys.exit(1)
+               ifjump = command[i + 1:].strip()
+
+               # get ifjump deref 
+               while len(ifjump) > 0 and ifjump[0] == "*":
+                  deref_if += 1
+                  ifjump = ifjump[1:].strip()
+                  
+               command = command[0:i].strip()
+               try:
+                  ifjump = int(ifjump)
+               except ValueError:
+                  print >> sys.stderr, "Error [line " + str(fileline) + "]: bad if jump line number `" + str(ifjump) + "'"
+                  sys.exit(1)
+               if deref_if == 0:
+                  goto_list += [(ifjump, fileline)]   
+            else:
+               ifjump = None
+            
+            # get y
+            if instr[0] != "?" and instr[0] != "^" and instr[0] != "#" and instr[0] != "$":
+               y = command.strip()
+               try:
+                  y = int(y)
+               except ValueError:
+                  print >> sys.stderr, "Error [line " + str(fileline) + "]: bad y value `" + str(y) + "'"
+                  sys.exit(1)
+            else:
+               y = None
+               if deref_y:
+                  print >> sys.stderr, "Error [line " + str(fileline) + "]: bad dereference"
+                  sys.exit(1)
+         
+            # add command to command list
+            command_list += [(instr, x, deref_x, y, deref_y, ifjump, deref_if)]  
+         
+         # get goto line number
+         deref_goto = 0
+         while len(goto) > 0 and goto[0] == "*":
+            deref_goto += 1
+            goto = goto[1:].strip()
+         if len(goto) < 1:
+            print >> sys.stderr, "Error [line " + str(fileline) + "]: missing jump line number"
+            sys.exit(1)
+         try:
+            goto = int(goto)
+         except ValueError:
+            print >> sys.stderr, "Error [line " + str(fileline) + "]: bad jump line number `" + str(goto) + "'"
+            sys.exit(1)
+         if deref_goto == 0:
+            goto_list += [(goto, fileline)]   
+            
+         # add line to program dictionary
+         try:
+            program[linenum]
+            print >> sys.stderr, "Error [line " + str(fileline) + "]: duplicate line number `" + str(linenum) + "'"
+            sys.exit(1)
+         except KeyError:
+            program[linenum] = (command_list, goto, deref_goto)    
+           
+      infile.close()
+   except IOError, e:
+      print >> sys.stderr, "Error reading program: " + str(e)
+      sys.exit(1)
+      
+   # check that there was at least one program line   
+   if firstline == None:
+      print >> sys.stderr, "Error: Program must have at least one command"
+      sys.exit(1)
+      
+   # check that all jumps are to valid line numbers 
+   for goto, fileline in goto_list:
+      if goto != 0 and not program.has_key(goto):
+         print >> sys.stderr, "Error [line " + str(fileline) + "]: jump to undefined line number `" + str(goto) + "'"
+         sys.exit(1)
+   goto_list = None      
+      
+   return (firstline, program)
+
+
+
+
+def get_cell(index):
+   """ 
+   Returns the cell value at the specified index, or 0 if the cell is
+   unused.
+   """
+   if glo_memory.has_key(index):
+      return glo_memory[index]
+   else:
+      return 0
+
+
+
+
+def set_cell(index, value):
+   """
+   Sets the value of the cell at the specified index.
+   """
+   glo_memory[index] = value
+  
+
+
+
+def interpret((firstline, program)):
+   """
+   Interprets the given Linguine program
+   """
+   line = firstline
+   index = 0
+   while line > 0:
+      # get the current command
+      commands = program[line][0]
+      command = commands[index]
+      instr = command[0]
+      x = command[1]
+      for i in xrange(command[2]):
+         x = get_cell(x)
+      y = command[3]
+      for i in xrange(command[4]):
+         y = get_cell(y)
+      ifjump = command[5]
+      for i in xrange(command[6]):
+         ifjump = get_cell(ifjump)
+      if ifjump != None and ifjump != 0 and not program.has_key(ifjump):
+         print >> sys.stderr, "Runtime error [line number " + str(line) + "]: bad ifjump line number `" + str(ifjump) + "'"
+         sys.exit(1)
+      if index + 1 >= len(commands):
+         goto = program[line][1]
+         for i in xrange(program[line][2]):
+            goto = get_cell(goto)
+         if goto != 0 and not program.has_key(goto):
+            print >> sys.stderr, "Runtime error [line number " + str(line) + "]: bad jump line number `" + str(goto) + "'"
+            sys.exit(1)
+         line = goto
+         index = 0
+      else:
+         index += 1     
+      
+      # execute instruction
+      if instr == "=":
+         set_cell(x, y) 
+      elif instr == "+":
+         set_cell(x, get_cell(x) + y) 
+      elif instr == "-":
+         set_cell(x, get_cell(x) - y) 
+      elif instr == "|":
+         set_cell(x, ~(get_cell(x) & y)) 
+      elif instr == ">":
+         if y < 0:
+            set_cell(x, get_cell(x) * (2**(-y))) 
+         else:
+            set_cell(x, get_cell(x) >> y) 
+      elif instr == "?":
+         ch = sys.stdin.read(1)
+         if len(ch) < 1:
+            ch = -1
+         else:
+            ch = ord(ch)
+         set_cell(x, ch)
+      elif instr == "^":
+         set_cell(x, int(time.time()))   
+      elif instr == "$":
+         sys.stdout.write(chr(get_cell(x) & 255))
+         sys.stdout.flush()
+      elif instr == "#":
+         sys.stdout.write(str(get_cell(x)))
+         sys.stdout.flush()
+      elif instr == "<" and get_cell(x) < y:
+         line = ifjump
+         index = 0
+      elif instr == "~" and get_cell(x) == y:
+         line = ifjump
+         index = 0
+
+
+
+
+def main():
+   """
+   Processes the command line, reads the program, and starts the Linguine 
+   interpreter.
+   """
+   (options, args) = OptionParser(usage="linguine.py [options] program", \
+                                  version=VERSION, \
+                                  description="Interprets the specified Linguine program.").parse_args()
+   if len(args) < 1:
+      print >> sys.stderr, "Missing program filename."
+      sys.exit(1)
+   elif len(args) > 1:   
+      print >> sys.stderr, "Too many filenames given."
+      sys.exit(1)
+   interpret(read(args[0]))
+
+
+
+
+if __name__ == "__main__":
+   main()
+