mirror of
https://github.com/catseye/SixtyPical.git
synced 2025-02-16 15:30:26 +00:00
Allow call
and goto
routines defined further down in the source.
This commit is contained in:
parent
45bc4bd0a0
commit
19dd089a03
@ -1,6 +1,11 @@
|
||||
History of SixtyPical
|
||||
=====================
|
||||
|
||||
0.10
|
||||
----
|
||||
|
||||
* Can `call` and `goto` routines that are defined further down in the source code.
|
||||
|
||||
0.9
|
||||
---
|
||||
|
||||
|
@ -46,11 +46,6 @@ Finish the little demo "game" where you can move a block around the screen with
|
||||
the joystick (i.e. bring it up to par with the original demo game that was written
|
||||
for SixtyPical)
|
||||
|
||||
### `call` routines that are defined further down in the source code
|
||||
|
||||
We might have a graph of states that refer to each other and that want to `goto`
|
||||
each other. Thus we need this. We have it for vectors, but we need it for `call`.
|
||||
|
||||
### Allow branches to diverge in what they touch
|
||||
|
||||
For example, if the routine inputs and outputs `foo`, and one branch of an `if`
|
||||
|
@ -108,7 +108,7 @@ class LocationRef(Ref):
|
||||
def is_constant(self):
|
||||
return isinstance(self.type, RoutineType)
|
||||
|
||||
def backpatch_labels(self, resolver):
|
||||
def backpatch_vector_labels(self, resolver):
|
||||
if isinstance(self.type, ExecutableType):
|
||||
t = self.type
|
||||
t.inputs = set([resolver(w) for w in t.inputs])
|
||||
|
@ -29,6 +29,27 @@ class Parser(object):
|
||||
raise SyntaxError('Undefined symbol "%s"' % name)
|
||||
return self.symbols[name].model
|
||||
|
||||
def backpatch_call_labels(self, block):
|
||||
"""Backpatches labels in call and goto instructions."""
|
||||
if block is None:
|
||||
return
|
||||
for instr in block.instrs:
|
||||
if instr.opcode == 'if':
|
||||
self.backpatch_call_labels(instr.block1)
|
||||
self.backpatch_call_labels(instr.block2)
|
||||
elif instr.opcode == 'repeat':
|
||||
self.backpatch_call_labels(instr.block)
|
||||
elif instr.opcode == 'with-sei':
|
||||
self.backpatch_call_labels(instr.block)
|
||||
elif instr.opcode in ('call', 'goto'):
|
||||
if isinstance(instr.location, basestring):
|
||||
name = instr.location
|
||||
if name not in self.symbols:
|
||||
raise SyntaxError('Undefined routine "%s"' % name)
|
||||
if not isinstance(self.symbols[name].model.type, ExecutableType):
|
||||
raise SyntaxError('Illegal call of non-executable "%s"' % name)
|
||||
instr.location = self.symbols[name].model
|
||||
|
||||
# --- grammar productions
|
||||
|
||||
def program(self):
|
||||
@ -51,9 +72,10 @@ class Parser(object):
|
||||
self.scanner.check_type('EOF')
|
||||
# now backpatch the executable types.
|
||||
for defn in defns:
|
||||
defn.location.backpatch_labels(lambda w: self.lookup(w))
|
||||
defn.location.backpatch_vector_labels(lambda w: self.lookup(w))
|
||||
for routine in routines:
|
||||
routine.location.backpatch_labels(lambda w: self.lookup(w))
|
||||
routine.location.backpatch_vector_labels(lambda w: self.lookup(w))
|
||||
self.backpatch_call_labels(routine.block)
|
||||
return Program(defns=defns, routines=routines)
|
||||
|
||||
def defn(self):
|
||||
@ -265,11 +287,8 @@ class Parser(object):
|
||||
self.scanner.scan()
|
||||
name = self.scanner.token
|
||||
self.scanner.scan()
|
||||
if name not in self.symbols:
|
||||
raise SyntaxError('Undefined routine "%s"' % name)
|
||||
if not isinstance(self.symbols[name].model.type, ExecutableType):
|
||||
raise SyntaxError('Illegal call of non-executable "%s"' % name)
|
||||
return Instr(opcode=opcode, location=self.symbols[name].model, dest=None, src=None)
|
||||
# this will be backpatched
|
||||
return Instr(opcode=opcode, location=name, dest=None, src=None)
|
||||
elif self.scanner.token in ("copy",):
|
||||
opcode = self.scanner.token
|
||||
self.scanner.scan()
|
||||
|
@ -239,6 +239,19 @@ And you can't call a non-routine.
|
||||
| }
|
||||
? SyntaxError
|
||||
|
||||
But you can call a routine that is yet to be defined, further on.
|
||||
|
||||
| routine main {
|
||||
| ld x, 0
|
||||
| ld y, 1
|
||||
| call up
|
||||
| call up
|
||||
| }
|
||||
| routine up {
|
||||
| ld a, 0
|
||||
| }
|
||||
= ok
|
||||
|
||||
Can't define two routines with the same name.
|
||||
|
||||
| routine main {
|
||||
@ -353,6 +366,14 @@ goto.
|
||||
| }
|
||||
= ok
|
||||
|
||||
| routine main {
|
||||
| goto foo
|
||||
| }
|
||||
| routine foo {
|
||||
| ld a, 0
|
||||
| }
|
||||
= ok
|
||||
|
||||
| vector foo
|
||||
|
|
||||
| routine main {
|
||||
|
Loading…
x
Reference in New Issue
Block a user