From e9e8915725c19e9b9dfaede13019b64c6d135314 Mon Sep 17 00:00:00 2001 From: Rangi42 Date: Sat, 23 Mar 2024 16:42:28 -0400 Subject: [PATCH] Refactor to keep `lexerState` and `lexerStateEOL` static Also run `clang-format` on everything --- include/asm/fstack.hpp | 7 +- include/asm/lexer.hpp | 22 +--- include/asm/macro.hpp | 1 - src/asm/fstack.cpp | 241 +++++++++++++++++++---------------------- src/asm/lexer.cpp | 87 ++++++++------- src/asm/macro.cpp | 3 +- src/asm/parser.y | 2 +- src/asm/rpn.cpp | 2 +- src/asm/symbol.cpp | 12 +- 9 files changed, 179 insertions(+), 198 deletions(-) diff --git a/include/asm/fstack.hpp b/include/asm/fstack.hpp index 59d7d0a9..62b54860 100644 --- a/include/asm/fstack.hpp +++ b/include/asm/fstack.hpp @@ -24,8 +24,9 @@ struct FileStackNode { data; std::shared_ptr parent; // Pointer to parent node, for error reporting - // Line at which the parent context was exited; meaningless for the root level - uint32_t lineNo; + // Line at which the parent context was exited + // Meaningless at the root level, but gets written to the object file anyway, so init it + uint32_t lineNo = 0; // Set only if referenced: ID within the object file, -1 if not output yet uint32_t ID = -1; @@ -61,7 +62,7 @@ void fstk_SetPreIncludeFile(std::string const &path); std::optional fstk_FindFile(std::string const &path); bool yywrap(); -void fstk_RunInclude(std::string const &path); +void fstk_RunInclude(std::string const &path, bool updateStateNow); void fstk_RunMacro(std::string const ¯oName, std::shared_ptr macroArgs); void fstk_RunRept(uint32_t count, int32_t reptLineNo, char const *body, size_t size); void fstk_RunFor( diff --git a/include/asm/lexer.hpp b/include/asm/lexer.hpp index f1368b67..ebfa81c0 100644 --- a/include/asm/lexer.hpp +++ b/include/asm/lexer.hpp @@ -94,19 +94,14 @@ struct LexerState { LexerState &operator=(LexerState &&) = default; LexerState &operator=(LexerState const &) = delete; + + void setAsCurrentState(); + bool setFileAsNextState(std::string const &filePath, bool updateStateNow); + void setViewAsNextState(char const *filePath, char const *buf, size_t size, uint32_t lineNo_); + + void clear(uint32_t lineNo_); }; -extern LexerState *lexerState; -extern LexerState *lexerStateEOL; - -static inline void lexer_SetState(LexerState *state) { - lexerState = state; -} - -static inline void lexer_SetStateAtEOL(LexerState *state) { - lexerStateEOL = state; -} - extern char binDigits[2]; extern char gfxDigits[4]; @@ -122,11 +117,6 @@ static inline void lexer_SetGfxDigits(char const digits[4]) { gfxDigits[3] = digits[3]; } -// `path` is referenced, but not held onto..! -bool lexer_OpenFile(LexerState &state, std::string const &path); -void lexer_OpenFileView( - LexerState &state, char const *path, char const *buf, size_t size, uint32_t lineNo -); void lexer_RestartRept(uint32_t lineNo); void lexer_Init(); void lexer_SetMode(LexerMode mode); diff --git a/include/asm/macro.hpp b/include/asm/macro.hpp index b1132a51..9cfbde7e 100644 --- a/include/asm/macro.hpp +++ b/include/asm/macro.hpp @@ -20,5 +20,4 @@ struct MacroArgs { void shiftArgs(int32_t count); }; - #endif // RGBDS_MACRO_H diff --git a/src/asm/fstack.cpp b/src/asm/fstack.cpp index 64d5ff76..1cdc5979 100644 --- a/src/asm/fstack.cpp +++ b/src/asm/fstack.cpp @@ -34,7 +34,7 @@ struct Context { // 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; + std::shared_ptr uniqueIDStr = nullptr; std::shared_ptr macroArgs = nullptr; // Macro args are *saved* here uint32_t nbReptIters = 0; bool isForLoop = false; @@ -130,7 +130,6 @@ void fstk_AddIncludePath(std::string const &path) { return; std::string &includePath = includePaths.emplace_back(path); - if (includePath.back() != '/') includePath += '/'; } @@ -151,20 +150,14 @@ static void printDep(std::string const &path) { } } -static bool isPathValid(std::string const &path) { - struct stat statbuf; - - if (stat(path.c_str(), &statbuf) != 0) - return false; - - // Reject directories - return !S_ISDIR(statbuf.st_mode); +static bool isValidFilePath(std::string const &path) { + struct stat statBuf; + return stat(path.c_str(), &statBuf) == 0 && !S_ISDIR(statBuf.st_mode); // Reject directories } std::optional fstk_FindFile(std::string const &path) { - for (std::string &str : includePaths) { - std::string fullPath = str + path; - if (isPathValid(fullPath)) { + for (std::string &incPath : includePaths) { + if (std::string fullPath = incPath + path; isValidFilePath(fullPath)) { printDep(fullPath); return fullPath; } @@ -221,34 +214,114 @@ bool yywrap() { } contextStack.pop(); - lexer_SetState(&contextStack.top().lexerState); + contextStack.top().lexerState.setAsCurrentState(); return false; } -// Make sure not to switch the lexer state before calling this, so the saved line no is correct. -// BE CAREFUL! This modifies the file stack directly, you should have set up the file info first. -// Callers should set `contextStack.top().lexerState` after this so it is not `nullptr`. -static Context &newContext(std::shared_ptr fileInfo) { +static void checkRecursionDepth() { if (contextStack.size() > maxRecursionDepth) fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth); - - fileInfo->parent = contextStack.top().fileInfo; - fileInfo->lineNo = lexer_GetLineNo(); - - 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. - .macroArgs = contextStack.top().macroArgs, - }); } -void fstk_RunInclude(std::string const &path) { +static bool newFileContext(std::string const &filePath, bool updateStateNow) { + checkRecursionDepth(); + + std::shared_ptr uniqueIDStr = nullptr; + std::shared_ptr macroArgs = nullptr; + + auto fileInfo = + std::make_shared(NODE_MACRO, filePath == "-" ? "" : filePath); + if (!contextStack.empty()) { + Context &oldContext = contextStack.top(); + fileInfo->parent = oldContext.fileInfo; + fileInfo->lineNo = lexer_GetLineNo(); // Called before setting the lexer state + uniqueIDStr = oldContext.uniqueIDStr; // Make a copy of the ID + macroArgs = oldContext.macroArgs; + } + + Context &context = contextStack.emplace(Context{ + .fileInfo = fileInfo, + .uniqueIDStr = uniqueIDStr, + .macroArgs = macroArgs, + }); + + return context.lexerState.setFileAsNextState(filePath, updateStateNow); +} + +static void newMacroContext(Symbol const ¯o, std::shared_ptr macroArgs) { + checkRecursionDepth(); + + Context &oldContext = contextStack.top(); + + std::string fileInfoName; + for (FileStackNode const *node = macro.src.get(); node; node = node->parent.get()) { + if (node->type != NODE_REPT) { + fileInfoName.append(node->name()); + break; + } + } + if (macro.src->type == NODE_REPT) { + std::vector const &srcIters = macro.src->iters(); + for (uint32_t i = srcIters.size(); i--;) { + fileInfoName.append("::REPT~"); + fileInfoName.append(std::to_string(srcIters[i])); + } + } + fileInfoName.append("::"); + fileInfoName.append(macro.name); + + auto fileInfo = std::make_shared(NODE_MACRO, fileInfoName); + assert(!contextStack.empty()); // The top level context cannot be a MACRO + fileInfo->parent = oldContext.fileInfo; + fileInfo->lineNo = lexer_GetLineNo(); + + Context &context = contextStack.emplace(Context{ + .fileInfo = fileInfo, + .uniqueIDStr = std::make_shared(), // Create a new, not-yet-generated ID + .macroArgs = macroArgs, + }); + + std::string_view *macroView = macro.getMacro(); + context.lexerState.setViewAsNextState( + "MACRO", macroView->data(), macroView->size(), macro.fileLine + ); +} + +static Context &newReptContext(int32_t reptLineNo, char const *body, size_t size, uint32_t count) { + checkRecursionDepth(); + + Context &oldContext = contextStack.top(); + + std::vector fileInfoIters{1}; + if (oldContext.fileInfo->type == NODE_REPT && !oldContext.fileInfo->iters().empty()) { + // Append all parent iter counts + fileInfoIters.insert(fileInfoIters.end(), RANGE(oldContext.fileInfo->iters())); + } + + auto fileInfo = std::make_shared(NODE_REPT, fileInfoIters); + assert(!contextStack.empty()); // The top level context cannot be a REPT + fileInfo->parent = oldContext.fileInfo; + fileInfo->lineNo = reptLineNo; + + Context &context = contextStack.emplace(Context{ + .fileInfo = fileInfo, + .uniqueIDStr = std::make_shared(), // Create a new, not-yet-generated ID + .macroArgs = oldContext.macroArgs, + }); + + context.lexerState.setViewAsNextState("REPT", body, size, reptLineNo); + + context.nbReptIters = count; + + return context; +} + +void fstk_RunInclude(std::string const &path, bool preInclude) { std::optional fullPath = fstk_FindFile(path); + if (!fullPath) { - if (generatedMissingIncludes) { + if (generatedMissingIncludes && !preInclude) { if (verbose) printf("Aborting (-MG) on INCLUDE file '%s' (%s)\n", path.c_str(), strerror(errno)); failedOnMissingInclude = true; @@ -258,30 +331,8 @@ void fstk_RunInclude(std::string const &path) { return; } - auto fileInfo = std::make_shared(NODE_FILE, *fullPath); - Context &context = newContext(fileInfo); - if (!lexer_OpenFile(context.lexerState, fileInfo->name())) + if (!newFileContext(*fullPath, false)) fatalerror("Failed to set up lexer for file include\n"); - lexer_SetStateAtEOL(&context.lexerState); -} - -// Similar to `fstk_RunInclude`, but not subject to `-MG`, and -// calling `lexer_SetState` instead of `lexer_SetStateAtEOL`. -static void runPreIncludeFile() { - if (preIncludeName.empty()) - return; - - std::optional fullPath = fstk_FindFile(preIncludeName); - if (!fullPath) { - error("Unable to open included file '%s': %s\n", preIncludeName.c_str(), strerror(errno)); - return; - } - - 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_SetState(&context.lexerState); } void fstk_RunMacro(std::string const ¯oName, std::shared_ptr macroArgs) { @@ -296,63 +347,14 @@ void fstk_RunMacro(std::string const ¯oName, std::shared_ptr macr return; } - auto fileInfo = std::make_shared(NODE_MACRO, ""); - - // Print the name... - std::string &fileInfoName = fileInfo->name(); - for (FileStackNode const *node = macro->src.get(); node; node = node->parent.get()) { - if (node->type != NODE_REPT) { - fileInfoName.append(node->name()); - break; - } - } - if (macro->src->type == NODE_REPT) { - std::vector const &srcIters = macro->src->iters(); - - for (uint32_t i = srcIters.size(); i--;) { - fileInfoName.append("::REPT~"); - fileInfoName.append(std::to_string(srcIters[i])); - } - } - fileInfoName.append("::"); - fileInfoName.append(macro->name); - - Context &context = newContext(fileInfo); - std::string_view *macroView = macro->getMacro(); - lexer_OpenFileView( - context.lexerState, "MACRO", macroView->data(), macroView->size(), macro->fileLine - ); - lexer_SetStateAtEOL(&context.lexerState); - context.macroArgs = macroArgs; -} - -static bool newReptContext(int32_t reptLineNo, char const *body, size_t size) { - auto fileInfo = std::make_shared(NODE_REPT, std::vector{1}); - - if (contextStack.top().fileInfo->type == NODE_REPT - && !contextStack.top().fileInfo->iters().empty()) { - // Append all parent iter counts - fileInfo->iters().insert( - fileInfo->iters().end(), RANGE(contextStack.top().fileInfo->iters()) - ); - } - - Context &context = newContext(fileInfo); - // Correct our line number, which currently points to the `ENDR` line - context.fileInfo->lineNo = reptLineNo; - lexer_OpenFileView(context.lexerState, "REPT", body, size, reptLineNo); - lexer_SetStateAtEOL(&context.lexerState); - - return true; + newMacroContext(*macro, macroArgs); } void fstk_RunRept(uint32_t count, int32_t reptLineNo, char const *body, size_t size) { if (count == 0) return; - if (!newReptContext(reptLineNo, body, size)) - return; - contextStack.top().nbReptIters = count; + newReptContext(reptLineNo, body, size, count); } void fstk_RunFor( @@ -364,13 +366,10 @@ void fstk_RunFor( char const *body, size_t size ) { - Symbol *sym = sym_AddVar(symName, start); - - if (sym->type != SYM_VAR) + if (Symbol *sym = sym_AddVar(symName, start); sym->type != SYM_VAR) return; uint32_t count = 0; - if (step > 0 && start < stop) count = ((int64_t)stop - start - 1) / step + 1; else if (step < 0 && stop < start) @@ -385,12 +384,8 @@ void fstk_RunFor( if (count == 0) return; - if (!newReptContext(reptLineNo, body, size)) - return; - Context &context = contextStack.top(); - - context.nbReptIters = count; + Context &context = newReptContext(reptLineNo, body, size, count); context.isForLoop = true; context.forValue = start; context.forStep = step; @@ -398,8 +393,7 @@ void fstk_RunFor( } void fstk_StopRept() { - // Prevent more iterations - contextStack.top().nbReptIters = 0; + contextStack.top().nbReptIters = 0; // Prevent more iterations } bool fstk_Break() { @@ -419,20 +413,11 @@ void fstk_NewRecursionDepth(size_t newDepth) { } void fstk_Init(std::string const &mainPath, size_t maxDepth) { - 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 (!newFileContext(mainPath, true)) fatalerror("Failed to open main file\n"); - lexer_SetState(&context.lexerState); - - context.fileInfo = std::make_shared(NODE_FILE, context.lexerState.path); - // lineNo and nbReptIters are unused on the top-level context - context.fileInfo->parent = nullptr; - context.fileInfo->lineNo = 0; // This still gets written to the object file, so init it maxRecursionDepth = maxDepth; - runPreIncludeFile(); + if (!preIncludeName.empty()) + fstk_RunInclude(preIncludeName, true); } diff --git a/src/asm/lexer.cpp b/src/asm/lexer.cpp index c8c9705e..357f012a 100644 --- a/src/asm/lexer.cpp +++ b/src/asm/lexer.cpp @@ -322,25 +322,27 @@ static bool isWhitespace(int c) { return c == ' ' || c == '\t'; } -LexerState *lexerState = nullptr; -LexerState *lexerStateEOL = nullptr; +static LexerState *lexerState = nullptr; +static LexerState *lexerStateEOL = nullptr; -static void initState(LexerState &state) { - state.mode = LEXER_NORMAL; - state.atLineStart = true; // yylex() will init colNo due to this - state.lastToken = T_(YYEOF); +void LexerState::clear(uint32_t lineNo_) { + mode = LEXER_NORMAL; + atLineStart = true; // yylex() will init colNo due to this + lastToken = T_(YYEOF); - state.ifStack.clear(); + ifStack.clear(); - state.capturing = false; - state.captureBuf = nullptr; + capturing = false; + captureBuf = nullptr; - state.disableMacroArgs = false; - state.disableInterpolation = false; - state.macroArgScanDistance = 0; - state.expandStrings = true; + disableMacroArgs = false; + disableInterpolation = false; + macroArgScanDistance = 0; + expandStrings = true; - state.expansions.clear(); + expansions.clear(); + + lineNo = lineNo_; // Will be incremented at next line start } static void nextLine() { @@ -379,19 +381,23 @@ void lexer_ReachELSEBlock() { lexerState->ifStack.front().reachedElseBlock = true; } -bool lexer_OpenFile(LexerState &state, std::string const &path) { - if (path == "-") { - state.path = ""; - state.content = BufferedLexerState{.fd = STDIN_FILENO, .index = 0, .buf = {}, .nbChars = 0}; +void LexerState::setAsCurrentState() { + lexerState = this; +} + +bool LexerState::setFileAsNextState(std::string const &filePath, bool updateStateNow) { + if (filePath == "-") { + path = ""; + content = BufferedLexerState{.fd = STDIN_FILENO, .index = 0, .buf = {}, .nbChars = 0}; if (verbose) printf("Opening stdin\n"); } else { - struct stat fileInfo; - if (stat(path.c_str(), &fileInfo) != 0) { - error("Failed to stat file \"%s\": %s\n", path.c_str(), strerror(errno)); + struct stat statBuf; + if (stat(filePath.c_str(), &statBuf) != 0) { + error("Failed to stat file \"%s\": %s\n", filePath.c_str(), strerror(errno)); return false; } - state.path = path; + path = filePath; int fd = open(path.c_str(), O_RDONLY); if (fd < 0) { @@ -401,16 +407,16 @@ bool lexer_OpenFile(LexerState &state, std::string const &path) { bool isMmapped = false; - if (fileInfo.st_size > 0) { + if (statBuf.st_size > 0) { // Try using `mmap` for better performance void *mappingAddr; - mapFile(mappingAddr, fd, path, fileInfo.st_size); + mapFile(mappingAddr, fd, path, statBuf.st_size); if (mappingAddr != MAP_FAILED) { close(fd); - state.content = MmappedLexerState{ + content = MmappedLexerState{ .ptr = (char *)mappingAddr, - .size = (size_t)fileInfo.st_size, + .size = (size_t)statBuf.st_size, .offset = 0, .isReferenced = false, }; @@ -422,9 +428,9 @@ bool lexer_OpenFile(LexerState &state, std::string const &path) { if (!isMmapped) { // Sometimes mmap() fails or isn't available, so have a fallback - state.content = BufferedLexerState{.fd = fd, .index = 0, .buf = {}, .nbChars = 0}; + content = BufferedLexerState{.fd = fd, .index = 0, .buf = {}, .nbChars = 0}; if (verbose) { - if (fileInfo.st_size == 0) { + if (statBuf.st_size == 0) { printf("File \"%s\" is empty\n", path.c_str()); } else { printf( @@ -435,18 +441,21 @@ bool lexer_OpenFile(LexerState &state, std::string const &path) { } } - initState(state); - state.lineNo = 0; // Will be incremented at first line start + clear(0); + if (updateStateNow) + lexerState = this; + else + lexerStateEOL = this; return true; } -void lexer_OpenFileView( - LexerState &state, char const *path, char const *buf, size_t size, uint32_t lineNo +void LexerState::setViewAsNextState( + char const *filePath, char const *buf, size_t size, uint32_t lineNo_ ) { - state.path = path; // Used to report read errors in `peekInternal` - state.content = ViewedLexerState{.ptr = buf, .size = size, .offset = 0}; - initState(state); - state.lineNo = lineNo; // Will be incremented at first line start + path = filePath; // Used to report read errors in `peekInternal` + content = ViewedLexerState{.ptr = buf, .size = size, .offset = 0}; + clear(lineNo_); + lexerStateEOL = this; } void lexer_RestartRept(uint32_t lineNo) { @@ -455,8 +464,7 @@ void lexer_RestartRept(uint32_t lineNo) { } else if (auto *view = std::get_if(&lexerState->content); view) { view->offset = 0; } - initState(*lexerState); - lexerState->lineNo = lineNo; + lexerState->clear(lineNo); } LexerState::~LexerState() { @@ -2151,10 +2159,9 @@ finish: yy::parser::symbol_type yylex() { if (lexerState->atLineStart && lexerStateEOL) { - lexer_SetState(lexerStateEOL); + lexerState = lexerStateEOL; lexerStateEOL = nullptr; } - // `lexer_SetState` updates `lexerState`, so check for EOF after it if (lexerState->lastToken == T_(EOB) && yywrap()) return yy::parser::make_YYEOF(); // Newlines read within an expansion should not increase the line count diff --git a/src/asm/macro.cpp b/src/asm/macro.cpp index 8b26d026..f04ec203 100644 --- a/src/asm/macro.cpp +++ b/src/asm/macro.cpp @@ -54,7 +54,8 @@ void MacroArgs::appendArg(std::shared_ptr arg) { } void MacroArgs::shiftArgs(int32_t count) { - if (size_t nbArgs = args.size(); count > 0 && ((uint32_t)count > nbArgs || shift > nbArgs - count)) { + if (size_t nbArgs = args.size(); + count > 0 && ((uint32_t)count > nbArgs || shift > nbArgs - count)) { warning(WARNING_MACRO_SHIFT, "Cannot shift macro arguments past their end\n"); shift = nbArgs; } else if (count < 0 && shift < (uint32_t)-count) { diff --git a/src/asm/parser.y b/src/asm/parser.y index 592bc12c..cacbd2d1 100644 --- a/src/asm/parser.y +++ b/src/asm/parser.y @@ -1128,7 +1128,7 @@ export_list_entry: include: label POP_INCLUDE string endofline { - fstk_RunInclude($3); + fstk_RunInclude($3, false); if (failedOnMissingInclude) YYACCEPT; } diff --git a/src/asm/rpn.cpp b/src/asm/rpn.cpp index 7f9e781d..1a2a2566 100644 --- a/src/asm/rpn.cpp +++ b/src/asm/rpn.cpp @@ -485,7 +485,7 @@ void Expression::makeBinaryOp(RPNCommand op, Expression &&src1, Expression const srcPatchSize = sizeof(bytes); } else { srcBytes = src2.rpn.data(); // Pointer to the right RPN - srcLen = src2.rpn.size(); // Size of the right RPN + srcLen = src2.rpn.size(); // Size of the right RPN srcPatchSize = src2.rpnPatchSize; } // Copy the right RPN and append the operator diff --git a/src/asm/symbol.cpp b/src/asm/symbol.cpp index a722dea9..b6ac6e05 100644 --- a/src/asm/symbol.cpp +++ b/src/asm/symbol.cpp @@ -594,13 +594,11 @@ void sym_Init(time_t now) { sym_AddString("__TIME__"s, std::make_shared(savedTIME))->isBuiltin = true; sym_AddString("__DATE__"s, std::make_shared(savedDATE))->isBuiltin = true; sym_AddString( - "__ISO_8601_LOCAL__"s, - std::make_shared(savedTIMESTAMP_ISO8601_LOCAL) - )->isBuiltin = true; - sym_AddString( - "__ISO_8601_UTC__"s, - std::make_shared(savedTIMESTAMP_ISO8601_UTC) - )->isBuiltin = true; + "__ISO_8601_LOCAL__"s, std::make_shared(savedTIMESTAMP_ISO8601_LOCAL) + ) + ->isBuiltin = true; + sym_AddString("__ISO_8601_UTC__"s, std::make_shared(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;