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