diff --git a/src/asm/symbol.cpp b/src/asm/symbol.cpp index 108fd90f..668743ec 100644 --- a/src/asm/symbol.cpp +++ b/src/asm/symbol.cpp @@ -120,22 +120,42 @@ static Symbol &createSymbol(std::string const &symName) { return sym; } +static bool isAutoScoped(std::string const &symName) { + // `labelScope` should be global if it's defined + assume(!labelScope || labelScope->name.find('.') == std::string::npos); + + size_t dotPos = symName.find('.'); + + // If there are no dots, it's not a local label + if (dotPos == std::string::npos) + return false; + + // Check for nothing after the dot + if (dotPos == symName.length() - 1) + fatalerror("'%s' is a nonsensical reference to an empty local label\n", symName.c_str()); + + // Check for more than one dot + if (symName.find('.', dotPos + 1) != std::string::npos) + fatalerror("'%s' is a nonsensical reference to a nested local label\n", symName.c_str()); + + // Check for already-qualified local label + if (dotPos > 0) + return false; + + // Check for unqualifiable local label + if (!labelScope) + fatalerror("Unqualified local label '%s' in main scope\n", symName.c_str()); + + return true; +} + Symbol *sym_FindExactSymbol(std::string const &symName) { auto search = symbols.find(symName); return search != symbols.end() ? &search->second : nullptr; } Symbol *sym_FindScopedSymbol(std::string const &symName) { - if (size_t dotPos = symName.find('.'); dotPos != std::string::npos) { - if (symName.find('.', dotPos + 1) != std::string::npos) - fatalerror( - "'%s' is a nonsensical reference to a nested local symbol\n", symName.c_str() - ); - // If auto-scoped local label, expand the name - if (dotPos == 0 && labelScope) - return sym_FindExactSymbol(labelScope->name + symName); - } - return sym_FindExactSymbol(symName); + return sym_FindExactSymbol(isAutoScoped(symName) ? labelScope->name + symName : symName); } Symbol *sym_FindScopedValidSymbol(std::string const &symName) { @@ -186,15 +206,7 @@ bool sym_IsPurgedExact(std::string const &symName) { } bool sym_IsPurgedScoped(std::string const &symName) { - if (size_t dotPos = symName.find('.'); dotPos != std::string::npos) { - // Check for a nonsensical reference to a nested scoped symbol - if (symName.find('.', dotPos + 1) != std::string::npos) - return false; - // If auto-scoped local label, expand the name - if (dotPos == 0 && labelScope) - return sym_IsPurgedExact(labelScope->name + symName); - } - return sym_IsPurgedExact(symName); + return sym_IsPurgedExact(isAutoScoped(symName) ? labelScope->name + symName : symName); } int32_t sym_GetRSValue() { @@ -353,7 +365,9 @@ Symbol *sym_AddVar(std::string const &symName, int32_t value) { } static Symbol *addLabel(std::string const &symName) { - assume(!symName.starts_with('.')); // The symbol name must have been expanded prior + // The symbol name should have been expanded already + assume(!symName.starts_with('.')); + Symbol *sym = sym_FindExactSymbol(symName); if (!sym) { @@ -380,29 +394,10 @@ static Symbol *addLabel(std::string const &symName) { } Symbol *sym_AddLocalLabel(std::string const &symName) { - // Assuming no dots in `labelScope` if defined - assume(!labelScope || labelScope->name.find('.') == std::string::npos); + // The symbol name should be local, qualified or not + assume(symName.find('.') != std::string::npos); - size_t dotPos = symName.find('.'); - - assume(dotPos != std::string::npos); // There should be at least one dot in `symName` - - // Check for something after the dot - if (dotPos == symName.length() - 1) { - fatalerror("'%s' is a nonsensical reference to an empty local label\n", symName.c_str()); - } - // Check for more than one dot - if (symName.find('.', dotPos + 1) != std::string::npos) - fatalerror("'%s' is a nonsensical reference to a nested local label\n", symName.c_str()); - - if (dotPos == 0) { - if (!labelScope) { - error("Unqualified local label '%s' in main scope\n", symName.c_str()); - return nullptr; - } - return addLabel(labelScope->name + symName); - } - return addLabel(symName); + return addLabel(isAutoScoped(symName) ? labelScope->name + symName : symName); } Symbol *sym_AddLabel(std::string const &symName) { @@ -496,14 +491,7 @@ Symbol *sym_Ref(std::string const &symName) { Symbol *sym = sym_FindScopedSymbol(symName); if (!sym) { - if (symName.starts_with('.')) { - if (!labelScope) - fatalerror("Local label reference '%s' in main scope\n", symName.c_str()); - sym = &createSymbol(labelScope->name + symName); - } else { - sym = &createSymbol(symName); - } - + sym = &createSymbol(isAutoScoped(symName) ? labelScope->name + symName : symName); sym->type = SYM_REF; } diff --git a/test/asm/empty-local-purged.asm b/test/asm/empty-local-purged.asm new file mode 100644 index 00000000..e712c909 --- /dev/null +++ b/test/asm/empty-local-purged.asm @@ -0,0 +1,3 @@ +SECTION "Test", ROM0 + +PURGE .test diff --git a/test/asm/empty-local-purged.err b/test/asm/empty-local-purged.err new file mode 100644 index 00000000..8404b93b --- /dev/null +++ b/test/asm/empty-local-purged.err @@ -0,0 +1,2 @@ +FATAL: empty-local-purged.asm(3): + Unqualified local label '.test' in main scope diff --git a/test/asm/empty-local-referenced.asm b/test/asm/empty-local-referenced.asm new file mode 100644 index 00000000..327ed26b --- /dev/null +++ b/test/asm/empty-local-referenced.asm @@ -0,0 +1,3 @@ +SECTION "Test", ROM0 + +dw Referenced. diff --git a/test/asm/empty-local-referenced.err b/test/asm/empty-local-referenced.err new file mode 100644 index 00000000..00c37418 --- /dev/null +++ b/test/asm/empty-local-referenced.err @@ -0,0 +1,2 @@ +FATAL: empty-local-referenced.asm(3): + 'Referenced.' is a nonsensical reference to an empty local label diff --git a/test/asm/empty-local-used.asm b/test/asm/empty-local-used.asm new file mode 100644 index 00000000..b302c9d2 --- /dev/null +++ b/test/asm/empty-local-used.asm @@ -0,0 +1,4 @@ +SECTION "Test", ROM0 + +Label: +dw Label. diff --git a/test/asm/empty-local-used.err b/test/asm/empty-local-used.err new file mode 100644 index 00000000..158af790 --- /dev/null +++ b/test/asm/empty-local-used.err @@ -0,0 +1,2 @@ +FATAL: empty-local-used.asm(4): + 'Label.' is a nonsensical reference to an empty local label diff --git a/test/asm/empty-local.asm b/test/asm/empty-local.asm index 4fd50b04..7d4256c3 100644 --- a/test/asm/empty-local.asm +++ b/test/asm/empty-local.asm @@ -1,4 +1,3 @@ - SECTION "Test", ROM0 Label: diff --git a/test/asm/empty-local.err b/test/asm/empty-local.err index f7b05b06..d81a9a41 100644 --- a/test/asm/empty-local.err +++ b/test/asm/empty-local.err @@ -1,2 +1,2 @@ -FATAL: empty-local.asm(5): +FATAL: empty-local.asm(4): 'Label.' is a nonsensical reference to an empty local label diff --git a/test/asm/local-ref-without-parent.asm b/test/asm/local-ref-without-parent.asm index 717b9ff0..3a38e3be 100644 --- a/test/asm/local-ref-without-parent.asm +++ b/test/asm/local-ref-without-parent.asm @@ -1,3 +1,3 @@ -SECTION "sec", ROM0 +SECTION "Test", ROM0 dw .test diff --git a/test/asm/local-ref-without-parent.err b/test/asm/local-ref-without-parent.err index d332bdf9..c598d21d 100644 --- a/test/asm/local-ref-without-parent.err +++ b/test/asm/local-ref-without-parent.err @@ -1,2 +1,2 @@ FATAL: local-ref-without-parent.asm(3): - Local label reference '.test' in main scope + Unqualified local label '.test' in main scope diff --git a/test/asm/local-without-parent.asm b/test/asm/local-without-parent.asm index a289769d..72b10c66 100644 --- a/test/asm/local-without-parent.asm +++ b/test/asm/local-without-parent.asm @@ -1,2 +1,3 @@ SECTION "Test", ROM0 + .test: diff --git a/test/asm/local-without-parent.err b/test/asm/local-without-parent.err index 71e2a7f5..7ce6e3f3 100644 --- a/test/asm/local-without-parent.err +++ b/test/asm/local-without-parent.err @@ -1,3 +1,2 @@ -error: local-without-parent.asm(2): +FATAL: local-without-parent.asm(3): Unqualified local label '.test' in main scope -error: Assembly aborted (1 error)! diff --git a/test/asm/nested-local-reference.err b/test/asm/nested-local-reference.err index 7e2ae7b7..6ca37987 100644 --- a/test/asm/nested-local-reference.err +++ b/test/asm/nested-local-reference.err @@ -1,2 +1,2 @@ FATAL: nested-local-reference.asm(8): - 'Parent.child.grandchild' is a nonsensical reference to a nested local symbol + 'Parent.child.grandchild' is a nonsensical reference to a nested local label