mirror of
https://github.com/catseye/SixtyPical.git
synced 2025-02-08 10:30:55 +00:00
Change how backpatching instructions is implemented.
This commit is contained in:
parent
19dd089a03
commit
dbbd99ffe5
@ -46,6 +46,11 @@ 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)
|
||||
|
||||
### `copy` (to vectors) 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 other things.
|
||||
|
||||
### Allow branches to diverge in what they touch
|
||||
|
||||
For example, if the routine inputs and outputs `foo`, and one branch of an `if`
|
||||
|
@ -23,33 +23,13 @@ class Parser(object):
|
||||
self.symbols[token] = SymEntry(None, LocationRef(TYPE_BYTE, token))
|
||||
for token in ('c', 'z', 'n', 'v'):
|
||||
self.symbols[token] = SymEntry(None, LocationRef(TYPE_BIT, token))
|
||||
self.backpatch_instrs = []
|
||||
|
||||
def lookup(self, name):
|
||||
if name not in self.symbols:
|
||||
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):
|
||||
@ -70,12 +50,21 @@ class Parser(object):
|
||||
self.symbols[name] = SymEntry(routine, routine.location)
|
||||
routines.append(routine)
|
||||
self.scanner.check_type('EOF')
|
||||
|
||||
# now backpatch the executable types.
|
||||
for defn in defns:
|
||||
defn.location.backpatch_vector_labels(lambda w: self.lookup(w))
|
||||
for routine in routines:
|
||||
routine.location.backpatch_vector_labels(lambda w: self.lookup(w))
|
||||
self.backpatch_call_labels(routine.block)
|
||||
for instr in self.backpatch_instrs:
|
||||
if instr.opcode in ('call', 'goto'):
|
||||
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
|
||||
|
||||
return Program(defns=defns, routines=routines)
|
||||
|
||||
def defn(self):
|
||||
@ -287,8 +276,9 @@ class Parser(object):
|
||||
self.scanner.scan()
|
||||
name = self.scanner.token
|
||||
self.scanner.scan()
|
||||
# this will be backpatched
|
||||
return Instr(opcode=opcode, location=name, dest=None, src=None)
|
||||
instr = Instr(opcode=opcode, location=name, dest=None, src=None)
|
||||
self.backpatch_instrs.append(instr)
|
||||
return instr
|
||||
elif self.scanner.token in ("copy",):
|
||||
opcode = self.scanner.token
|
||||
self.scanner.scan()
|
||||
|
Loading…
x
Reference in New Issue
Block a user