1.1 --- a/translator.py Fri Jan 20 17:39:52 2017 +0100
1.2 +++ b/translator.py Fri Jan 20 18:39:33 2017 +0100
1.3 @@ -3,7 +3,7 @@
1.4 """
1.5 Translate programs.
1.6
1.7 -Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
1.8 +Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
1.9
1.10 This program is free software; you can redistribute it and/or modify it under
1.11 the terms of the GNU General Public License as published by the Free Software
1.12 @@ -29,6 +29,7 @@
1.13 from os.path import exists, join
1.14 from os import makedirs
1.15 from referencing import Reference
1.16 +from StringIO import StringIO
1.17 import compiler
1.18 import results
1.19
1.20 @@ -41,6 +42,7 @@
1.21 self.deducer = deducer
1.22 self.optimiser = optimiser
1.23 self.output = output
1.24 + self.modules = {}
1.25
1.26 def to_output(self):
1.27 output = join(self.output, "src")
1.28 @@ -55,6 +57,7 @@
1.29 if parts[0] != "native":
1.30 tm = TranslatedModule(module.name, self.importer, self.deducer, self.optimiser)
1.31 tm.translate(module.filename, join(output, "%s.c" % module.name))
1.32 + self.modules[module.name] = tm
1.33
1.34 # Classes representing intermediate translation results.
1.35
1.36 @@ -267,7 +270,7 @@
1.37
1.38 # Output stream.
1.39
1.40 - self.out = None
1.41 + self.out_toplevel = self.out = None
1.42 self.indent = 0
1.43 self.tabstop = " "
1.44
1.45 @@ -286,6 +289,10 @@
1.46 self.attr_accesses = {}
1.47 self.attr_accessors = {}
1.48
1.49 + # Special variable usage.
1.50 +
1.51 + self.temp_usage = {}
1.52 +
1.53 def __repr__(self):
1.54 return "TranslatedModule(%r, %r)" % (self.name, self.importer)
1.55
1.56 @@ -307,7 +314,7 @@
1.57
1.58 self.reset_lambdas()
1.59
1.60 - self.out = open(output_filename, "w")
1.61 + self.out_toplevel = self.out = open(output_filename, "w")
1.62 try:
1.63 self.start_output()
1.64
1.65 @@ -696,15 +703,42 @@
1.66 subs = {
1.67 "<expr>" : str(attr_expr),
1.68 "<assexpr>" : str(self.in_assignment),
1.69 + }
1.70 +
1.71 + temp_subs = {
1.72 "<context>" : "__tmp_context",
1.73 "<accessor>" : "__tmp_value",
1.74 "<target_accessor>" : "__tmp_target_value",
1.75 + "<set_accessor>" : "__tmp_value",
1.76 + "<set_target_accessor>" : "__tmp_target_value",
1.77 }
1.78
1.79 + op_subs = {
1.80 + "<set_accessor>" : "__set_accessor",
1.81 + "<set_target_accessor>" : "__set_target_accessor",
1.82 + }
1.83 +
1.84 + subs.update(temp_subs)
1.85 + subs.update(op_subs)
1.86 +
1.87 output = []
1.88 + substituted = set()
1.89 +
1.90 + # Obtain encoded versions of each instruction, accumulating temporary
1.91 + # variables.
1.92
1.93 for instruction in self.optimiser.access_instructions[location]:
1.94 - output.append(encode_access_instruction(instruction, subs))
1.95 + encoded, _substituted = encode_access_instruction(instruction, subs)
1.96 + output.append(encoded)
1.97 + substituted.update(_substituted)
1.98 +
1.99 + # Record temporary name usage.
1.100 +
1.101 + for sub in substituted:
1.102 + if temp_subs.has_key(sub):
1.103 + self.record_temp(temp_subs[sub])
1.104 +
1.105 + # Format the output.
1.106
1.107 if len(output) == 1:
1.108 out = output[0]
1.109 @@ -1146,6 +1180,7 @@
1.110 # set to null.
1.111
1.112 if context_required:
1.113 + self.record_temp("__tmp_targets")
1.114 args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target]
1.115 else:
1.116 args = ["__NULL"]
1.117 @@ -1240,6 +1275,7 @@
1.118 # Without a known specific callable, the expression provides the target.
1.119
1.120 if not target or context_required:
1.121 + self.record_temp("__tmp_targets")
1.122 stages.append("__tmp_targets[%d] = %s" % (self.function_target, expr))
1.123
1.124 # Any specific callable is then obtained.
1.125 @@ -1247,6 +1283,7 @@
1.126 if target:
1.127 stages.append(target)
1.128 elif function:
1.129 + self.record_temp("__tmp_targets")
1.130 stages.append("__load_via_object(__tmp_targets[%d].value, %s).fn" % (
1.131 self.function_target, encode_symbol("pos", "__fn__")))
1.132
1.133 @@ -1259,6 +1296,7 @@
1.134 # the callable and argument collections.
1.135
1.136 else:
1.137 + self.record_temp("__tmp_targets")
1.138 output = "(%s, __invoke(\n__tmp_targets[%d],\n%d, %d, %s, %s,\n%d, %s\n))" % (
1.139 ",\n".join(stages),
1.140 self.function_target,
1.141 @@ -1312,6 +1350,7 @@
1.142 # copy.
1.143
1.144 else:
1.145 + self.record_temp("__tmp_value")
1.146 return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, (__attr) {.context=0, .value=__tmp_value})" % (
1.147 encode_path(function_name),
1.148 encode_symbol("obj", function_name),
1.149 @@ -1331,6 +1370,8 @@
1.150 (__tmp_result = <a>, __BOOL(__tmp_result)) ? __tmp_result : <b>
1.151 """
1.152
1.153 + self.record_temp("__tmp_result")
1.154 +
1.155 if isinstance(n, compiler.ast.And):
1.156 op = "!"
1.157 else:
1.158 @@ -1638,6 +1679,35 @@
1.159 self.indent -= 1
1.160 self.writeline("}")
1.161
1.162 + # Special variable usage.
1.163 +
1.164 + def record_temp(self, name):
1.165 +
1.166 + """
1.167 + Record the use of the temporary 'name' in the current namespace. At the
1.168 + class or module level, the temporary name is associated with the module,
1.169 + since the variable will then be allocated in the module's own main
1.170 + program.
1.171 + """
1.172 +
1.173 + if self.in_function:
1.174 + path = self.get_namespace_path()
1.175 + else:
1.176 + path = self.name
1.177 +
1.178 + init_item(self.temp_usage, path, set)
1.179 + self.temp_usage[path].add(name)
1.180 +
1.181 + def uses_temp(self, path, name):
1.182 +
1.183 + """
1.184 + Return whether the given namespace 'path' employs a temporary variable
1.185 + with the given 'name'. Note that 'path' should only be a module or a
1.186 + function or method, not a class.
1.187 + """
1.188 +
1.189 + return self.temp_usage.has_key(path) and name in self.temp_usage[path]
1.190 +
1.191 # Output generation.
1.192
1.193 def start_output(self):
1.194 @@ -1654,6 +1724,28 @@
1.195 #include "main.h"
1.196 """
1.197
1.198 + def start_unit(self):
1.199 +
1.200 + "Record output within a generated function for later use."
1.201 +
1.202 + self.out = StringIO()
1.203 +
1.204 + def end_unit(self, name):
1.205 +
1.206 + "Add declarations and generated code."
1.207 +
1.208 + # Restore the output stream.
1.209 +
1.210 + out = self.out
1.211 + self.out = self.out_toplevel
1.212 +
1.213 + self.write_temporaries(name)
1.214 + out.seek(0)
1.215 + self.out.write(out.read())
1.216 +
1.217 + self.indent -= 1
1.218 + print >>self.out, "}"
1.219 +
1.220 def start_module(self):
1.221
1.222 "Write the start of each module's main function."
1.223 @@ -1661,14 +1753,13 @@
1.224 print >>self.out, "void __main_%s()" % encode_path(self.name)
1.225 print >>self.out, "{"
1.226 self.indent += 1
1.227 - self.write_temporaries(self.importer.function_targets.get(self.name))
1.228 + self.start_unit()
1.229
1.230 def end_module(self):
1.231
1.232 "End each module by closing its main function."
1.233
1.234 - self.indent -= 1
1.235 - print >>self.out, "}"
1.236 + self.end_unit(self.name)
1.237
1.238 def start_function(self, name):
1.239
1.240 @@ -1677,7 +1768,6 @@
1.241 print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name)
1.242 print >>self.out, "{"
1.243 self.indent += 1
1.244 - self.write_temporaries(self.importer.function_targets.get(name))
1.245
1.246 # Obtain local names from parameters.
1.247
1.248 @@ -1702,29 +1792,39 @@
1.249 self.writeline("__attr %s;" % ", ".join(names))
1.250
1.251 self.write_parameters(name)
1.252 + self.start_unit()
1.253
1.254 def end_function(self, name):
1.255
1.256 "End the function having the given 'name'."
1.257
1.258 - self.indent -= 1
1.259 - print >>self.out, "}"
1.260 + self.end_unit(name)
1.261 print >>self.out
1.262
1.263 - def write_temporaries(self, targets):
1.264 -
1.265 - """
1.266 - Write temporary storage employed by functions, providing space for the
1.267 - given number of 'targets'.
1.268 - """
1.269 -
1.270 - targets = targets is not None and "__tmp_targets[%d], " % targets or ""
1.271 -
1.272 - self.writeline("__ref __tmp_context, __tmp_value, __tmp_target_value;")
1.273 - self.writeline("__attr %s__tmp_result;" % targets)
1.274 + def write_temporaries(self, name):
1.275 +
1.276 + "Write temporary storage employed by 'name'."
1.277 +
1.278 + # Provide space for the given number of targets.
1.279 +
1.280 + if self.uses_temp(name, "__tmp_targets"):
1.281 + targets = self.importer.function_targets.get(name)
1.282 + self.writeline("__attr __tmp_targets[%d];" % targets)
1.283 +
1.284 + # Add temporary variable usage details.
1.285 +
1.286 + if self.uses_temp(name, "__tmp_context"):
1.287 + self.writeline("__ref __tmp_context;")
1.288 + if self.uses_temp(name, "__tmp_value"):
1.289 + self.writeline("__ref __tmp_value;")
1.290 + if self.uses_temp(name, "__tmp_target_value"):
1.291 + self.writeline("__ref __tmp_target_value;")
1.292 + if self.uses_temp(name, "__tmp_result"):
1.293 + self.writeline("__attr __tmp_result;")
1.294
1.295 module = self.importer.get_module(self.name)
1.296 - if self.get_namespace_path() in module.exception_namespaces:
1.297 +
1.298 + if name in module.exception_namespaces:
1.299 self.writeline("__exc __tmp_exc;")
1.300
1.301 def write_parameters(self, name):