[Python-checkins] python/nondist/sandbox/parrot parrot-gen.py,1.4,1.5

akuchling@users.sourceforge.net akuchling@users.sourceforge.net
Sat, 20 Jul 2002 17:12:08 -0700


Update of /cvsroot/python/python/nondist/sandbox/parrot
In directory usw-pr-cvs1:/tmp/cvs-serv2641

Modified Files:
	parrot-gen.py 
Log Message:
Partial implementation of 'def', 'return', and function calls
Implement some more operators (**, <<, >>, 'and', 'or')
Add -t option to trace generated code when running it
Delete a bunch of visitor methods that will never be implemented because
    compile_expr() will handle them

Parrot 0.0.7 includes an intermediate-code compiler called 'imcc', which will
   take care of  register scheduling, calling conventions, and other annoying
   trivia for you.  My plan is to now rework parrot-gen.py to output
   IMCC-format code, which should make the implementation easier.  Once that's
   running, I'll think about implementing PythonString, PythonInt, &c.
   objects.


Index: parrot-gen.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/parrot/parrot-gen.py,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** parrot-gen.py	20 Jul 2002 11:31:31 -0000	1.4
--- parrot-gen.py	21 Jul 2002 00:12:06 -0000	1.5
***************
*** 9,14 ****
  """
  
- # created 2001/09/21, AMK
- 
  __revision__ = "$Id$"
  
--- 9,12 ----
***************
*** 19,22 ****
--- 17,21 ----
    -r        Run Parrot assembler and interpreter on output
    -S        Only produce assembly source code (.pasm file)
+   -t        Use trace option when running generated code
  """
  
***************
*** 29,38 ****
  # List 31 of the 32 PMC registers as being available
  FREE_REGISTERS = []
! for i in range(1, 32):
      FREE_REGISTERS.append('P' + str(i))
  
- # Global variable: maps local variable names to their assigned register
- LOCAL_REGS = {}
- 
  symcount = 1                            # Counter for symbols
  def gensym ():
--- 28,34 ----
  # List 31 of the 32 PMC registers as being available
  FREE_REGISTERS = []
! for i in range(2, 32):
      FREE_REGISTERS.append('P' + str(i))
  
  symcount = 1                            # Counter for symbols
  def gensym ():
***************
*** 51,62 ****
  
      Attributes:
!       lines : list of strings, each one a line of output.
      """
      
      def __init__ (self):
          self.lines = []
!         self.symcount = 0
          self._last_lineno = None
!         
      def add_line (self, line):
          """add_line(line:string)
--- 47,68 ----
  
      Attributes:
!       lines : [string]
!         A list of strings, each one a line of assembly source code.
!       functions : [string]
!         More lines of assembly source, containing the functions.
      """
      
      def __init__ (self):
          self.lines = []
!         self.functions = []
!         self.symcount = 0               # Current number of symbol
!         self.regcount = 0               # Current number of temp. register
          self._last_lineno = None
! 
!     def next_register (self, type='P'):
!         reg = 'P%i' % self.regcount
!         self.regcount += 1
!         return reg
!     
      def add_line (self, line):
          """add_line(line:string)
***************
*** 88,100 ****
          else:
              return []
          
      # Visitor methods.  Most of them are currently unimplemented.
      def visitAssign (self, node):
          a_name = node.nodes[0].name
!         reg = LOCAL_REGS[a_name]
          lines = (self.set_lineno(node) + 
                   compile_expr(node.expr, reg, FREE_REGISTERS) )
          self.add_lines(lines)
!         # XXX assign result to 'a_name.name'
  
      def visitClass (self, node):
--- 94,108 ----
          else:
              return []
+ 
          
      # Visitor methods.  Most of them are currently unimplemented.
      def visitAssign (self, node):
          a_name = node.nodes[0].name
!         reg = 'P0'#self.next_register()
          lines = (self.set_lineno(node) + 
                   compile_expr(node.expr, reg, FREE_REGISTERS) )
          self.add_lines(lines)
!         self.add_line('store_global %s, "%s"' % (reg, a_name))
!         # XXX assign result to 'a_name'
  
      def visitClass (self, node):
***************
*** 129,134 ****
          self.add_lines(lines)
  
- ##     def visitAnd(self, node):
- ##         assert 0, "not implemented"
  ##     def visitAssAttr(self, node):
  ##         assert 0, "not implemented"
--- 137,140 ----
***************
*** 157,164 ****
  ##     def visitBackquote(self, node):
  ##         assert 0, "not implemented"
- ##     def visitBitand(self, node):
- ##         assert 0, "not implemented"
- ##     def visitBitor(self, node):
- ##         assert 0, "not implemented"
  ##     def visitBitxor(self, node):
  ##         assert 0, "not implemented"
--- 163,166 ----
***************
*** 171,176 ****
  ##     def visitCompare(self, node):
  ##         assert 0, "not implemented"
- ##     def visitConst(self, node):
- ##         assert 0, "not implemented"
  ##     def visitContinue(self, node):
  ##         assert 0, "not implemented"
