mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Consistently handle auto-scoping of local symbols
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
3
test/asm/empty-local-purged.asm
Normal file
3
test/asm/empty-local-purged.asm
Normal file
@@ -0,0 +1,3 @@
|
||||
SECTION "Test", ROM0
|
||||
|
||||
PURGE .test
|
||||
2
test/asm/empty-local-purged.err
Normal file
2
test/asm/empty-local-purged.err
Normal file
@@ -0,0 +1,2 @@
|
||||
FATAL: empty-local-purged.asm(3):
|
||||
Unqualified local label '.test' in main scope
|
||||
3
test/asm/empty-local-referenced.asm
Normal file
3
test/asm/empty-local-referenced.asm
Normal file
@@ -0,0 +1,3 @@
|
||||
SECTION "Test", ROM0
|
||||
|
||||
dw Referenced.
|
||||
2
test/asm/empty-local-referenced.err
Normal file
2
test/asm/empty-local-referenced.err
Normal file
@@ -0,0 +1,2 @@
|
||||
FATAL: empty-local-referenced.asm(3):
|
||||
'Referenced.' is a nonsensical reference to an empty local label
|
||||
4
test/asm/empty-local-used.asm
Normal file
4
test/asm/empty-local-used.asm
Normal file
@@ -0,0 +1,4 @@
|
||||
SECTION "Test", ROM0
|
||||
|
||||
Label:
|
||||
dw Label.
|
||||
2
test/asm/empty-local-used.err
Normal file
2
test/asm/empty-local-used.err
Normal file
@@ -0,0 +1,2 @@
|
||||
FATAL: empty-local-used.asm(4):
|
||||
'Label.' is a nonsensical reference to an empty local label
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
SECTION "Test", ROM0
|
||||
|
||||
Label:
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
FATAL: empty-local.asm(5):
|
||||
FATAL: empty-local.asm(4):
|
||||
'Label.' is a nonsensical reference to an empty local label
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
SECTION "sec", ROM0
|
||||
SECTION "Test", ROM0
|
||||
|
||||
dw .test
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
SECTION "Test", ROM0
|
||||
|
||||
.test:
|
||||
|
||||
@@ -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)!
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user