mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
symbol table fixes
This commit is contained in:
parent
614f90fc35
commit
e6804b2bf9
@ -31,12 +31,12 @@ class PlyParser:
|
||||
self.check_directives(module)
|
||||
self.process_imports(module)
|
||||
self.create_multiassigns(module)
|
||||
self.check_and_merge_zeropages(module)
|
||||
self.process_all_expressions(module)
|
||||
if not self.parsing_import:
|
||||
# these shall only be done on the main module after all imports have been done:
|
||||
self.apply_directive_options(module)
|
||||
self.determine_subroutine_usage(module)
|
||||
self.check_and_merge_zeropages(module)
|
||||
except ParseError as x:
|
||||
self.handle_parse_error(x)
|
||||
if self.parse_errors:
|
||||
@ -60,6 +60,7 @@ class PlyParser:
|
||||
zeropage.scope.add_node(node, 0)
|
||||
elif isinstance(node, VarDef):
|
||||
zeropage.scope.add_node(node)
|
||||
print("ADDED ZP VAR", node) # XXX
|
||||
else:
|
||||
raise ParseError("only variables and directives allowed in zeropage block", node.sourceref)
|
||||
else:
|
||||
@ -72,7 +73,11 @@ class PlyParser:
|
||||
@no_type_check
|
||||
def process_all_expressions(self, module: Module) -> None:
|
||||
# process/simplify all expressions (constant folding etc)
|
||||
encountered_blocks = set()
|
||||
for block, parent in module.all_scopes():
|
||||
if block.name in encountered_blocks:
|
||||
raise ValueError("block names not unique:", block.name)
|
||||
encountered_blocks.add(block.name)
|
||||
for node in block.nodes:
|
||||
try:
|
||||
node.process_expressions(block.scope)
|
||||
@ -266,7 +271,7 @@ class PlyParser:
|
||||
if len(splits) == 2:
|
||||
for match in re.finditer(r"(?P<symbol>[a-zA-Z_$][a-zA-Z0-9_\.]+)", splits[1]):
|
||||
name = match.group("symbol")
|
||||
if name[0] == '$':
|
||||
if name[0] == '$' or "." not in name:
|
||||
continue
|
||||
try:
|
||||
symbol = parent_scope[name]
|
||||
@ -274,7 +279,8 @@ class PlyParser:
|
||||
pass
|
||||
else:
|
||||
if isinstance(symbol, Subroutine):
|
||||
usages[(parent_scope.name, symbol.name)].add(str(asmnode.sourceref))
|
||||
namespace, name = name.rsplit(".", maxsplit=2)
|
||||
usages[(namespace, name)].add(str(asmnode.sourceref))
|
||||
|
||||
def check_directives(self, module: Module) -> None:
|
||||
for node, parent in module.all_scopes():
|
||||
@ -329,7 +335,7 @@ class PlyParser:
|
||||
# append the imported module's contents (blocks) at the end of the current module
|
||||
for imported_module in imported:
|
||||
for block in imported_module.scope.filter_nodes(Block):
|
||||
module.scope.nodes.append(block)
|
||||
module.scope.add_node(block)
|
||||
|
||||
def import_file(self, filename: str) -> Tuple[Module, int]:
|
||||
sub_parser = PlyParser(parsing_import=True)
|
||||
|
@ -127,6 +127,7 @@ class AssemblyGenerator:
|
||||
self.p("{:s}\t.proc\n".format(zpblock.label))
|
||||
self.generate_block_init(zpblock)
|
||||
self.generate_block_vars(zpblock)
|
||||
# there's no code in the zero page block.
|
||||
self.p("\v.pend\n")
|
||||
for block in sorted(self.module.scope.filter_nodes(Block), key=lambda b: b.address or 0):
|
||||
if block.name == "ZP":
|
||||
@ -149,8 +150,8 @@ class AssemblyGenerator:
|
||||
self.p("\v{:s} = {:s}".format(subdef.name, to_hex(subdef.address)))
|
||||
self.p("; end external subroutines\n")
|
||||
for stmt in block.scope.nodes:
|
||||
if isinstance(stmt, (VarDef, Directive)):
|
||||
continue # should have been handled already
|
||||
if isinstance(stmt, (VarDef, Directive, Subroutine)):
|
||||
continue # should have been handled already or will be later
|
||||
self.generate_statement(stmt)
|
||||
if block.name == "main" and isinstance(stmt, Label) and stmt.name == "start":
|
||||
# make sure the main.start routine clears the decimal and carry flags as first steps
|
||||
@ -215,12 +216,13 @@ class AssemblyGenerator:
|
||||
# generate the block initializer
|
||||
# @todo add a block initializer subroutine that can contain custom reset/init code? (static initializer)
|
||||
self.p("_il65_init_block\v; (re)set vars to initial values")
|
||||
# @todo optimize init order (sort on value first to avoid needless register loads, etc)
|
||||
self.p("\vlda #0\n\vldx #0")
|
||||
float_inits = {}
|
||||
string_inits = []
|
||||
prev_value = 0
|
||||
for variable in [vd for vd in block.scope.filter_nodes(VarDef) if vd.vartype == VarType.VAR]:
|
||||
vardefs = [vd for vd in block.scope.filter_nodes(VarDef) if vd.vartype == VarType.VAR]
|
||||
# @todo optimize init order (sort on value first to avoid needless register loads, etc)
|
||||
for variable in vardefs:
|
||||
vname = variable.name
|
||||
vvalue = variable.value
|
||||
if variable.datatype == DataType.BYTE:
|
||||
|
@ -53,6 +53,8 @@ start = "start"
|
||||
@attr.s(cmp=False, slots=True, frozen=False)
|
||||
class AstNode:
|
||||
sourceref = attr.ib(type=SourceRef)
|
||||
# when evaluating an expression, does it have to be a constant value?:
|
||||
processed_expr_must_be_constant = attr.ib(type=bool, init=False, default=False)
|
||||
|
||||
@property
|
||||
def lineref(self) -> str:
|
||||
@ -410,8 +412,8 @@ class VarDef(AstNode):
|
||||
raise ParseError("constant value assignment is missing",
|
||||
attr.evolve(self.sourceref, column=self.sourceref.column+len(self.name)))
|
||||
# if the value is an expression, mark it as a *constant* expression here
|
||||
if isinstance(self.value, Expression):
|
||||
self.value.processed_must_be_constant = True
|
||||
if isinstance(self.value, AstNode):
|
||||
self.value.processed_expr_must_be_constant = True
|
||||
elif self.value is None and self.datatype in (DataType.BYTE, DataType.WORD, DataType.FLOAT):
|
||||
self.value = 0
|
||||
# note: value coercion is done later, when all expressions are evaluated
|
||||
@ -423,7 +425,7 @@ class VarDef(AstNode):
|
||||
try:
|
||||
_, self.value = coerce_value(self.datatype, self.value, self.sourceref)
|
||||
except (TypeError, OverflowError) as x:
|
||||
raise ParseError(str(x), self.sourceref) from None
|
||||
raise ParseError("processed expression vor vardef is not a constant value: " + str(x), self.sourceref) from None
|
||||
|
||||
|
||||
@attr.s(cmp=False, slots=True, repr=False)
|
||||
@ -548,7 +550,6 @@ class Expression(AstNode):
|
||||
operator = attr.ib(type=str)
|
||||
right = attr.ib()
|
||||
unary = attr.ib(type=bool, default=False)
|
||||
processed_must_be_constant = attr.ib(type=bool, init=False, default=False) # does the expression have to be a constant value?
|
||||
|
||||
def __attrs_post_init__(self):
|
||||
assert self.operator not in ("++", "--"), "incr/decr should not be an expression"
|
||||
@ -586,8 +587,8 @@ class Expression(AstNode):
|
||||
|
||||
def process_expression(value: Any, scope: Scope, sourceref: SourceRef) -> Any:
|
||||
# process/simplify all expressions (constant folding etc)
|
||||
if isinstance(value, Expression):
|
||||
must_be_constant = value.processed_must_be_constant
|
||||
if isinstance(value, AstNode):
|
||||
must_be_constant = value.processed_expr_must_be_constant
|
||||
else:
|
||||
must_be_constant = False
|
||||
if must_be_constant:
|
||||
@ -631,7 +632,6 @@ def process_constant_expression(expr: Any, sourceref: SourceRef, symbolscope: Sc
|
||||
raise ParseError(str(x), expr.sourceref) from None
|
||||
elif isinstance(expr, SubCall):
|
||||
if isinstance(expr.target, CallTarget):
|
||||
print("CALLTARGET", expr.target.address_of, expr.target.target) # XXX
|
||||
target = expr.target.target
|
||||
if isinstance(target, SymbolName): # 'function(1,2,3)'
|
||||
funcname = target.name
|
||||
|
@ -125,10 +125,10 @@
|
||||
; taking the address of things from the ZP will work even when it is a var
|
||||
; because zp-vars get assigned a specific address (from a pool). Also, it's a byte.
|
||||
|
||||
var .word initword0a = &ZP.zpmem1 ; @todo should work, reference this symbols' generated address (@todo generate address for ZP)
|
||||
var .word initword0 = &ZP.zpvar1
|
||||
var .word initword0a = &ZP.zpmem1
|
||||
var .word initword0 = &ZP.zpvar1 ; @todo should work, reference this symbols' generated address (@todo generate address for ZP)
|
||||
var initbytea0 = &ZP.zpmem1
|
||||
var .word initworda1 = &ZP.zpvar1
|
||||
var .word initworda1 = &ZP.zpvar1 ; @todo should work, reference this symbols' generated address (@todo generate address for ZP)
|
||||
|
||||
|
||||
; (constant) expressions
|
||||
|
@ -1,6 +1,6 @@
|
||||
; floating point tests
|
||||
|
||||
%output prg, basic
|
||||
%output basic
|
||||
|
||||
%import c64lib
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
%zp restore , clobber ; clobber over the zp memory normally used by basic/kernel rom, frees up more zp
|
||||
|
||||
|
||||
~ main $0a00
|
||||
~ main
|
||||
{
|
||||
; this is the main block with the start routine.
|
||||
|
||||
@ -178,7 +178,7 @@ somelabel1:
|
||||
}
|
||||
|
||||
|
||||
~ fidget $1000
|
||||
~ fidget $0c00
|
||||
{
|
||||
|
||||
subroutine:
|
||||
|
Loading…
Reference in New Issue
Block a user