Use std::shared_ptr<std::string> for lexed/parsed strings

This commit is contained in:
ISSOtm
2024-03-17 15:32:46 -04:00
committed by Sylvie
parent 412073774c
commit 9f239f6dcc
9 changed files with 199 additions and 264 deletions

View File

@@ -4,6 +4,7 @@
#define RGBDS_ASM_LEXER_H
#include <deque>
#include <memory>
#include <optional>
#include <stdint.h>
#include <string>
@@ -31,13 +32,10 @@ enum LexerMode {
struct Expansion {
std::optional<std::string> 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<std::string> 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();

View File

@@ -3,26 +3,22 @@
#ifndef RGBDS_MACRO_H
#define RGBDS_MACRO_H
#include <memory>
#include <stdint.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include "helpers.hpp"
#include "asm/warning.hpp"
struct MacroArgs {
unsigned int shift;
std::vector<std::string> args;
std::vector<std::shared_ptr<std::string>> args;
void append(std::string s);
void append(std::shared_ptr<std::string> arg);
};
MacroArgs *macro_GetCurrentArgs();
void macro_UseNewArgs(MacroArgs *args);
char const *macro_GetArg(uint32_t i);
char const *macro_GetAllArgs();
std::shared_ptr<std::string> macro_GetArg(uint32_t i);
std::shared_ptr<std::string> macro_GetAllArgs();
void macro_ShiftCurrentArgs(int32_t count);
uint32_t macro_NbArgs();

View File

@@ -39,7 +39,7 @@ struct Symbol {
int32_t, // If isNumeric()
int32_t (*)(), // If isNumeric() and has a callback
std::string_view *, // For SYM_MACRO
std::string * // For SYM_EQUS
std::shared_ptr<std::string> // 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<std::string> 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<std::string> value);
Symbol *sym_RedefString(std::string const &symName, std::shared_ptr<std::string> value);
void sym_Purge(std::string const &symName);
void sym_Init(time_t now);

View File

@@ -5,6 +5,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <algorithm>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
@@ -95,13 +96,13 @@ static void mapFile(void *&mappingAddr, int fd, std::string const &path, size_t
struct Token {
int type;
std::variant<std::monostate, uint32_t, String, std::string> value;
std::variant<std::monostate, uint32_t, std::string> 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<std::string> str, std::optional<std::string> name) {
if (name)
lexer_CheckRecursionDepth();
lexerState->expansions.push_front({
.name = name ? std::optional<std::string>(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,35 +575,43 @@ static uint32_t readBracketedMacroArgNum() {
return num;
}
static char const *readMacroArg(char name) {
char const *str = nullptr;
static std::shared_ptr<std::string> 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');
}
if (!str)
auto str = macro_GetArg(name - '0');
if (!str) {
error("Macro argument '\\%c' not defined\n", name);
}
return str;
}
}
static size_t readInternal(BufferedLexerState &cbuf, size_t bufIndex, size_t nbChars) {
// This buffer overflow made me lose WEEKS of my life. Never again.
@@ -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<std::string> 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<std::string> 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<std::string> 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<std::string>();
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<std::string>();
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<std::string>(token.value));
if (sym && sym->type == SYM_EQUS) {
char const *str = sym->getEqus()->c_str();
std::shared_ptr<std::string> 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<uint32_t>(&token.value); numValue) {
return yy::parser::symbol_type(token.type, *numValue);
} else if (auto *stringValue = std::get_if<String>(&token.value); stringValue) {
return yy::parser::symbol_type(token.type, *stringValue);
} else if (auto *strValue = std::get_if<std::string>(&token.value); strValue) {
return yy::parser::symbol_type(token.type, *strValue);
} else {

View File

@@ -2,22 +2,24 @@
#include "asm/macro.hpp"
#include <errno.h>
#include <inttypes.h>
#include <new>
#include <stdio.h>
#include <string.h>
#include <string>
#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<std::string> 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<std::string> 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<std::string> macro_GetAllArgs() {
if (!macroArgs)
return nullptr;
size_t nbArgs = macroArgs->args.size();
if (macroArgs->shift >= nbArgs)
return "";
return std::make_shared<std::string>("");
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<std::string>();
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;
}

View File

@@ -2,13 +2,8 @@
#include "asm/main.hpp"
#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <stdarg.h>
#include <memory>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -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<std::string>(equals + 1));
} else {
sym_AddString(musl_optarg, "1");
sym_AddString(musl_optarg, std::make_shared<std::string>("1"));
}
break;

View File

@@ -6,16 +6,13 @@
%code requires {
#include <stdint.h>
#include <inttypes.h>
#include <string>
#include <variant>
#include <vector>
#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 <algorithm>
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <new>
#include <stdio.h>
#include <stdlib.h>
@@ -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 <SectionSpec> sect_attrs
%token <int32_t> NUMBER "number"
%token <String> STRING "string"
%token <std::string> STRING "string"
%token PERIOD "."
%token COMMA ","
@@ -524,7 +524,7 @@ macro_args:
}
| macro_args STRING {
$$ = $1;
$$->append($2.string);
$$->append(std::make_shared<std::string>($2));
}
;
@@ -663,7 +663,7 @@ equs:
$1.c_str(),
$1.c_str()
);
sym_AddString($1, $3.c_str());
sym_AddString($1, std::make_shared<std::string>($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<std::string>($3));
}
;
redef_equs:
redef_id POP_EQUS string {
sym_RedefString($1, $3.c_str());
sym_RedefString($1, std::make_shared<std::string>($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()) {

View File

@@ -79,9 +79,9 @@ std::string_view *Symbol::getMacro() const {
return std::get<std::string_view *>(data);
}
std::string *Symbol::getEqus() const {
assert(std::holds_alternative<std::string *>(data));
return std::get<std::string *>(data);
std::shared_ptr<std::string> Symbol::getEqus() const {
assert(std::holds_alternative<std::shared_ptr<std::string>>(data));
return std::get<std::shared_ptr<std::string>>(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<std::string> 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<std::string> 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<std::string>(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<std::string>(savedTIME))->isBuiltin = true;
sym_AddString("__DATE__"s, std::make_shared<std::string>(savedDATE))->isBuiltin = true;
sym_AddString(
"__ISO_8601_LOCAL__"s,
std::make_shared<std::string>(savedTIMESTAMP_ISO8601_LOCAL)
)->isBuiltin = true;
sym_AddString(
"__ISO_8601_UTC__"s,
std::make_shared<std::string>(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;

View File

@@ -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]
!