mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
fixed ZP merge errors
This commit is contained in:
parent
dd96cd506d
commit
f06721a4ce
@ -33,12 +33,11 @@ class PlyParser:
|
|||||||
self.check_directives(module)
|
self.check_directives(module)
|
||||||
module.scope.define_builtin_functions()
|
module.scope.define_builtin_functions()
|
||||||
self.process_imports(module)
|
self.process_imports(module)
|
||||||
self.check_all_symbolnames(module)
|
|
||||||
self.create_multiassigns(module)
|
|
||||||
self.check_and_merge_zeropages(module)
|
self.check_and_merge_zeropages(module)
|
||||||
self.simplify_some_assignments(module)
|
self.create_multiassigns(module)
|
||||||
if not self.imported_module:
|
if not self.imported_module:
|
||||||
# the following shall only be done on the main module after all imports have been done:
|
# the following shall only be done on the main module after all imports have been done:
|
||||||
|
self.check_all_symbolnames(module)
|
||||||
self.apply_directive_options(module)
|
self.apply_directive_options(module)
|
||||||
self.determine_subroutine_usage(module)
|
self.determine_subroutine_usage(module)
|
||||||
self.all_parents_connected(module)
|
self.all_parents_connected(module)
|
||||||
@ -74,7 +73,10 @@ class PlyParser:
|
|||||||
# check that all parents are connected in all nodes
|
# check that all parents are connected in all nodes
|
||||||
def check(node: AstNode, expected_parent: AstNode) -> None:
|
def check(node: AstNode, expected_parent: AstNode) -> None:
|
||||||
if node.parent is not expected_parent:
|
if node.parent is not expected_parent:
|
||||||
raise CompileError("parent node invalid", node, node.parent, expected_parent, node.sourceref, expected_parent.sourceref)
|
print("\nINTERNAL ERROR: parent node invalid of node", node, node.sourceref)
|
||||||
|
print(" current parent:", node.parent)
|
||||||
|
print(" expected parent:", expected_parent, expected_parent.sourceref)
|
||||||
|
raise CompileError("parent node invalid, see message above")
|
||||||
for child_node in node.nodes:
|
for child_node in node.nodes:
|
||||||
if isinstance(child_node, AstNode):
|
if isinstance(child_node, AstNode):
|
||||||
check(child_node, node)
|
check(child_node, node)
|
||||||
@ -86,14 +88,18 @@ class PlyParser:
|
|||||||
# perform semantic analysis / checks on the syntactic parse tree we have so far
|
# perform semantic analysis / checks on the syntactic parse tree we have so far
|
||||||
# (note: symbol names have already been checked to exist when we start this)
|
# (note: symbol names have already been checked to exist when we start this)
|
||||||
previous_stmt = None
|
previous_stmt = None
|
||||||
|
encountered_block_names = set() # type: Set[str]
|
||||||
encountered_blocks = set() # type: Set[Block]
|
encountered_blocks = set() # type: Set[Block]
|
||||||
for node in module.all_nodes():
|
for node in module.all_nodes():
|
||||||
if isinstance(node, Block):
|
if isinstance(node, Block):
|
||||||
|
if node in encountered_blocks:
|
||||||
|
raise CompileError("parse tree malformed; block duplicated", node, node.name, node.sourceref)
|
||||||
parentname = (node.parent.name + ".") if node.parent else ""
|
parentname = (node.parent.name + ".") if node.parent else ""
|
||||||
blockname = parentname + node.name
|
blockname = parentname + node.name
|
||||||
if blockname in encountered_blocks:
|
if blockname in encountered_block_names:
|
||||||
raise ValueError("block names not unique:", blockname)
|
raise CompileError("block names not unique:", blockname)
|
||||||
encountered_blocks.add(blockname)
|
encountered_block_names.add(blockname)
|
||||||
|
encountered_blocks.add(node)
|
||||||
if isinstance(node, Scope):
|
if isinstance(node, Scope):
|
||||||
if node.nodes and isinstance(node.parent, (Block, Subroutine)):
|
if node.nodes and isinstance(node.parent, (Block, Subroutine)):
|
||||||
if isinstance(node.parent, Block) and node.parent.name != "ZP":
|
if isinstance(node.parent, Block) and node.parent.name != "ZP":
|
||||||
@ -146,26 +152,26 @@ class PlyParser:
|
|||||||
if arg.name != param[0]:
|
if arg.name != param[0]:
|
||||||
raise ParseError("parameter name mismatch", arg.sourceref)
|
raise ParseError("parameter name mismatch", arg.sourceref)
|
||||||
|
|
||||||
|
@no_type_check
|
||||||
def check_and_merge_zeropages(self, module: Module) -> None:
|
def check_and_merge_zeropages(self, module: Module) -> None:
|
||||||
# merge all ZP blocks into one
|
# merge all ZP blocks into one
|
||||||
zeropage = None
|
for zeropage in module.all_nodes(Block):
|
||||||
for block in module.all_nodes(Block):
|
if zeropage.name == "ZP":
|
||||||
if block.name == "ZP": # type: ignore
|
break
|
||||||
if zeropage:
|
else:
|
||||||
# merge other ZP block into first ZP block
|
return
|
||||||
for node in block.scope.nodes:
|
for block in list(module.all_nodes(Block)):
|
||||||
if isinstance(node, Directive):
|
if block is not zeropage and block.name == "ZP":
|
||||||
zeropage.scope.add_node(node, 0)
|
# merge other ZP block into first ZP block
|
||||||
elif isinstance(node, VarDef):
|
for node in block.scope.nodes:
|
||||||
zeropage.scope.add_node(node)
|
if isinstance(node, Directive):
|
||||||
else:
|
zeropage.scope.add_node(node, 0)
|
||||||
raise ParseError("only variables and directives allowed in zeropage block", node.sourceref)
|
elif isinstance(node, VarDef):
|
||||||
else:
|
zeropage.scope.add_node(node)
|
||||||
zeropage = block
|
else:
|
||||||
|
raise ParseError("only variables and directives allowed in zeropage block", node.sourceref)
|
||||||
block.parent.remove_node(block)
|
block.parent.remove_node(block)
|
||||||
if zeropage:
|
block.parent._populate_symboltable(zeropage) # re-add the 'ZP' symbol
|
||||||
# add the zero page again, as the very first block
|
|
||||||
module.scope.add_node(zeropage, 0)
|
|
||||||
|
|
||||||
def allocate_zeropage_vars(self, module: Module) -> None:
|
def allocate_zeropage_vars(self, module: Module) -> None:
|
||||||
# allocate zeropage variables to the available free zp addresses
|
# allocate zeropage variables to the available free zp addresses
|
||||||
@ -188,32 +194,6 @@ class PlyParser:
|
|||||||
for node in module.all_nodes(SymbolName):
|
for node in module.all_nodes(SymbolName):
|
||||||
check_symbol_definition(node.name, node.my_scope(), node.sourceref) # type: ignore
|
check_symbol_definition(node.name, node.my_scope(), node.sourceref) # type: ignore
|
||||||
|
|
||||||
def simplify_some_assignments(self, module: Module) -> None:
|
|
||||||
# simplify some assignment statements,
|
|
||||||
# note taht most of the expression optimization (constant folding etc) is done in the optimizer.
|
|
||||||
for node in module.all_nodes():
|
|
||||||
if isinstance(node, IncrDecr) and node.howmuch not in (0, 1):
|
|
||||||
_, node.howmuch = coerce_constant_value(datatype_of(node.target, node.my_scope()), node.howmuch, node.sourceref)
|
|
||||||
attr.validate(node)
|
|
||||||
elif isinstance(node, VarDef):
|
|
||||||
dtype = DataType.WORD if node.vartype == VarType.MEMORY else node.datatype
|
|
||||||
try:
|
|
||||||
_, node.value = coerce_constant_value(dtype, node.value, node.sourceref) # type: ignore
|
|
||||||
attr.validate(node)
|
|
||||||
except OverflowError as x:
|
|
||||||
raise ParseError(str(x), node.sourceref) from None
|
|
||||||
elif isinstance(node, Assignment):
|
|
||||||
lvalue_types = set(datatype_of(lv, node.my_scope()) for lv in node.left.nodes)
|
|
||||||
if len(lvalue_types) == 1:
|
|
||||||
_, newright = coerce_constant_value(lvalue_types.pop(), node.right, node.sourceref)
|
|
||||||
if isinstance(newright, Expression):
|
|
||||||
node.right = newright # type: ignore
|
|
||||||
else:
|
|
||||||
raise TypeError("invalid coerced constant type", newright)
|
|
||||||
else:
|
|
||||||
for lv_dt in lvalue_types:
|
|
||||||
coerce_constant_value(lv_dt, node.right, node.sourceref)
|
|
||||||
|
|
||||||
@no_type_check
|
@no_type_check
|
||||||
def create_multiassigns(self, module: Module) -> None:
|
def create_multiassigns(self, module: Module) -> None:
|
||||||
# create multi-assign statements from nested assignments (A=B=C=5),
|
# create multi-assign statements from nested assignments (A=B=C=5),
|
||||||
|
@ -30,8 +30,10 @@ class ZpOptions(enum.Enum):
|
|||||||
CLOBBER_RESTORE = "clobber_restore"
|
CLOBBER_RESTORE = "clobber_restore"
|
||||||
|
|
||||||
|
|
||||||
math_functions = {name: func for name, func in vars(math).items() if inspect.isbuiltin(func) and name != "pow"}
|
math_functions = {name: func for name, func in vars(math).items()
|
||||||
builtin_functions = {name: func for name, func in vars(builtins).items() if inspect.isbuiltin(func)}
|
if inspect.isbuiltin(func) and name != "pow" and not name.startswith("_")}
|
||||||
|
builtin_functions = {name: func for name, func in vars(builtins).items()
|
||||||
|
if inspect.isbuiltin(func) and not name.startswith("_")}
|
||||||
|
|
||||||
|
|
||||||
class ParseError(Exception):
|
class ParseError(Exception):
|
||||||
@ -922,6 +924,7 @@ def p_start(p):
|
|||||||
scope.name = "<" + p.lexer.source_filename + " global scope>"
|
scope.name = "<" + p.lexer.source_filename + " global scope>"
|
||||||
p[0] = Module(name=p.lexer.source_filename, sourceref=SourceRef(lexer.source_filename, 1, 1))
|
p[0] = Module(name=p.lexer.source_filename, sourceref=SourceRef(lexer.source_filename, 1, 1))
|
||||||
p[0].nodes.append(scope)
|
p[0].nodes.append(scope)
|
||||||
|
print("CREATED ROOT SCOPE AND MODULE", p[0])
|
||||||
|
|
||||||
|
|
||||||
def p_module(p):
|
def p_module(p):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user