diff --git a/include/asm/lexer.hpp b/include/asm/lexer.hpp index 55c060da..03bc4df5 100644 --- a/include/asm/lexer.hpp +++ b/include/asm/lexer.hpp @@ -4,6 +4,7 @@ #define RGBDS_ASM_LEXER_H #include +#include #include #include #include @@ -31,13 +32,10 @@ enum LexerMode { struct Expansion { std::optional name; - union { - char const *unowned; - char *owned; // Non-`const` only so it can be `delete []`d - } contents; - size_t size; // Length of the contents + std::shared_ptr contents; size_t offset; // Cursor into the contents - bool owned; // Whether or not to free contents when this expansion is freed + + size_t size() const { return contents->size(); } }; struct IfStackEntry { @@ -140,10 +138,6 @@ struct CaptureBody { size_t size; }; -struct String { - char string[MAXSTRLEN + 1]; -}; - void lexer_CheckRecursionDepth(); uint32_t lexer_GetLineNo(); uint32_t lexer_GetColNo(); diff --git a/include/asm/macro.hpp b/include/asm/macro.hpp index e9f0db4a..a758460a 100644 --- a/include/asm/macro.hpp +++ b/include/asm/macro.hpp @@ -3,26 +3,22 @@ #ifndef RGBDS_MACRO_H #define RGBDS_MACRO_H +#include #include -#include #include #include -#include "helpers.hpp" - -#include "asm/warning.hpp" - struct MacroArgs { unsigned int shift; - std::vector args; + std::vector> args; - void append(std::string s); + void append(std::shared_ptr arg); }; MacroArgs *macro_GetCurrentArgs(); void macro_UseNewArgs(MacroArgs *args); -char const *macro_GetArg(uint32_t i); -char const *macro_GetAllArgs(); +std::shared_ptr macro_GetArg(uint32_t i); +std::shared_ptr macro_GetAllArgs(); void macro_ShiftCurrentArgs(int32_t count); uint32_t macro_NbArgs(); diff --git a/include/asm/symbol.hpp b/include/asm/symbol.hpp index 0ceaed6c..ba32c748 100644 --- a/include/asm/symbol.hpp +++ b/include/asm/symbol.hpp @@ -36,10 +36,10 @@ struct Symbol { uint32_t fileLine; // Line where the symbol was defined std::variant< - int32_t, // If isNumeric() - int32_t (*)(), // If isNumeric() and has a callback - std::string_view *, // For SYM_MACRO - std::string * // For SYM_EQUS + int32_t, // If isNumeric() + int32_t (*)(), // If isNumeric() and has a callback + std::string_view *, // For SYM_MACRO + std::shared_ptr // For SYM_EQUS > data; @@ -62,7 +62,7 @@ struct Symbol { int32_t getValue() const; int32_t getOutputValue() const; std::string_view *getMacro() const; - std::string *getEqus() const; + std::shared_ptr getEqus() const; uint32_t getConstantValue() const; }; @@ -90,8 +90,8 @@ Symbol *sym_FindScopedValidSymbol(std::string const &symName); Symbol const *sym_GetPC(); Symbol *sym_AddMacro(std::string const &symName, int32_t defLineNo, char const *body, size_t size); Symbol *sym_Ref(std::string const &symName); -Symbol *sym_AddString(std::string const &symName, char const *value); -Symbol *sym_RedefString(std::string const &symName, char const *value); +Symbol *sym_AddString(std::string const &symName, std::shared_ptr value); +Symbol *sym_RedefString(std::string const &symName, std::shared_ptr value); void sym_Purge(std::string const &symName); void sym_Init(time_t now); diff --git a/src/asm/lexer.cpp b/src/asm/lexer.cpp index 18fd1c8f..303fa8b9 100644 --- a/src/asm/lexer.cpp +++ b/src/asm/lexer.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -95,13 +96,13 @@ static void mapFile(void *&mappingAddr, int fd, std::string const &path, size_t struct Token { int type; - std::variant value; + std::variant value; Token() : type(T_(NUMBER)), value(std::monostate{}) {} Token(int type_) : type(type_), value(std::monostate{}) {} Token(int type_, uint32_t value_) : type(type_), value(value_) {} - Token(int type_, String &value_) : type(type_), value(value_) {} - Token(int type_, std::string &value_) : type(type_), value(value_) {} + Token(int type_, std::string const &value_) : type(type_), value(value_) {} + Token(int type_, std::string &&value_) : type(type_), value(value_) {} }; struct CaseInsensitive { @@ -490,23 +491,15 @@ void lexer_ToggleStringExpansion(bool enable) { // Functions for the actual lexer to obtain characters -static void beginExpansion(char const *str, bool owned, char const *name) { - size_t size = strlen(str); - - // Do not expand empty strings - if (!size) - return; - +static void beginExpansion(std::shared_ptr str, std::optional name) { if (name) lexer_CheckRecursionDepth(); - lexerState->expansions.push_front({ - .name = name ? std::optional(name) : std::nullopt, - .contents = {.unowned = str}, - .size = size, - .offset = 0, - .owned = owned, - }); + // Do not expand empty strings + if (str->empty()) + return; + + lexerState->expansions.push_front({.name = name, .contents = str, .offset = 0}); } void lexer_CheckRecursionDepth() { @@ -514,11 +507,6 @@ void lexer_CheckRecursionDepth() { fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth); } -static void freeExpansion(Expansion &expansion) { - if (expansion.owned) - delete[] expansion.contents.owned; -} - static bool isMacroChar(char c) { return c == '@' || c == '#' || c == '<' || (c >= '0' && c <= '9'); } @@ -587,34 +575,42 @@ static uint32_t readBracketedMacroArgNum() { return num; } -static char const *readMacroArg(char name) { - char const *str = nullptr; - +static std::shared_ptr readMacroArg(char name) { if (name == '@') { - auto maybeStr = fstk_GetUniqueIDStr(); - str = maybeStr ? maybeStr->c_str() : nullptr; + auto str = fstk_GetUniqueIDStr(); + if (!str) { + error("'\\@' cannot be used outside of a macro or REPT/FOR block\n"); + } + return str; } else if (name == '#') { - str = macro_GetAllArgs(); + auto str = macro_GetAllArgs(); + if (!str) { + error("'\\#' cannot be used outside of a macro"); + } + return str; } else if (name == '<') { uint32_t num = readBracketedMacroArgNum(); - - if (num == 0) + if (num == 0) { + // The error was already reported by `readBracketedMacroArgNum`. return nullptr; - str = macro_GetArg(num); - if (!str) + } + + auto str = macro_GetArg(num); + if (!str) { error("Macro argument '\\<%" PRIu32 ">' not defined\n", num); + } return str; } else if (name == '0') { error("Invalid macro argument '\\0'\n"); return nullptr; } else { assert(name > '0' && name <= '9'); - str = macro_GetArg(name - '0'); + auto str = macro_GetArg(name - '0'); + if (!str) { + error("Macro argument '\\%c' not defined\n", name); + } + return str; } - - if (!str) - error("Macro argument '\\%c' not defined\n", name); - return str; } static size_t readInternal(BufferedLexerState &cbuf, size_t bufIndex, size_t nbChars) { @@ -632,12 +628,12 @@ static size_t readInternal(BufferedLexerState &cbuf, size_t bufIndex, size_t nbC // We only need one character of lookahead, for macro arguments static int peekInternal(uint8_t distance) { for (Expansion &exp : lexerState->expansions) { - // An expansion that has reached its end will have `exp->offset` == `exp->size`, + // An expansion that has reached its end will have `exp->offset` == `exp->size()`, // and `peekInternal` will continue with its parent - assert(exp.offset <= exp.size); - if (distance < exp.size - exp.offset) - return exp.contents.unowned[exp.offset + distance]; - distance -= exp.size - exp.offset; + assert(exp.offset <= exp.size()); + if (distance < exp.size() - exp.offset) + return (*exp.contents)[exp.offset + distance]; + distance -= exp.size() - exp.offset; } if (distance >= LEXER_BUF_SIZE) @@ -697,7 +693,7 @@ static int peekInternal(uint8_t distance) { // forward declarations for peek static void shiftChar(); -static char const *readInterpolation(size_t depth); +static std::shared_ptr readInterpolation(size_t depth); static int peek() { int c = peekInternal(0); @@ -714,30 +710,32 @@ static int peek() { if (isMacroChar(c)) { shiftChar(); shiftChar(); - char const *str = readMacroArg(c); - // If the macro arg is invalid or an empty string, it cannot be - // expanded, so skip it and keep peeking. - if (!str || !str[0]) + std::shared_ptr str = readMacroArg(c); + // If the macro arg is invalid or an empty string, it cannot be expanded, + // so skip it and keep peeking. + if (!str || str->empty()) { return peek(); + } - beginExpansion(str, c == '#', nullptr); + beginExpansion(str, std::nullopt); // Assuming macro args can't be recursive (I'll be damned if a way // is found...), then we mark the entire macro arg as scanned. - lexerState->macroArgScanDistance += strlen(str); + lexerState->macroArgScanDistance += str->length(); - c = str[0]; + c = str->front(); } else { c = '\\'; } } else if (c == '{' && !lexerState->disableInterpolation) { // If character is an open brace, do symbol interpolation shiftChar(); - char const *str = readInterpolation(0); - if (str && str[0]) - beginExpansion(str, false, str); + if (auto str = readInterpolation(0); str) { + beginExpansion(str, *str); + } + return peek(); } @@ -758,12 +756,11 @@ restart: // Advance within the current expansion Expansion &expansion = lexerState->expansions.front(); - assert(expansion.offset <= expansion.size); + assert(expansion.offset <= expansion.size()); expansion.offset++; - if (expansion.offset > expansion.size) { - // When advancing would go past an expansion's end, free it, - // move up to its parent, and try again to advance - freeExpansion(expansion); + if (expansion.offset > expansion.size()) { + // When advancing would go past an expansion's end, + // move up to its parent and try again to advance lexerState->expansions.pop_front(); goto restart; } @@ -1124,7 +1121,7 @@ static Token readIdentifier(char firstChar) { // Functions to read strings -static char const *readInterpolation(size_t depth) { +static std::shared_ptr readInterpolation(size_t depth) { if (depth > maxRecursionDepth) fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth); @@ -1142,10 +1139,9 @@ static char const *readInterpolation(size_t depth) { if (c == '{') { // Nested interpolation shiftChar(); - char const *str = readInterpolation(depth + 1); + auto str = readInterpolation(depth + 1); - if (str && str[0]) - beginExpansion(str, false, str); + beginExpansion(str, *str); continue; // Restart, reading from the new buffer } else if (c == EOF || c == '\r' || c == '\n' || c == '"') { error("Missing }\n"); @@ -1175,67 +1171,50 @@ static char const *readInterpolation(size_t depth) { if (!sym) { error("Interpolated symbol \"%s\" does not exist\n", fmtBuf.c_str()); } else if (sym->type == SYM_EQUS) { - static std::string buf; - buf.clear(); - fmt.appendString(buf, *sym->getEqus()); - return buf.c_str(); + auto buf = std::make_shared(); + fmt.appendString(*buf, *sym->getEqus()); + return buf; } else if (sym->isNumeric()) { - static std::string buf; - buf.clear(); - fmt.appendNumber(buf, sym->getConstantValue()); - return buf.c_str(); + auto buf = std::make_shared(); + fmt.appendNumber(*buf, sym->getConstantValue()); + return buf; } else { error("Only numerical and string symbols can be interpolated\n"); } return nullptr; } -#define append_yylval_string(c) \ - do { \ - /* Evaluate c exactly once in case it has side effects */ \ - if (char v = (c); i < sizeof(yylval.string)) \ - yylval.string[i++] = v; \ - } while (0) - -static size_t appendEscapedSubstring(String &yylval, char const *str, size_t i) { - // Copy one extra to flag overflow - while (*str) { - char c = *str++; - +static void appendEscapedSubstring(std::string &yylval, std::string const &str) { + for (char c : str) { // Escape characters that need escaping switch (c) { case '\\': case '"': case '{': - append_yylval_string('\\'); + yylval += '\\'; + // fallthrough + default: + yylval += c; break; case '\n': - append_yylval_string('\\'); - c = 'n'; + yylval += "\\n"; break; case '\r': - append_yylval_string('\\'); - c = 'r'; + yylval += "\\r"; break; case '\t': - append_yylval_string('\\'); - c = 't'; + yylval += "\\t"; break; } - - append_yylval_string(c); } - - return i; } -static void readString(String &yylval, bool raw) { +static std::string readString(bool raw) { lexerState->disableMacroArgs = true; lexerState->disableInterpolation = true; - size_t i = 0; + std::string yylval; bool multiline = false; - char const *str; // We reach this function after reading a single quote, but we also support triple quotes if (peek() == '"') { @@ -1278,7 +1257,7 @@ static void readString(String &yylval, bool raw) { break; shiftChar(); if (peek() != '"') { - append_yylval_string('"'); + yylval += '"'; break; } shiftChar(); @@ -1332,10 +1311,8 @@ static void readString(String &yylval, bool raw) { case '9': case '<': shiftChar(); - str = readMacroArg(c); - if (str) { - while (*str) - append_yylval_string(*str++); + if (auto str = readMacroArg(c); str) { + yylval.append(*str); } continue; // Do not copy an additional character @@ -1357,10 +1334,8 @@ static void readString(String &yylval, bool raw) { // We'll be exiting the string scope, so re-enable expansions // (Not interpolations, since they're handled by the function itself...) lexerState->disableMacroArgs = false; - str = readInterpolation(0); - if (str) { - while (*str) - append_yylval_string(*str++); + if (auto interpolation = readInterpolation(0); interpolation) { + yylval.append(*interpolation); } lexerState->disableMacroArgs = true; continue; // Do not copy an additional character @@ -1368,35 +1343,35 @@ static void readString(String &yylval, bool raw) { // Regular characters will just get copied } - append_yylval_string(c); + yylval += c; } finish: - if (i == sizeof(yylval.string)) { - i--; + if (yylval.length() > MAXSTRLEN) { warning(WARNING_LONG_STR, "String constant too long\n"); + yylval.resize(MAXSTRLEN); } - yylval.string[i] = '\0'; lexerState->disableMacroArgs = false; lexerState->disableInterpolation = false; + + return yylval; } -static size_t appendStringLiteral(String &yylval, size_t i, bool raw) { +static void appendStringLiteral(std::string &yylval, bool raw) { lexerState->disableMacroArgs = true; lexerState->disableInterpolation = true; bool multiline = false; - char const *str; // We reach this function after reading a single quote, but we also support triple quotes - append_yylval_string('"'); + yylval += '"'; if (peek() == '"') { - append_yylval_string('"'); + yylval += '"'; shiftChar(); if (peek() == '"') { // """ begins a multi-line string - append_yylval_string('"'); + yylval += '"'; shiftChar(); multiline = true; } else { @@ -1431,14 +1406,14 @@ static size_t appendStringLiteral(String &yylval, size_t i, bool raw) { // Only """ ends a multi-line string if (peek() != '"') break; - append_yylval_string('"'); + yylval += '"'; shiftChar(); if (peek() != '"') break; - append_yylval_string('"'); + yylval += '"'; shiftChar(); } - append_yylval_string('"'); + yylval += '"'; goto finish; case '\\': // Character escape or macro arg @@ -1455,7 +1430,7 @@ static size_t appendStringLiteral(String &yylval, size_t i, bool raw) { case 'r': case 't': // Return that character unchanged - append_yylval_string('\\'); + yylval += '\\'; shiftChar(); break; @@ -1479,12 +1454,14 @@ static size_t appendStringLiteral(String &yylval, size_t i, bool raw) { case '7': case '8': case '9': - case '<': + case '<': { shiftChar(); - str = readMacroArg(c); - if (str && str[0]) - i = appendEscapedSubstring(yylval, str, i); + auto str = readMacroArg(c); + if (str) { + appendEscapedSubstring(yylval, *str); + } continue; // Do not copy an additional character + } case EOF: // Can't really print that one error("Illegal character escape at end of input\n"); @@ -1504,29 +1481,27 @@ static size_t appendStringLiteral(String &yylval, size_t i, bool raw) { // We'll be exiting the string scope, so re-enable expansions // (Not interpolations, since they're handled by the function itself...) lexerState->disableMacroArgs = false; - str = readInterpolation(0); - if (str && str[0]) - i = appendEscapedSubstring(yylval, str, i); + auto str = readInterpolation(0); + if (str) { + appendEscapedSubstring(yylval, *str); + } lexerState->disableMacroArgs = true; continue; // Do not copy an additional character // Regular characters will just get copied } - append_yylval_string(c); + yylval += c; } finish: - if (i == sizeof(yylval.string)) { - i--; + if (yylval.length() > MAXSTRLEN) { warning(WARNING_LONG_STR, "String constant too long\n"); + yylval.resize(MAXSTRLEN); } - yylval.string[i] = '\0'; lexerState->disableMacroArgs = false; lexerState->disableInterpolation = false; - - return i; } // Lexer core @@ -1749,11 +1724,8 @@ static Token yylex_NORMAL() { // Handle strings - case '"': { - String yylval; - readString(yylval, false); - return Token(T_(STRING), yylval); - } + case '"': + return Token(T_(STRING), readString(false)); // Handle newlines and EOF @@ -1779,9 +1751,7 @@ static Token yylex_NORMAL() { case '#': if (peek() == '"') { shiftChar(); - String yylval; - readString(yylval, true); - return Token(T_(STRING), yylval); + return Token(T_(STRING), readString(true)); } // fallthrough @@ -1809,11 +1779,10 @@ static Token yylex_NORMAL() { Symbol const *sym = sym_FindExactSymbol(std::get(token.value)); if (sym && sym->type == SYM_EQUS) { - char const *str = sym->getEqus()->c_str(); + std::shared_ptr str = sym->getEqus(); assert(str); - if (str[0]) - beginExpansion(str, false, sym->name.c_str()); + beginExpansion(str, sym->name); continue; // Restart, reading from the new buffer } } @@ -1836,9 +1805,8 @@ static Token yylex_NORMAL() { static Token yylex_RAW() { // This is essentially a modified `appendStringLiteral` - String yylval; + std::string yylval; size_t parenDepth = 0; - size_t i = 0; int c; // Trim left whitespace (stops at a block comment) @@ -1865,15 +1833,15 @@ static Token yylex_RAW() { switch (c) { case '"': // String literals inside macro args shiftChar(); - i = appendStringLiteral(yylval, i, false); + appendStringLiteral(yylval, false); break; case '#': // Raw string literals inside macro args - append_yylval_string(c); + yylval += c; shiftChar(); if (peek() == '"') { shiftChar(); - i = appendStringLiteral(yylval, i, true); + appendStringLiteral(yylval, true); } break; @@ -1893,7 +1861,7 @@ static Token yylex_RAW() { discardBlockComment(); continue; } - append_yylval_string(c); // Append the slash + yylval += c; // Append the slash break; case ',': // End of macro arg @@ -1958,21 +1926,20 @@ backslash: default: // Regular characters will just get copied append: - append_yylval_string(c); + yylval += c; shiftChar(); break; } } finish: - if (i == sizeof(yylval.string)) { - i--; + if (yylval.length() > MAXSTRLEN) { warning(WARNING_LONG_STR, "Macro argument too long\n"); + yylval.resize(MAXSTRLEN); } // Trim right whitespace - while (i && isWhitespace(yylval.string[i - 1])) - i--; - yylval.string[i] = '\0'; + auto rightPos = std::find_if_not(yylval.rbegin(), yylval.rend(), isWhitespace); + yylval.resize(rightPos.base() - yylval.begin()); // Returning COMMAs to the parser would mean that two consecutive commas // (i.e. an empty argument) need to return two different tokens (STRING @@ -1989,7 +1956,7 @@ finish: // an empty raw string before it). This will not be treated as a // macro argument. To pass an empty last argument, use a second // trailing comma. - if (i > 0) + if (!yylval.empty()) return Token(T_(STRING), yylval); lexer_SetMode(LEXER_NORMAL); @@ -2002,8 +1969,6 @@ finish: return Token(T_(YYEOF)); } -#undef append_yylval_string - // This function uses the fact that `if`, etc. constructs are only valid when // there's nothing before them on their lines. This enables filtering // "meaningful" (= at line start) vs. "meaningless" (everything else) tokens. @@ -2213,8 +2178,6 @@ yy::parser::symbol_type yylex() { if (auto *numValue = std::get_if(&token.value); numValue) { return yy::parser::symbol_type(token.type, *numValue); - } else if (auto *stringValue = std::get_if(&token.value); stringValue) { - return yy::parser::symbol_type(token.type, *stringValue); } else if (auto *strValue = std::get_if(&token.value); strValue) { return yy::parser::symbol_type(token.type, *strValue); } else { diff --git a/src/asm/macro.cpp b/src/asm/macro.cpp index 25a3cabc..9d10a08e 100644 --- a/src/asm/macro.cpp +++ b/src/asm/macro.cpp @@ -2,22 +2,24 @@ #include "asm/macro.hpp" -#include -#include -#include #include #include +#include + +#include "helpers.hpp" + +#include "asm/warning.hpp" #define MAXMACROARGS 99999 static MacroArgs *macroArgs = nullptr; -void MacroArgs::append(std::string s) { - if (s.empty()) +void MacroArgs::append(std::shared_ptr arg) { + if (arg->empty()) warning(WARNING_EMPTY_MACRO_ARG, "Empty macro argument\n"); if (args.size() == MAXMACROARGS) error("A maximum of " EXPAND_AND_STR(MAXMACROARGS) " arguments is allowed\n"); - args.push_back(s); + args.push_back(arg); } MacroArgs *macro_GetCurrentArgs() { @@ -28,47 +30,41 @@ void macro_UseNewArgs(MacroArgs *args) { macroArgs = args; } -char const *macro_GetArg(uint32_t i) { +std::shared_ptr macro_GetArg(uint32_t i) { if (!macroArgs) return nullptr; uint32_t realIndex = i + macroArgs->shift - 1; - return realIndex >= macroArgs->args.size() ? nullptr : macroArgs->args[realIndex].c_str(); + return realIndex >= macroArgs->args.size() ? nullptr : macroArgs->args[realIndex]; } -char const *macro_GetAllArgs() { +std::shared_ptr macro_GetAllArgs() { if (!macroArgs) return nullptr; size_t nbArgs = macroArgs->args.size(); if (macroArgs->shift >= nbArgs) - return ""; + return std::make_shared(""); size_t len = 0; for (uint32_t i = macroArgs->shift; i < nbArgs; i++) - len += macroArgs->args[i].length() + 1; // 1 for comma + len += macroArgs->args[i]->length() + 1; // 1 for comma - char *str = new (std::nothrow) char[len + 1]; // 1 for '\0' - char *ptr = str; - - if (!str) - fatalerror("Failed to allocate memory for expanding '\\#': %s\n", strerror(errno)); + auto str = std::make_shared(); + str->reserve(len + 1); // 1 for comma for (uint32_t i = macroArgs->shift; i < nbArgs; i++) { - std::string const &arg = macroArgs->args[i]; - size_t n = arg.length(); + auto const &arg = macroArgs->args[i]; - memcpy(ptr, arg.c_str(), n); - ptr += n; + str->append(*arg); // Commas go between args and after a last empty arg - if (i < nbArgs - 1 || n == 0) - *ptr++ = ','; // no space after comma + if (i < nbArgs - 1 || arg->empty()) + str->push_back(','); // no space after comma } - *ptr = '\0'; return str; } diff --git a/src/asm/main.cpp b/src/asm/main.cpp index c91d6231..ce3c27d5 100644 --- a/src/asm/main.cpp +++ b/src/asm/main.cpp @@ -2,13 +2,8 @@ #include "asm/main.hpp" -#include -#include -#include -#include #include -#include -#include +#include #include #include #include @@ -19,13 +14,9 @@ #include "version.hpp" #include "asm/charmap.hpp" -#include "asm/fixpoint.hpp" -#include "asm/format.hpp" #include "asm/fstack.hpp" -#include "asm/lexer.hpp" #include "asm/opt.hpp" #include "asm/output.hpp" -#include "asm/rpn.hpp" #include "asm/symbol.hpp" #include "asm/warning.hpp" @@ -186,9 +177,9 @@ int main(int argc, char *argv[]) { equals = strchr(musl_optarg, '='); if (equals) { *equals = '\0'; - sym_AddString(musl_optarg, equals + 1); + sym_AddString(musl_optarg, std::make_shared(equals + 1)); } else { - sym_AddString(musl_optarg, "1"); + sym_AddString(musl_optarg, std::make_shared("1")); } break; diff --git a/src/asm/parser.y b/src/asm/parser.y index b3e5dda9..d2feec93 100644 --- a/src/asm/parser.y +++ b/src/asm/parser.y @@ -6,16 +6,13 @@ %code requires { #include - #include #include #include #include - #include "asm/format.hpp" - #include "asm/lexer.hpp" #include "asm/macro.hpp" #include "asm/rpn.hpp" - #include "asm/symbol.hpp" + #include "asm/section.hpp" #include "linkdefs.hpp" @@ -48,6 +45,7 @@ #include #include #include + #include #include #include #include @@ -56,12 +54,14 @@ #include "asm/charmap.hpp" #include "asm/fixpoint.hpp" + #include "asm/format.hpp" #include "asm/fstack.hpp" + #include "asm/lexer.hpp" #include "asm/main.hpp" #include "asm/opt.hpp" #include "asm/output.hpp" #include "asm/section.hpp" - #include "util.hpp" + #include "asm/symbol.hpp" #include "asm/warning.hpp" #include "extern/utf8decoder.hpp" @@ -129,7 +129,7 @@ %type sect_attrs %token NUMBER "number" -%token STRING "string" +%token STRING "string" %token PERIOD "." %token COMMA "," @@ -524,7 +524,7 @@ macro_args: } | macro_args STRING { $$ = $1; - $$->append($2.string); + $$->append(std::make_shared($2)); } ; @@ -663,7 +663,7 @@ equs: $1.c_str(), $1.c_str() ); - sym_AddString($1, $3.c_str()); + sym_AddString($1, std::make_shared($3)); } ; @@ -757,7 +757,7 @@ opt_list: opt_list_entry: STRING { - opt_Parse($1.string); + opt_Parse($1.c_str()); } ; @@ -1077,13 +1077,13 @@ def_rl: def_equs: def_id POP_EQUS string { - sym_AddString($1, $3.c_str()); + sym_AddString($1, std::make_shared($3)); } ; redef_equs: redef_id POP_EQUS string { - sym_RedefString($1, $3.c_str()); + sym_RedefString($1, std::make_shared($3)); } ; @@ -1553,7 +1553,7 @@ opt_q_arg: string: STRING { - $$ = $1.string; + $$ = std::move($1); } | OP_STRSUB LPAREN string COMMA const COMMA uconst RPAREN { size_t len = strlenUTF8($3); @@ -2655,19 +2655,16 @@ static std::string strfmt( ) { std::string str; size_t argIndex = 0; - char const *ptr = spec.c_str(); - while (str.length() <= MAXSTRLEN) { - int c = *ptr++; + for (size_t i = 0; spec[i] != '\0' && str.length() <= MAXSTRLEN; ++i) { + int c = spec[i]; - if (c == '\0') { - break; - } else if (c != '%') { + if (c != '%') { str += c; continue; } - c = *ptr++; + c = spec[++i]; if (c == '%') { str += c; @@ -2680,7 +2677,7 @@ static std::string strfmt( fmt.useCharacter(c); if (fmt.isFinished()) break; - c = *ptr++; + c = spec[++i]; } if (fmt.isEmpty()) { diff --git a/src/asm/symbol.cpp b/src/asm/symbol.cpp index 49f2e068..2e0bc798 100644 --- a/src/asm/symbol.cpp +++ b/src/asm/symbol.cpp @@ -79,9 +79,9 @@ std::string_view *Symbol::getMacro() const { return std::get(data); } -std::string *Symbol::getEqus() const { - assert(std::holds_alternative(data)); - return std::get(data); +std::shared_ptr Symbol::getEqus() const { + assert(std::holds_alternative>(data)); + return std::get>(data); } static void dumpFilename(Symbol const &sym) { @@ -121,14 +121,6 @@ static Symbol &createSymbol(std::string const &symName) { return sym; } -static void assignStringSymbol(Symbol &sym, char const *value) { - std::string *equs = new (std::nothrow) std::string(value); - if (!equs) - fatalerror("No memory for string equate: %s\n", strerror(errno)); - sym.type = SYM_EQUS; - sym.data = equs; -} - Symbol *sym_FindExactSymbol(std::string const &symName) { auto search = symbols.find(symName); return search != symbols.end() ? &search->second : nullptr; @@ -310,21 +302,22 @@ Symbol *sym_RedefEqu(std::string const &symName, int32_t value) { * of the string are enough: sym_AddString("M_PI"s, "3.1415"). This is the same * as ``` M_PI EQUS "3.1415" ``` */ -Symbol *sym_AddString(std::string const &symName, char const *value) { +Symbol *sym_AddString(std::string const &symName, std::shared_ptr str) { Symbol *sym = createNonrelocSymbol(symName, false); if (!sym) return nullptr; - assignStringSymbol(*sym, value); + sym->type = SYM_EQUS; + sym->data = str; return sym; } -Symbol *sym_RedefString(std::string const &symName, char const *value) { +Symbol *sym_RedefString(std::string const &symName, std::shared_ptr str) { Symbol *sym = sym_FindExactSymbol(symName); if (!sym) - return sym_AddString(symName, value); + return sym_AddString(symName, str); if (sym->type != SYM_EQUS) { if (sym->isDefined()) @@ -339,9 +332,7 @@ Symbol *sym_RedefString(std::string const &symName, char const *value) { } updateSymbolFilename(*sym); - // FIXME: this leaks the previous `sym->getEqus()`, but this can't delete it because the - // expansion may be redefining itself. - assignStringSymbol(*sym, value); + sym->data = str; return sym; } @@ -564,7 +555,8 @@ void sym_Init(time_t now) { _RSSymbol = sym_AddVar("_RS"s, 0); _RSSymbol->isBuiltin = true; - sym_AddString("__RGBDS_VERSION__"s, get_package_version_string())->isBuiltin = true; + sym_AddString("__RGBDS_VERSION__"s, std::make_shared(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; @@ -598,10 +590,16 @@ void sym_Init(time_t now) { time_utc ); - sym_AddString("__TIME__"s, savedTIME)->isBuiltin = true; - sym_AddString("__DATE__"s, savedDATE)->isBuiltin = true; - sym_AddString("__ISO_8601_LOCAL__"s, savedTIMESTAMP_ISO8601_LOCAL)->isBuiltin = true; - sym_AddString("__ISO_8601_UTC__"s, savedTIMESTAMP_ISO8601_UTC)->isBuiltin = true; + 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; sym_AddEqu("__UTC_YEAR__"s, time_utc->tm_year + 1900)->isBuiltin = true; sym_AddEqu("__UTC_MONTH__"s, time_utc->tm_mon + 1)->isBuiltin = true; diff --git a/test/asm/unique-id.err b/test/asm/unique-id.err index aacac297..1cd180b7 100644 --- a/test/asm/unique-id.err +++ b/test/asm/unique-id.err @@ -23,7 +23,7 @@ warning: unique-id.asm(14) -> unique-id.asm::m(8): [-Wuser] _u4! while expanding symbol "warn_unique" error: unique-id.asm(15): - Macro argument '\@' not defined + '\@' cannot be used outside of a macro or REPT/FOR block while expanding symbol "warn_unique" warning: unique-id.asm(15): [-Wuser] !