diff --git a/include/asm/fstack.hpp b/include/asm/fstack.hpp index 4b58e022..16a6545e 100644 --- a/include/asm/fstack.hpp +++ b/include/asm/fstack.hpp @@ -41,6 +41,9 @@ struct FileStackNode { : type(type_), data(data_){}; std::string const &dump(uint32_t curLineNo) const; + + // If true, entering this context generates a new unique ID. + bool generatesUniqueID() const { return type == NODE_REPT || type == NODE_MACRO; } }; #define DEFAULT_MAX_DEPTH 64 @@ -50,6 +53,7 @@ struct MacroArgs; void fstk_DumpCurrent(); std::shared_ptr fstk_GetFileStack(); +std::shared_ptr fstk_GetUniqueIDStr(); void fstk_AddIncludePath(std::string const &path); void fstk_SetPreIncludeFile(std::string const &path); diff --git a/include/asm/macro.hpp b/include/asm/macro.hpp index 37759a07..e9f0db4a 100644 --- a/include/asm/macro.hpp +++ b/include/asm/macro.hpp @@ -24,11 +24,6 @@ void macro_UseNewArgs(MacroArgs *args); char const *macro_GetArg(uint32_t i); char const *macro_GetAllArgs(); -uint32_t macro_GetUniqueID(); -char const *macro_GetUniqueIDStr(); -void macro_SetUniqueID(uint32_t id); -uint32_t macro_UseNewUniqueID(); -uint32_t macro_UndefUniqueID(); void macro_ShiftCurrentArgs(int32_t count); uint32_t macro_NbArgs(); diff --git a/src/asm/fstack.cpp b/src/asm/fstack.cpp index 70c389f2..2b557be8 100644 --- a/src/asm/fstack.cpp +++ b/src/asm/fstack.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -23,10 +24,17 @@ #include "asm/symbol.hpp" #include "asm/warning.hpp" +using namespace std::literals; + struct Context { std::shared_ptr fileInfo; LexerState lexerState{}; - uint32_t uniqueID = 0; + // If the shared_ptr is empty, `\@` is not permitted for this context. + // Otherwise, if the pointee string is empty, it means that a unique ID has not been requested + // for this context yet, and it should be generated. + // Note that several contexts can share the same unique ID (since `INCLUDE` preserves its + // parent's, and likewise "back-propagates" a unique ID if requested), hence using `shared_ptr`. + std::shared_ptr uniqueIDStr; MacroArgs *macroArgs = nullptr; // Macro args are *saved* here uint32_t nbReptIters = 0; bool isForLoop = false; @@ -99,6 +107,18 @@ std::shared_ptr fstk_GetFileStack() { return contextStack.empty() ? nullptr : contextStack.top().fileInfo; } +std::shared_ptr fstk_GetUniqueIDStr() { + static uint64_t nextUniqueID = 1; + + std::shared_ptr &str = contextStack.top().uniqueIDStr; + + // If a unique ID is allowed but has not been generated yet, generate one now. + if (str && str->empty()) + *str = "_u"s + std::to_string(nextUniqueID++); + + return str; +} + void fstk_AddIncludePath(std::string const &path) { if (path.empty()) return; @@ -187,7 +207,7 @@ bool yywrap() { // If this wasn't the last iteration, wrap instead of popping if (fileInfoIters.front() <= context.nbReptIters) { lexer_RestartRept(context.fileInfo->lineNo); - context.uniqueID = macro_UseNewUniqueID(); + context.uniqueIDStr->clear(); // Invalidate the current unique ID (if any). return false; } } else if (contextStack.size() == 1) { @@ -202,11 +222,6 @@ bool yywrap() { // Restore args if a macro (not REPT) saved them if (oldContext.fileInfo->type == NODE_MACRO) macro_UseNewArgs(contextStack.top().macroArgs); - // Restore the `\@` value if the old context was supposed to define one - // (i.e. it either is a macro or REPT, or it initialized `\@` for its parent) - if (oldContext.fileInfo->type == NODE_REPT || oldContext.fileInfo->type == NODE_MACRO - || contextStack.top().uniqueID > 0) - macro_SetUniqueID(contextStack.top().uniqueID); lexer_SetState(&contextStack.top().lexerState); @@ -220,13 +235,15 @@ static Context &newContext(std::shared_ptr fileInfo) { if (contextStack.size() > maxRecursionDepth) fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth); - // Save the current `\@` value, to be restored when this context ends - contextStack.top().uniqueID = macro_GetUniqueID(); - fileInfo->parent = contextStack.top().fileInfo; fileInfo->lineNo = lexer_GetLineNo(); - return contextStack.emplace(Context{.fileInfo = fileInfo}); + return contextStack.emplace(Context{ + .fileInfo = fileInfo, + .uniqueIDStr = fileInfo->generatesUniqueID() + ? std::make_shared() // Create a new, not-yet-generated ID. + : contextStack.top().uniqueIDStr, // Make a copy. + }); } void fstk_RunInclude(std::string const &path) { @@ -242,17 +259,11 @@ void fstk_RunInclude(std::string const &path) { return; } - uint32_t uniqueID = contextStack.top().uniqueID; - auto fileInfo = std::make_shared(NODE_FILE, *fullPath); Context &context = newContext(fileInfo); if (!lexer_OpenFile(context.lexerState, fileInfo->name())) fatalerror("Failed to set up lexer for file include\n"); lexer_SetStateAtEOL(&context.lexerState); - // We're back at top-level, so most things are reset, - // but not the unique ID, since INCLUDE may be inside a - // MACRO or REPT/FOR loop - context.uniqueID = uniqueID; } // Similar to `fstk_RunInclude`, but not subject to `-MG`, and @@ -272,8 +283,6 @@ static void runPreIncludeFile() { if (!lexer_OpenFile(context.lexerState, fileInfo->name())) fatalerror("Failed to set up lexer for file include\n"); lexer_SetState(&context.lexerState); - // We're back at top-level, so most things are reset - context.uniqueID = macro_UndefUniqueID(); } void fstk_RunMacro(std::string const ¯oName, MacroArgs &args) { @@ -316,7 +325,6 @@ void fstk_RunMacro(std::string const ¯oName, MacroArgs &args) { context.lexerState, "MACRO", macroView->data(), macroView->size(), macro->fileLine ); lexer_SetStateAtEOL(&context.lexerState); - context.uniqueID = macro_UseNewUniqueID(); macro_UseNewArgs(&args); } @@ -336,7 +344,6 @@ static bool newReptContext(int32_t reptLineNo, char const *body, size_t size) { context.fileInfo->lineNo = reptLineNo; lexer_OpenFileView(context.lexerState, "REPT", body, size, reptLineNo); lexer_SetStateAtEOL(&context.lexerState); - context.uniqueID = macro_UseNewUniqueID(); return true; } @@ -414,7 +421,10 @@ void fstk_NewRecursionDepth(size_t newDepth) { } void fstk_Init(std::string const &mainPath, size_t maxDepth) { - Context &context = contextStack.emplace(); + Context &context = contextStack.emplace(Context{ + .fileInfo = nullptr, // We're going to init it just below. + .uniqueIDStr = nullptr, // `\@` is not allowed at top level. + }); if (!lexer_OpenFile(context.lexerState, mainPath)) fatalerror("Failed to open main file\n"); lexer_SetState(&context.lexerState); @@ -424,8 +434,6 @@ void fstk_Init(std::string const &mainPath, size_t maxDepth) { context.fileInfo->parent = nullptr; context.fileInfo->lineNo = 0; // This still gets written to the object file, so init it - context.uniqueID = macro_UndefUniqueID(); - maxRecursionDepth = maxDepth; runPreIncludeFile(); diff --git a/src/asm/lexer.cpp b/src/asm/lexer.cpp index 0969cd6a..eb746cc1 100644 --- a/src/asm/lexer.cpp +++ b/src/asm/lexer.cpp @@ -591,7 +591,8 @@ static char const *readMacroArg(char name) { char const *str = nullptr; if (name == '@') { - str = macro_GetUniqueIDStr(); + auto maybeStr = fstk_GetUniqueIDStr(); + str = maybeStr ? maybeStr->c_str() : nullptr; } else if (name == '#') { str = macro_GetAllArgs(); } else if (name == '<') { diff --git a/src/asm/macro.cpp b/src/asm/macro.cpp index eda6250a..25a3cabc 100644 --- a/src/asm/macro.cpp +++ b/src/asm/macro.cpp @@ -11,10 +11,6 @@ #define MAXMACROARGS 99999 static MacroArgs *macroArgs = nullptr; -static uint32_t uniqueID = 0; -static uint32_t maxUniqueID = 0; -static char uniqueIDBuf[sizeof("_u4294967295")] = {}; // UINT32_MAX -static char *uniqueIDPtr = nullptr; void MacroArgs::append(std::string s) { if (s.empty()) @@ -77,42 +73,6 @@ char const *macro_GetAllArgs() { return str; } -uint32_t macro_GetUniqueID() { - return uniqueID; -} - -char const *macro_GetUniqueIDStr() { - // Generate a new unique ID on the first use of `\@` - if (uniqueID == 0) - macro_SetUniqueID(++maxUniqueID); - - return uniqueIDPtr; -} - -void macro_SetUniqueID(uint32_t id) { - uniqueID = id; - if (id == 0 || id == (uint32_t)-1) { - uniqueIDPtr = nullptr; - } else { - // The buffer is guaranteed to be the correct size - // This is a valid label fragment, but not a valid numeric - sprintf(uniqueIDBuf, "_u%" PRIu32, id); - uniqueIDPtr = uniqueIDBuf; - } -} - -uint32_t macro_UseNewUniqueID() { - // A new ID will be generated on the first use of `\@` - macro_SetUniqueID(0); - return uniqueID; -} - -uint32_t macro_UndefUniqueID() { - // No ID will be generated; use of `\@` is an error - macro_SetUniqueID((uint32_t)-1); - return uniqueID; -} - void macro_ShiftCurrentArgs(int32_t count) { if (!macroArgs) { error("Cannot shift macro arguments outside of a macro\n");