mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Simplify toggling of enabling/disabling expansions
This commit is contained in:
@@ -92,9 +92,8 @@ struct LexerState {
|
|||||||
size_t captureSize; // Amount of text captured
|
size_t captureSize; // Amount of text captured
|
||||||
std::shared_ptr<std::vector<char>> captureBuf; // Buffer to send the captured text to if set
|
std::shared_ptr<std::vector<char>> captureBuf; // Buffer to send the captured text to if set
|
||||||
|
|
||||||
bool disableMacroArgs;
|
bool disableExpansions;
|
||||||
bool disableInterpolation;
|
size_t expansionScanDistance; // Max distance already scanned for expansions
|
||||||
size_t macroArgScanDistance; // Max distance already scanned for macro args
|
|
||||||
bool expandStrings;
|
bool expandStrings;
|
||||||
std::deque<Expansion> expansions; // Front is the innermost current expansion
|
std::deque<Expansion> expansions; // Front is the innermost current expansion
|
||||||
|
|
||||||
|
|||||||
@@ -272,9 +272,8 @@ void LexerState::clear(uint32_t lineNo_) {
|
|||||||
capturing = false;
|
capturing = false;
|
||||||
captureBuf = nullptr;
|
captureBuf = nullptr;
|
||||||
|
|
||||||
disableMacroArgs = false;
|
disableExpansions = false;
|
||||||
disableInterpolation = false;
|
expansionScanDistance = 0;
|
||||||
macroArgScanDistance = 0;
|
|
||||||
expandStrings = true;
|
expandStrings = true;
|
||||||
|
|
||||||
expansions.clear();
|
expansions.clear();
|
||||||
@@ -517,13 +516,10 @@ static int nextChar();
|
|||||||
static uint32_t readDecimalNumber(int initial);
|
static uint32_t readDecimalNumber(int initial);
|
||||||
|
|
||||||
static uint32_t readBracketedMacroArgNum() {
|
static uint32_t readBracketedMacroArgNum() {
|
||||||
bool disableMacroArgs = lexerState->disableMacroArgs;
|
bool disableExpansions = lexerState->disableExpansions;
|
||||||
bool disableInterpolation = lexerState->disableInterpolation;
|
lexerState->disableExpansions = false;
|
||||||
lexerState->disableMacroArgs = false;
|
|
||||||
lexerState->disableInterpolation = false;
|
|
||||||
Defer restoreExpansions{[&] {
|
Defer restoreExpansions{[&] {
|
||||||
lexerState->disableMacroArgs = disableMacroArgs;
|
lexerState->disableExpansions = disableExpansions;
|
||||||
lexerState->disableInterpolation = disableInterpolation;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
int32_t num = 0;
|
int32_t num = 0;
|
||||||
@@ -713,15 +709,17 @@ static std::shared_ptr<std::string> readInterpolation(size_t depth);
|
|||||||
static int peek() {
|
static int peek() {
|
||||||
int c = lexerState->peekChar();
|
int c = lexerState->peekChar();
|
||||||
|
|
||||||
if (lexerState->macroArgScanDistance > 0) {
|
if (lexerState->expansionScanDistance > 0) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
++lexerState->macroArgScanDistance; // Do not consider again
|
++lexerState->expansionScanDistance; // Do not consider again
|
||||||
|
|
||||||
if (c == '\\' && !lexerState->disableMacroArgs) {
|
if (lexerState->disableExpansions) {
|
||||||
|
return c;
|
||||||
|
} else if (c == '\\') {
|
||||||
// If character is a backslash, check for a macro arg
|
// If character is a backslash, check for a macro arg
|
||||||
++lexerState->macroArgScanDistance;
|
++lexerState->expansionScanDistance;
|
||||||
if (!isMacroChar(lexerState->peekCharAhead())) {
|
if (!isMacroChar(lexerState->peekCharAhead())) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@@ -734,11 +732,11 @@ static int peek() {
|
|||||||
// Mark the entire macro arg expansion as "painted blue"
|
// Mark the entire macro arg expansion as "painted blue"
|
||||||
// so that macro args can't be recursive
|
// so that macro args can't be recursive
|
||||||
// https://en.wikipedia.org/wiki/Painted_blue
|
// https://en.wikipedia.org/wiki/Painted_blue
|
||||||
lexerState->macroArgScanDistance += str->length();
|
lexerState->expansionScanDistance += str->length();
|
||||||
}
|
}
|
||||||
|
|
||||||
return peek(); // Tail recursion
|
return peek(); // Tail recursion
|
||||||
} else if (c == '{' && !lexerState->disableInterpolation) {
|
} else if (c == '{') {
|
||||||
// If character is an open brace, do symbol interpolation
|
// If character is an open brace, do symbol interpolation
|
||||||
shiftChar();
|
shiftChar();
|
||||||
if (std::shared_ptr<std::string> str = readInterpolation(0); str) {
|
if (std::shared_ptr<std::string> str = readInterpolation(0); str) {
|
||||||
@@ -759,7 +757,7 @@ static void shiftChar() {
|
|||||||
++lexerState->captureSize;
|
++lexerState->captureSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
--lexerState->macroArgScanDistance;
|
--lexerState->expansionScanDistance;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!lexerState->expansions.empty()) {
|
if (!lexerState->expansions.empty()) {
|
||||||
@@ -811,11 +809,9 @@ static void handleCRLF(int c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static auto scopedDisableExpansions() {
|
static auto scopedDisableExpansions() {
|
||||||
lexerState->disableMacroArgs = true;
|
lexerState->disableExpansions = true;
|
||||||
lexerState->disableInterpolation = true;
|
|
||||||
return Defer{[&] {
|
return Defer{[&] {
|
||||||
lexerState->disableMacroArgs = false;
|
lexerState->disableExpansions = false;
|
||||||
lexerState->disableInterpolation = false;
|
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1217,21 +1213,19 @@ static std::shared_ptr<std::string> readInterpolation(size_t depth) {
|
|||||||
std::string fmtBuf;
|
std::string fmtBuf;
|
||||||
FormatSpec fmt{};
|
FormatSpec fmt{};
|
||||||
|
|
||||||
// In a context where `lexerState->disableInterpolation` is true, `peek` will expand
|
for (;;) {
|
||||||
// nested interpolations itself, which can lead to stack overflow. This lets
|
// If `lexerState->disableExpansions` is false, `peek()` will expand nested interpolations
|
||||||
// `readInterpolation` handle its own nested expansions, increasing `depth` each time.
|
// and recursively call `readInterpolation()`, which can cause stack overflow.
|
||||||
bool disableInterpolation = lexerState->disableInterpolation;
|
// `lexerState->peekChar()` lets `readInterpolation()` handle its own nested expansions,
|
||||||
lexerState->disableInterpolation = true;
|
// increasing `depth` each time.
|
||||||
|
if (lexerState->peekChar() == '{') {
|
||||||
// Reset `lexerState->disableInterpolation` when exiting this loop
|
++lexerState->expansionScanDistance; // Prevent `shiftChar()` from calling `peek()`
|
||||||
for (Defer reset{[&] { lexerState->disableInterpolation = disableInterpolation; }};;) {
|
|
||||||
if (int c = peek(); c == '{') { // Nested interpolation
|
|
||||||
shiftChar();
|
shiftChar();
|
||||||
if (std::shared_ptr<std::string> str = readInterpolation(depth + 1); str) {
|
if (std::shared_ptr<std::string> str = readInterpolation(depth + 1); str) {
|
||||||
beginExpansion(str, *str);
|
beginExpansion(str, *str);
|
||||||
}
|
}
|
||||||
continue; // Restart, reading from the new buffer
|
continue; // Restart, reading from the new buffer
|
||||||
} else if (c == EOF || c == '\r' || c == '\n' || c == '"') {
|
} else if (int c = peek(); c == EOF || c == '\r' || c == '\n' || c == '"') {
|
||||||
error("Missing }");
|
error("Missing }");
|
||||||
break;
|
break;
|
||||||
} else if (c == '}') {
|
} else if (c == '}') {
|
||||||
@@ -1329,12 +1323,11 @@ static void appendCharInLiteral(std::string &str, int c) {
|
|||||||
// Symbol interpolation
|
// Symbol interpolation
|
||||||
if (c == '{') {
|
if (c == '{') {
|
||||||
// We'll be exiting the string/character scope, so re-enable expansions
|
// We'll be exiting the string/character scope, so re-enable expansions
|
||||||
// (Not interpolations, since they're handled by the function itself...)
|
lexerState->disableExpansions = false;
|
||||||
lexerState->disableMacroArgs = false;
|
|
||||||
if (std::shared_ptr<std::string> interpolation = readInterpolation(0); interpolation) {
|
if (std::shared_ptr<std::string> interpolation = readInterpolation(0); interpolation) {
|
||||||
appendExpandedString(str, *interpolation);
|
appendExpandedString(str, *interpolation);
|
||||||
}
|
}
|
||||||
lexerState->disableMacroArgs = true;
|
lexerState->disableExpansions = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user