--- 173,176 ----
***************
*** 193,200 ****
  ##     def visitFrom(self, node):
  ##         assert 0, "not implemented"
! ##     def visitFunction(self, node):
! ##         assert 0, "not implemented"
! ##     def visitFunction(self, node):
! ##         assert 0, "not implemented"
  ##     def visitGetattr(self, node):
  ##         assert 0, "not implemented"
--- 193,210 ----
  ##     def visitFrom(self, node):
  ##         assert 0, "not implemented"
!     def visitFunction(self, node):
!         symbol = gensym()
!         self.add_lines(['set_addr I0, %s' % symbol,
!                         'new P0, .Sub',
!                         'set P0, I0',
!                         'store_global P0, "%s"' % node.name])
!         
!         # Generate code for the function body
!         vtor = visitor.ASTVisitor()
!         pv = ParrotVisitor()
!         vtor.preorder(node.code, pv)
!         self.functions += (['%s:' % symbol] + pv.lines + ['\t' 'ret'] +
!                            pv.functions)
! 
  ##     def visitGetattr(self, node):
  ##         assert 0, "not implemented"
***************
*** 207,212 ****
      def visitImport(self, node):
          assert 0, "not implemented"
- ##     def visitInvert(self, node):
- ##         assert 0, "not implemented"
  ##     def visitKeyword(self, node):
  ##         assert 0, "not implemented"
--- 217,220 ----
***************
*** 215,220 ****
  ##     def visitLambda(self, node):
  ##         assert 0, "not implemented"
- ##     def visitLeftShift(self, node):
- ##         assert 0, "not implemented"
  ##     def visitList(self, node):
  ##         assert 0, "not implemented"
--- 223,226 ----
***************
*** 228,250 ****
  ##         pass
  ##         #assert 0, "not implemented"
- ##     def visitMul(self, node):
- ##         assert 0, "not implemented"
- ##     def visitName(self, node):
- ##         assert 0, "not implemented"
- ##     def visitNot(self, node):
- ##         assert 0, "not implemented"
- ##     def visitOr(self, node):
- ##         assert 0, "not implemented"
      def visitPass(self, node):
          self.add_lines(self.set_lineno(node))
          self.add_lines(["noop"])
- ##     def visitPower(self, node):
- ##         assert 0, "not implemented"
  ##     def visitRaise(self, node):
  ##         assert 0, "not implemented"
! ##     def visitReturn(self, node):
! ##         assert 0, "not implemented"
! ##     def visitRightShift(self, node):
! ##         assert 0, "not implemented"
  ##     def visitSlice(self, node, aug_flag=None):
  ##         assert 0, "not implemented"
--- 234,247 ----
  ##         pass
  ##         #assert 0, "not implemented"
      def visitPass(self, node):
          self.add_lines(self.set_lineno(node))
          self.add_lines(["noop"])
  ##     def visitRaise(self, node):
  ##         assert 0, "not implemented"
!     def visitReturn(self, node):
!         lines = compile_expr(node.value, 'P0', FREE_REGISTERS[:])
!         self.add_lines(lines)
!         # XXX should ensure None is returned here
!         self.add_line('\t' 'ret')
  ##     def visitSlice(self, node, aug_flag=None):
  ##         assert 0, "not implemented"
***************
*** 263,272 ****
  ##     def visitTuple(self, node):
  ##         assert 0, "not implemented"
- ##     def visitUnaryAdd(self, node):
- ##         assert 0, "not implemented"
- ##     def visitUnaryInvert(self, node):
- ##         assert 0, "not implemented"
- ##     def visitUnarySub(self, node):
- ##         assert 0, "not implemented"
  
      def visitWhile(self, node):
