[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'