1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-11-25 23:49:17 +00:00

Resolve forward references more explicitly.

This commit is contained in:
Chris Pressey 2018-09-07 13:20:18 +01:00
parent 5bad7ff576
commit 33d5093e5a
2 changed files with 38 additions and 24 deletions

View File

@ -37,14 +37,16 @@ class AST(object):
def all_children(self): def all_children(self):
for attr in self.children_attrs: for attr in self.children_attrs:
for child in self.attrs[attr]: for child in self.attrs[attr]:
if child is not None:
yield child
for subchild in child.all_children():
yield subchild
for attr in self.child_attrs:
child = self.attrs[attr]
if child is not None:
yield child yield child
for subchild in child.all_children(): for subchild in child.all_children():
yield subchild yield subchild
for attr in self.child_attrs:
child = self.attrs[attr]
yield child
for subchild in child.all_children():
yield subchild
class Program(AST): class Program(AST):

View File

@ -18,6 +18,14 @@ class SymEntry(object):
return "%s(%r, %r)" % (self.__class__.__name__, self.ast_node, self.model) return "%s(%r, %r)" % (self.__class__.__name__, self.ast_node, self.model)
class ForwardReference(object):
def __init__(self, name):
self.name = name
def __repr__(self):
return "%s(%r)" % (self.__class__.__name__, self.name)
class ParsingContext(object): class ParsingContext(object):
def __init__(self): def __init__(self):
self.symbols = {} # token -> SymEntry self.symbols = {} # token -> SymEntry
@ -45,7 +53,6 @@ class Parser(object):
def __init__(self, context, text, filename): def __init__(self, context, text, filename):
self.context = context self.context = context
self.scanner = Scanner(text, filename) self.scanner = Scanner(text, filename)
self.backpatch_instrs = []
def syntax_error(self, msg): def syntax_error(self, msg):
self.scanner.syntax_error(msg) self.scanner.syntax_error(msg)
@ -102,21 +109,28 @@ class Parser(object):
defn.location.type.backpatch_constraint_labels(lambda w: self.lookup(w)) defn.location.type.backpatch_constraint_labels(lambda w: self.lookup(w))
for routine in routines: for routine in routines:
routine.location.type.backpatch_constraint_labels(lambda w: self.lookup(w)) routine.location.type.backpatch_constraint_labels(lambda w: self.lookup(w))
for instr in self.backpatch_instrs:
if instr.opcode in ('call', 'goto'):
name = instr.location
model = self.lookup(name)
if not isinstance(model.type, (RoutineType, VectorType)):
self.syntax_error('Illegal call of non-executable "%s"' % name)
instr.location = model
if instr.opcode in ('copy',) and isinstance(instr.src, str):
name = instr.src
model = self.lookup(name)
if not isinstance(model.type, (RoutineType, VectorType)):
self.syntax_error('Illegal copy of non-executable "%s"' % name)
instr.src = model
return Program(self.scanner.line_number, defns=defns, routines=routines) program = Program(self.scanner.line_number, defns=defns, routines=routines)
for node in program.all_children():
if isinstance(node, SingleOp):
instr = node
if instr.opcode in ('call', 'goto'):
forward_reference = instr.location
name = forward_reference.name
model = self.lookup(name)
if not isinstance(model.type, (RoutineType, VectorType)):
self.syntax_error('Illegal call of non-executable "%s"' % name)
instr.location = model
if instr.opcode in ('copy',) and isinstance(instr.src, ForwardReference):
forward_reference = instr.src
name = forward_reference.name
model = self.lookup(name)
if not isinstance(model.type, (RoutineType, VectorType)):
self.syntax_error('Illegal copy of non-executable "%s"' % name)
instr.src = model
return program
def typedef(self): def typedef(self):
self.scanner.expect('typedef') self.scanner.expect('typedef')
@ -337,7 +351,7 @@ class Parser(object):
if loc is not None: if loc is not None:
return loc return loc
else: else:
return name return ForwardReference(name)
else: else:
loc = self.lookup(self.scanner.token) loc = self.lookup(self.scanner.token)
self.scanner.scan() self.scanner.scan()
@ -452,8 +466,7 @@ class Parser(object):
self.scanner.scan() self.scanner.scan()
name = self.scanner.token name = self.scanner.token
self.scanner.scan() self.scanner.scan()
instr = SingleOp(self.scanner.line_number, opcode=opcode, location=name, dest=None, src=None) instr = SingleOp(self.scanner.line_number, opcode=opcode, location=ForwardReference(name), dest=None, src=None)
self.backpatch_instrs.append(instr)
return instr return instr
elif self.scanner.token in ("copy",): elif self.scanner.token in ("copy",):
opcode = self.scanner.token opcode = self.scanner.token
@ -462,7 +475,6 @@ class Parser(object):
self.scanner.expect(',') self.scanner.expect(',')
dest = self.indlocexpr() dest = self.indlocexpr()
instr = SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=src) instr = SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=src)
self.backpatch_instrs.append(instr)
return instr return instr
elif self.scanner.consume("with"): elif self.scanner.consume("with"):
self.scanner.expect("interrupts") self.scanner.expect("interrupts")