14479Sbinkertn@umich.edu# This file provides the runtime support for running a basic program
24479Sbinkertn@umich.edu# Assumes the program has been parsed using basparse.py
34479Sbinkertn@umich.edu
44479Sbinkertn@umich.eduimport sys
54479Sbinkertn@umich.eduimport math
64479Sbinkertn@umich.eduimport random
74479Sbinkertn@umich.edu
84479Sbinkertn@umich.educlass BasicInterpreter:
94479Sbinkertn@umich.edu
104479Sbinkertn@umich.edu    # Initialize the interpreter. prog is a dictionary
114479Sbinkertn@umich.edu    # containing (line,statement) mappings
124479Sbinkertn@umich.edu    def __init__(self,prog):
134479Sbinkertn@umich.edu         self.prog = prog
144479Sbinkertn@umich.edu
154479Sbinkertn@umich.edu         self.functions = {           # Built-in function table
164479Sbinkertn@umich.edu             'SIN' : lambda z: math.sin(self.eval(z)),
174479Sbinkertn@umich.edu             'COS' : lambda z: math.cos(self.eval(z)),
184479Sbinkertn@umich.edu             'TAN' : lambda z: math.tan(self.eval(z)),
194479Sbinkertn@umich.edu             'ATN' : lambda z: math.atan(self.eval(z)),
204479Sbinkertn@umich.edu             'EXP' : lambda z: math.exp(self.eval(z)),
214479Sbinkertn@umich.edu             'ABS' : lambda z: abs(self.eval(z)),
224479Sbinkertn@umich.edu             'LOG' : lambda z: math.log(self.eval(z)),
234479Sbinkertn@umich.edu             'SQR' : lambda z: math.sqrt(self.eval(z)),
244479Sbinkertn@umich.edu             'INT' : lambda z: int(self.eval(z)),
254479Sbinkertn@umich.edu             'RND' : lambda z: random.random()
264479Sbinkertn@umich.edu         }
274479Sbinkertn@umich.edu
284479Sbinkertn@umich.edu    # Collect all data statements
294479Sbinkertn@umich.edu    def collect_data(self):
304479Sbinkertn@umich.edu         self.data = []
314479Sbinkertn@umich.edu         for lineno in self.stat:
324479Sbinkertn@umich.edu              if self.prog[lineno][0] == 'DATA':
334479Sbinkertn@umich.edu                  self.data = self.data + self.prog[lineno][1]
344479Sbinkertn@umich.edu         self.dc = 0                  # Initialize the data counter
354479Sbinkertn@umich.edu
364479Sbinkertn@umich.edu    # Check for end statements
374479Sbinkertn@umich.edu    def check_end(self):
384479Sbinkertn@umich.edu         has_end = 0
394479Sbinkertn@umich.edu         for lineno in self.stat:
404479Sbinkertn@umich.edu             if self.prog[lineno][0] == 'END' and not has_end:
414479Sbinkertn@umich.edu                  has_end = lineno
424479Sbinkertn@umich.edu         if not has_end:
436498Snate@binkert.org             print("NO END INSTRUCTION")
444479Sbinkertn@umich.edu             self.error = 1
456498Snate@binkert.org             return
464479Sbinkertn@umich.edu         if has_end != lineno:
476498Snate@binkert.org             print("END IS NOT LAST")
484479Sbinkertn@umich.edu             self.error = 1
494479Sbinkertn@umich.edu
504479Sbinkertn@umich.edu    # Check loops
514479Sbinkertn@umich.edu    def check_loops(self):
524479Sbinkertn@umich.edu         for pc in range(len(self.stat)):
534479Sbinkertn@umich.edu             lineno = self.stat[pc]
544479Sbinkertn@umich.edu             if self.prog[lineno][0] == 'FOR':
554479Sbinkertn@umich.edu                  forinst = self.prog[lineno]
564479Sbinkertn@umich.edu                  loopvar = forinst[1]
574479Sbinkertn@umich.edu                  for i in range(pc+1,len(self.stat)):
584479Sbinkertn@umich.edu                       if self.prog[self.stat[i]][0] == 'NEXT':
594479Sbinkertn@umich.edu                            nextvar = self.prog[self.stat[i]][1]
604479Sbinkertn@umich.edu                            if nextvar != loopvar: continue
614479Sbinkertn@umich.edu                            self.loopend[pc] = i
624479Sbinkertn@umich.edu                            break
634479Sbinkertn@umich.edu                  else:
646498Snate@binkert.org                       print("FOR WITHOUT NEXT AT LINE %s" % self.stat[pc])
654479Sbinkertn@umich.edu                       self.error = 1
666498Snate@binkert.org
674479Sbinkertn@umich.edu    # Evaluate an expression
684479Sbinkertn@umich.edu    def eval(self,expr):
694479Sbinkertn@umich.edu        etype = expr[0]
704479Sbinkertn@umich.edu        if etype == 'NUM': return expr[1]
714479Sbinkertn@umich.edu        elif etype == 'GROUP': return self.eval(expr[1])
724479Sbinkertn@umich.edu        elif etype == 'UNARY':
734479Sbinkertn@umich.edu             if expr[1] == '-': return -self.eval(expr[2])
744479Sbinkertn@umich.edu        elif etype == 'BINOP':
754479Sbinkertn@umich.edu             if expr[1] == '+': return self.eval(expr[2])+self.eval(expr[3])
764479Sbinkertn@umich.edu             elif expr[1] == '-': return self.eval(expr[2])-self.eval(expr[3])
774479Sbinkertn@umich.edu             elif expr[1] == '*': return self.eval(expr[2])*self.eval(expr[3])
784479Sbinkertn@umich.edu             elif expr[1] == '/': return float(self.eval(expr[2]))/self.eval(expr[3])
794479Sbinkertn@umich.edu             elif expr[1] == '^': return abs(self.eval(expr[2]))**self.eval(expr[3])
804479Sbinkertn@umich.edu        elif etype == 'VAR':
814479Sbinkertn@umich.edu             var,dim1,dim2 = expr[1]
824479Sbinkertn@umich.edu             if not dim1 and not dim2:
836498Snate@binkert.org                  if var in self.vars:
844479Sbinkertn@umich.edu                       return self.vars[var]
854479Sbinkertn@umich.edu                  else:
866498Snate@binkert.org                       print("UNDEFINED VARIABLE %s AT LINE %s" % (var, self.stat[self.pc]))
874479Sbinkertn@umich.edu                       raise RuntimeError
884479Sbinkertn@umich.edu             # May be a list lookup or a function evaluation
894479Sbinkertn@umich.edu             if dim1 and not dim2:
906498Snate@binkert.org                if var in self.functions:
914479Sbinkertn@umich.edu                      # A function
924479Sbinkertn@umich.edu                      return self.functions[var](dim1)
934479Sbinkertn@umich.edu                else:
944479Sbinkertn@umich.edu                      # A list evaluation
956498Snate@binkert.org                      if var in self.lists:
964479Sbinkertn@umich.edu                            dim1val = self.eval(dim1)
974479Sbinkertn@umich.edu                            if dim1val < 1 or dim1val > len(self.lists[var]):
986498Snate@binkert.org                                 print("LIST INDEX OUT OF BOUNDS AT LINE %s" % self.stat[self.pc])
994479Sbinkertn@umich.edu                                 raise RuntimeError
1004479Sbinkertn@umich.edu                            return self.lists[var][dim1val-1]
1014479Sbinkertn@umich.edu             if dim1 and dim2:
1026498Snate@binkert.org                 if var in self.tables:
1034479Sbinkertn@umich.edu                      dim1val = self.eval(dim1)
1044479Sbinkertn@umich.edu                      dim2val = self.eval(dim2)
1054479Sbinkertn@umich.edu                      if dim1val < 1 or dim1val > len(self.tables[var]) or dim2val < 1 or dim2val > len(self.tables[var][0]):
1066498Snate@binkert.org                           print("TABLE INDEX OUT OUT BOUNDS AT LINE %s" % self.stat[self.pc])
1074479Sbinkertn@umich.edu                           raise RuntimeError
1084479Sbinkertn@umich.edu                      return self.tables[var][dim1val-1][dim2val-1]
1096498Snate@binkert.org             print("UNDEFINED VARIABLE %s AT LINE %s" % (var, self.stat[self.pc]))
1104479Sbinkertn@umich.edu             raise RuntimeError
1114479Sbinkertn@umich.edu
1124479Sbinkertn@umich.edu    # Evaluate a relational expression
1134479Sbinkertn@umich.edu    def releval(self,expr):
1144479Sbinkertn@umich.edu         etype = expr[1]
1154479Sbinkertn@umich.edu         lhs   = self.eval(expr[2])
1164479Sbinkertn@umich.edu         rhs   = self.eval(expr[3])
1174479Sbinkertn@umich.edu         if etype == '<':
1184479Sbinkertn@umich.edu             if lhs < rhs: return 1
1194479Sbinkertn@umich.edu             else: return 0
1204479Sbinkertn@umich.edu
1214479Sbinkertn@umich.edu         elif etype == '<=':
1224479Sbinkertn@umich.edu             if lhs <= rhs: return 1
1234479Sbinkertn@umich.edu             else: return 0
1244479Sbinkertn@umich.edu
1254479Sbinkertn@umich.edu         elif etype == '>':
1264479Sbinkertn@umich.edu             if lhs > rhs: return 1
1274479Sbinkertn@umich.edu             else: return 0
1284479Sbinkertn@umich.edu
1294479Sbinkertn@umich.edu         elif etype == '>=':
1304479Sbinkertn@umich.edu             if lhs >= rhs: return 1
1314479Sbinkertn@umich.edu             else: return 0
1324479Sbinkertn@umich.edu
1334479Sbinkertn@umich.edu         elif etype == '=':
1344479Sbinkertn@umich.edu             if lhs == rhs: return 1
1354479Sbinkertn@umich.edu             else: return 0
1364479Sbinkertn@umich.edu
1374479Sbinkertn@umich.edu         elif etype == '<>':
1384479Sbinkertn@umich.edu             if lhs != rhs: return 1
1394479Sbinkertn@umich.edu             else: return 0
1404479Sbinkertn@umich.edu
1414479Sbinkertn@umich.edu    # Assignment
1424479Sbinkertn@umich.edu    def assign(self,target,value):
1434479Sbinkertn@umich.edu        var, dim1, dim2 = target
1444479Sbinkertn@umich.edu        if not dim1 and not dim2:
1454479Sbinkertn@umich.edu            self.vars[var] = self.eval(value)
1464479Sbinkertn@umich.edu        elif dim1 and not dim2:
1474479Sbinkertn@umich.edu            # List assignment
1484479Sbinkertn@umich.edu            dim1val = self.eval(dim1)
1496498Snate@binkert.org            if not var in self.lists:
1504479Sbinkertn@umich.edu                 self.lists[var] = [0]*10
1514479Sbinkertn@umich.edu
1524479Sbinkertn@umich.edu            if dim1val > len(self.lists[var]):
1536498Snate@binkert.org                 print ("DIMENSION TOO LARGE AT LINE %s" % self.stat[self.pc])
1544479Sbinkertn@umich.edu                 raise RuntimeError
1554479Sbinkertn@umich.edu            self.lists[var][dim1val-1] = self.eval(value)
1564479Sbinkertn@umich.edu        elif dim1 and dim2:
1574479Sbinkertn@umich.edu            dim1val = self.eval(dim1)
1584479Sbinkertn@umich.edu            dim2val = self.eval(dim2)
1596498Snate@binkert.org            if not var in self.tables:
1604479Sbinkertn@umich.edu                 temp = [0]*10
1614479Sbinkertn@umich.edu                 v = []
1624479Sbinkertn@umich.edu                 for i in range(10): v.append(temp[:])
1634479Sbinkertn@umich.edu                 self.tables[var] = v
1644479Sbinkertn@umich.edu            # Variable already exists
1654479Sbinkertn@umich.edu            if dim1val > len(self.tables[var]) or dim2val > len(self.tables[var][0]):
1666498Snate@binkert.org                 print("DIMENSION TOO LARGE AT LINE %s" % self.stat[self.pc])
1674479Sbinkertn@umich.edu                 raise RuntimeError
1684479Sbinkertn@umich.edu            self.tables[var][dim1val-1][dim2val-1] = self.eval(value)
1694479Sbinkertn@umich.edu
1704479Sbinkertn@umich.edu    # Change the current line number
1714479Sbinkertn@umich.edu    def goto(self,linenum):
1726498Snate@binkert.org         if not linenum in self.prog:
1736498Snate@binkert.org              print("UNDEFINED LINE NUMBER %d AT LINE %d" % (linenum, self.stat[self.pc]))
1744479Sbinkertn@umich.edu              raise RuntimeError
1754479Sbinkertn@umich.edu         self.pc = self.stat.index(linenum)
1764479Sbinkertn@umich.edu
1774479Sbinkertn@umich.edu    # Run it
1784479Sbinkertn@umich.edu    def run(self):
1794479Sbinkertn@umich.edu        self.vars   = { }            # All variables
1804479Sbinkertn@umich.edu        self.lists  = { }            # List variables
1814479Sbinkertn@umich.edu        self.tables = { }            # Tables
1824479Sbinkertn@umich.edu        self.loops  = [ ]            # Currently active loops
1834479Sbinkertn@umich.edu        self.loopend= { }            # Mapping saying where loops end
1844479Sbinkertn@umich.edu        self.gosub  = None           # Gosub return point (if any)
1854479Sbinkertn@umich.edu        self.error  = 0              # Indicates program error
1864479Sbinkertn@umich.edu
1876498Snate@binkert.org        self.stat = list(self.prog)  # Ordered list of all line numbers
1884479Sbinkertn@umich.edu        self.stat.sort()
1894479Sbinkertn@umich.edu        self.pc = 0                  # Current program counter
1904479Sbinkertn@umich.edu
1914479Sbinkertn@umich.edu        # Processing prior to running
1924479Sbinkertn@umich.edu
1934479Sbinkertn@umich.edu        self.collect_data()          # Collect all of the data statements
1944479Sbinkertn@umich.edu        self.check_end()
1954479Sbinkertn@umich.edu        self.check_loops()
1964479Sbinkertn@umich.edu
1974479Sbinkertn@umich.edu        if self.error: raise RuntimeError
1984479Sbinkertn@umich.edu
1994479Sbinkertn@umich.edu        while 1:
2004479Sbinkertn@umich.edu            line  = self.stat[self.pc]
2014479Sbinkertn@umich.edu            instr = self.prog[line]
2026498Snate@binkert.org
2034479Sbinkertn@umich.edu            op = instr[0]
2044479Sbinkertn@umich.edu
2054479Sbinkertn@umich.edu            # END and STOP statements
2064479Sbinkertn@umich.edu            if op == 'END' or op == 'STOP':
2074479Sbinkertn@umich.edu                 break           # We're done
2084479Sbinkertn@umich.edu
2094479Sbinkertn@umich.edu            # GOTO statement
2104479Sbinkertn@umich.edu            elif op == 'GOTO':
2114479Sbinkertn@umich.edu                 newline = instr[1]
2124479Sbinkertn@umich.edu                 self.goto(newline)
2134479Sbinkertn@umich.edu                 continue
2144479Sbinkertn@umich.edu
2154479Sbinkertn@umich.edu            # PRINT statement
2164479Sbinkertn@umich.edu            elif op == 'PRINT':
2174479Sbinkertn@umich.edu                 plist = instr[1]
2184479Sbinkertn@umich.edu                 out = ""
2194479Sbinkertn@umich.edu                 for label,val in plist:
2204479Sbinkertn@umich.edu                     if out:
2214479Sbinkertn@umich.edu                          out += ' '*(15 - (len(out) % 15))
2224479Sbinkertn@umich.edu                     out += label
2234479Sbinkertn@umich.edu                     if val:
2244479Sbinkertn@umich.edu                          if label: out += " "
2254479Sbinkertn@umich.edu                          eval = self.eval(val)
2264479Sbinkertn@umich.edu                          out += str(eval)
2274479Sbinkertn@umich.edu                 sys.stdout.write(out)
2284479Sbinkertn@umich.edu                 end = instr[2]
2296498Snate@binkert.org                 if not (end == ',' or end == ';'):
2304479Sbinkertn@umich.edu                     sys.stdout.write("\n")
2314479Sbinkertn@umich.edu                 if end == ',': sys.stdout.write(" "*(15-(len(out) % 15)))
2324479Sbinkertn@umich.edu                 if end == ';': sys.stdout.write(" "*(3-(len(out) % 3)))
2336498Snate@binkert.org
2344479Sbinkertn@umich.edu            # LET statement
2354479Sbinkertn@umich.edu            elif op == 'LET':
2364479Sbinkertn@umich.edu                 target = instr[1]
2374479Sbinkertn@umich.edu                 value  = instr[2]
2384479Sbinkertn@umich.edu                 self.assign(target,value)
2394479Sbinkertn@umich.edu
2404479Sbinkertn@umich.edu            # READ statement
2414479Sbinkertn@umich.edu            elif op == 'READ':
2424479Sbinkertn@umich.edu                 for target in instr[1]:
2434479Sbinkertn@umich.edu                      if self.dc < len(self.data):
2444479Sbinkertn@umich.edu                          value = ('NUM',self.data[self.dc])
2454479Sbinkertn@umich.edu                          self.assign(target,value)
2464479Sbinkertn@umich.edu                          self.dc += 1
2474479Sbinkertn@umich.edu                      else:
2484479Sbinkertn@umich.edu                          # No more data.  Program ends
2494479Sbinkertn@umich.edu                          return
2504479Sbinkertn@umich.edu            elif op == 'IF':
2514479Sbinkertn@umich.edu                 relop = instr[1]
2524479Sbinkertn@umich.edu                 newline = instr[2]
2534479Sbinkertn@umich.edu                 if (self.releval(relop)):
2544479Sbinkertn@umich.edu                     self.goto(newline)
2554479Sbinkertn@umich.edu                     continue
2564479Sbinkertn@umich.edu
2574479Sbinkertn@umich.edu            elif op == 'FOR':
2584479Sbinkertn@umich.edu                 loopvar = instr[1]
2594479Sbinkertn@umich.edu                 initval = instr[2]
2604479Sbinkertn@umich.edu                 finval  = instr[3]
2614479Sbinkertn@umich.edu                 stepval = instr[4]
2626498Snate@binkert.org
2634479Sbinkertn@umich.edu                 # Check to see if this is a new loop
2644479Sbinkertn@umich.edu                 if not self.loops or self.loops[-1][0] != self.pc:
2654479Sbinkertn@umich.edu                        # Looks like a new loop. Make the initial assignment
2664479Sbinkertn@umich.edu                        newvalue = initval
2674479Sbinkertn@umich.edu                        self.assign((loopvar,None,None),initval)
2684479Sbinkertn@umich.edu                        if not stepval: stepval = ('NUM',1)
2694479Sbinkertn@umich.edu                        stepval = self.eval(stepval)    # Evaluate step here
2704479Sbinkertn@umich.edu                        self.loops.append((self.pc,stepval))
2714479Sbinkertn@umich.edu                 else:
2724479Sbinkertn@umich.edu                        # It's a repeat of the previous loop
2734479Sbinkertn@umich.edu                        # Update the value of the loop variable according to the step
2744479Sbinkertn@umich.edu                        stepval = ('NUM',self.loops[-1][1])
2754479Sbinkertn@umich.edu                        newvalue = ('BINOP','+',('VAR',(loopvar,None,None)),stepval)
2764479Sbinkertn@umich.edu
2774479Sbinkertn@umich.edu                 if self.loops[-1][1] < 0: relop = '>='
2784479Sbinkertn@umich.edu                 else: relop = '<='
2794479Sbinkertn@umich.edu                 if not self.releval(('RELOP',relop,newvalue,finval)):
2804479Sbinkertn@umich.edu                      # Loop is done. Jump to the NEXT
2814479Sbinkertn@umich.edu                      self.pc = self.loopend[self.pc]
2824479Sbinkertn@umich.edu                      self.loops.pop()
2834479Sbinkertn@umich.edu                 else:
2844479Sbinkertn@umich.edu                      self.assign((loopvar,None,None),newvalue)
2854479Sbinkertn@umich.edu
2864479Sbinkertn@umich.edu            elif op == 'NEXT':
2874479Sbinkertn@umich.edu                 if not self.loops:
2886498Snate@binkert.org                       print("NEXT WITHOUT FOR AT LINE %s" % line)
2894479Sbinkertn@umich.edu                       return
2906498Snate@binkert.org
2914479Sbinkertn@umich.edu                 nextvar = instr[1]
2924479Sbinkertn@umich.edu                 self.pc = self.loops[-1][0]
2934479Sbinkertn@umich.edu                 loopinst = self.prog[self.stat[self.pc]]
2944479Sbinkertn@umich.edu                 forvar = loopinst[1]
2954479Sbinkertn@umich.edu                 if nextvar != forvar:
2966498Snate@binkert.org                       print("NEXT DOESN'T MATCH FOR AT LINE %s" % line)
2974479Sbinkertn@umich.edu                       return
2984479Sbinkertn@umich.edu                 continue
2994479Sbinkertn@umich.edu            elif op == 'GOSUB':
3004479Sbinkertn@umich.edu                 newline = instr[1]
3014479Sbinkertn@umich.edu                 if self.gosub:
3026498Snate@binkert.org                       print("ALREADY IN A SUBROUTINE AT LINE %s" % line)
3034479Sbinkertn@umich.edu                       return
3044479Sbinkertn@umich.edu                 self.gosub = self.stat[self.pc]
3054479Sbinkertn@umich.edu                 self.goto(newline)
3064479Sbinkertn@umich.edu                 continue
3074479Sbinkertn@umich.edu
3084479Sbinkertn@umich.edu            elif op == 'RETURN':
3094479Sbinkertn@umich.edu                 if not self.gosub:
3106498Snate@binkert.org                      print("RETURN WITHOUT A GOSUB AT LINE %s" % line)
3114479Sbinkertn@umich.edu                      return
3124479Sbinkertn@umich.edu                 self.goto(self.gosub)
3134479Sbinkertn@umich.edu                 self.gosub = None
3144479Sbinkertn@umich.edu
3154479Sbinkertn@umich.edu            elif op == 'FUNC':
3164479Sbinkertn@umich.edu                 fname = instr[1]
3174479Sbinkertn@umich.edu                 pname = instr[2]
3184479Sbinkertn@umich.edu                 expr  = instr[3]
3194479Sbinkertn@umich.edu                 def eval_func(pvalue,name=pname,self=self,expr=expr):
3204479Sbinkertn@umich.edu                      self.assign((pname,None,None),pvalue)
3214479Sbinkertn@umich.edu                      return self.eval(expr)
3224479Sbinkertn@umich.edu                 self.functions[fname] = eval_func
3234479Sbinkertn@umich.edu
3244479Sbinkertn@umich.edu            elif op == 'DIM':
3254479Sbinkertn@umich.edu                 for vname,x,y in instr[1]:
3264479Sbinkertn@umich.edu                     if y == 0:
3274479Sbinkertn@umich.edu                          # Single dimension variable
3284479Sbinkertn@umich.edu                          self.lists[vname] = [0]*x
3294479Sbinkertn@umich.edu                     else:
3304479Sbinkertn@umich.edu                          # Double dimension variable
3314479Sbinkertn@umich.edu                          temp = [0]*y
3324479Sbinkertn@umich.edu                          v = []
3334479Sbinkertn@umich.edu                          for i in range(x):
3344479Sbinkertn@umich.edu                              v.append(temp[:])
3354479Sbinkertn@umich.edu                          self.tables[vname] = v
3364479Sbinkertn@umich.edu
3376498Snate@binkert.org            self.pc += 1
3384479Sbinkertn@umich.edu
3394479Sbinkertn@umich.edu    # Utility functions for program listing
3404479Sbinkertn@umich.edu    def expr_str(self,expr):
3414479Sbinkertn@umich.edu        etype = expr[0]
3424479Sbinkertn@umich.edu        if etype == 'NUM': return str(expr[1])
3434479Sbinkertn@umich.edu        elif etype == 'GROUP': return "(%s)" % self.expr_str(expr[1])
3444479Sbinkertn@umich.edu        elif etype == 'UNARY':
3454479Sbinkertn@umich.edu             if expr[1] == '-': return "-"+str(expr[2])
3464479Sbinkertn@umich.edu        elif etype == 'BINOP':
3474479Sbinkertn@umich.edu             return "%s %s %s" % (self.expr_str(expr[2]),expr[1],self.expr_str(expr[3]))
3484479Sbinkertn@umich.edu        elif etype == 'VAR':
3494479Sbinkertn@umich.edu              return self.var_str(expr[1])
3504479Sbinkertn@umich.edu
3514479Sbinkertn@umich.edu    def relexpr_str(self,expr):
3524479Sbinkertn@umich.edu         return "%s %s %s" % (self.expr_str(expr[2]),expr[1],self.expr_str(expr[3]))
3534479Sbinkertn@umich.edu
3544479Sbinkertn@umich.edu    def var_str(self,var):
3554479Sbinkertn@umich.edu         varname,dim1,dim2 = var
3564479Sbinkertn@umich.edu         if not dim1 and not dim2: return varname
3574479Sbinkertn@umich.edu         if dim1 and not dim2: return "%s(%s)" % (varname, self.expr_str(dim1))
3584479Sbinkertn@umich.edu         return "%s(%s,%s)" % (varname, self.expr_str(dim1),self.expr_str(dim2))
3594479Sbinkertn@umich.edu
3604479Sbinkertn@umich.edu    # Create a program listing
3614479Sbinkertn@umich.edu    def list(self):
3626498Snate@binkert.org         stat = list(self.prog)      # Ordered list of all line numbers
3634479Sbinkertn@umich.edu         stat.sort()
3644479Sbinkertn@umich.edu         for line in stat:
3654479Sbinkertn@umich.edu             instr = self.prog[line]
3664479Sbinkertn@umich.edu             op = instr[0]
3674479Sbinkertn@umich.edu             if op in ['END','STOP','RETURN']:
3686498Snate@binkert.org                   print("%s %s" % (line, op))
3694479Sbinkertn@umich.edu                   continue
3704479Sbinkertn@umich.edu             elif op == 'REM':
3716498Snate@binkert.org                   print("%s %s" % (line, instr[1]))
3724479Sbinkertn@umich.edu             elif op == 'PRINT':
3736498Snate@binkert.org                   _out = "%s %s " % (line, op)
3744479Sbinkertn@umich.edu                   first = 1
3754479Sbinkertn@umich.edu                   for p in instr[1]:
3766498Snate@binkert.org                         if not first: _out += ", "
3776498Snate@binkert.org                         if p[0] and p[1]: _out += '"%s"%s' % (p[0],self.expr_str(p[1]))
3786498Snate@binkert.org                         elif p[1]: _out += self.expr_str(p[1])
3796498Snate@binkert.org                         else: _out += '"%s"' % (p[0],)
3804479Sbinkertn@umich.edu                         first = 0
3816498Snate@binkert.org                   if instr[2]: _out += instr[2]
3826498Snate@binkert.org                   print(_out)
3834479Sbinkertn@umich.edu             elif op == 'LET':
3846498Snate@binkert.org                   print("%s LET %s = %s" % (line,self.var_str(instr[1]),self.expr_str(instr[2])))
3854479Sbinkertn@umich.edu             elif op == 'READ':
3866498Snate@binkert.org                   _out = "%s READ " % line
3874479Sbinkertn@umich.edu                   first = 1
3884479Sbinkertn@umich.edu                   for r in instr[1]:
3896498Snate@binkert.org                         if not first: _out += ","
3906498Snate@binkert.org                         _out += self.var_str(r)
3914479Sbinkertn@umich.edu                         first = 0
3926498Snate@binkert.org                   print(_out)
3934479Sbinkertn@umich.edu             elif op == 'IF':
3946498Snate@binkert.org                   print("%s IF %s THEN %d" % (line,self.relexpr_str(instr[1]),instr[2]))
3954479Sbinkertn@umich.edu             elif op == 'GOTO' or op == 'GOSUB':
3966498Snate@binkert.org                   print("%s %s %s" % (line, op, instr[1]))
3974479Sbinkertn@umich.edu             elif op == 'FOR':
3986498Snate@binkert.org                   _out = "%s FOR %s = %s TO %s" % (line,instr[1],self.expr_str(instr[2]),self.expr_str(instr[3]))
3996498Snate@binkert.org                   if instr[4]: _out += " STEP %s" % (self.expr_str(instr[4]))
4006498Snate@binkert.org                   print(_out)
4014479Sbinkertn@umich.edu             elif op == 'NEXT':
4026498Snate@binkert.org                   print("%s NEXT %s" % (line, instr[1]))
4034479Sbinkertn@umich.edu             elif op == 'FUNC':
4046498Snate@binkert.org                   print("%s DEF %s(%s) = %s" % (line,instr[1],instr[2],self.expr_str(instr[3])))
4054479Sbinkertn@umich.edu             elif op == 'DIM':
4066498Snate@binkert.org                   _out = "%s DIM " % line
4074479Sbinkertn@umich.edu                   first = 1
4084479Sbinkertn@umich.edu                   for vname,x,y in instr[1]:
4096498Snate@binkert.org                         if not first: _out += ","
4104479Sbinkertn@umich.edu                         first = 0
4114479Sbinkertn@umich.edu                         if y == 0:
4126498Snate@binkert.org                               _out += "%s(%d)" % (vname,x)
4134479Sbinkertn@umich.edu                         else:
4146498Snate@binkert.org                               _out += "%s(%d,%d)" % (vname,x,y)
4156498Snate@binkert.org
4166498Snate@binkert.org                   print(_out)
4174479Sbinkertn@umich.edu             elif op == 'DATA':
4186498Snate@binkert.org                   _out = "%s DATA " % line
4194479Sbinkertn@umich.edu                   first = 1
4204479Sbinkertn@umich.edu                   for v in instr[1]:
4216498Snate@binkert.org                        if not first: _out += ","
4224479Sbinkertn@umich.edu                        first = 0
4236498Snate@binkert.org                        _out += v
4246498Snate@binkert.org                   print(_out)
4254479Sbinkertn@umich.edu
4264479Sbinkertn@umich.edu    # Erase the current program
4274479Sbinkertn@umich.edu    def new(self):
4284479Sbinkertn@umich.edu         self.prog = {}
4296498Snate@binkert.org
4304479Sbinkertn@umich.edu    # Insert statements
4314479Sbinkertn@umich.edu    def add_statements(self,prog):
4324479Sbinkertn@umich.edu         for line,stat in prog.items():
4334479Sbinkertn@umich.edu              self.prog[line] = stat
4344479Sbinkertn@umich.edu
4354479Sbinkertn@umich.edu    # Delete a statement
4364479Sbinkertn@umich.edu    def del_line(self,lineno):
4374479Sbinkertn@umich.edu         try:
4384479Sbinkertn@umich.edu             del self.prog[lineno]
4394479Sbinkertn@umich.edu         except KeyError:
4404479Sbinkertn@umich.edu             pass
4414479Sbinkertn@umich.edu
442