mirror of
https://github.com/catseye/SixtyPical.git
synced 2025-08-10 06:24:56 +00:00
Change how backpatching instructions is implemented.
This commit is contained in:
@@ -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
|
the joystick (i.e. bring it up to par with the original demo game that was written
|
||||||
for SixtyPical)
|
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
|
### Allow branches to diverge in what they touch
|
||||||
|
|
||||||
For example, if the routine inputs and outputs `foo`, and one branch of an `if`
|
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))
|
self.symbols[token] = SymEntry(None, LocationRef(TYPE_BYTE, token))
|
||||||
for token in ('c', 'z', 'n', 'v'):
|
for token in ('c', 'z', 'n', 'v'):
|
||||||
self.symbols[token] = SymEntry(None, LocationRef(TYPE_BIT, token))
|
self.symbols[token] = SymEntry(None, LocationRef(TYPE_BIT, token))
|
||||||
|
self.backpatch_instrs = []
|
||||||
|
|
||||||
def lookup(self, name):
|
def lookup(self, name):
|
||||||
if name not in self.symbols:
|
if name not in self.symbols:
|
||||||
raise SyntaxError('Undefined symbol "%s"' % name)
|
raise SyntaxError('Undefined symbol "%s"' % name)
|
||||||
return self.symbols[name].model
|
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
|
# --- grammar productions
|
||||||
|
|
||||||
def program(self):
|
def program(self):
|
||||||
@@ -70,12 +50,21 @@ class Parser(object):
|
|||||||
self.symbols[name] = SymEntry(routine, routine.location)
|
self.symbols[name] = SymEntry(routine, routine.location)
|
||||||
routines.append(routine)
|
routines.append(routine)
|
||||||
self.scanner.check_type('EOF')
|
self.scanner.check_type('EOF')
|
||||||
|
|
||||||
# now backpatch the executable types.
|
# now backpatch the executable types.
|
||||||
for defn in defns:
|
for defn in defns:
|
||||||
defn.location.backpatch_vector_labels(lambda w: self.lookup(w))
|
defn.location.backpatch_vector_labels(lambda w: self.lookup(w))
|
||||||
for routine in routines:
|
for routine in routines:
|
||||||
routine.location.backpatch_vector_labels(lambda w: self.lookup(w))
|
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)
|
return Program(defns=defns, routines=routines)
|
||||||
|
|
||||||
def defn(self):
|
def defn(self):
|
||||||
@@ -287,8 +276,9 @@ class Parser(object):
|
|||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
name = self.scanner.token
|
name = self.scanner.token
|
||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
# this will be backpatched
|
instr = Instr(opcode=opcode, location=name, dest=None, src=None)
|
||||||
return Instr(opcode=opcode, location=name, dest=None, src=None)
|
self.backpatch_instrs.append(instr)
|
||||||
|
return instr
|
||||||
elif self.scanner.token in ("copy",):
|
elif self.scanner.token in ("copy",):
|
||||||
opcode = self.scanner.token
|
opcode = self.scanner.token
|
||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
|
Reference in New Issue
Block a user