git @ Cat's Eye Technologies SixtyPical / 7a3b52d
More correct determination of tail position for purposes of `goto`. Chris Pressey 4 years ago
3 changed file(s) with 47 addition(s) and 7 deletion(s). Raw diff Collapse all Expand all
44 ----
55
66 * `--origin` and `--output-format` options added to reference compiler.
7 * "Tail position" is now more correctly determined for the purposes of
8 insisting that `goto` only appears in it.
79 * Fixed bug when `--prelude` option was missing.
810 * Fixed bug when reporting line numbers of scanner-level syntax errors.
911
100100 self._touched = set()
101101 self._range = dict()
102102 self._writeable = set()
103 self._has_encountered_goto = False
103104
104105 for ref in inputs:
105106 if ref.is_constant():
242243 for ref in refs:
243244 self._writeable.remove(ref)
244245
246 def set_encountered_goto(self):
247 self._has_encountered_goto = True
248
249 def has_encountered_goto(self):
250 return self._has_encountered_goto
251
245252
246253 class Analyzer(object):
247254
248255 def __init__(self, debug=False):
249256 self.current_routine = None
250 self.has_encountered_goto = False
251257 self.routines = {}
252258 self.debug = debug
253259
280286 def analyze_routine(self, routine):
281287 assert isinstance(routine, Routine)
282288 self.current_routine = routine
283 self.has_encountered_goto = False
284289 if routine.block is None:
285290 # it's an extern, that's fine
286291 return
311316 if ref in type_.outputs:
312317 raise UnmeaningfulOutputError(routine, ref.name)
313318
314 if not self.has_encountered_goto:
319 if not context.has_encountered_goto():
315320 for ref in type_.outputs:
316321 context.assert_meaningful(ref, exception_class=UnmeaningfulOutputError)
317322 for ref in context.each_touched():
322327 def analyze_block(self, block, context):
323328 assert isinstance(block, Block)
324329 for i in block.instrs:
325 if self.has_encountered_goto:
326 raise IllegalJumpError(i, i)
327330 self.analyze_instr(i, context)
328331
329332 def analyze_instr(self, instr, context):
345348 opcode = instr.opcode
346349 dest = instr.dest
347350 src = instr.src
348
351
352 if context.has_encountered_goto():
353 raise IllegalJumpError(instr, instr)
354
349355 if opcode == 'ld':
350356 if isinstance(src, IndexedRef):
351357 if TableType.is_a_table_type(src.ref.type, TYPE_BYTE) and dest.type == TYPE_BYTE:
559565 self.assert_affected_within('outputs', type_, current_type)
560566 self.assert_affected_within('trashes', type_, current_type)
561567
562 self.has_encountered_goto = True
568 context.set_encountered_goto()
563569 elif opcode == 'trash':
564570 context.set_touched(instr.dest)
565571 context.set_unmeaningful(instr.dest)
600606 context._touched = set(context1._touched) | set(context2._touched)
601607 context.set_meaningful(*list(outgoing_meaningful))
602608 context._writeable = set(context1._writeable) | set(context2._writeable)
609 if context1.has_encountered_goto() or context2.has_encountered_goto():
610 context.set_encountered_goto()
603611
604612 for ref in outgoing_trashes:
605613 context.set_touched(ref)
22462246 | }
22472247 = ok
22482248
2249 | routine bar trashes x, z, n {
2250 | ld x, 200
2251 | }
2252 |
2253 | routine main trashes x, z, n {
2254 | ld x, 0
2255 | if z {
2256 | ld x, 1
2257 | goto bar
2258 | } else {
2259 | ld x, 0
2260 | }
2261 | }
2262 = ok
2263
2264 For the purposes of `goto`, the end of a loop is never tail position.
2265
2266 | routine bar trashes x, z, n {
2267 | ld x, 200
2268 | }
2269 |
2270 | routine main trashes x, z, n {
2271 | ld x, 0
2272 | repeat {
2273 | inc x
2274 | goto bar
2275 | } until z
2276 | }
2277 ? IllegalJumpError
2278
22492279 Can't `goto` a routine that outputs or trashes more than the current routine.
22502280
22512281 | routine bar trashes x, y, z, n {