mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-21 02:32:06 +00:00
Simplify \@ handling by using std::shared_ptr<std::string>
This has been relocated from macro.cpp to fstack.cpp, since both MACRO and REPT/FOR nodes have their own unique `\@` values.
This commit is contained in:
@@ -41,6 +41,9 @@ struct FileStackNode {
|
|||||||
: type(type_), data(data_){};
|
: type(type_), data(data_){};
|
||||||
|
|
||||||
std::string const &dump(uint32_t curLineNo) const;
|
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
|
#define DEFAULT_MAX_DEPTH 64
|
||||||
@@ -50,6 +53,7 @@ struct MacroArgs;
|
|||||||
|
|
||||||
void fstk_DumpCurrent();
|
void fstk_DumpCurrent();
|
||||||
std::shared_ptr<FileStackNode> fstk_GetFileStack();
|
std::shared_ptr<FileStackNode> fstk_GetFileStack();
|
||||||
|
std::shared_ptr<std::string> fstk_GetUniqueIDStr();
|
||||||
|
|
||||||
void fstk_AddIncludePath(std::string const &path);
|
void fstk_AddIncludePath(std::string const &path);
|
||||||
void fstk_SetPreIncludeFile(std::string const &path);
|
void fstk_SetPreIncludeFile(std::string const &path);
|
||||||
|
|||||||
@@ -24,11 +24,6 @@ void macro_UseNewArgs(MacroArgs *args);
|
|||||||
char const *macro_GetArg(uint32_t i);
|
char const *macro_GetArg(uint32_t i);
|
||||||
char const *macro_GetAllArgs();
|
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);
|
void macro_ShiftCurrentArgs(int32_t count);
|
||||||
uint32_t macro_NbArgs();
|
uint32_t macro_NbArgs();
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <memory>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -23,10 +24,17 @@
|
|||||||
#include "asm/symbol.hpp"
|
#include "asm/symbol.hpp"
|
||||||
#include "asm/warning.hpp"
|
#include "asm/warning.hpp"
|
||||||
|
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
std::shared_ptr<FileStackNode> fileInfo;
|
std::shared_ptr<FileStackNode> fileInfo;
|
||||||
LexerState lexerState{};
|
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<std::string> uniqueIDStr;
|
||||||
MacroArgs *macroArgs = nullptr; // Macro args are *saved* here
|
MacroArgs *macroArgs = nullptr; // Macro args are *saved* here
|
||||||
uint32_t nbReptIters = 0;
|
uint32_t nbReptIters = 0;
|
||||||
bool isForLoop = false;
|
bool isForLoop = false;
|
||||||
@@ -99,6 +107,18 @@ std::shared_ptr<FileStackNode> fstk_GetFileStack() {
|
|||||||
return contextStack.empty() ? nullptr : contextStack.top().fileInfo;
|
return contextStack.empty() ? nullptr : contextStack.top().fileInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<std::string> fstk_GetUniqueIDStr() {
|
||||||
|
static uint64_t nextUniqueID = 1;
|
||||||
|
|
||||||
|
std::shared_ptr<std::string> &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) {
|
void fstk_AddIncludePath(std::string const &path) {
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
return;
|
return;
|
||||||
@@ -187,7 +207,7 @@ bool yywrap() {
|
|||||||
// If this wasn't the last iteration, wrap instead of popping
|
// If this wasn't the last iteration, wrap instead of popping
|
||||||
if (fileInfoIters.front() <= context.nbReptIters) {
|
if (fileInfoIters.front() <= context.nbReptIters) {
|
||||||
lexer_RestartRept(context.fileInfo->lineNo);
|
lexer_RestartRept(context.fileInfo->lineNo);
|
||||||
context.uniqueID = macro_UseNewUniqueID();
|
context.uniqueIDStr->clear(); // Invalidate the current unique ID (if any).
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (contextStack.size() == 1) {
|
} else if (contextStack.size() == 1) {
|
||||||
@@ -202,11 +222,6 @@ bool yywrap() {
|
|||||||
// Restore args if a macro (not REPT) saved them
|
// Restore args if a macro (not REPT) saved them
|
||||||
if (oldContext.fileInfo->type == NODE_MACRO)
|
if (oldContext.fileInfo->type == NODE_MACRO)
|
||||||
macro_UseNewArgs(contextStack.top().macroArgs);
|
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);
|
lexer_SetState(&contextStack.top().lexerState);
|
||||||
|
|
||||||
@@ -220,13 +235,15 @@ static Context &newContext(std::shared_ptr<FileStackNode> fileInfo) {
|
|||||||
if (contextStack.size() > maxRecursionDepth)
|
if (contextStack.size() > maxRecursionDepth)
|
||||||
fatalerror("Recursion limit (%zu) exceeded\n", 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->parent = contextStack.top().fileInfo;
|
||||||
fileInfo->lineNo = lexer_GetLineNo();
|
fileInfo->lineNo = lexer_GetLineNo();
|
||||||
|
|
||||||
return contextStack.emplace(Context{.fileInfo = fileInfo});
|
return contextStack.emplace(Context{
|
||||||
|
.fileInfo = fileInfo,
|
||||||
|
.uniqueIDStr = fileInfo->generatesUniqueID()
|
||||||
|
? std::make_shared<std::string>() // Create a new, not-yet-generated ID.
|
||||||
|
: contextStack.top().uniqueIDStr, // Make a copy.
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void fstk_RunInclude(std::string const &path) {
|
void fstk_RunInclude(std::string const &path) {
|
||||||
@@ -242,17 +259,11 @@ void fstk_RunInclude(std::string const &path) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t uniqueID = contextStack.top().uniqueID;
|
|
||||||
|
|
||||||
auto fileInfo = std::make_shared<FileStackNode>(NODE_FILE, *fullPath);
|
auto fileInfo = std::make_shared<FileStackNode>(NODE_FILE, *fullPath);
|
||||||
Context &context = newContext(fileInfo);
|
Context &context = newContext(fileInfo);
|
||||||
if (!lexer_OpenFile(context.lexerState, fileInfo->name()))
|
if (!lexer_OpenFile(context.lexerState, fileInfo->name()))
|
||||||
fatalerror("Failed to set up lexer for file include\n");
|
fatalerror("Failed to set up lexer for file include\n");
|
||||||
lexer_SetStateAtEOL(&context.lexerState);
|
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
|
// Similar to `fstk_RunInclude`, but not subject to `-MG`, and
|
||||||
@@ -272,8 +283,6 @@ static void runPreIncludeFile() {
|
|||||||
if (!lexer_OpenFile(context.lexerState, fileInfo->name()))
|
if (!lexer_OpenFile(context.lexerState, fileInfo->name()))
|
||||||
fatalerror("Failed to set up lexer for file include\n");
|
fatalerror("Failed to set up lexer for file include\n");
|
||||||
lexer_SetState(&context.lexerState);
|
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) {
|
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
|
context.lexerState, "MACRO", macroView->data(), macroView->size(), macro->fileLine
|
||||||
);
|
);
|
||||||
lexer_SetStateAtEOL(&context.lexerState);
|
lexer_SetStateAtEOL(&context.lexerState);
|
||||||
context.uniqueID = macro_UseNewUniqueID();
|
|
||||||
macro_UseNewArgs(&args);
|
macro_UseNewArgs(&args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +344,6 @@ static bool newReptContext(int32_t reptLineNo, char const *body, size_t size) {
|
|||||||
context.fileInfo->lineNo = reptLineNo;
|
context.fileInfo->lineNo = reptLineNo;
|
||||||
lexer_OpenFileView(context.lexerState, "REPT", body, size, reptLineNo);
|
lexer_OpenFileView(context.lexerState, "REPT", body, size, reptLineNo);
|
||||||
lexer_SetStateAtEOL(&context.lexerState);
|
lexer_SetStateAtEOL(&context.lexerState);
|
||||||
context.uniqueID = macro_UseNewUniqueID();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -414,7 +421,10 @@ void fstk_NewRecursionDepth(size_t newDepth) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void fstk_Init(std::string const &mainPath, size_t maxDepth) {
|
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))
|
if (!lexer_OpenFile(context.lexerState, mainPath))
|
||||||
fatalerror("Failed to open main file\n");
|
fatalerror("Failed to open main file\n");
|
||||||
lexer_SetState(&context.lexerState);
|
lexer_SetState(&context.lexerState);
|
||||||
@@ -424,8 +434,6 @@ void fstk_Init(std::string const &mainPath, size_t maxDepth) {
|
|||||||
context.fileInfo->parent = nullptr;
|
context.fileInfo->parent = nullptr;
|
||||||
context.fileInfo->lineNo = 0; // This still gets written to the object file, so init it
|
context.fileInfo->lineNo = 0; // This still gets written to the object file, so init it
|
||||||
|
|
||||||
context.uniqueID = macro_UndefUniqueID();
|
|
||||||
|
|
||||||
maxRecursionDepth = maxDepth;
|
maxRecursionDepth = maxDepth;
|
||||||
|
|
||||||
runPreIncludeFile();
|
runPreIncludeFile();
|
||||||
|
|||||||
@@ -591,7 +591,8 @@ static char const *readMacroArg(char name) {
|
|||||||
char const *str = nullptr;
|
char const *str = nullptr;
|
||||||
|
|
||||||
if (name == '@') {
|
if (name == '@') {
|
||||||
str = macro_GetUniqueIDStr();
|
auto maybeStr = fstk_GetUniqueIDStr();
|
||||||
|
str = maybeStr ? maybeStr->c_str() : nullptr;
|
||||||
} else if (name == '#') {
|
} else if (name == '#') {
|
||||||
str = macro_GetAllArgs();
|
str = macro_GetAllArgs();
|
||||||
} else if (name == '<') {
|
} else if (name == '<') {
|
||||||
|
|||||||
@@ -11,10 +11,6 @@
|
|||||||
#define MAXMACROARGS 99999
|
#define MAXMACROARGS 99999
|
||||||
|
|
||||||
static MacroArgs *macroArgs = nullptr;
|
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) {
|
void MacroArgs::append(std::string s) {
|
||||||
if (s.empty())
|
if (s.empty())
|
||||||
@@ -77,42 +73,6 @@ char const *macro_GetAllArgs() {
|
|||||||
return str;
|
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) {
|
void macro_ShiftCurrentArgs(int32_t count) {
|
||||||
if (!macroArgs) {
|
if (!macroArgs) {
|
||||||
error("Cannot shift macro arguments outside of a macro\n");
|
error("Cannot shift macro arguments outside of a macro\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user