--- 260,263 ----
***************
*** 298,301 ****
--- 289,303 ----
      XXX how to handle string constants, or constants of other types?
      """
+     dict_lr = {ast.Add: "add", ast.Sub: "sub",
+             ast.Mul: "mul", ast.Div: "div",
+             ast.Mod: "mod",
+             ast.Power: "pow",
+             ast.RightShift: 'shr', ast.LeftShift: 'shl'}
+     dict_bool = {ast.And: 'and', ast.Or: 'or'}
+ 
+     # XXX Parrot 0.0.7 seems to have a mysterious core-dumping bug
+     # with register P1. 
+     if dest_register == 'P1': raise RuntimeError
+     
      # Copy avail_registers, because we'll be mutating it later
      avail_registers = avail_registers[:]
***************
*** 322,338 ****
  
      elif isinstance(expr, ast.Name):
!         reg = LOCAL_REGS[expr.name]
!         return ["set %s, %s" % (dest_register, reg)]
      
!     elif (isinstance(expr, ast.Add) or
!           isinstance(expr, ast.Sub) or
!           isinstance(expr, ast.Mul) or
!           isinstance(expr, ast.Div) or
!           isinstance(expr, ast.Mod)
!           ):
!         dict = {ast.Add: "add", ast.Sub: "sub",
!                 ast.Mul: "mul", ast.Div: "div",
!                 ast.Mod: "mod"}
!         opcode = dict[expr.__class__]
          temp1 = random.choice(avail_registers)
          avail_registers.remove(temp1)
--- 324,331 ----
  
      elif isinstance(expr, ast.Name):
!         return ['find_global %s, "%s"' % (dest_register, expr.name)]
      
!     elif isinstance(expr, tuple(dict_lr.keys())):
!         opcode = dict_lr[expr.__class__]
          temp1 = random.choice(avail_registers)
          avail_registers.remove(temp1)
***************
*** 346,349 ****
--- 339,355 ----
                  )
  
+     elif isinstance(expr, tuple(dict_bool.keys())):
+         opcode = dict_bool[expr.__class__]
+         temp1 = random.choice(avail_registers)
+         avail_registers.remove(temp1)
+         lines = []
+         lines += compile_expr(expr.nodes[0], dest_register, avail_registers)
+         for n in expr.nodes[1:-1]:
+             lines += compile_expr(n, temp1, avail_registers)
+             lines += ["%s %s, %s, %s" % (opcode, dest_register, dest_register, temp1)]
+         lines += compile_expr(expr.nodes[-1], temp1, avail_registers)
+         lines += ["%s %s, %s, %s" % (opcode, dest_register, dest_register, temp1)]
+         
+ 
      elif isinstance(expr, ast.Compare):
          dict = {'<':'lt', '>':'gt', '==':'eq',
***************
*** 370,373 ****
--- 376,397 ----
                        "%s:" % sym2]
  
+     elif isinstance(expr, ast.CallFunc):
+         assert expr.args == [], 'Arguments not handled'
+         assert expr.star_args is None, '*args not handled'
+         assert expr.dstar_args is None, '**args not handled'
+         temp1 = random.choice(avail_registers)
+         assert isinstance(expr.node, ast.Name), \
+                "can only call functions directly"
+         name = expr.node.name
+         lines = compile_expr(expr.node, temp1, avail_registers)
+         
+         # XXX fix case where dest_register == 'P0'
+         if dest_register != 'P0':
+             lines.append('save P0')
+         lines += ['find_global P0, "%s"' % name,
+                   'call']
+         if dest_register != 'P0':
+             lines += ['add %s, P0, 0' % dest_register, 'restore P0']
+     
      else:
          raise RuntimeError, "Unexpected node in expression: %r" % expr
***************
*** 381,389 ****
  ##    print ast
      
!     # Determine locals and assign them to registers 
!     lnf = walk(ast, LocalNameFinder(), verbose=0)
!     for name in lnf.getLocals().elements():
!         reg = LOCAL_REGS[name] = random.choice(FREE_REGISTERS)
!         FREE_REGISTERS.remove(reg)
  ##    print LOCAL_REGS
      
--- 405,414 ----
  ##    print ast
      
!     # Determine locals and assign them to registers
!     # Disabled -- all variables are global for the moment
! ##    lnf = walk(ast, LocalNameFinder(), verbose=0)
! ##    for name in lnf.getLocals().elements():
! ##        reg = LOCAL_REGS[name] = random.choice(FREE_REGISTERS)
! ##        FREE_REGISTERS.remove(reg)
  ##    print LOCAL_REGS
      
***************
*** 399,417 ****
      # Generate lines of assembly code
      vtor.preorder(ast, pv)
! 
!     pv.add_line('end')
      
      # Write the generated assembly code
!     lines = ["main:\n"] + pv.lines + ["\tend\n"]
      output = open(output_name, 'w')
!     output.writelines(pv.lines)
      output.close()
  
      
  def main():
!     opts, args = getopt.getopt(sys.argv[1:], 'hrS', ['help'])
  
      do_run = 0
      do_assemble = 1
      for opt, param in opts:
          if opt in ['-h', '--help']:
--- 424,442 ----
      # Generate lines of assembly code
      vtor.preorder(ast, pv)
!     pv.add_line('\t' 'end')
      
      # Write the generated assembly code
!     lines = pv.lines + pv.functions
      output = open(output_name, 'w')
!     output.writelines(lines)
      output.close()
  
      
  def main():
!     opts, args = getopt.getopt(sys.argv[1:], 'hrSt', ['help'])
  
      do_run = 0
      do_assemble = 1
+     do_trace = 0
      for opt, param in opts:
          if opt in ['-h', '--help']:
***************
*** 422,425 ****
--- 447,452 ----
          elif opt == '-S':
              do_assemble = 0
+         elif opt == '-t':
+             do_trace = 1
              
      if len(args) != 1:
***************
*** 438,443 ****
              if err: sys.exit(err)
          if do_run:
!             err = os.system('%s/parrot -t %s' % (PARROT_SRC,
!                                                    bytecode_filename))
              if err == 139:
                  print 'Parrot interpreter dumped core'
--- 465,474 ----
              if err: sys.exit(err)
          if do_run:
!             if do_trace: trace_opt = '-t'
!             else: trace_opt = ''
!             cmd_line = '%s/parrot %s %s' % (PARROT_SRC, trace_opt,
!                                             bytecode_filename)
!             print cmd_line
!             err = os.system(cmd_line)
              if err == 139:
                  print 'Parrot interpreter dumped core'