1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-06-14 23:29:29 +00:00

More correct determination of tail position for purposes of goto.

This commit is contained in:
Chris Pressey 2018-03-13 17:00:49 +00:00
parent 5f62de11c2
commit 7a3b52dc1e
3 changed files with 47 additions and 7 deletions

View File

@ -5,6 +5,8 @@ History of SixtyPical
----
* `--origin` and `--output-format` options added to reference compiler.
* "Tail position" is now more correctly determined for the purposes of
insisting that `goto` only appears in it.
* Fixed bug when `--prelude` option was missing.
* Fixed bug when reporting line numbers of scanner-level syntax errors.

View File

@ -101,6 +101,7 @@ class Context(object):
self._touched = set()
self._range = dict()
self._writeable = set()
self._has_encountered_goto = False
for ref in inputs:
if ref.is_constant():
@ -243,12 +244,17 @@ class Context(object):
for ref in refs:
self._writeable.remove(ref)
def set_encountered_goto(self):
self._has_encountered_goto = True
def has_encountered_goto(self):
return self._has_encountered_goto
class Analyzer(object):
def __init__(self, debug=False):
self.current_routine = None
self.has_encountered_goto = False
self.routines = {}
self.debug = debug
@ -281,7 +287,6 @@ class Analyzer(object):
def analyze_routine(self, routine):
assert isinstance(routine, Routine)
self.current_routine = routine
self.has_encountered_goto = False
if routine.block is None:
# it's an extern, that's fine
return
@ -312,7 +317,7 @@ class Analyzer(object):
if ref in type_.outputs:
raise UnmeaningfulOutputError(routine, ref.name)
if not self.has_encountered_goto:
if not context.has_encountered_goto():
for ref in type_.outputs:
context.assert_meaningful(ref, exception_class=UnmeaningfulOutputError)
for ref in context.each_touched():
@ -323,8 +328,6 @@ class Analyzer(object):
def analyze_block(self, block, context):
assert isinstance(block, Block)
for i in block.instrs:
if self.has_encountered_goto:
raise IllegalJumpError(i, i)
self.analyze_instr(i, context)
def analyze_instr(self, instr, context):
@ -346,7 +349,10 @@ class Analyzer(object):
opcode = instr.opcode
dest = instr.dest
src = instr.src
if context.has_encountered_goto():
raise IllegalJumpError(instr, instr)
if opcode == 'ld':
if isinstance(src, IndexedRef):
if TableType.is_a_table_type(src.ref.type, TYPE_BYTE) and dest.type == TYPE_BYTE:
@ -560,7 +566,7 @@ class Analyzer(object):
self.assert_affected_within('outputs', type_, current_type)
self.assert_affected_within('trashes', type_, current_type)
self.has_encountered_goto = True
context.set_encountered_goto()
elif opcode == 'trash':
context.set_touched(instr.dest)
context.set_unmeaningful(instr.dest)
@ -601,6 +607,8 @@ class Analyzer(object):
context._touched = set(context1._touched) | set(context2._touched)
context.set_meaningful(*list(outgoing_meaningful))
context._writeable = set(context1._writeable) | set(context2._writeable)
if context1.has_encountered_goto() or context2.has_encountered_goto():
context.set_encountered_goto()
for ref in outgoing_trashes:
context.set_touched(ref)

View File

@ -2247,6 +2247,36 @@ Calling the vector does indeed trash the things the vector says it does.
| }
= ok
| routine bar trashes x, z, n {
| ld x, 200
| }
|
| routine main trashes x, z, n {
| ld x, 0
| if z {
| ld x, 1
| goto bar
| } else {
| ld x, 0
| }
| }
= ok
For the purposes of `goto`, the end of a loop is never tail position.
| routine bar trashes x, z, n {
| ld x, 200
| }
|
| routine main trashes x, z, n {
| ld x, 0
| repeat {
| inc x
| goto bar
| } until z
| }
? IllegalJumpError
Can't `goto` a routine that outputs or trashes more than the current routine.
| routine bar trashes x, y, z, n {