Intern strings used as identifiers (for labels, constants, macros, charmaps, etc) (#1980)

This commit is contained in:
Rangi
2026-05-25 16:22:29 -04:00
committed by GitHub
parent ed19806434
commit cfa0adf295
22 changed files with 341 additions and 218 deletions
+1
View File
@@ -65,6 +65,7 @@ rgbasm_obj := \
src/asm/fixpoint.o \
src/asm/format.o \
src/asm/fstack.o \
src/asm/intern.o \
src/asm/lexer.o \
src/asm/macro.o \
src/asm/main.o \
+3
View File
@@ -180,6 +180,9 @@ These files have been copied ("vendored") from external authors and adapted for
- **`fstack.cpp`:**
Functions and data related to "fstack" nodes (the contents of top-level or `INCLUDE`d files, macro expansions, or `REPT`/`FOR` loop iterations) and their "contexts" (metadata that is only relevant while a node's content is being lexed and parsed).
This file *owns* the `Context`s in its `contextStack` collection. Each of those `Context`s *owns* its `LexerState`, and *refers* to its `FileStackNode`, `uniqueIDStr`, and `macroArgs`. Each `FileStackNode` also *references* its `parent`.
- **`intern.cpp`:**
[Interned strings](https://en.wikipedia.org/wiki/String_interning), which are used for the names of keywords, symbols (labels, constants, variables, string constants, macros, etc), and charmaps.
This file *owns* the strings in its `internedStrings` collection, which its `internedIndexes` collection *references* by view and index.
- **`lexer.cpp`:**
Functions and data related to [lexing](https://en.wikipedia.org/wiki/Lexical_analysis) assembly source code into tokens, which can then be parsed.
This file maintains static `lexerState` and `lexerStateEOL` pointers to `LexerState`s from the `Context`s in `fstack.cpp`.
+4 -3
View File
@@ -13,7 +13,8 @@
#include "linkdefs.hpp" // AssertionType, RPNCommand
#include "asm/rpn.hpp" // Expression
#include "asm/intern.hpp" // InternedStr
#include "asm/rpn.hpp" // Expression
struct AlignmentSpec {
uint8_t alignment;
@@ -54,8 +55,8 @@ std::string act_StringFormat(
std::string const &spec, std::vector<std::variant<uint32_t, std::string>> const &args
);
std::string act_SectionName(std::string const &symName);
std::string act_SectionName(InternedStr symName);
void act_CompoundAssignment(std::string const &symName, RPNCommand op, int32_t constValue);
void act_CompoundAssignment(InternedStr symName, RPNCommand op, int32_t constValue);
#endif // RGBDS_ASM_ACTIONS_HPP
+5 -4
View File
@@ -10,13 +10,14 @@
#include <string_view>
#include <vector>
#include "asm/intern.hpp"
void charmap_Init();
bool charmap_ForEach(
void (*mapFunc)(std::string const &),
void (*charFunc)(std::string const &, std::vector<int32_t>)
void (*mapFunc)(InternedStr), void (*charFunc)(std::string const &, std::vector<int32_t>)
);
void charmap_New(std::string const &name, std::string const *baseName);
void charmap_Set(std::string const &name);
void charmap_New(InternedStr name, InternedStr const *baseName);
void charmap_Set(InternedStr name);
void charmap_Push();
void charmap_Pop();
void charmap_CheckStack();
+3 -4
View File
@@ -15,6 +15,7 @@
#include "linkdefs.hpp"
#include "asm/intern.hpp"
#include "asm/lexer.hpp"
struct FileStackNode {
@@ -68,12 +69,10 @@ bool fstk_FailedOnMissingInclude();
bool yywrap();
bool fstk_RunInclude(std::string const &path, bool isQuiet);
void fstk_RunMacro(
std::string const &macroName, std::shared_ptr<MacroArgs> macroArgs, bool isQuiet
);
void fstk_RunMacro(InternedStr macroName, std::shared_ptr<MacroArgs> macroArgs, bool isQuiet);
void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span, bool isQuiet);
void fstk_RunFor(
std::string const &symName,
InternedStr symName,
int32_t start,
int32_t stop,
int32_t step,
+34
View File
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: MIT
#ifndef RGBDS_ASM_INTERN_HPP
#define RGBDS_ASM_INTERN_HPP
#include <stddef.h>
#include <string>
#include <string_view>
#include <utility> // hash
class InternedStr {
size_t index;
public:
constexpr InternedStr() : index(static_cast<size_t>(-1)) {}
explicit constexpr InternedStr(size_t index_) : index(index_) {}
std::string const &str() const;
char const *c_str() const { return str().c_str(); }
bool operator==(InternedStr const &rhs) const { return index == rhs.index; }
template<typename T>
friend struct std::hash;
};
template<>
struct std::hash<InternedStr> {
size_t operator()(InternedStr const &str) const { return std::hash<size_t>{}(str.index); }
};
InternedStr intern(std::string_view str);
#endif // RGBDS_ASM_INTERN_HPP
+3 -1
View File
@@ -14,6 +14,8 @@
#include "platform.hpp" // SSIZE_MAX
#include "asm/intern.hpp"
// This value is a compromise between `LexerState` allocation performance when reading the entire
// file works, and buffering performance when it doesn't (e.g. when piping a file into RGBASM).
static constexpr size_t LEXER_BUF_SIZE = 64;
@@ -32,7 +34,7 @@ enum LexerMode {
};
struct Expansion {
std::optional<std::string> name;
std::optional<InternedStr> name;
std::shared_ptr<std::string> contents;
size_t offset; // Cursor into `contents`
+6 -4
View File
@@ -10,16 +10,18 @@
#include "linkdefs.hpp"
#include "asm/intern.hpp"
struct Symbol;
struct RPNValue {
RPNCommand command; // The RPN_* command ID
std::variant<std::monostate, uint8_t, uint32_t, std::string> data; // Data after the ID, if any
std::variant<std::monostate, uint8_t, uint32_t, InternedStr> data; // Data after the ID, if any
RPNValue(RPNCommand cmd);
RPNValue(RPNCommand cmd, uint8_t val);
RPNValue(RPNCommand cmd, uint32_t val);
RPNValue(RPNCommand cmd, std::string const &name);
RPNValue(RPNCommand cmd, InternedStr name);
void appendEncoded(std::vector<uint8_t> &buffer) const;
};
@@ -40,8 +42,8 @@ struct Expression {
bool isDiffConstant(Symbol const *symName) const;
void makeNumber(uint32_t value);
void makeSymbol(std::string const &symName);
void makeBankSymbol(std::string const &symName);
void makeSymbol(InternedStr symName);
void makeBankSymbol(InternedStr symName);
void makeBankSection(std::string const &sectName);
void makeSizeOfSection(std::string const &sectName);
void makeStartOfSection(std::string const &sectName);
+2 -1
View File
@@ -11,6 +11,7 @@
#include <string>
#include <vector>
#include "intern.hpp"
#include "linkdefs.hpp"
struct Expression;
@@ -107,6 +108,6 @@ void sect_PushSection();
void sect_PopSection();
void sect_CheckStack();
std::string sect_PushSectionFragmentLiteral();
InternedStr sect_PushSectionFragmentLiteral();
#endif // RGBDS_ASM_SECTION_HPP
+20 -21
View File
@@ -10,6 +10,7 @@
#include <utility>
#include <variant>
#include "asm/intern.hpp"
#include "asm/lexer.hpp"
#include "asm/section.hpp"
@@ -26,7 +27,7 @@ struct Symbol; // Forward declaration for `sym_IsPC`
bool sym_IsPC(Symbol const *sym); // Forward declaration for `getSection`
struct Symbol {
std::string name;
InternedStr name;
SymbolType type;
bool isBuiltin;
bool isExported; // Not relevant for SYM_MACRO or SYM_EQUS
@@ -68,36 +69,34 @@ struct Symbol {
uint32_t getConstantValue() const;
};
bool sym_IsDotScope(std::string const &symName);
bool sym_IsDotScope(InternedStr symName);
void sym_ForEach(void (*callback)(Symbol &));
Symbol *sym_AddLocalLabel(std::string const &symName);
Symbol *sym_AddLabel(std::string const &symName);
Symbol *sym_AddLocalLabel(InternedStr symName);
Symbol *sym_AddLabel(InternedStr symName);
Symbol *sym_AddAnonLabel();
std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg);
void sym_Export(std::string const &symName);
Symbol *sym_AddEqu(std::string const &symName, int32_t value);
Symbol *sym_RedefEqu(std::string const &symName, int32_t value);
Symbol *sym_AddVar(std::string const &symName, int32_t value);
InternedStr sym_MakeAnonLabelName(uint32_t ofs, bool neg);
void sym_Export(InternedStr symName);
Symbol *sym_AddEqu(InternedStr symName, int32_t value);
Symbol *sym_RedefEqu(InternedStr symName, int32_t value);
Symbol *sym_AddVar(InternedStr symName, int32_t value);
int32_t sym_GetRSValue();
void sym_SetRSValue(int32_t value);
// Find a symbol by exact name, bypassing expansion checks
Symbol *sym_FindExactSymbol(std::string const &symName);
Symbol *sym_FindExactSymbol(InternedStr symName);
// Find a symbol, possibly scoped, by name
Symbol *sym_FindScopedSymbol(std::string const &symName);
Symbol *sym_FindScopedSymbol(InternedStr symName);
// Find a scoped symbol by name; do not return `@` or `_NARG` when they have no value
Symbol *sym_FindScopedValidSymbol(std::string const &symName);
Symbol *sym_FindScopedValidSymbol(InternedStr symName);
Symbol const *sym_GetPC();
Symbol *sym_AddMacro(
std::string const &symName, int32_t defLineNo, ContentSpan const &span, bool isQuiet
);
Symbol *sym_Ref(std::string const &symName);
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);
bool sym_IsPurgedExact(std::string const &symName);
bool sym_IsPurgedScoped(std::string const &symName);
Symbol *sym_AddMacro(InternedStr symName, int32_t defLineNo, ContentSpan const &span, bool isQuiet);
Symbol *sym_Ref(InternedStr symName);
Symbol *sym_AddString(InternedStr symName, std::shared_ptr<std::string> value);
Symbol *sym_RedefString(InternedStr symName, std::shared_ptr<std::string> value);
void sym_Purge(InternedStr symName);
bool sym_IsPurgedExact(InternedStr symName);
bool sym_IsPurgedScoped(InternedStr symName);
void sym_Init(time_t now);
// Functions to save and restore the current label scopes.
+1
View File
@@ -38,6 +38,7 @@ add_executable(rgbasm $<TARGET_OBJECTS:common>
"asm/fixpoint.cpp"
"asm/format.cpp"
"asm/fstack.cpp"
"asm/intern.cpp"
"asm/lexer.cpp"
"asm/macro.cpp"
"asm/main.cpp"
+3 -2
View File
@@ -22,6 +22,7 @@
#include "asm/charmap.hpp"
#include "asm/format.hpp"
#include "asm/fstack.hpp"
#include "asm/intern.hpp"
#include "asm/lexer.hpp"
#include "asm/output.hpp"
#include "asm/rpn.hpp" // Expression
@@ -607,7 +608,7 @@ std::string act_StringFormat(
return str;
}
std::string act_SectionName(std::string const &symName) {
std::string act_SectionName(InternedStr symName) {
Symbol *sym = sym_FindScopedValidSymbol(symName);
if (!sym) {
if (sym_IsPurgedScoped(symName)) {
@@ -625,7 +626,7 @@ std::string act_SectionName(std::string const &symName) {
return section->name;
}
void act_CompoundAssignment(std::string const &symName, RPNCommand op, int32_t constValue) {
void act_CompoundAssignment(InternedStr symName, RPNCommand op, int32_t constValue) {
Expression oldExpr, constExpr, newExpr;
oldExpr.makeSymbol(symName);
constExpr.makeNumber(constValue);
+13 -11
View File
@@ -21,9 +21,10 @@
#include "itertools.hpp" // InsertionOrderedMap
#include "util.hpp"
#include "asm/intern.hpp"
#include "asm/warning.hpp"
#define DEFAULT_CHARMAP_NAME "main"
static InternedStr mainCharmapName;
static bool compareNode(std::pair<char, size_t> edge, char c) {
return edge.first < c;
@@ -50,7 +51,7 @@ struct CharmapNode {
};
struct Charmap {
std::string name;
InternedStr name;
std::vector<CharmapNode> nodes; // Trie of mappings (first node is reserved for the root node)
size_t nextIndexOrAdd(size_t nodeIdx, char c) {
@@ -88,18 +89,18 @@ bool forEachChar(
return true;
}
static InsertionOrderedMap<std::string, Charmap> charmaps;
static InsertionOrderedMap<InternedStr, Charmap> charmaps;
static Charmap *currentCharmap;
static std::stack<Charmap *> charmapStack;
void charmap_Init() {
charmap_New(DEFAULT_CHARMAP_NAME, nullptr);
mainCharmapName = intern("main");
charmap_New(mainCharmapName, nullptr);
}
bool charmap_ForEach(
void (*mapFunc)(std::string const &),
void (*charFunc)(std::string const &, std::vector<int32_t>)
void (*mapFunc)(InternedStr), void (*charFunc)(std::string const &, std::vector<int32_t>)
) {
for (Charmap const &charmap : charmaps) {
std::map<size_t, std::string> mappings;
@@ -116,7 +117,7 @@ bool charmap_ForEach(
return !charmaps.empty();
}
void charmap_New(std::string const &name, std::string const *baseName) {
void charmap_New(InternedStr name, InternedStr const *baseName) {
std::optional<size_t> baseIdx = std::nullopt;
if (baseName != nullptr) {
@@ -143,7 +144,7 @@ void charmap_New(std::string const &name, std::string const *baseName) {
currentCharmap = &charmap;
}
void charmap_Set(std::string const &name) {
void charmap_Set(InternedStr name) {
if (auto index = charmaps.findIndex(name); index) {
currentCharmap = &charmaps[*index];
} else {
@@ -294,11 +295,12 @@ size_t charmap_ConvertNext(std::string_view &input, std::vector<int32_t> *output
// Warn if this character is not mapped but any others are
if (int firstChar = input[inputIdx]; charmap.nodes.size() > 1) {
warning(WARNING_UNMAPPED_CHAR_1, "Unmapped character %s", printChar(firstChar));
} else if (charmap.name != DEFAULT_CHARMAP_NAME) {
} else if (charmap.name != mainCharmapName) {
warning(
WARNING_UNMAPPED_CHAR_2,
"Unmapped character %s not in `" DEFAULT_CHARMAP_NAME "` charmap",
printChar(firstChar)
"Unmapped character %s not in `%s` charmap",
printChar(firstChar),
mainCharmapName.c_str()
);
}
+8 -9
View File
@@ -25,6 +25,7 @@
#include "platform.hpp" // strncasecmp
#include "verbosity.hpp"
#include "asm/intern.hpp"
#include "asm/lexer.hpp"
#include "asm/macro.hpp"
#include "asm/main.hpp"
@@ -47,7 +48,7 @@ struct Context {
bool isForLoop = false;
int32_t forValue = 0;
int32_t forStep = 0;
std::string forName{};
InternedStr forName{};
};
static std::stack<Context> contextStack;
@@ -309,7 +310,7 @@ static void
}
}
fileInfoName.append(NODE_SEPARATOR);
fileInfoName.append(macro.name);
fileInfoName.append(macro.name.str());
auto fileInfo = std::make_shared<FileStackNode>(NODE_MACRO, fileInfoName, isQuiet);
assume(!contextStack.empty()); // The top level context cannot be a MACRO
@@ -389,9 +390,7 @@ bool fstk_RunInclude(std::string const &path, bool isQuiet) {
return fstk_FileError(path, "`INCLUDE`");
}
void fstk_RunMacro(
std::string const &macroName, std::shared_ptr<MacroArgs> macroArgs, bool isQuiet
) {
void fstk_RunMacro(InternedStr macroName, std::shared_ptr<MacroArgs> macroArgs, bool isQuiet) {
auto makeSuggestion = [&macroName, &macroArgs]() -> std::optional<std::string> {
std::shared_ptr<std::string> arg = macroArgs->getArg(1);
if (!arg) {
@@ -402,14 +401,14 @@ void fstk_RunMacro(
static char const *types[] = {"EQUS", "EQU", "RB", "RW", "RL", "="};
for (char const *type : types) {
if (strncasecmp(str, type, strlen(type)) == 0) {
return "\"DEF "s + macroName + " " + type + " ...\"";
return "\"DEF "s + macroName.str() + " " + type + " ...\"";
}
}
if (strncasecmp(str, "SET", literal_strlen("SET")) == 0) {
return "\"DEF "s + macroName + " = ...\"";
return "\"DEF "s + macroName.str() + " = ...\"";
}
if (str[0] == ':') {
return "a label \""s + macroName + (str[1] == ':' ? "::" : ":") + "\"";
return "a label \""s + macroName.str() + (str[1] == ':' ? "::" : ":") + "\"";
}
return std::nullopt;
@@ -439,7 +438,7 @@ void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span, b
}
void fstk_RunFor(
std::string const &symName,
InternedStr symName,
int32_t start,
int32_t stop,
int32_t step,
+45
View File
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: MIT
#include "asm/intern.hpp"
#include <deque>
#include <functional> // equal_to
#include <stddef.h>
#include <stdint.h>
#include <string>
#include <string_view>
#include <unordered_map>
#include "helpers.hpp" // assume
#include "verbosity.hpp"
// Avoid `std::string` allocations when looking up heterogeneous values in `internedIndexes`
struct StringHash {
using is_transparent = void;
size_t operator()(std::string_view str) const { return std::hash<std::string_view>{}(str); }
};
// Use a `deque` not a `vector` to prevent reallocation so `internedIndexes` keys stay valid
static std::deque<std::string> internedStrings;
// Keys are views of values in `internedStrings`; values are their corresponding indexes
static std::unordered_map<std::string_view, size_t, StringHash, std::equal_to<>> internedIndexes;
std::string const &InternedStr::str() const {
assume(index != static_cast<size_t>(-1));
return internedStrings[index];
}
InternedStr intern(std::string_view str) {
if (auto search = internedIndexes.find(str); search != internedIndexes.end()) {
return InternedStr(search->second);
}
size_t index = internedStrings.size();
std::string &interned = internedStrings.emplace_back(str);
internedIndexes.emplace(interned, index);
verbosePrint(VERB_TRACE, "Interned string \"%s\"\n", interned.c_str());
return InternedStr(index);
}
+51 -31
View File
@@ -34,6 +34,7 @@
#include "asm/format.hpp"
#include "asm/fstack.hpp"
#include "asm/intern.hpp"
#include "asm/macro.hpp"
#include "asm/main.hpp"
#include "asm/rpn.hpp"
@@ -47,7 +48,7 @@
struct Token {
int type;
std::variant<std::monostate, uint32_t, std::string> value;
std::variant<std::monostate, InternedStr, uint32_t, std::string> value;
Token() : type(T_(NUMBER)), value(std::monostate{}) {
assume(
@@ -63,15 +64,15 @@ struct Token {
}
Token(int type_, uint32_t value_) : type(type_), value(value_) { assume(type == T_(NUMBER)); }
Token(int type_, std::string const &value_) : type(type_), value(std::move(value_)) {
assume(
type == T_(STRING) || type == T_(CHARACTER) || type == T_(SYMBOL) || type == T_(LABEL)
|| type == T_(LOCAL) || type == T_(ANON) || type == T_(QMACRO)
);
assume(type == T_(STRING) || type == T_(CHARACTER));
}
Token(int type_, std::string &&value_) : type(type_), value(std::move(value_)) {
assume(type == T_(STRING) || type == T_(CHARACTER));
}
Token(int type_, InternedStr value_) : type(type_), value(value_) {
assume(
type == T_(STRING) || type == T_(CHARACTER) || type == T_(SYMBOL) || type == T_(LABEL)
|| type == T_(LOCAL) || type == T_(ANON) || type == T_(QMACRO)
type == T_(SYMBOL) || type == T_(LABEL) || type == T_(LOCAL) || type == T_(ANON)
|| type == T_(QMACRO)
);
}
};
@@ -519,7 +520,7 @@ void lexer_ToggleStringExpansion(bool enable) {
// Functions for the actual lexer to obtain characters
static void beginExpansion(std::shared_ptr<std::string> str, std::optional<std::string> name) {
static void beginExpansion(std::shared_ptr<std::string> str, std::optional<InternedStr> name) {
if (name) {
lexer_CheckRecursionDepth();
}
@@ -582,11 +583,13 @@ static uint32_t readBracketedMacroArgNum() {
}
}
std::string symName;
std::string builder;
for (; continuesIdentifier(c); c = nextChar()) {
symName += c;
builder += c;
}
InternedStr symName = intern(builder);
if (Symbol const *sym = sym_FindScopedValidSymbol(symName); !sym) {
if (sym_IsPurgedScoped(symName)) {
error("Bracketed symbol `%s` does not exist; it was purged", symName.c_str());
@@ -950,7 +953,7 @@ static void discardLineContinuation() {
// Functions to read tokenizable values
static std::string readAnonLabelRef(char c) {
static InternedStr readAnonLabelRef(char c) {
assume(c == '+' || c == '-');
// We come here having already peeked at one char, so no need to do it again
@@ -1229,7 +1232,7 @@ static uint32_t readGfxConstant() {
static Token readIdentifier(char firstChar, bool raw) {
assume(startsIdentifier(firstChar));
std::string identifier(1, firstChar);
std::string builder(1, firstChar);
bool keywordBeforeLocal = false;
int tokenType = firstChar == '.' ? T_(LOCAL) : T_(SYMBOL);
@@ -1238,19 +1241,21 @@ static Token readIdentifier(char firstChar, bool raw) {
// If the char was a dot, the identifier is a local label
if (c == '.') {
// Check for a keyword before a non-raw local label
if (!raw && tokenType != T_(LOCAL) && keywords.find(identifier) != keywords.end()) {
if (!raw && tokenType != T_(LOCAL) && keywords.find(builder) != keywords.end()) {
keywordBeforeLocal = true;
}
tokenType = T_(LOCAL);
}
identifier += c;
builder += c;
}
InternedStr identifier = intern(builder);
// Check for a keyword if the identifier is not raw and not a local label
if (!raw && tokenType != T_(LOCAL)) {
if (auto search = keywords.find(identifier); search != keywords.end()) {
if (auto search = keywords.find(builder); search != keywords.end()) {
return Token(search->second);
}
}
@@ -1278,7 +1283,7 @@ static std::pair<Symbol const *, std::shared_ptr<std::string>> readInterpolation
fatal("Recursion limit (%zu) exceeded", options.maxRecursionDepth);
}
std::string identifier;
std::string builder;
FormatSpec fmt{};
bool invalid = false;
@@ -1299,15 +1304,15 @@ static std::pair<Symbol const *, std::shared_ptr<std::string>> readInterpolation
break;
} else if (c == ':' && !fmt.isParsed()) { // Format spec, only once
shiftChar();
size_t n = fmt.parseSpec(identifier.c_str());
if (!fmt.isValid() || n != identifier.length()) {
error("Invalid interpolation format spec \"%s\"", identifier.c_str());
size_t n = fmt.parseSpec(builder.c_str());
if (!fmt.isValid() || n != builder.length()) {
error("Invalid interpolation format spec \"%s\"", builder.c_str());
invalid = true;
}
identifier.clear(); // Now that format has been set, restart at beginning of string.
builder.clear(); // Now that format has been set, restart at beginning of string.
} else {
shiftChar();
identifier += c;
builder += c;
}
}
@@ -1315,19 +1320,21 @@ static std::pair<Symbol const *, std::shared_ptr<std::string>> readInterpolation
return {nullptr, nullptr}; // Don't allow invalid interpolation to occur.
}
if (identifier.starts_with('#')) {
if (builder.starts_with('#')) {
// Skip a '#' raw symbol prefix, but after expanding any nested interpolations.
identifier.erase(0, 1);
} else if (keywords.find(identifier) != keywords.end()) {
builder.erase(0, 1);
} else if (keywords.find(builder) != keywords.end()) {
// Don't allow symbols that alias keywords without a '#' prefix.
error(
"Interpolated symbol `%s` is a reserved keyword; add a '#' prefix to use it as a raw "
"symbol",
identifier.c_str()
builder.c_str()
);
return {nullptr, nullptr};
}
InternedStr identifier = intern(builder);
if (Symbol const *sym = sym_FindScopedValidSymbol(identifier); !sym || !sym->isDefined()) {
if (sym_IsPurgedScoped(identifier)) {
error("Interpolated symbol `%s` does not exist; it was purged", identifier.c_str());
@@ -1902,9 +1909,9 @@ static Token yylex_NORMAL() {
return token;
}
// `token` is either a `SYMBOL` or a `LOCAL`, and both have a `std::string` value.
assume(std::holds_alternative<std::string>(token.value));
std::string const &identifier = std::get<std::string>(token.value);
// `token` is either a `SYMBOL` or a `LOCAL`, and both have an `InternedStr` value.
assume(std::holds_alternative<InternedStr>(token.value));
InternedStr identifier = std::get<InternedStr>(token.value);
// Raw symbols and local symbols cannot be string expansions
if (!raw && token.type == T_(SYMBOL) && lexerState->enableStringExpansions) {
@@ -2116,13 +2123,13 @@ static Token skipToLeadingKeyword(
if (c == EOF) {
return Token(T_(YYEOF));
} else if (isLetter(c)) {
std::string keyword(1, c);
std::string builder(1, c);
shiftFn();
for (c = peekFn(); continuesIdentifier(c); c = peekFn()) {
keyword += c;
builder += c;
shiftFn();
}
if (auto search = keywords.find(keyword); search != keywords.end()) {
if (auto search = keywords.find(builder); search != keywords.end()) {
finalizeFn();
return Token(search->second);
}
@@ -2347,6 +2354,19 @@ yy::parser::symbol_type yylex() {
}
// LCOV_EXCL_STOP
return yy::parser::symbol_type(token.type, std::get<std::string>(token.value));
} else if (std::holds_alternative<InternedStr>(token.value)) {
// LCOV_EXCL_START
if (checkVerbosity(VERB_TRACE)) {
style_Set(stderr, STYLE_MAGENTA, false);
fprintf(
stderr, "Lexed `%s` token (interned ", yy::parser::symbol_type(token.type).name()
);
verboseOutputString(std::get<InternedStr>(token.value).str());
fputs(")\n", stderr);
style_Reset(stderr);
}
// LCOV_EXCL_STOP
return yy::parser::symbol_type(token.type, std::get<InternedStr>(token.value));
} else {
// LCOV_EXCL_START
verbosePrint(VERB_TRACE, "Lexed `%s` token\n", yy::parser::symbol_type(token.type).name());
+2 -2
View File
@@ -190,9 +190,9 @@ static void parseArg(int ch, char *arg) {
char *equals = strchr(arg, '=');
if (equals) {
*equals = '\0';
sym_AddString(arg, std::make_shared<std::string>(equals + 1));
sym_AddString(intern(arg), std::make_shared<std::string>(equals + 1));
} else {
sym_AddString(arg, std::make_shared<std::string>("1"));
sym_AddString(intern(arg), std::make_shared<std::string>("1"));
}
break;
}
+3 -2
View File
@@ -20,6 +20,7 @@
#include "asm/charmap.hpp"
#include "asm/fstack.hpp"
#include "asm/intern.hpp"
#include "asm/lexer.hpp"
#include "asm/main.hpp"
#include "asm/rpn.hpp"
@@ -107,7 +108,7 @@ static void writeSection(Section const &sect, FILE *file) {
}
static void writeSymbol(Symbol const &sym, FILE *file) {
putString(sym.name, file);
putString(sym.name.str(), file);
if (!sym.isDefined()) {
putc(SYMTYPE_IMPORT, file);
} else {
@@ -338,7 +339,7 @@ static bool dumpCharmaps(FILE *file) {
// Characters are ordered by charmap, then by definition order
return charmap_ForEach(
[](std::string const &name) { fprintf(charmapFile, "newcharmap %s\n", name.c_str()); },
[](InternedStr name) { fprintf(charmapFile, "newcharmap %s\n", name.c_str()); },
[](std::string const &mapping, std::vector<int32_t> value) {
fputs("charmap \"", charmapFile);
dumpString(mapping, charmapFile);
+37 -37
View File
@@ -59,7 +59,7 @@
yy::parser::symbol_type yylex(); // Provided by lexer.cpp
static auto handleSymbolByType(
std::string const &symName,
InternedStr symName,
std::invocable<Expression const &> auto numCallback,
std::invocable<std::string const &> auto strCallback
) {
@@ -324,11 +324,11 @@
%token <int32_t> NUMBER "number"
%token <std::string> STRING "string"
%token <std::string> CHARACTER "character"
%token <std::string> SYMBOL "symbol"
%token <std::string> LABEL "label"
%token <std::string> LOCAL "local label"
%token <std::string> ANON "anonymous label"
%token <std::string> QMACRO "quiet macro"
%token <InternedStr> SYMBOL "symbol"
%token <InternedStr> LABEL "label"
%token <InternedStr> LOCAL "local label"
%token <InternedStr> ANON "anonymous label"
%token <InternedStr> QMACRO "quiet macro"
/******************** Data types ********************/
@@ -355,23 +355,23 @@
%type <std::string> string_literal
%type <std::string> strcat_args
// Strings used for identifiers
%type <std::string> def_id
%type <std::string> redef_id
%type <std::string> def_numeric
%type <std::string> def_equ
%type <std::string> redef_equ
%type <std::string> def_set
%type <std::string> def_rb
%type <std::string> def_rw
%type <std::string> def_rl
%type <std::string> def_equs
%type <std::string> redef_equs
%type <std::string> scoped_sym
%type <InternedStr> def_id
%type <InternedStr> redef_id
%type <InternedStr> def_numeric
%type <InternedStr> def_equ
%type <InternedStr> redef_equ
%type <InternedStr> def_set
%type <InternedStr> def_rb
%type <InternedStr> def_rw
%type <InternedStr> def_rl
%type <InternedStr> def_equs
%type <InternedStr> redef_equs
%type <InternedStr> scoped_sym
// `scoped_sym_no_anon` exists because anonymous labels usually count as "scoped symbols", but some
// contexts treat anonymous labels and other labels/symbols differently, e.g. `purge` or `export`.
%type <std::string> scoped_sym_no_anon
%type <std::string> fragment_literal
%type <std::string> fragment_literal_name
%type <InternedStr> scoped_sym_no_anon
%type <InternedStr> fragment_literal
%type <InternedStr> fragment_literal_name
// SM83 instruction parameters
%type <int32_t> reg_r
@@ -399,7 +399,7 @@
%type <std::vector<Expression>> ds_args
%type <ForArgs> for_args
%type <std::shared_ptr<MacroArgs>> macro_args
%type <std::vector<std::string>> purge_args
%type <std::vector<InternedStr>> purge_args
%type <SectionSpec> sect_attrs
%type <SectionModifier> sect_mod
%type <SectionType> sect_type
@@ -507,7 +507,7 @@ def_id:
lexer_ToggleStringExpansion(false);
} SYMBOL {
lexer_ToggleStringExpansion(true);
$$ = std::move($3);
$$ = $3;
}
;
@@ -516,7 +516,7 @@ redef_id:
lexer_ToggleStringExpansion(false);
} SYMBOL {
lexer_ToggleStringExpansion(true);
$$ = std::move($3);
$$ = $3;
}
;
@@ -912,40 +912,40 @@ endu:
def_equ:
def_id POP_EQU iconst {
$$ = std::move($1);
$$ = $1;
sym_AddEqu($$, $3);
}
;
redef_equ:
redef_id POP_EQU iconst {
$$ = std::move($1);
$$ = $1;
sym_RedefEqu($$, $3);
}
;
def_set:
def_id POP_EQUAL iconst {
$$ = std::move($1);
$$ = $1;
sym_AddVar($$, $3);
}
| redef_id POP_EQUAL iconst {
$$ = std::move($1);
$$ = $1;
sym_AddVar($$, $3);
}
| def_id compound_eq iconst {
$$ = std::move($1);
$$ = $1;
act_CompoundAssignment($$, $2, $3);
}
| redef_id compound_eq iconst {
$$ = std::move($1);
$$ = $1;
act_CompoundAssignment($$, $2, $3);
}
;
def_rb:
def_id POP_RB rs_uconst {
$$ = std::move($1);
$$ = $1;
uint32_t rs = sym_GetRSValue();
sym_AddEqu($$, rs);
sym_SetRSValue(rs + $3);
@@ -954,7 +954,7 @@ def_rb:
def_rw:
def_id POP_RW rs_uconst {
$$ = std::move($1);
$$ = $1;
uint32_t rs = sym_GetRSValue();
sym_AddEqu($$, rs);
sym_SetRSValue(rs + 2 * $3);
@@ -963,7 +963,7 @@ def_rw:
def_rl:
def_id SM83_RL rs_uconst {
$$ = std::move($1);
$$ = $1;
uint32_t rs = sym_GetRSValue();
sym_AddEqu($$, rs);
sym_SetRSValue(rs + 4 * $3);
@@ -972,14 +972,14 @@ def_rl:
def_equs:
def_id POP_EQUS string {
$$ = std::move($1);
$$ = $1;
sym_AddString($$, std::make_shared<std::string>($3));
}
;
redef_equs:
redef_id POP_EQUS string {
$$ = std::move($1);
$$ = $1;
sym_RedefString($$, std::make_shared<std::string>($3));
}
;
@@ -988,7 +988,7 @@ purge:
POP_PURGE {
lexer_ToggleStringExpansion(false);
} purge_args trailing_comma {
for (std::string &arg : $3) {
for (InternedStr arg : $3) {
sym_Purge(arg);
}
lexer_ToggleStringExpansion(true);
@@ -1254,7 +1254,7 @@ reloc_16bit:
fragment_literal:
LBRACKS fragment_literal_name asm_file RBRACKS {
sect_PopSection();
$$ = std::move($2);
$$ = $2;
}
;
+15 -15
View File
@@ -37,7 +37,7 @@ Symbol const *Expression::symbolOf() const {
if (rpn.size() != 1 || rpn[0].command != RPN_SYM) {
return nullptr;
}
return sym_FindScopedSymbol(std::get<std::string>(rpn[0].data));
return sym_FindScopedSymbol(std::get<InternedStr>(rpn[0].data));
}
bool Expression::isDiffConstant(Symbol const *sym) const {
@@ -58,7 +58,7 @@ void Expression::makeNumber(uint32_t value) {
data = static_cast<int32_t>(value);
}
void Expression::makeSymbol(std::string const &symName) {
void Expression::makeSymbol(InternedStr symName) {
assume(rpn.empty());
if (Symbol *sym = sym_FindScopedSymbol(symName); sym_IsPC(sym) && !sect_GetSymbolSection()) {
error("PC has no value outside of a section");
@@ -69,8 +69,8 @@ void Expression::makeSymbol(std::string const &symName) {
} else if (!sym || !sym->isConstant()) {
data = sym_IsPC(sym) ? "PC is not constant at assembly time"
: (sym && sym->isDefined()
? "`"s + symName + "` is not constant at assembly time"
: "undefined symbol `"s + symName + "`")
? "`"s + symName.str() + "` is not constant at assembly time"
: "undefined symbol `"s + symName.str() + "`")
+ (sym_IsPurgedScoped(symName) ? "; it was purged" : "");
sym = sym_Ref(symName);
rpn.emplace_back(RPN_SYM, sym->name);
@@ -79,7 +79,7 @@ void Expression::makeSymbol(std::string const &symName) {
}
}
void Expression::makeBankSymbol(std::string const &symName) {
void Expression::makeBankSymbol(InternedStr symName) {
assume(rpn.empty());
if (Symbol const *sym = sym_FindScopedSymbol(symName); sym_IsPC(sym)) {
// The @ symbol is treated differently.
@@ -103,8 +103,8 @@ void Expression::makeBankSymbol(std::string const &symName) {
data = static_cast<int32_t>(sym->getSection()->bank);
} else {
data = sym_IsPurgedScoped(symName)
? "`"s + symName + "`'s bank is not known; it was purged"
: "`"s + symName + "`'s bank is not known";
? "`"s + symName.str() + "`'s bank is not known; it was purged"
: "`"s + symName.str() + "`'s bank is not known";
rpn.emplace_back(RPN_BANK_SYM, sym->name);
}
}
@@ -116,7 +116,7 @@ void Expression::makeBankSection(std::string const &sectName) {
data = static_cast<int32_t>(sect->bank);
} else {
data = "Section \""s + sectName + "\"'s bank is not known";
rpn.emplace_back(RPN_BANK_SECT, sectName);
rpn.emplace_back(RPN_BANK_SECT, intern(sectName));
}
}
@@ -126,7 +126,7 @@ void Expression::makeSizeOfSection(std::string const &sectName) {
data = static_cast<int32_t>(sect->size);
} else {
data = "Section \""s + sectName + "\"'s size is not known";
rpn.emplace_back(RPN_SIZEOF_SECT, sectName);
rpn.emplace_back(RPN_SIZEOF_SECT, intern(sectName));
}
}
@@ -136,7 +136,7 @@ void Expression::makeStartOfSection(std::string const &sectName) {
data = static_cast<int32_t>(sect->org);
} else {
data = "Section \""s + sectName + "\"'s start is not known";
rpn.emplace_back(RPN_STARTOF_SECT, sectName);
rpn.emplace_back(RPN_STARTOF_SECT, intern(sectName));
}
}
@@ -550,7 +550,7 @@ RPNValue::RPNValue(RPNCommand cmd, uint32_t val) : command(cmd), data(val) {
assume(cmd == RPN_CONST);
}
RPNValue::RPNValue(RPNCommand cmd, std::string const &name) : command(cmd), data(name) {
RPNValue::RPNValue(RPNCommand cmd, InternedStr name) : command(cmd), data(name) {
assume(
cmd == RPN_SYM || cmd == RPN_BANK_SYM || cmd == RPN_BANK_SECT || cmd == RPN_SIZEOF_SECT
|| cmd == RPN_STARTOF_SECT
@@ -576,9 +576,9 @@ void RPNValue::appendEncoded(std::vector<uint8_t> &buffer) const {
case RPN_SYM:
case RPN_BANK_SYM: {
// The command ID is followed by a four-byte symbol ID
assume(std::holds_alternative<std::string>(data));
assume(std::holds_alternative<InternedStr>(data));
// The symbol name is always written expanded
Symbol *sym = sym_FindExactSymbol(std::get<std::string>(data));
Symbol *sym = sym_FindExactSymbol(std::get<InternedStr>(data));
out_RegisterSymbol(*sym); // Ensure that `sym->ID` is set
buffer.push_back(sym->ID & 0xFF);
buffer.push_back(sym->ID >> 8);
@@ -591,8 +591,8 @@ void RPNValue::appendEncoded(std::vector<uint8_t> &buffer) const {
case RPN_SIZEOF_SECT:
case RPN_STARTOF_SECT: {
// The command ID is followed by a NUL-terminated section name string
assume(std::holds_alternative<std::string>(data));
std::string const &name = std::get<std::string>(data);
assume(std::holds_alternative<InternedStr>(data));
std::string const &name = std::get<InternedStr>(data).str();
buffer.reserve(buffer.size() + name.length() + 1);
buffer.insert(buffer.end(), RANGE(name));
buffer.push_back('\0');
+2 -2
View File
@@ -1158,7 +1158,7 @@ void sect_EndSection() {
sym_ResetCurrentLabelScopes();
}
std::string sect_PushSectionFragmentLiteral() {
InternedStr sect_PushSectionFragmentLiteral() {
static uint64_t nextFragmentLiteralID = 0;
// Like `requireCodeSection` but fatal
@@ -1192,5 +1192,5 @@ std::string sect_PushSectionFragmentLiteral() {
currentSection = sect;
// Return a symbol ID to use for the address of this section fragment
return "$"s + std::to_string(nextFragmentLiteralID++);
return intern("$"s + std::to_string(nextFragmentLiteralID++));
}
+80 -69
View File
@@ -22,6 +22,7 @@
#include "version.hpp"
#include "asm/fstack.hpp"
#include "asm/intern.hpp"
#include "asm/lexer.hpp"
#include "asm/macro.hpp"
#include "asm/main.hpp"
@@ -31,8 +32,8 @@
using namespace std::literals;
static std::unordered_map<std::string, Symbol> symbols;
static std::unordered_set<std::string> purgedSymbols;
static std::unordered_map<InternedStr, Symbol> symbols;
static std::unordered_set<InternedStr> purgedSymbols;
static Symbol const *globalScope = nullptr; // Current section's global label scope
static Symbol const *localScope = nullptr; // Current section's local label scope
@@ -44,6 +45,10 @@ static Symbol *globalScopeSymbol;
static Symbol *localScopeSymbol;
static Symbol *RSSymbol;
static InternedStr PCName;
static InternedStr globalScopeName;
static InternedStr localScopeName;
static char savedTIME[256];
static char savedDATE[256];
static char savedTIMESTAMP_ISO8601_LOCAL[256];
@@ -53,10 +58,10 @@ bool sym_IsPC(Symbol const *sym) {
return sym == PCSymbol;
}
bool sym_IsDotScope(std::string const &symName) {
bool sym_IsDotScope(InternedStr symName) {
// Label scopes `.` and `..` are the only nonlocal identifiers that start with a dot.
// Three or more dots are considered a nonsensical local label.
return symName == "." || symName == "..";
return symName == globalScopeName || symName == localScopeName;
}
void sym_ForEach(void (*callback)(Symbol &)) {
@@ -76,9 +81,9 @@ static int32_t NARGCallback() {
static std::shared_ptr<std::string> SCOPECallback() {
if (localScope) {
return std::make_shared<std::string>("..");
return std::make_shared<std::string>(localScopeName.str());
} else if (globalScope) {
return std::make_shared<std::string>(".");
return std::make_shared<std::string>(globalScopeName.str());
} else {
if (!sect_GetSymbolSection()) {
error("`__SCOPE__` has no value outside of a section");
@@ -92,7 +97,7 @@ static std::shared_ptr<std::string> globalScopeCallback() {
error("`.` has no value outside of a label scope");
return std::make_shared<std::string>("");
}
return std::make_shared<std::string>(globalScope->name);
return std::make_shared<std::string>(globalScope->name.str());
}
static std::shared_ptr<std::string> localScopeCallback() {
@@ -100,7 +105,7 @@ static std::shared_ptr<std::string> localScopeCallback() {
error("`..` has no value outside of a local label scope");
return std::make_shared<std::string>("");
}
return std::make_shared<std::string>(localScope->name);
return std::make_shared<std::string>(localScope->name.str());
}
static int32_t PCCallback() {
@@ -219,13 +224,13 @@ static void redefinedError(Symbol const &sym) {
}
}
static void assumeAlreadyExpanded(std::string const &symName) {
static void assumeAlreadyExpanded(InternedStr symName) {
// Either the symbol name is `Global.local` or entirely '.'s (for scopes `.` and `..`),
// but cannot be unqualified `.local` or more than two '.'s
assume(!symName.starts_with('.') || sym_IsDotScope(symName));
assume(!symName.str().starts_with('.') || sym_IsDotScope(symName));
}
static Symbol &createSymbol(std::string const &symName) {
static Symbol &createSymbol(InternedStr symName) {
assumeAlreadyExpanded(symName);
static uint32_t nextDefIndex = 0;
@@ -245,13 +250,13 @@ static Symbol &createSymbol(std::string const &symName) {
return sym;
}
static bool isAutoScoped(std::string const &symName) {
static bool isAutoScoped(InternedStr symName) {
// `globalScope` should be global if it's defined
assume(!globalScope || globalScope->name.find('.') == std::string::npos);
assume(!globalScope || globalScope->name.str().find('.') == std::string::npos);
// `localScope` should be qualified local if it's defined
assume(!localScope || localScope->name.find('.') != std::string::npos);
assume(!localScope || localScope->name.str().find('.') != std::string::npos);
size_t dotPos = symName.find('.');
size_t dotPos = symName.str().find('.');
// If there are no dots, it's not a local label
if (dotPos == std::string::npos) {
@@ -264,12 +269,12 @@ static bool isAutoScoped(std::string const &symName) {
}
// Check for nothing after the dot
if (dotPos == symName.length() - 1) {
if (dotPos == symName.str().length() - 1) {
fatal("`%s` is a nonsensical reference to an empty local label", symName.c_str());
}
// Check for more than one dot
if (symName.find('.', dotPos + 1) != std::string::npos) {
if (symName.str().find('.', dotPos + 1) != std::string::npos) {
fatal("`%s` is a nonsensical reference to a nested local label", symName.c_str());
}
@@ -286,22 +291,22 @@ static bool isAutoScoped(std::string const &symName) {
return true;
}
static std::string expandedSymName(std::string const &symName) {
return isAutoScoped(symName) ? globalScope->name + symName : symName;
static InternedStr expandedSymName(InternedStr symName) {
return isAutoScoped(symName) ? intern(globalScope->name.str() + symName.str()) : symName;
}
Symbol *sym_FindExactSymbol(std::string const &symName) {
Symbol *sym_FindExactSymbol(InternedStr symName) {
assumeAlreadyExpanded(symName);
auto search = symbols.find(symName);
return search != symbols.end() ? &search->second : nullptr;
}
Symbol *sym_FindScopedSymbol(std::string const &symName) {
Symbol *sym_FindScopedSymbol(InternedStr symName) {
return sym_FindExactSymbol(expandedSymName(symName));
}
Symbol *sym_FindScopedValidSymbol(std::string const &symName) {
Symbol *sym_FindScopedValidSymbol(InternedStr symName) {
Symbol *sym = sym_FindScopedSymbol(symName);
// `@` has no value outside of a section
@@ -332,7 +337,7 @@ Symbol const *sym_GetPC() {
return PCSymbol;
}
void sym_Purge(std::string const &symName) {
void sym_Purge(InternedStr symName) {
Symbol *sym = sym_FindScopedValidSymbol(symName);
if (!sym) {
@@ -363,13 +368,13 @@ void sym_Purge(std::string const &symName) {
}
}
bool sym_IsPurgedExact(std::string const &symName) {
bool sym_IsPurgedExact(InternedStr symName) {
assumeAlreadyExpanded(symName);
return purgedSymbols.find(symName) != purgedSymbols.end();
}
bool sym_IsPurgedScoped(std::string const &symName) {
bool sym_IsPurgedScoped(InternedStr symName) {
return sym_IsPurgedExact(expandedSymName(symName));
}
@@ -405,9 +410,9 @@ void sym_SetCurrentLabelScopes(std::pair<Symbol const *, Symbol const *> newScop
localScope = std::get<1>(newScopes);
// `globalScope` should be global if it's defined
assume(!globalScope || globalScope->name.find('.') == std::string::npos);
assume(!globalScope || globalScope->name.str().find('.') == std::string::npos);
// `localScope` should be qualified local if it's defined
assume(!localScope || localScope->name.find('.') != std::string::npos);
assume(!localScope || localScope->name.str().find('.') != std::string::npos);
}
void sym_ResetCurrentLabelScopes() {
@@ -415,7 +420,7 @@ void sym_ResetCurrentLabelScopes() {
localScope = nullptr;
}
static Symbol *createNonrelocSymbol(std::string const &symName, bool numeric) {
static Symbol *createNonrelocSymbol(InternedStr symName, bool numeric) {
Symbol *sym = sym_FindExactSymbol(symName);
if (!sym) {
@@ -436,7 +441,7 @@ static Symbol *createNonrelocSymbol(std::string const &symName, bool numeric) {
return sym;
}
Symbol *sym_AddEqu(std::string const &symName, int32_t value) {
Symbol *sym_AddEqu(InternedStr symName, int32_t value) {
Symbol *sym = createNonrelocSymbol(symName, true);
if (!sym) {
@@ -449,7 +454,7 @@ Symbol *sym_AddEqu(std::string const &symName, int32_t value) {
return sym;
}
Symbol *sym_RedefEqu(std::string const &symName, int32_t value) {
Symbol *sym_RedefEqu(InternedStr symName, int32_t value) {
Symbol *sym = sym_FindExactSymbol(symName);
if (!sym) {
@@ -471,7 +476,7 @@ Symbol *sym_RedefEqu(std::string const &symName, int32_t value) {
return sym;
}
Symbol *sym_AddString(std::string const &symName, std::shared_ptr<std::string> str) {
Symbol *sym_AddString(InternedStr symName, std::shared_ptr<std::string> str) {
Symbol *sym = createNonrelocSymbol(symName, false);
if (!sym) {
@@ -483,7 +488,7 @@ Symbol *sym_AddString(std::string const &symName, std::shared_ptr<std::string> s
return sym;
}
Symbol *sym_RedefString(std::string const &symName, std::shared_ptr<std::string> str) {
Symbol *sym_RedefString(InternedStr symName, std::shared_ptr<std::string> str) {
Symbol *sym = sym_FindExactSymbol(symName);
if (!sym) {
@@ -511,7 +516,7 @@ Symbol *sym_RedefString(std::string const &symName, std::shared_ptr<std::string>
return sym;
}
Symbol *sym_AddVar(std::string const &symName, int32_t value) {
Symbol *sym_AddVar(InternedStr symName, int32_t value) {
Symbol *sym = sym_FindExactSymbol(symName);
if (!sym) {
@@ -529,7 +534,7 @@ Symbol *sym_AddVar(std::string const &symName, int32_t value) {
return sym;
}
static Symbol *addLabel(std::string const &symName) {
static Symbol *addLabel(InternedStr symName) {
assumeAlreadyExpanded(symName);
Symbol *sym = sym_FindExactSymbol(symName);
@@ -546,7 +551,7 @@ static Symbol *addLabel(std::string const &symName) {
sym->type = SYM_LABEL;
sym->data = static_cast<int32_t>(sect_GetSymbolOffset());
// Don't export anonymous labels
if (options.exportAll && !symName.starts_with('!')) {
if (options.exportAll && !symName.str().starts_with('!')) {
sym->isExported = true;
}
sym->section = sect_GetSymbolSection();
@@ -558,9 +563,9 @@ static Symbol *addLabel(std::string const &symName) {
return sym;
}
Symbol *sym_AddLocalLabel(std::string const &symName) {
Symbol *sym_AddLocalLabel(InternedStr symName) {
// The symbol name should be local, qualified or not
assume(symName.find('.') != std::string::npos);
assume(symName.str().find('.') != std::string::npos);
Symbol *sym = addLabel(expandedSymName(symName));
@@ -571,9 +576,9 @@ Symbol *sym_AddLocalLabel(std::string const &symName) {
return sym;
}
Symbol *sym_AddLabel(std::string const &symName) {
Symbol *sym_AddLabel(InternedStr symName) {
// The symbol name should be global
assume(symName.find('.') == std::string::npos);
assume(symName.str().find('.') == std::string::npos);
Symbol *sym = addLabel(symName);
@@ -596,12 +601,12 @@ Symbol *sym_AddAnonLabel() {
// LCOV_EXCL_STOP
}
std::string anon = sym_MakeAnonLabelName(0, true); // The direction is important!
InternedStr anon = sym_MakeAnonLabelName(0, true); // The direction is important!
++anonLabelID;
return addLabel(anon);
}
std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg) {
InternedStr sym_MakeAnonLabelName(uint32_t ofs, bool neg) {
uint32_t id = 0;
if (neg) {
@@ -632,11 +637,11 @@ std::string sym_MakeAnonLabelName(uint32_t ofs, bool neg) {
}
}
return "!"s + std::to_string(id);
return intern("!"s + std::to_string(id));
}
void sym_Export(std::string const &symName) {
if (symName.starts_with('!')) {
void sym_Export(InternedStr symName) {
if (symName.str().starts_with('!')) {
// LCOV_EXCL_START
// The parser does not accept anonymous labels for an `EXPORT` directive
error("Cannot export anonymous label");
@@ -655,9 +660,8 @@ void sym_Export(std::string const &symName) {
sym->isExported = true;
}
Symbol *sym_AddMacro(
std::string const &symName, int32_t defLineNo, ContentSpan const &span, bool isQuiet
) {
Symbol *
sym_AddMacro(InternedStr symName, int32_t defLineNo, ContentSpan const &span, bool isQuiet) {
Symbol *sym = createNonrelocSymbol(symName, false);
if (!sym) {
@@ -678,7 +682,7 @@ Symbol *sym_AddMacro(
// Flag that a symbol is referenced in an RPN expression
// and create it if it doesn't exist yet
Symbol *sym_Ref(std::string const &symName) {
Symbol *sym_Ref(InternedStr symName) {
Symbol *sym = sym_FindScopedSymbol(symName);
if (!sym) {
@@ -691,41 +695,46 @@ Symbol *sym_Ref(std::string const &symName) {
// Define the built-in symbols
void sym_Init(time_t now) {
PCSymbol = &createSymbol("@"s);
PCName = intern("@");
PCSymbol = &createSymbol(PCName);
PCSymbol->type = SYM_LABEL;
PCSymbol->data = PCCallback;
PCSymbol->isBuiltin = true;
NARGSymbol = &createSymbol("_NARG"s);
NARGSymbol = &createSymbol(intern("_NARG"));
NARGSymbol->type = SYM_EQU;
NARGSymbol->data = NARGCallback;
NARGSymbol->isBuiltin = true;
globalScopeSymbol = &createSymbol("."s);
globalScopeName = intern(".");
globalScopeSymbol = &createSymbol(globalScopeName);
globalScopeSymbol->type = SYM_EQUS;
globalScopeSymbol->data = globalScopeCallback;
globalScopeSymbol->isBuiltin = true;
localScopeSymbol = &createSymbol(".."s);
localScopeName = intern("..");
localScopeSymbol = &createSymbol(localScopeName);
localScopeSymbol->type = SYM_EQUS;
localScopeSymbol->data = localScopeCallback;
localScopeSymbol->isBuiltin = true;
SCOPESymbol = &createSymbol("__SCOPE__"s);
SCOPESymbol = &createSymbol(intern("__SCOPE__"));
SCOPESymbol->type = SYM_EQUS;
SCOPESymbol->data = SCOPECallback;
SCOPESymbol->isBuiltin = true;
RSSymbol = sym_AddVar("_RS"s, 0);
RSSymbol = sym_AddVar(intern("_RS"), 0);
RSSymbol->isBuiltin = true;
sym_AddString("__RGBDS_VERSION__"s, std::make_shared<std::string>(get_package_version_string()))
sym_AddString(
intern("__RGBDS_VERSION__"), 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;
sym_AddEqu(intern("__RGBDS_MAJOR__"), PACKAGE_VERSION_MAJOR)->isBuiltin = true;
sym_AddEqu(intern("__RGBDS_MINOR__"), PACKAGE_VERSION_MINOR)->isBuiltin = true;
sym_AddEqu(intern("__RGBDS_PATCH__"), PACKAGE_VERSION_PATCH)->isBuiltin = true;
#ifdef PACKAGE_VERSION_RC
sym_AddEqu("__RGBDS_RC__"s, PACKAGE_VERSION_RC)->isBuiltin = true;
sym_AddEqu(intern("__RGBDS_RC__"), PACKAGE_VERSION_RC)->isBuiltin = true;
#endif
// LCOV_EXCL_START
@@ -756,7 +765,7 @@ void sym_Init(time_t now) {
time_utc
);
Symbol *timeSymbol = &createSymbol("__TIME__"s);
Symbol *timeSymbol = &createSymbol(intern("__TIME__"));
timeSymbol->type = SYM_EQUS;
timeSymbol->data = []() {
warning(WARNING_OBSOLETE, "`__TIME__` is deprecated; use `__ISO_8601_LOCAL__`");
@@ -764,7 +773,7 @@ void sym_Init(time_t now) {
};
timeSymbol->isBuiltin = true;
Symbol *dateSymbol = &createSymbol("__DATE__"s);
Symbol *dateSymbol = &createSymbol(intern("__DATE__"));
dateSymbol->type = SYM_EQUS;
dateSymbol->data = []() {
warning(WARNING_OBSOLETE, "`__DATE__` is deprecated; use `__ISO_8601_LOCAL__`");
@@ -773,16 +782,18 @@ void sym_Init(time_t now) {
dateSymbol->isBuiltin = true;
sym_AddString(
"__ISO_8601_LOCAL__"s, std::make_shared<std::string>(savedTIMESTAMP_ISO8601_LOCAL)
intern("__ISO_8601_LOCAL__"), std::make_shared<std::string>(savedTIMESTAMP_ISO8601_LOCAL)
)
->isBuiltin = true;
sym_AddString("__ISO_8601_UTC__"s, std::make_shared<std::string>(savedTIMESTAMP_ISO8601_UTC))
sym_AddString(
intern("__ISO_8601_UTC__"), 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;
sym_AddEqu("__UTC_DAY__"s, time_utc->tm_mday)->isBuiltin = true;
sym_AddEqu("__UTC_HOUR__"s, time_utc->tm_hour)->isBuiltin = true;
sym_AddEqu("__UTC_MINUTE__"s, time_utc->tm_min)->isBuiltin = true;
sym_AddEqu("__UTC_SECOND__"s, time_utc->tm_sec)->isBuiltin = true;
sym_AddEqu(intern("__UTC_YEAR__"), time_utc->tm_year + 1900)->isBuiltin = true;
sym_AddEqu(intern("__UTC_MONTH__"), time_utc->tm_mon + 1)->isBuiltin = true;
sym_AddEqu(intern("__UTC_DAY__"), time_utc->tm_mday)->isBuiltin = true;
sym_AddEqu(intern("__UTC_HOUR__"), time_utc->tm_hour)->isBuiltin = true;
sym_AddEqu(intern("__UTC_MINUTE__"), time_utc->tm_min)->isBuiltin = true;
sym_AddEqu(intern("__UTC_SECOND__"), time_utc->tm_sec)->isBuiltin = true;
}