mirror of
https://github.com/gbdev/rgbds.git
synced 2026-09-24 14:47:06 +00:00
Intern strings used as identifiers (for labels, constants, macros, charmaps, etc) (#1980)
This commit is contained in:
+80
-69
@@ -22,6 +22,7 @@
|
||||
#include "version.hpp"
|
||||
|
||||
#include "asm/fstack.hpp"
|
||||
#include "asm/intern.hpp"
|
||||
#include "asm/lexer.hpp"
|
||||
#include "asm/macro.hpp"
|
||||
#include "asm/main.hpp"
|
||||
@@ -31,8 +32,8 @@
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
static std::unordered_map<std::string, Symbol> symbols;
|
||||
static std::unordered_set<std::string> purgedSymbols;
|
||||
static std::unordered_map<InternedStr, Symbol> symbols;
|
||||
static std::unordered_set<InternedStr> purgedSymbols;
|
||||
|
||||
static Symbol const *globalScope = nullptr; // Current section's global label scope
|
||||
static Symbol const *localScope = nullptr; // Current section's local label scope
|
||||
@@ -44,6 +45,10 @@ static Symbol *globalScopeSymbol;
|
||||
static Symbol *localScopeSymbol;
|
||||
static Symbol *RSSymbol;
|
||||
|
||||
static InternedStr PCName;
|
||||
static InternedStr globalScopeName;
|
||||
static InternedStr localScopeName;
|
||||
|
||||
static char savedTIME[256];
|
||||
static char savedDATE[256];
|
||||
static char savedTIMESTAMP_ISO8601_LOCAL[256];
|
||||
@@ -53,10 +58,10 @@ bool sym_IsPC(Symbol const *sym) {
|
||||
return sym == PCSymbol;
|
||||
}
|
||||
|
||||
bool sym_IsDotScope(std::string const &symName) {
|
||||
bool sym_IsDotScope(InternedStr symName) {
|
||||
// Label scopes `.` and `..` are the only nonlocal identifiers that start with a dot.
|
||||
// Three or more dots are considered a nonsensical local label.
|
||||
return symName == "." || symName == "..";
|
||||
return symName == globalScopeName || symName == localScopeName;
|
||||
}
|
||||
|
||||
void sym_ForEach(void (*callback)(Symbol &)) {
|
||||
@@ -76,9 +81,9 @@ static int32_t NARGCallback() {
|
||||
|
||||
static std::shared_ptr<std::string> SCOPECallback() {
|
||||
if (localScope) {
|
||||
return std::make_shared<std::string>("..");
|
||||
return std::make_shared<std::string>(localScopeName.str());
|
||||
} else if (globalScope) {
|
||||
return std::make_shared<std::string>(".");
|
||||
return std::make_shared<std::string>(globalScopeName.str());
|
||||
} else {
|
||||
if (!sect_GetSymbolSection()) {
|
||||
error("`__SCOPE__` has no value outside of a section");
|
||||
@@ -92,7 +97,7 @@ static std::shared_ptr<std::string> globalScopeCallback() {
|
||||
error("`.` has no value outside of a label scope");
|
||||
return std::make_shared<std::string>("");
|
||||
}
|
||||
return std::make_shared<std::string>(globalScope->name);
|
||||
return std::make_shared<std::string>(globalScope->name.str());
|
||||
}
|
||||
|
||||
static std::shared_ptr<std::string> localScopeCallback() {
|
||||
@@ -100,7 +105,7 @@ static std::shared_ptr<std::string> localScopeCallback() {
|
||||
error("`..` has no value outside of a local label scope");
|
||||
return std::make_shared<std::string>("");
|
||||
}
|
||||
return std::make_shared<std::string>(localScope->name);
|
||||
return std::make_shared<std::string>(localScope->name.str());
|
||||
}
|
||||
|
||||
static int32_t PCCallback() {
|
||||
@@ -219,13 +224,13 @@ static void redefinedError(Symbol const &sym) {
|
||||
}
|
||||
}
|
||||
|
||||
static void assumeAlreadyExpanded(std::string const &symName) {
|
||||
static void assumeAlreadyExpanded(InternedStr symName) {
|
||||
// Either the symbol name is `Global.local` or entirely '.'s (for scopes `.` and `..`),
|
||||
// but cannot be unqualified `.local` or more than two '.'s
|
||||
assume(!symName.starts_with('.') || sym_IsDotScope(symName));
|
||||
assume(!symName.str().starts_with('.') || sym_IsDotScope(symName));
|
||||
}
|
||||
|
||||
static Symbol &createSymbol(std::string const &symName) {
|
||||
static Symbol &createSymbol(InternedStr symName) {
|
||||
assumeAlreadyExpanded(symName);
|
||||
|
||||
static uint32_t nextDefIndex = 0;
|
||||
@@ -245,13 +250,13 @@ static Symbol &createSymbol(std::string const &symName) {
|
||||
return sym;
|
||||
}
|
||||
|
||||
static bool isAutoScoped(std::string const &symName) {
|
||||
static bool isAutoScoped(InternedStr symName) {
|
||||
// `globalScope` should be global if it's defined
|
||||
assume(!globalScope || globalScope->name.find('.') == std::string::npos);
|
||||
assume(!globalScope || globalScope->name.str().find('.') == std::string::npos);
|
||||
// `localScope` should be qualified local if it's defined
|
||||
assume(!localScope || localScope->name.find('.') != std::string::npos);
|
||||
assume(!localScope || localScope->name.str().find('.') != std::string::npos);
|
||||
|
||||
size_t dotPos = symName.find('.');
|
||||
size_t dotPos = symName.str().find('.');
|
||||
|
||||
// If there are no dots, it's not a local label
|
||||
if (dotPos == std::string::npos) {
|
||||
@@ -264,12 +269,12 @@ static bool isAutoScoped(std::string const &symName) {
|
||||
}
|
||||
|
||||
// Check for nothing after the dot
|
||||
if (dotPos == symName.length() - 1) {
|
||||
if (dotPos == symName.str().length() - 1) {
|
||||
fatal("`%s` is a nonsensical reference to an empty local label", symName.c_str());
|
||||
}
|
||||
|
||||
// Check for more than one dot
|
||||
if (symName.find('.', dotPos + 1) != std::string::npos) {
|
||||
if (symName.str().find('.', dotPos + 1) != std::string::npos) {
|
||||
fatal("`%s` is a nonsensical reference to a nested local label", symName.c_str());
|
||||
}
|
||||
|
||||
@@ -286,22 +291,22 @@ static bool isAutoScoped(std::string const &symName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string expandedSymName(std::string const &symName) {
|
||||
return isAutoScoped(symName) ? globalScope->name + symName : symName;
|
||||
static InternedStr expandedSymName(InternedStr symName) {
|
||||
return isAutoScoped(symName) ? intern(globalScope->name.str() + symName.str()) : symName;
|
||||
}
|
||||
|
||||
Symbol *sym_FindExactSymbol(std::string const &symName) {
|
||||
Symbol *sym_FindExactSymbol(InternedStr symName) {
|
||||
assumeAlreadyExpanded(symName);
|
||||
|
||||
auto search = symbols.find(symName);
|
||||
return search != symbols.end() ? &search->second : nullptr;
|
||||
}
|
||||
|
||||
Symbol *sym_FindScopedSymbol(std::string const &symName) {
|
||||
Symbol *sym_FindScopedSymbol(InternedStr symName) {
|
||||
return sym_FindExactSymbol(expandedSymName(symName));
|
||||
}
|
||||
|
||||
Symbol *sym_FindScopedValidSymbol(std::string const &symName) {
|
||||
Symbol *sym_FindScopedValidSymbol(InternedStr symName) {
|
||||
Symbol *sym = sym_FindScopedSymbol(symName);
|
||||
|
||||
// `@` has no value outside of a section
|
||||
@@ -332,7 +337,7 @@ Symbol const *sym_GetPC() {
|
||||
return PCSymbol;
|
||||
}
|
||||
|
||||
void sym_Purge(std::string const &symName) {
|
||||
void sym_Purge(InternedStr symName) {
|
||||
Symbol *sym = sym_FindScopedValidSymbol(symName);
|
||||
|
||||
if (!sym) {
|
||||
@@ -363,13 +368,13 @@ void sym_Purge(std::string const &symName) {
|
||||
}
|
||||
}
|
||||
|
||||
bool sym_IsPurgedExact(std::string const &symName) {
|
||||
bool sym_IsPurgedExact(InternedStr symName) {
|
||||
assumeAlreadyExpanded(symName);
|
||||
|
||||
return purgedSymbols.find(symName) != purgedSymbols.end();
|
||||
}
|
||||
|
||||
bool sym_IsPurgedScoped(std::string const &symName) {
|
||||
bool sym_IsPurgedScoped(InternedStr symName) {
|
||||
return sym_IsPurgedExact(expandedSymName(symName));
|
||||
}
|
||||
|
||||
@@ -405,9 +410,9 @@ void sym_SetCurrentLabelScopes(std::pair<Symbol const *, Symbol const *> newScop
|
||||
localScope = std::get<1>(newScopes);
|
||||
|
||||
// `globalScope` should be global if it's defined
|
||||
assume(!globalScope || globalScope->name.find('.') == std::string::npos);
|
||||
assume(!globalScope || globalScope->name.str().find('.') == std::string::npos);
|
||||
// `localScope` should be qualified local if it's defined
|
||||
assume(!localScope || localScope->name.find('.') != std::string::npos);
|
||||
assume(!localScope || localScope->name.str().find('.') != std::string::npos);
|
||||
}
|
||||
|
||||
void sym_ResetCurrentLabelScopes() {
|
||||
@@ -415,7 +420,7 @@ void sym_ResetCurrentLabelScopes() {
|
||||
localScope = nullptr;
|
||||
}
|
||||
|
||||
static Symbol *createNonrelocSymbol(std::string const &symName, bool numeric) {
|
||||
static Symbol *createNonrelocSymbol(InternedStr symName, bool numeric) {
|
||||
Symbol *sym = sym_FindExactSymbol(symName);
|
||||
|
||||
if (!sym) {
|
||||
@@ -436,7 +441,7 @@ static Symbol *createNonrelocSymbol(std::string const &symName, bool numeric) {
|
||||
return sym;
|
||||
}
|
||||
|
||||
Symbol *sym_AddEqu(std::string const &symName, int32_t value) {
|
||||
Symbol *sym_AddEqu(InternedStr symName, int32_t value) {
|
||||
Symbol *sym = createNonrelocSymbol(symName, true);
|
||||
|
||||
if (!sym) {
|
||||
@@ -449,7 +454,7 @@ Symbol *sym_AddEqu(std::string const &symName, int32_t value) {
|
||||
return sym;
|
||||
}
|
||||
|
||||
Symbol *sym_RedefEqu(std::string const &symName, int32_t value) {
|
||||
Symbol *sym_RedefEqu(InternedStr symName, int32_t value) {
|
||||
Symbol *sym = sym_FindExactSymbol(symName);
|
||||
|
||||
if (!sym) {
|
||||
@@ -471,7 +476,7 @@ Symbol *sym_RedefEqu(std::string const &symName, int32_t value) {
|
||||
return sym;
|
||||
}
|
||||
|
||||
Symbol *sym_AddString(std::string const &symName, std::shared_ptr<std::string> str) {
|
||||
Symbol *sym_AddString(InternedStr symName, std::shared_ptr<std::string> str) {
|
||||
Symbol *sym = createNonrelocSymbol(symName, false);
|
||||
|
||||
if (!sym) {
|
||||
@@ -483,7 +488,7 @@ Symbol *sym_AddString(std::string const &symName, std::shared_ptr<std::string> s
|
||||
return sym;
|
||||
}
|
||||
|
||||
Symbol *sym_RedefString(std::string const &symName, std::shared_ptr<std::string> str) {
|
||||
Symbol *sym_RedefString(InternedStr symName, std::shared_ptr<std::string> str) {
|
||||
Symbol *sym = sym_FindExactSymbol(symName);
|
||||
|
||||
if (!sym) {
|
||||
@@ -511,7 +516,7 @@ Symbol *sym_RedefString(std::string const &symName, std::shared_ptr<std::string>
|
||||
return sym;
|
||||
}
|
||||
|
||||
Symbol *sym_AddVar(std::string const &symName, int32_t value) {
|
||||
Symbol *sym_AddVar(InternedStr symName, int32_t value) {
|
||||
Symbol *sym = sym_FindExactSymbol(symName);
|
||||
|
||||
if (!sym) {
|
||||
@@ -529,7 +534,7 @@ Symbol *sym_AddVar(std::string const &symName, int32_t value) {
|
||||
return sym;
|
||||
}
|
||||
|
||||
static Symbol *addLabel(std::string const &symName) {
|
||||
static Symbol *addLabel(InternedStr symName) {
|
||||
assumeAlreadyExpanded(symName);
|
||||
|
||||
Symbol *sym = sym_FindExactSymbol(symName);
|
||||
@@ -546,7 +551,7 @@ static Symbol *addLabel(std::string const &symName) {
|
||||
sym->type = SYM_LABEL;
|
||||
sym->data = static_cast<int32_t>(sect_GetSymbolOffset());
|
||||
// Don't export anonymous labels
|
||||
if (options.exportAll && !symName.starts_with('!')) {
|
||||
if (options.exportAll && !symName.str().starts_with('!')) {
|
||||
sym->isExported = true;
|
||||
}
|
||||
sym->section = sect_GetSymbolSection();
|
||||
@@ -558,9 +563,9 @@ static Symbol *addLabel(std::string const &symName) {
|
||||
return sym;
|
||||
}
|
||||
|
||||
Symbol *sym_AddLocalLabel(std::string const &symName) {
|
||||
Symbol *sym_AddLocalLabel(InternedStr symName) {
|
||||
// The symbol name should be local, qualified or not
|
||||
assume(symName.find('.') != std::string::npos);
|
||||
assume(symName.str().find('.') != std::string::npos);
|
||||
|
||||
Symbol *sym = addLabel(expandedSymName(symName));
|
||||
|
||||
@@ -571,9 +576,9 @@ Symbol *sym_AddLocalLabel(std::string const &symName) {
|
||||
return sym;
|
||||
}
|
||||
|
||||
Symbol *sym_AddLabel(std::string const &symName) {
|
||||
Symbol *sym_AddLabel(InternedStr symName) {
|
||||
// The symbol name should be global
|
||||
assume(symName.find('.') == std::string::npos);
|
||||
assume(symName.str().find('.') == std::string::npos);
|
||||
|
||||
Symbol *sym = addLabel(symName);
|
||||
|
||||
@@ -596,12 +601,12 @@ Symbol *sym_AddAnonLabel() {
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
std::string anon = sym_MakeAnonLabelName(0, true); // The direction is important!
|
||||
InternedStr anon = sym_MakeAnonLabelName(0, true); // The direction is important!
|
||||
++anonLabelID;
|
||||
return addLabel(anon);
|
||||
}
|
||||
|
||||
std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg) {
|
||||
InternedStr sym_MakeAnonLabelName(uint32_t ofs, bool neg) {
|
||||
uint32_t id = 0;
|
||||
|
||||
if (neg) {
|
||||
@@ -632,11 +637,11 @@ std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg) {
|
||||
}
|
||||
}
|
||||
|
||||
return "!"s + std::to_string(id);
|
||||
return intern("!"s + std::to_string(id));
|
||||
}
|
||||
|
||||
void sym_Export(std::string const &symName) {
|
||||
if (symName.starts_with('!')) {
|
||||
void sym_Export(InternedStr symName) {
|
||||
if (symName.str().starts_with('!')) {
|
||||
// LCOV_EXCL_START
|
||||
// The parser does not accept anonymous labels for an `EXPORT` directive
|
||||
error("Cannot export anonymous label");
|
||||
@@ -655,9 +660,8 @@ void sym_Export(std::string const &symName) {
|
||||
sym->isExported = true;
|
||||
}
|
||||
|
||||
Symbol *sym_AddMacro(
|
||||
std::string const &symName, int32_t defLineNo, ContentSpan const &span, bool isQuiet
|
||||
) {
|
||||
Symbol *
|
||||
sym_AddMacro(InternedStr symName, int32_t defLineNo, ContentSpan const &span, bool isQuiet) {
|
||||
Symbol *sym = createNonrelocSymbol(symName, false);
|
||||
|
||||
if (!sym) {
|
||||
@@ -678,7 +682,7 @@ Symbol *sym_AddMacro(
|
||||
|
||||
// Flag that a symbol is referenced in an RPN expression
|
||||
// and create it if it doesn't exist yet
|
||||
Symbol *sym_Ref(std::string const &symName) {
|
||||
Symbol *sym_Ref(InternedStr symName) {
|
||||
Symbol *sym = sym_FindScopedSymbol(symName);
|
||||
|
||||
if (!sym) {
|
||||
@@ -691,41 +695,46 @@ Symbol *sym_Ref(std::string const &symName) {
|
||||
|
||||
// Define the built-in symbols
|
||||
void sym_Init(time_t now) {
|
||||
PCSymbol = &createSymbol("@"s);
|
||||
PCName = intern("@");
|
||||
PCSymbol = &createSymbol(PCName);
|
||||
PCSymbol->type = SYM_LABEL;
|
||||
PCSymbol->data = PCCallback;
|
||||
PCSymbol->isBuiltin = true;
|
||||
|
||||
NARGSymbol = &createSymbol("_NARG"s);
|
||||
NARGSymbol = &createSymbol(intern("_NARG"));
|
||||
NARGSymbol->type = SYM_EQU;
|
||||
NARGSymbol->data = NARGCallback;
|
||||
NARGSymbol->isBuiltin = true;
|
||||
|
||||
globalScopeSymbol = &createSymbol("."s);
|
||||
globalScopeName = intern(".");
|
||||
globalScopeSymbol = &createSymbol(globalScopeName);
|
||||
globalScopeSymbol->type = SYM_EQUS;
|
||||
globalScopeSymbol->data = globalScopeCallback;
|
||||
globalScopeSymbol->isBuiltin = true;
|
||||
|
||||
localScopeSymbol = &createSymbol(".."s);
|
||||
localScopeName = intern("..");
|
||||
localScopeSymbol = &createSymbol(localScopeName);
|
||||
localScopeSymbol->type = SYM_EQUS;
|
||||
localScopeSymbol->data = localScopeCallback;
|
||||
localScopeSymbol->isBuiltin = true;
|
||||
|
||||
SCOPESymbol = &createSymbol("__SCOPE__"s);
|
||||
SCOPESymbol = &createSymbol(intern("__SCOPE__"));
|
||||
SCOPESymbol->type = SYM_EQUS;
|
||||
SCOPESymbol->data = SCOPECallback;
|
||||
SCOPESymbol->isBuiltin = true;
|
||||
|
||||
RSSymbol = sym_AddVar("_RS"s, 0);
|
||||
RSSymbol = sym_AddVar(intern("_RS"), 0);
|
||||
RSSymbol->isBuiltin = true;
|
||||
|
||||
sym_AddString("__RGBDS_VERSION__"s, std::make_shared<std::string>(get_package_version_string()))
|
||||
sym_AddString(
|
||||
intern("__RGBDS_VERSION__"), std::make_shared<std::string>(get_package_version_string())
|
||||
)
|
||||
->isBuiltin = true;
|
||||
sym_AddEqu("__RGBDS_MAJOR__"s, PACKAGE_VERSION_MAJOR)->isBuiltin = true;
|
||||
sym_AddEqu("__RGBDS_MINOR__"s, PACKAGE_VERSION_MINOR)->isBuiltin = true;
|
||||
sym_AddEqu("__RGBDS_PATCH__"s, PACKAGE_VERSION_PATCH)->isBuiltin = true;
|
||||
sym_AddEqu(intern("__RGBDS_MAJOR__"), PACKAGE_VERSION_MAJOR)->isBuiltin = true;
|
||||
sym_AddEqu(intern("__RGBDS_MINOR__"), PACKAGE_VERSION_MINOR)->isBuiltin = true;
|
||||
sym_AddEqu(intern("__RGBDS_PATCH__"), PACKAGE_VERSION_PATCH)->isBuiltin = true;
|
||||
#ifdef PACKAGE_VERSION_RC
|
||||
sym_AddEqu("__RGBDS_RC__"s, PACKAGE_VERSION_RC)->isBuiltin = true;
|
||||
sym_AddEqu(intern("__RGBDS_RC__"), PACKAGE_VERSION_RC)->isBuiltin = true;
|
||||
#endif
|
||||
|
||||
// LCOV_EXCL_START
|
||||
@@ -756,7 +765,7 @@ void sym_Init(time_t now) {
|
||||
time_utc
|
||||
);
|
||||
|
||||
Symbol *timeSymbol = &createSymbol("__TIME__"s);
|
||||
Symbol *timeSymbol = &createSymbol(intern("__TIME__"));
|
||||
timeSymbol->type = SYM_EQUS;
|
||||
timeSymbol->data = []() {
|
||||
warning(WARNING_OBSOLETE, "`__TIME__` is deprecated; use `__ISO_8601_LOCAL__`");
|
||||
@@ -764,7 +773,7 @@ void sym_Init(time_t now) {
|
||||
};
|
||||
timeSymbol->isBuiltin = true;
|
||||
|
||||
Symbol *dateSymbol = &createSymbol("__DATE__"s);
|
||||
Symbol *dateSymbol = &createSymbol(intern("__DATE__"));
|
||||
dateSymbol->type = SYM_EQUS;
|
||||
dateSymbol->data = []() {
|
||||
warning(WARNING_OBSOLETE, "`__DATE__` is deprecated; use `__ISO_8601_LOCAL__`");
|
||||
@@ -773,16 +782,18 @@ void sym_Init(time_t now) {
|
||||
dateSymbol->isBuiltin = true;
|
||||
|
||||
sym_AddString(
|
||||
"__ISO_8601_LOCAL__"s, std::make_shared<std::string>(savedTIMESTAMP_ISO8601_LOCAL)
|
||||
intern("__ISO_8601_LOCAL__"), std::make_shared<std::string>(savedTIMESTAMP_ISO8601_LOCAL)
|
||||
)
|
||||
->isBuiltin = true;
|
||||
sym_AddString("__ISO_8601_UTC__"s, std::make_shared<std::string>(savedTIMESTAMP_ISO8601_UTC))
|
||||
sym_AddString(
|
||||
intern("__ISO_8601_UTC__"), std::make_shared<std::string>(savedTIMESTAMP_ISO8601_UTC)
|
||||
)
|
||||
->isBuiltin = true;
|
||||
|
||||
sym_AddEqu("__UTC_YEAR__"s, time_utc->tm_year + 1900)->isBuiltin = true;
|
||||
sym_AddEqu("__UTC_MONTH__"s, time_utc->tm_mon + 1)->isBuiltin = true;
|
||||
sym_AddEqu("__UTC_DAY__"s, time_utc->tm_mday)->isBuiltin = true;
|
||||
sym_AddEqu("__UTC_HOUR__"s, time_utc->tm_hour)->isBuiltin = true;
|
||||
sym_AddEqu("__UTC_MINUTE__"s, time_utc->tm_min)->isBuiltin = true;
|
||||
sym_AddEqu("__UTC_SECOND__"s, time_utc->tm_sec)->isBuiltin = true;
|
||||
sym_AddEqu(intern("__UTC_YEAR__"), time_utc->tm_year + 1900)->isBuiltin = true;
|
||||
sym_AddEqu(intern("__UTC_MONTH__"), time_utc->tm_mon + 1)->isBuiltin = true;
|
||||
sym_AddEqu(intern("__UTC_DAY__"), time_utc->tm_mday)->isBuiltin = true;
|
||||
sym_AddEqu(intern("__UTC_HOUR__"), time_utc->tm_hour)->isBuiltin = true;
|
||||
sym_AddEqu(intern("__UTC_MINUTE__"), time_utc->tm_min)->isBuiltin = true;
|
||||
sym_AddEqu(intern("__UTC_SECOND__"), time_utc->tm_sec)->isBuiltin = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user