mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +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;
|
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) {
|
Symbol *sym_FindExactSymbol(std::string const &symName) {
|
||||||
auto search = symbols.find(symName);
|
auto search = symbols.find(symName);
|
||||||
return search != symbols.end() ? &search->second : nullptr;
|
return search != symbols.end() ? &search->second : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol *sym_FindScopedSymbol(std::string const &symName) {
|
Symbol *sym_FindScopedSymbol(std::string const &symName) {
|
||||||
if (size_t dotPos = symName.find('.'); dotPos != std::string::npos) {
|
return sym_FindExactSymbol(isAutoScoped(symName) ? labelScope->name + symName : symName);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol *sym_FindScopedValidSymbol(std::string const &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) {
|
bool sym_IsPurgedScoped(std::string const &symName) {
|
||||||
if (size_t dotPos = symName.find('.'); dotPos != std::string::npos) {
|
return sym_IsPurgedExact(isAutoScoped(symName) ? labelScope->name + symName : symName);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t sym_GetRSValue() {
|
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) {
|
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);
|
Symbol *sym = sym_FindExactSymbol(symName);
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
@@ -380,29 +394,10 @@ static Symbol *addLabel(std::string const &symName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Symbol *sym_AddLocalLabel(std::string const &symName) {
|
Symbol *sym_AddLocalLabel(std::string const &symName) {
|
||||||
// Assuming no dots in `labelScope` if defined
|
// The symbol name should be local, qualified or not
|
||||||
assume(!labelScope || labelScope->name.find('.') == std::string::npos);
|
assume(symName.find('.') != std::string::npos);
|
||||||
|
|
||||||
size_t dotPos = symName.find('.');
|
return addLabel(isAutoScoped(symName) ? labelScope->name + symName : symName);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol *sym_AddLabel(std::string const &symName) {
|
Symbol *sym_AddLabel(std::string const &symName) {
|
||||||
@@ -496,14 +491,7 @@ Symbol *sym_Ref(std::string const &symName) {
|
|||||||
Symbol *sym = sym_FindScopedSymbol(symName);
|
Symbol *sym = sym_FindScopedSymbol(symName);
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
if (symName.starts_with('.')) {
|
sym = &createSymbol(isAutoScoped(symName) ? labelScope->name + symName : symName);
|
||||||
if (!labelScope)
|
|
||||||
fatalerror("Local label reference '%s' in main scope\n", symName.c_str());
|
|
||||||
sym = &createSymbol(labelScope->name + symName);
|
|
||||||
} else {
|
|
||||||
sym = &createSymbol(symName);
|
|
||||||
}
|
|
||||||
|
|
||||||
sym->type = SYM_REF;
|
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
|
SECTION "Test", ROM0
|
||||||
|
|
||||||
Label:
|
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
|
'Label.' is a nonsensical reference to an empty local label
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
SECTION "sec", ROM0
|
SECTION "Test", ROM0
|
||||||
|
|
||||||
dw .test
|
dw .test
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
FATAL: local-ref-without-parent.asm(3):
|
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
|
SECTION "Test", ROM0
|
||||||
|
|
||||||
.test:
|
.test:
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
error: local-without-parent.asm(2):
|
FATAL: local-without-parent.asm(3):
|
||||||
Unqualified local label '.test' in main scope
|
Unqualified local label '.test' in main scope
|
||||||
error: Assembly aborted (1 error)!
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
FATAL: nested-local-reference.asm(8):
|
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