1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/simplify/generator.py Mon Aug 06 00:54:45 2007 +0200
1.3 @@ -0,0 +1,166 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +"""
1.7 +Generate RSVP code from simplified nodes.
1.8 +
1.9 +Copyright (C) 2007 Paul Boddie <paul@boddie.org.uk>
1.10 +
1.11 +This program is free software; you can redistribute it and/or modify it under
1.12 +the terms of the GNU General Public License as published by the Free Software
1.13 +Foundation; either version 3 of the License, or (at your option) any later
1.14 +version.
1.15 +
1.16 +This program is distributed in the hope that it will be useful, but WITHOUT
1.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.19 +details.
1.20 +
1.21 +You should have received a copy of the GNU General Public License along with
1.22 +this program. If not, see <http://www.gnu.org/licenses/>.
1.23 +"""
1.24 +
1.25 +from simplify.simplified import *
1.26 +import rsvp
1.27 +
1.28 +# Classes.
1.29 +
1.30 +class Generator(Visitor):
1.31 +
1.32 + "An RSVP code generator."
1.33 +
1.34 + def __init__(self):
1.35 +
1.36 + "Initialise the visitor."
1.37 +
1.38 + Visitor.__init__(self)
1.39 + self.assemblers = []
1.40 + self.current_assemblers = []
1.41 +
1.42 + # Satisfy visitor issues.
1.43 +
1.44 + self.visitor = self
1.45 +
1.46 + def get_code(self):
1.47 + return rsvp.get_image(*self.assemblers)
1.48 +
1.49 + def assembler(self):
1.50 + return self.current_assemblers[-1]
1.51 +
1.52 + def process(self, module):
1.53 +
1.54 + """
1.55 + Process the given 'module', creating RSVP assemblers to store code and
1.56 + data.
1.57 + """
1.58 +
1.59 + self.module = module
1.60 +
1.61 + main = rsvp.RSVPAssembler(1)
1.62 + self.current_assemblers.append(main)
1.63 +
1.64 + # Store constants.
1.65 +
1.66 + for name, const in module.simplifier.constants.items():
1.67 + main.label("const$%s$%s" % (self.module.name, name))
1.68 + main.add(const.value)
1.69 +
1.70 + # Reserve the namespace.
1.71 +
1.72 + for name in module.namespace.keys():
1.73 + main.label("global$%s$%s" % (self.module.name, name))
1.74 + main.add(None)
1.75 +
1.76 + # Generate subprograms.
1.77 +
1.78 + for subprogram in module.simplifier.subprograms:
1.79 + if not subprogram.internal:
1.80 +
1.81 + # Generate specific subprograms.
1.82 +
1.83 + for specialisation in subprogram.specialisations():
1.84 + self.process_subprogram(specialisation)
1.85 +
1.86 + # Generate the initialisation.
1.87 +
1.88 + self.dispatch(module)
1.89 +
1.90 + # Remember the assembler used.
1.91 +
1.92 + self.current_assemblers.pop()
1.93 + self.assemblers.append(main)
1.94 +
1.95 + def default(self, node, *args):
1.96 + if hasattr(node, "code"):
1.97 + self.dispatches(node.code)
1.98 +
1.99 + def visitInvoke(self, invoke):
1.100 +
1.101 + "Process the given 'invoke' node."
1.102 +
1.103 + sub = self.assembler()
1.104 +
1.105 + # NOTE: Generate arguments in a way compatible with subprogram
1.106 + # NOTE: consumption as parameters.
1.107 +
1.108 + for subprogram in invoke.invocations:
1.109 +
1.110 + # NOTE: Generate switch table.
1.111 +
1.112 + # Reserve the namespace.
1.113 +
1.114 + params = subprogram.paramtypes.keys()
1.115 + nparams = len(params)
1.116 + if not invoke.share_locals:
1.117 + sub.add("NSF", nparams)
1.118 +
1.119 + sub.add("JAS", subprogram.full_name())
1.120 +
1.121 + if not invoke.share_locals:
1.122 + sub.add("PSF") # previous stack frame
1.123 +
1.124 + visitInvokeFunction = visitInvoke
1.125 + visitInvokeRef = visitInvoke
1.126 +
1.127 + def visitModule(self, module):
1.128 +
1.129 + "Process the given 'module'."
1.130 +
1.131 + self.dispatches(module.code)
1.132 +
1.133 + def visitSubprogram(self, subprogram):
1.134 +
1.135 + "Process the 'subprogram'."
1.136 +
1.137 + if subprogram.internal:
1.138 + self.process_subprogram(subprogram)
1.139 +
1.140 + def process_subprogram(self, subprogram):
1.141 +
1.142 + sub = rsvp.RSVPAssembler(1)
1.143 + self.current_assemblers.append(sub)
1.144 +
1.145 + sub.label("sub$%s$%s" % (self.module.name, subprogram.full_name()))
1.146 +
1.147 + locals = subprogram.namespace.keys()
1.148 + params = subprogram.paramtypes.keys()
1.149 + nparams = len(params)
1.150 + non_params = len(locals) - nparams
1.151 +
1.152 + if non_params > 0:
1.153 + sub.add("ESF", non_params) # extend stack frame for locals
1.154 +
1.155 + # Produce the standard end of subprogram return.
1.156 +
1.157 + sub.add("RAC") # return
1.158 +
1.159 + self.current_assemblers.pop()
1.160 + self.assemblers.append(sub)
1.161 +
1.162 +# Convenience functions.
1.163 +
1.164 +def generate(module):
1.165 + generator = Generator()
1.166 + generator.process(module)
1.167 + return generator.get_code()
1.168 +
1.169 +# vim: tabstop=4 expandtab shiftwidth=4