From e74073e4805fa3cce90a99946fc9994ae2970f9b Mon Sep 17 00:00:00 2001 From: Sylvie <35663410+Rangi42@users.noreply.github.com> Date: Mon, 4 Mar 2024 14:22:49 -0500 Subject: [PATCH] Run `clang-format` on everything (#1332) --- .clang-format | 14 +- include/asm/format.hpp | 3 +- include/asm/fstack.hpp | 26 +- include/asm/lexer.hpp | 38 +- include/asm/macro.hpp | 4 +- include/asm/output.hpp | 4 +- include/asm/rpn.hpp | 13 +- include/asm/section.hpp | 20 +- include/asm/symbol.hpp | 17 +- include/asm/warning.hpp | 39 +- include/error.hpp | 3 +- include/extern/getopt.hpp | 11 +- include/file.hpp | 53 +- include/gfx/main.hpp | 38 +- include/gfx/pal_sorting.hpp | 14 +- include/gfx/rgba.hpp | 8 +- include/helpers.hpp | 69 +- include/itertools.hpp | 15 +- include/link/main.hpp | 24 +- include/link/patch.hpp | 4 +- include/link/section.hpp | 4 +- include/link/symbol.hpp | 7 +- include/linkdefs.hpp | 97 +- include/platform.hpp | 64 +- include/version.hpp | 1 - src/asm/charmap.cpp | 49 +- src/asm/fixpoint.cpp | 58 +- src/asm/format.cpp | 44 +- src/asm/fstack.cpp | 133 +- src/asm/lexer.cpp | 900 ++++---- src/asm/macro.cpp | 43 +- src/asm/main.cpp | 138 +- src/asm/opt.cpp | 39 +- src/asm/output.cpp | 85 +- src/asm/parser.y | 4002 +++++++++++++++++++---------------- src/asm/rpn.cpp | 166 +- src/asm/section.cpp | 398 ++-- src/asm/symbol.cpp | 220 +- src/asm/warning.cpp | 275 ++- src/error.cpp | 28 +- src/extern/getopt.cpp | 90 +- src/extern/utf8decoder.cpp | 57 +- src/fix/main.cpp | 412 ++-- src/gfx/main.cpp | 205 +- src/gfx/pal_packing.cpp | 112 +- src/gfx/pal_sorting.cpp | 18 +- src/gfx/pal_spec.cpp | 146 +- src/gfx/process.cpp | 281 ++- src/gfx/proto_palette.cpp | 4 +- src/gfx/reverse.cpp | 166 +- src/gfx/rgba.cpp | 10 +- src/link/assign.cpp | 144 +- src/link/main.cpp | 200 +- src/link/object.cpp | 389 ++-- src/link/output.cpp | 258 +-- src/link/patch.cpp | 216 +- src/link/script.y | 200 +- src/link/sdas_obj.cpp | 349 ++- src/link/section.cpp | 257 ++- src/link/symbol.cpp | 23 +- src/linkdefs.cpp | 123 +- src/opmath.cpp | 22 +- src/util.cpp | 10 +- src/version.cpp | 21 +- test/gfx/randtilegen.cpp | 35 +- test/gfx/rgbgfx_test.cpp | 132 +- 66 files changed, 6091 insertions(+), 4957 deletions(-) diff --git a/.clang-format b/.clang-format index 82b1cc6a..cd82ea10 100644 --- a/.clang-format +++ b/.clang-format @@ -1,13 +1,13 @@ AccessModifierOffset: -4 -AlignAfterOpenBracket: Align +AlignAfterOpenBracket: BlockIndent AlignArrayOfStructures: Left AlignConsecutiveAssignments: None AlignConsecutiveBitFields: Consecutive AlignConsecutiveDeclarations: None AlignConsecutiveMacros: Consecutive -AlignEscapedNewlines: Left +AlignEscapedNewlines: DontAlign AlignOperands: Align -AlignTrailingComments: false +AlignTrailingComments: true AllowShortBlocksOnASingleLine: Empty AllowShortCaseLabelsOnASingleLine: false AllowShortEnumsOnASingleLine: true @@ -21,8 +21,8 @@ AlwaysBreakTemplateDeclarations: Yes AttributeMacros: - format_ - attr_ -BinPackArguments: true -BinPackParameters: true +BinPackArguments: false +BinPackParameters: false BitFieldColonSpacing: Both BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Attach @@ -60,8 +60,8 @@ IndentPPDirectives: BeforeHash IndentRequires: true IndentWidth: 4 IndentWrappedFunctionNames: true -# Only support for Javascript as of clang-format 13... -# InsertTrailingCommas: true +# Only support for Javascript as of clang-format 14... +# InsertTrailingCommas: Wrapped KeepEmptyLinesAtTheStartOfBlocks: false LambdaBodyIndentation: Signature Language: Cpp diff --git a/include/asm/format.hpp b/include/asm/format.hpp index 85521eb8..d56ce7c1 100644 --- a/include/asm/format.hpp +++ b/include/asm/format.hpp @@ -3,6 +3,7 @@ #ifndef RGBDS_FORMAT_SPEC_H #define RGBDS_FORMAT_SPEC_H +#include #include enum FormatState { @@ -30,7 +31,7 @@ class FormatSpec { public: bool isEmpty() const { return !state; } bool isValid() const { return valid || state == FORMAT_DONE; } - bool isFinished() const { return state >= FORMAT_DONE;} + bool isFinished() const { return state >= FORMAT_DONE; } void useCharacter(int c); void finishCharacters(); diff --git a/include/asm/fstack.hpp b/include/asm/fstack.hpp index cea7e558..5c20bd38 100644 --- a/include/asm/fstack.hpp +++ b/include/asm/fstack.hpp @@ -11,24 +11,25 @@ #include #include -#include "asm/lexer.hpp" - #include "linkdefs.hpp" +#include "asm/lexer.hpp" + struct FileStackNode { FileStackNode *parent; // Pointer to parent node, for error reporting // Line at which the parent context was exited; meaningless for the root level uint32_t lineNo; bool referenced; // If referenced by a Symbol, Section, or Patch's `src`, don't `delete`! - uint32_t ID; // Set only if referenced: ID within the object file, -1 if not output yet + uint32_t ID; // Set only if referenced: ID within the object file, -1 if not output yet enum FileStackNodeType type; std::variant< - std::monostate, // Default constructed; `.type` and `.data` must be set manually - std::vector, // NODE_REPT - std::string // NODE_FILE, NODE_MACRO - > data; + std::monostate, // Default constructed; `.type` and `.data` must be set manually + std::vector, // NODE_REPT + std::string // NODE_FILE, NODE_MACRO + > + data; // REPT iteration counts since last named node, in reverse depth order std::vector &iters(); @@ -62,8 +63,15 @@ bool yywrap(); void fstk_RunInclude(char const *path); void fstk_RunMacro(char const *macroName, MacroArgs &args); void fstk_RunRept(uint32_t count, int32_t reptLineNo, char const *body, size_t size); -void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step, - int32_t reptLineNo, char const *body, size_t size); +void fstk_RunFor( + char const *symName, + int32_t start, + int32_t stop, + int32_t step, + int32_t reptLineNo, + char const *body, + size_t size +); void fstk_StopRept(); bool fstk_Break(); diff --git a/include/asm/lexer.hpp b/include/asm/lexer.hpp index c81239ee..81bb2e7a 100644 --- a/include/asm/lexer.hpp +++ b/include/asm/lexer.hpp @@ -34,13 +34,13 @@ struct Expansion { char const *unowned; char *owned; // Non-`const` only so it can be `delete []`d } contents; - size_t size; // Length of the contents + size_t size; // Length of the contents size_t offset; // Cursor into the contents - bool owned; // Whether or not to free contents when this expansion is freed + bool owned; // Whether or not to free contents when this expansion is freed }; struct IfStackEntry { - bool ranIfBlock; // Whether an IF/ELIF/ELSE block ran already + bool ranIfBlock; // Whether an IF/ELIF/ELSE block ran already bool reachedElseBlock; // Whether an ELSE block ran already }; @@ -59,9 +59,9 @@ struct ViewedLexerState { struct BufferedLexerState { int fd; - size_t index; // Read index into the buffer + size_t index; // Read index into the buffer char buf[LEXER_BUF_SIZE]; // Circular buffer - size_t nbChars; // Number of "fresh" chars in the buffer + size_t nbChars; // Number of "fresh" chars in the buffer }; struct LexerState { @@ -75,8 +75,8 @@ struct LexerState { std::deque ifStack; - bool capturing; // Whether the text being lexed should be captured - size_t captureSize; // Amount of text captured + bool capturing; // Whether the text being lexed should be captured + size_t captureSize; // Amount of text captured std::vector *captureBuf; // Buffer to send the captured text to if non-null bool disableMacroArgs; @@ -85,38 +85,29 @@ struct LexerState { bool expandStrings; std::deque expansions; // Front is the innermost current expansion - std::variant< - std::monostate, - MmappedLexerState, - ViewedLexerState, - BufferedLexerState - > content; + std::variant content; }; extern LexerState *lexerState; extern LexerState *lexerStateEOL; -static inline void lexer_SetState(LexerState *state) -{ +static inline void lexer_SetState(LexerState *state) { lexerState = state; } -static inline void lexer_SetStateAtEOL(LexerState *state) -{ +static inline void lexer_SetStateAtEOL(LexerState *state) { lexerStateEOL = state; } extern char binDigits[2]; extern char gfxDigits[4]; -static inline void lexer_SetBinDigits(char const digits[2]) -{ +static inline void lexer_SetBinDigits(char const digits[2]) { binDigits[0] = digits[0]; binDigits[1] = digits[1]; } -static inline void lexer_SetGfxDigits(char const digits[4]) -{ +static inline void lexer_SetGfxDigits(char const digits[4]) { gfxDigits[0] = digits[0]; gfxDigits[1] = digits[1]; gfxDigits[2] = digits[2]; @@ -125,8 +116,9 @@ static inline void lexer_SetGfxDigits(char const digits[4]) // `path` is referenced, but not held onto..! bool lexer_OpenFile(LexerState &state, char const *path); -void lexer_OpenFileView(LexerState &state, char const *path, char const *buf, size_t size, - uint32_t lineNo); +void lexer_OpenFileView( + LexerState &state, char const *path, char const *buf, size_t size, uint32_t lineNo +); void lexer_RestartRept(uint32_t lineNo); void lexer_CleanupState(LexerState &state); void lexer_Init(); diff --git a/include/asm/macro.hpp b/include/asm/macro.hpp index b90007a7..37759a07 100644 --- a/include/asm/macro.hpp +++ b/include/asm/macro.hpp @@ -8,10 +8,10 @@ #include #include -#include "asm/warning.hpp" - #include "helpers.hpp" +#include "asm/warning.hpp" + struct MacroArgs { unsigned int shift; std::vector args; diff --git a/include/asm/output.hpp b/include/asm/output.hpp index 9e7390d6..67d5c594 100644 --- a/include/asm/output.hpp +++ b/include/asm/output.hpp @@ -16,7 +16,9 @@ void out_RegisterNode(FileStackNode *node); void out_ReplaceNode(FileStackNode *node); void out_SetFileName(char *s); void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32_t pcShift); -void out_CreateAssert(enum AssertionType type, Expression const &expr, char const *message, uint32_t ofs); +void out_CreateAssert( + enum AssertionType type, Expression const &expr, char const *message, uint32_t ofs +); void out_WriteObject(); #endif // RGBDS_ASM_OUTPUT_H diff --git a/include/asm/rpn.hpp b/include/asm/rpn.hpp index 4f67ac86..8715a81d 100644 --- a/include/asm/rpn.hpp +++ b/include/asm/rpn.hpp @@ -5,18 +5,19 @@ #include #include +#include #include "linkdefs.hpp" struct Symbol; struct Expression { - int32_t val; // If the expression's value is known, it's here + int32_t val; // If the expression's value is known, it's here std::string *reason; // Why the expression is not known, if it isn't - bool isKnown; // Whether the expression's value is known at assembly time - bool isSymbol; // Whether the expression represents a symbol suitable for const diffing + bool isKnown; // Whether the expression's value is known at assembly time + bool isSymbol; // Whether the expression represents a symbol suitable for const diffing std::vector *rpn; // Bytes serializing the RPN expression - uint32_t rpnPatchSize; // Size the expression will take in the object file + uint32_t rpnPatchSize; // Size the expression will take in the object file int32_t getConstVal() const; Symbol const *symbolOf() const; @@ -26,7 +27,9 @@ struct Expression { void rpn_Number(Expression &expr, uint32_t val); void rpn_Symbol(Expression &expr, char const *symName); void rpn_LOGNOT(Expression &expr, const Expression &src); -void rpn_BinaryOp(enum RPNCommand op, Expression &expr, const Expression &src1, const Expression &src2); +void rpn_BinaryOp( + enum RPNCommand op, Expression &expr, const Expression &src1, const Expression &src2 +); void rpn_HIGH(Expression &expr, const Expression &src); void rpn_LOW(Expression &expr, const Expression &src); void rpn_ISCONST(Expression &expr, const Expression &src); diff --git a/include/asm/section.hpp b/include/asm/section.hpp index ca765e85..96f99c88 100644 --- a/include/asm/section.hpp +++ b/include/asm/section.hpp @@ -30,7 +30,7 @@ struct Section { enum SectionType type; enum SectionModifier modifier; FileStackNode const *src; // Where the section was defined - uint32_t fileLine; // Line where the section was defined + uint32_t fileLine; // Line where the section was defined uint32_t size; uint32_t org; uint32_t bank; @@ -52,10 +52,20 @@ extern std::deque
sectionList; extern Section *currentSection; Section *sect_FindSectionByName(char const *name); -void sect_NewSection(char const *name, enum SectionType type, uint32_t org, - SectionSpec const &attrs, enum SectionModifier mod); -void sect_SetLoadSection(char const *name, enum SectionType type, uint32_t org, - SectionSpec const &attrs, enum SectionModifier mod); +void sect_NewSection( + char const *name, + enum SectionType type, + uint32_t org, + SectionSpec const &attrs, + enum SectionModifier mod +); +void sect_SetLoadSection( + char const *name, + enum SectionType type, + uint32_t org, + SectionSpec const &attrs, + enum SectionModifier mod +); void sect_EndLoadSection(); Section *sect_GetSymbolSection(); diff --git a/include/asm/symbol.hpp b/include/asm/symbol.hpp index 2a4e58a8..8f46daf8 100644 --- a/include/asm/symbol.hpp +++ b/include/asm/symbol.hpp @@ -4,8 +4,8 @@ #define RGBDS_SYMBOL_H #include -#include #include +#include #include #include #include @@ -23,7 +23,7 @@ enum SymbolType { SYM_REF // Forward reference to a label }; -struct Symbol; // For the `sym_IsPC` forward declaration +struct Symbol; // For the `sym_IsPC` forward declaration bool sym_IsPC(Symbol const *sym); // For the inline `getSection` method struct Symbol { @@ -33,14 +33,15 @@ struct Symbol { bool isBuiltin; // Whether the symbol is a built-in Section *section; FileStackNode *src; // Where the symbol was defined - uint32_t fileLine; // Line where the symbol was defined + uint32_t fileLine; // Line where the symbol was defined std::variant< - int32_t, // If isNumeric() - int32_t (*)(), // If isNumeric() and has a callback - std::string_view *, // For SYM_MACRO - std::string * // For SYM_EQUS - > data; + int32_t, // If isNumeric() + int32_t (*)(), // If isNumeric() and has a callback + std::string_view *, // For SYM_MACRO + std::string * // For SYM_EQUS + > + data; uint32_t ID; // ID of the symbol in the object file (-1 if none) diff --git a/include/asm/warning.hpp b/include/asm/warning.hpp index d091ef87..a7e3b008 100644 --- a/include/asm/warning.hpp +++ b/include/asm/warning.hpp @@ -7,34 +7,29 @@ extern unsigned int nbErrors, maxErrors; -enum WarningState { - WARNING_DEFAULT, - WARNING_DISABLED, - WARNING_ENABLED, - WARNING_ERROR -}; +enum WarningState { WARNING_DEFAULT, WARNING_DISABLED, WARNING_ENABLED, WARNING_ERROR }; enum WarningID { - WARNING_ASSERT, // Assertions - WARNING_BACKWARDS_FOR, // `for` loop with backwards range - WARNING_BUILTIN_ARG, // Invalid args to builtins - WARNING_CHARMAP_REDEF, // Charmap entry re-definition - WARNING_DIV, // Division undefined behavior + WARNING_ASSERT, // Assertions + WARNING_BACKWARDS_FOR, // `for` loop with backwards range + WARNING_BUILTIN_ARG, // Invalid args to builtins + WARNING_CHARMAP_REDEF, // Charmap entry re-definition + WARNING_DIV, // Division undefined behavior WARNING_EMPTY_DATA_DIRECTIVE, // `db`, `dw` or `dl` directive without data in ROM WARNING_EMPTY_MACRO_ARG, // Empty macro argument - WARNING_EMPTY_STRRPL, // Empty second argument in `STRRPL` - WARNING_LARGE_CONSTANT, // Constants too large - WARNING_LONG_STR, // String too long for internal buffers - WARNING_MACRO_SHIFT, // Shift past available arguments in macro - WARNING_NESTED_COMMENT, // Comment-start delimiter in a block comment - WARNING_OBSOLETE, // Obsolete things - WARNING_SHIFT, // Shifting undefined behavior - WARNING_SHIFT_AMOUNT, // Strange shift amount - WARNING_USER, // User warnings + WARNING_EMPTY_STRRPL, // Empty second argument in `STRRPL` + WARNING_LARGE_CONSTANT, // Constants too large + WARNING_LONG_STR, // String too long for internal buffers + WARNING_MACRO_SHIFT, // Shift past available arguments in macro + WARNING_NESTED_COMMENT, // Comment-start delimiter in a block comment + WARNING_OBSOLETE, // Obsolete things + WARNING_SHIFT, // Shifting undefined behavior + WARNING_SHIFT_AMOUNT, // Strange shift amount + WARNING_USER, // User warnings NB_PLAIN_WARNINGS, - // Warnings past this point are "parametric" warnings, only mapping to a single flag +// Warnings past this point are "parametric" warnings, only mapping to a single flag #define PARAM_WARNINGS_START NB_PLAIN_WARNINGS // Treating string as number may lose some bits WARNING_NUMERIC_STRING_1 = PARAM_WARNINGS_START, @@ -49,7 +44,7 @@ enum WarningID { NB_PLAIN_AND_PARAM_WARNINGS, #define NB_PARAM_WARNINGS (NB_PLAIN_AND_PARAM_WARNINGS - PARAM_WARNINGS_START) - // Warnings past this point are "meta" warnings +// Warnings past this point are "meta" warnings #define META_WARNINGS_START NB_PLAIN_AND_PARAM_WARNINGS WARNING_ALL = META_WARNINGS_START, WARNING_EXTRA, diff --git a/include/error.hpp b/include/error.hpp index efcd699a..a735d4f9 100644 --- a/include/error.hpp +++ b/include/error.hpp @@ -8,12 +8,11 @@ extern "C" { -void warn(char const *fmt ...) format_(printf, 1, 2); +void warn(char const *fmt...) format_(printf, 1, 2); void warnx(char const *fmt, ...) format_(printf, 1, 2); [[noreturn]] void err(char const *fmt, ...) format_(printf, 1, 2); [[noreturn]] void errx(char const *fmt, ...) format_(printf, 1, 2); - } #endif // RGBDS_ERROR_H diff --git a/include/extern/getopt.hpp b/include/extern/getopt.hpp index 6808260d..fc6a892b 100644 --- a/include/extern/getopt.hpp +++ b/include/extern/getopt.hpp @@ -17,12 +17,13 @@ struct option { int val; }; -int musl_getopt_long_only(int argc, char **argv, char const *optstring, - const option *longopts, int *idx); +int musl_getopt_long_only( + int argc, char **argv, char const *optstring, const option *longopts, int *idx +); -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 } // extern "C" diff --git a/include/file.hpp b/include/file.hpp index 64cba9c6..f8cb917d 100644 --- a/include/file.hpp +++ b/include/file.hpp @@ -11,8 +11,8 @@ #include #include #include -#include #include +#include #include #include @@ -40,8 +40,11 @@ public: assert(!(mode & std::ios_base::out)); _file.emplace(std::cin.rdbuf()); if (setmode(STDIN_FILENO, (mode & std::ios_base::binary) ? O_BINARY : O_TEXT) == -1) { - fatal("Failed to set stdin to %s mode: %s", - mode & std::ios_base::binary ? "binary" : "text", strerror(errno)); + fatal( + "Failed to set stdin to %s mode: %s", + mode & std::ios_base::binary ? "binary" : "text", + strerror(errno) + ); } } else { assert(mode & std::ios_base::out); @@ -50,9 +53,12 @@ public: return this; } std::streambuf &operator*() { - return std::visit(Visitor{[](std::filebuf &file) -> std::streambuf & { return file; }, - [](std::streambuf *buf) -> std::streambuf & { return *buf; }}, - _file); + return std::visit( + Visitor{ + [](std::filebuf &file) -> std::streambuf & { return file; }, + [](std::streambuf *buf) -> std::streambuf & { return *buf; }}, + _file + ); } std::streambuf const &operator*() const { // The non-`const` version does not perform any modifications, so it's okay. @@ -65,25 +71,32 @@ public: } File *close() { - return std::visit(Visitor{[this](std::filebuf &file) { - // This is called by the destructor, and an explicit `close` - // shouldn't close twice. - _file.emplace(nullptr); - return file.close() != nullptr; - }, - [](std::streambuf *buf) { return buf != nullptr; }}, - _file) + return std::visit( + Visitor{ + [this](std::filebuf &file) { + // This is called by the destructor, and an explicit `close` + // shouldn't close twice. + _file.emplace(nullptr); + return file.close() != nullptr; + }, + [](std::streambuf *buf) { return buf != nullptr; }, + }, + _file + ) ? this : nullptr; } char const *c_str(std::string const &path) const { - return std::visit(Visitor{[&path](std::filebuf const &) { return path.c_str(); }, - [](std::streambuf const *buf) { - return buf == std::cin.rdbuf() - ? "" : ""; - }}, - _file); + return std::visit( + Visitor{ + [&path](std::filebuf const &) { return path.c_str(); }, + [](std::streambuf const *buf) { + return buf == std::cin.rdbuf() ? "" : ""; + }, + }, + _file + ); } }; diff --git a/include/gfx/main.hpp b/include/gfx/main.hpp index aac7bae7..d89c9330 100644 --- a/include/gfx/main.hpp +++ b/include/gfx/main.hpp @@ -19,13 +19,13 @@ struct Options { uint16_t reversedWidth = 0; // -r, in tiles bool reverse() const { return reversedWidth != 0; } - bool useColorCurve = false; // -C + bool useColorCurve = false; // -C bool allowMirroring = false; // -m - bool allowDedup = false; // -u - bool columnMajor = false; // -Z, previously -h - uint8_t verbosity = 0; // -v + bool allowDedup = false; // -u + bool columnMajor = false; // -Z, previously -h + uint8_t verbosity = 0; // -v - std::string attrmap{}; // -a, -A + std::string attrmap{}; // -a, -A std::array baseTileIDs{0, 0}; // -b enum { NO_SPEC, @@ -39,25 +39,25 @@ struct Options { uint16_t top; uint16_t width; uint16_t height; - } inputSlice{0, 0, 0, 0}; // -L (margins in clockwise order, like CSS) + } inputSlice{0, 0, 0, 0}; // -L (margins in clockwise order, like CSS) std::array maxNbTiles{UINT16_MAX, 0}; // -N - uint8_t nbPalettes = 8; // -n - std::string output{}; // -o - std::string palettes{}; // -p, -P - std::string palmap{}; // -q, -Q - uint8_t nbColorsPerPal = 0; // -s; 0 means "auto" = 1 << bitDepth; - std::string tilemap{}; // -t, -T - uint64_t trim = 0; // -x + uint8_t nbPalettes = 8; // -n + std::string output{}; // -o + std::string palettes{}; // -p, -P + std::string palmap{}; // -q, -Q + uint8_t nbColorsPerPal = 0; // -s; 0 means "auto" = 1 << bitDepth; + std::string tilemap{}; // -t, -T + uint64_t trim = 0; // -x std::string input{}; // positional arg - static constexpr uint8_t VERB_NONE = 0; // Normal, no extra output - static constexpr uint8_t VERB_CFG = 1; // Print configuration after parsing options - static constexpr uint8_t VERB_LOG_ACT = 2; // Log actions before doing them - static constexpr uint8_t VERB_INTERM = 3; // Print some intermediate results - static constexpr uint8_t VERB_DEBUG = 4; // Internals are logged + static constexpr uint8_t VERB_NONE = 0; // Normal, no extra output + static constexpr uint8_t VERB_CFG = 1; // Print configuration after parsing options + static constexpr uint8_t VERB_LOG_ACT = 2; // Log actions before doing them + static constexpr uint8_t VERB_INTERM = 3; // Print some intermediate results + static constexpr uint8_t VERB_DEBUG = 4; // Internals are logged static constexpr uint8_t VERB_UNMAPPED = 5; // Unused so far - static constexpr uint8_t VERB_VVVVVV = 6; // What, can't I have a little fun? + static constexpr uint8_t VERB_VVVVVV = 6; // What, can't I have a little fun? format_(printf, 3, 4) void verbosePrint(uint8_t level, char const *fmt, ...) const; mutable bool hasTransparentPixels = false; diff --git a/include/gfx/pal_sorting.hpp b/include/gfx/pal_sorting.hpp index 73957a3c..333401aa 100644 --- a/include/gfx/pal_sorting.hpp +++ b/include/gfx/pal_sorting.hpp @@ -15,10 +15,16 @@ struct Palette; namespace sorting { -void indexed(std::vector &palettes, int palSize, png_color const *palRGB, - int palAlphaSize, png_byte *palAlpha); -void grayscale(std::vector &palettes, - std::array, 0x8001> const &colors); +void indexed( + std::vector &palettes, + int palSize, + png_color const *palRGB, + int palAlphaSize, + png_byte *palAlpha +); +void grayscale( + std::vector &palettes, std::array, 0x8001> const &colors +); void rgb(std::vector &palettes); } // namespace sorting diff --git a/include/gfx/rgba.hpp b/include/gfx/rgba.hpp index 65e49218..359c0a9f 100644 --- a/include/gfx/rgba.hpp +++ b/include/gfx/rgba.hpp @@ -25,8 +25,12 @@ struct Rgba { fiveBpp &= 0b11111; // For caller's convenience return fiveBpp << 3 | fiveBpp >> 2; }; - return {_5to8(cgbColor), _5to8(cgbColor >> 5), _5to8(cgbColor >> 10), - (uint8_t)(cgbColor & 0x8000 ? 0x00 : 0xFF)}; + return { + _5to8(cgbColor), + _5to8(cgbColor >> 5), + _5to8(cgbColor >> 10), + (uint8_t)(cgbColor & 0x8000 ? 0x00 : 0xFF), + }; } /* diff --git a/include/helpers.hpp b/include/helpers.hpp index d7f64dc0..13f5e1a9 100644 --- a/include/helpers.hpp +++ b/include/helpers.hpp @@ -6,8 +6,8 @@ // Ideally, we'd use `__has_attribute` and `__has_builtin`, but these were only introduced in GCC 9 #ifdef __GNUC__ // GCC or compatible #define format_(archetype, str_index, first_arg) \ - __attribute__ ((format (archetype, str_index, first_arg))) - #define attr_(...) __attribute__ ((__VA_ARGS__)) + __attribute__((format(archetype, str_index, first_arg))) + #define attr_(...) __attribute__((__VA_ARGS__)) // In release builds, define "unreachable" as such, but trap in debug builds #ifdef NDEBUG #define unreachable_ __builtin_unreachable @@ -18,9 +18,10 @@ // Unsupported, but no need to throw a fit #define format_(archetype, str_index, first_arg) #define attr_(...) - // This seems to generate similar code to __builtin_unreachable, despite different semantics - // Note that executing this is undefined behavior (declared [[noreturn]], but does return) - [[noreturn]] static inline void unreachable_() {} +// This seems to generate similar code to __builtin_unreachable, despite different semantics +// Note that executing this is undefined behavior (declared [[noreturn]], but does return) +[[noreturn]] static inline void unreachable_() { +} #endif // Use builtins whenever possible, and shim them otherwise @@ -32,50 +33,46 @@ #include #include #pragma intrinsic(_BitScanReverse, _BitScanForward) - static inline int ctz(unsigned int x) - { - unsigned long cnt; +static inline int ctz(unsigned int x) { + unsigned long cnt; - assert(x != 0); - _BitScanForward(&cnt, x); - return cnt; - } - static inline int clz(unsigned int x) - { - unsigned long cnt; + assert(x != 0); + _BitScanForward(&cnt, x); + return cnt; +} +static inline int clz(unsigned int x) { + unsigned long cnt; - assert(x != 0); - _BitScanReverse(&cnt, x); - return 31 - cnt; - } + assert(x != 0); + _BitScanReverse(&cnt, x); + return 31 - cnt; +} #else #include - static inline int ctz(unsigned int x) - { - int cnt = 0; +static inline int ctz(unsigned int x) { + int cnt = 0; - while (!(x & 1)) { - x >>= 1; - cnt++; - } - return cnt; + while (!(x & 1)) { + x >>= 1; + cnt++; } + return cnt; +} - static inline int clz(unsigned int x) - { - int cnt = 0; +static inline int clz(unsigned int x) { + int cnt = 0; - while (x <= UINT_MAX / 2) { - x <<= 1; - cnt++; - } - return cnt; + while (x <= UINT_MAX / 2) { + x <<= 1; + cnt++; } + return cnt; +} #endif // Macros for stringification -#define STR(x) #x +#define STR(x) #x #define EXPAND_AND_STR(x) STR(x) // Obtaining the size of an array; `arr` must be an expression, not a type! diff --git a/include/itertools.hpp b/include/itertools.hpp index 2e4f8cef..1a83dde8 100644 --- a/include/itertools.hpp +++ b/include/itertools.hpp @@ -64,8 +64,9 @@ public: } auto operator*() const { - return std::apply([](auto &&...it) { return std::tuple(*it...); }, - _iters); + return std::apply( + [](auto &&...it) { return std::tuple(*it...); }, _iters + ); } friend auto operator==(Zip const &lhs, Zip const &rhs) { @@ -92,7 +93,8 @@ public: using std::begin; return std::make_tuple(begin(containers)...); }, - _containers)); + _containers + )); } auto end() { @@ -101,14 +103,15 @@ public: using std::end; return std::make_tuple(end(containers)...); }, - _containers)); + _containers + )); } }; // Take ownership of objects and rvalue refs passed to us, but not lvalue refs template -using Holder = std::conditional_t, T, - std::remove_cv_t>>; +using Holder = std:: + conditional_t, T, std::remove_cv_t>>; } // namespace detail // Does the same number of iterations as the first container's iterator! diff --git a/include/link/main.hpp b/include/link/main.hpp index e48567ab..78bbbfac 100644 --- a/include/link/main.hpp +++ b/include/link/main.hpp @@ -31,10 +31,11 @@ extern bool isWRAM0Mode; extern bool disablePadding; // Helper macro for printing verbose-mode messages -#define verbosePrint(...) do { \ - if (beVerbose) \ - fprintf(stderr, __VA_ARGS__); \ -} while (0) +#define verbosePrint(...) \ + do { \ + if (beVerbose) \ + fprintf(stderr, __VA_ARGS__); \ + } while (0) struct FileStackNode { FileStackNode *parent; @@ -43,10 +44,11 @@ struct FileStackNode { enum FileStackNodeType type; std::variant< - std::monostate, // Default constructed; `.type` and `.data` must be set manually - std::vector, // NODE_REPT - std::string // NODE_FILE, NODE_MACRO - > data; + std::monostate, // Default constructed; `.type` and `.data` must be set manually + std::vector, // NODE_REPT + std::string // NODE_FILE, NODE_MACRO + > + data; // REPT iteration counts since last named node, in reverse depth order std::vector &iters(); @@ -58,8 +60,10 @@ struct FileStackNode { std::string const *dumpFileStack() const; }; -void warning(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4); +void warning(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) + format_(printf, 3, 4); void error(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4); -[[noreturn]] void fatal(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) format_(printf, 3, 4); +[[noreturn]] void fatal(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) + format_(printf, 3, 4); #endif // RGBDS_LINK_MAIN_H diff --git a/include/link/patch.hpp b/include/link/patch.hpp index 4036d6ea..c4faceed 100644 --- a/include/link/patch.hpp +++ b/include/link/patch.hpp @@ -8,10 +8,10 @@ #include #include -#include "link/section.hpp" - #include "linkdefs.hpp" +#include "link/section.hpp" + struct Assertion { Patch patch; // Also used for its `.type` std::string message; diff --git a/include/link/section.hpp b/include/link/section.hpp index 181f6769..8ee62ee3 100644 --- a/include/link/section.hpp +++ b/include/link/section.hpp @@ -10,10 +10,10 @@ #include #include -#include "link/main.hpp" - #include "linkdefs.hpp" +#include "link/main.hpp" + struct FileStackNode; struct Section; struct Symbol; diff --git a/include/link/symbol.hpp b/include/link/symbol.hpp index d49e0272..5e043b5e 100644 --- a/include/link/symbol.hpp +++ b/include/link/symbol.hpp @@ -30,9 +30,10 @@ struct Symbol { FileStackNode const *src; int32_t lineNo; std::variant< - int32_t, // Constants just have a numeric value - Label // Label values refer to an offset within a specific section - > data; + int32_t, // Constants just have a numeric value + Label // Label values refer to an offset within a specific section + > + data; Label &label(); Label const &label() const; diff --git a/include/linkdefs.hpp b/include/linkdefs.hpp index 41a4f292..d601d512 100644 --- a/include/linkdefs.hpp +++ b/include/linkdefs.hpp @@ -8,56 +8,52 @@ #include #define RGBDS_OBJECT_VERSION_STRING "RGBA" -#define RGBDS_OBJECT_REV 10U +#define RGBDS_OBJECT_REV 10U -enum AssertionType { - ASSERT_WARN, - ASSERT_ERROR, - ASSERT_FATAL -}; +enum AssertionType { ASSERT_WARN, ASSERT_ERROR, ASSERT_FATAL }; enum RPNCommand { - RPN_ADD = 0x00, - RPN_SUB = 0x01, - RPN_MUL = 0x02, - RPN_DIV = 0x03, - RPN_MOD = 0x04, - RPN_NEG = 0x05, - RPN_EXP = 0x06, + RPN_ADD = 0x00, + RPN_SUB = 0x01, + RPN_MUL = 0x02, + RPN_DIV = 0x03, + RPN_MOD = 0x04, + RPN_NEG = 0x05, + RPN_EXP = 0x06, - RPN_OR = 0x10, - RPN_AND = 0x11, - RPN_XOR = 0x12, - RPN_NOT = 0x13, + RPN_OR = 0x10, + RPN_AND = 0x11, + RPN_XOR = 0x12, + RPN_NOT = 0x13, - RPN_LOGAND = 0x21, - RPN_LOGOR = 0x22, - RPN_LOGNOT = 0x23, + RPN_LOGAND = 0x21, + RPN_LOGOR = 0x22, + RPN_LOGNOT = 0x23, - RPN_LOGEQ = 0x30, - RPN_LOGNE = 0x31, - RPN_LOGGT = 0x32, - RPN_LOGLT = 0x33, - RPN_LOGGE = 0x34, - RPN_LOGLE = 0x35, + RPN_LOGEQ = 0x30, + RPN_LOGNE = 0x31, + RPN_LOGGT = 0x32, + RPN_LOGLT = 0x33, + RPN_LOGGE = 0x34, + RPN_LOGLE = 0x35, - RPN_SHL = 0x40, - RPN_SHR = 0x41, - RPN_USHR = 0x42, + RPN_SHL = 0x40, + RPN_SHR = 0x41, + RPN_USHR = 0x42, - RPN_BANK_SYM = 0x50, - RPN_BANK_SECT = 0x51, - RPN_BANK_SELF = 0x52, - RPN_SIZEOF_SECT = 0x53, - RPN_STARTOF_SECT = 0x54, - RPN_SIZEOF_SECTTYPE = 0x55, - RPN_STARTOF_SECTTYPE = 0x56, + RPN_BANK_SYM = 0x50, + RPN_BANK_SECT = 0x51, + RPN_BANK_SELF = 0x52, + RPN_SIZEOF_SECT = 0x53, + RPN_STARTOF_SECT = 0x54, + RPN_SIZEOF_SECTTYPE = 0x55, + RPN_STARTOF_SECTTYPE = 0x56, - RPN_HRAM = 0x60, - RPN_RST = 0x61, + RPN_HRAM = 0x60, + RPN_RST = 0x61, - RPN_CONST = 0x80, - RPN_SYM = 0x81 + RPN_CONST = 0x80, + RPN_SYM = 0x81 }; enum SectionType { @@ -96,8 +92,7 @@ extern struct SectionTypeInfo { * @param type The section's type * @return `true` if the section's definition includes data */ -static inline bool sect_HasData(enum SectionType type) -{ +static inline bool sect_HasData(enum SectionType type) { assert(type != SECTTYPE_INVALID); return type == SECTTYPE_ROM0 || type == SECTTYPE_ROMX; } @@ -106,8 +101,7 @@ static inline bool sect_HasData(enum SectionType type) * Computes a memory region's end address (last byte), eg. 0x7FFF * @return The address of the last byte in that memory region */ -static inline uint16_t endaddr(enum SectionType type) -{ +static inline uint16_t endaddr(enum SectionType type) { return sectionTypeInfo[type].startAddr + sectionTypeInfo[type].size - 1; } @@ -115,24 +109,15 @@ static inline uint16_t endaddr(enum SectionType type) * Computes a memory region's number of banks * @return The number of banks, 1 for regions without banking */ -static inline uint32_t nbbanks(enum SectionType type) -{ +static inline uint32_t nbbanks(enum SectionType type) { return sectionTypeInfo[type].lastBank - sectionTypeInfo[type].firstBank + 1; } -enum SectionModifier { - SECTION_NORMAL, - SECTION_UNION, - SECTION_FRAGMENT -}; +enum SectionModifier { SECTION_NORMAL, SECTION_UNION, SECTION_FRAGMENT }; extern char const * const sectionModNames[]; -enum ExportLevel { - SYMTYPE_LOCAL, - SYMTYPE_IMPORT, - SYMTYPE_EXPORT -}; +enum ExportLevel { SYMTYPE_LOCAL, SYMTYPE_IMPORT, SYMTYPE_EXPORT }; enum PatchType { PATCHTYPE_BYTE, diff --git a/include/platform.hpp b/include/platform.hpp index 8360df21..dd383b03 100644 --- a/include/platform.hpp +++ b/include/platform.hpp @@ -7,62 +7,62 @@ // MSVC doesn't have str(n)casecmp, use a suitable replacement #ifdef _MSC_VER -# include -# define strcasecmp _stricmp -# define strncasecmp _strnicmp + #include + #define strcasecmp _stricmp + #define strncasecmp _strnicmp #else -# include + #include #endif // MSVC prefixes the names of S_* macros with underscores, // and doesn't define any S_IS* macros; define them ourselves #ifdef _MSC_VER -# define S_IFMT _S_IFMT -# define S_IFDIR _S_IFDIR -# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) + #define S_IFMT _S_IFMT + #define S_IFDIR _S_IFDIR + #define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) #endif // gcc has __PRETTY_FUNCTION__, MSVC has __FUNCSIG__, __func__ is standard #ifndef __PRETTY_FUNCTION__ -# ifdef __FUNCSIG__ -# define __PRETTY_FUNCTION__ __FUNCSIG__ -# else -# define __PRETTY_FUNCTION__ __func__ -# endif + #ifdef __FUNCSIG__ + #define __PRETTY_FUNCTION__ __FUNCSIG__ + #else + #define __PRETTY_FUNCTION__ __func__ + #endif #endif // MSVC doesn't use POSIX types or defines for `read` #ifdef _MSC_VER -# include -# define STDIN_FILENO 0 -# define STDOUT_FILENO 1 -# define STDERR_FILENO 2 -# define ssize_t int -# define SSIZE_MAX INT_MAX + #include + #define STDIN_FILENO 0 + #define STDOUT_FILENO 1 + #define STDERR_FILENO 2 + #define ssize_t int + #define SSIZE_MAX INT_MAX #else -# include -# include -# include + #include + #include + #include #endif // MSVC uses a different name for O_RDWR, and needs an additional _O_BINARY flag #ifdef _MSC_VER -# include -# define O_RDWR _O_RDWR -# define S_ISREG(field) ((field) & _S_IFREG) -# define O_BINARY _O_BINARY -# define O_TEXT _O_TEXT + #include + #define O_RDWR _O_RDWR + #define S_ISREG(field) ((field)&_S_IFREG) + #define O_BINARY _O_BINARY + #define O_TEXT _O_TEXT #elif !defined(O_BINARY) // Cross-compilers define O_BINARY -# define O_BINARY 0 // POSIX says we shouldn't care! -# define O_TEXT 0 // Assume that it's not defined either -#endif // _MSC_VER + #define O_BINARY 0 // POSIX says we shouldn't care! + #define O_TEXT 0 // Assume that it's not defined either +#endif // _MSC_VER // Windows has stdin and stdout open as text by default, which we may not want #if defined(_MSC_VER) || defined(__MINGW32__) -# include -# define setmode(fd, mode) _setmode(fd, mode) + #include + #define setmode(fd, mode) _setmode(fd, mode) #else -# define setmode(fd, mode) (0) + #define setmode(fd, mode) (0) #endif #endif // RGBDS_PLATFORM_H diff --git a/include/version.hpp b/include/version.hpp index 7c6c5f21..a1b8937e 100644 --- a/include/version.hpp +++ b/include/version.hpp @@ -10,7 +10,6 @@ extern "C" { #define PACKAGE_VERSION_PATCH 0 char const *get_package_version_string(); - } #endif // EXTERN_VERSION_H diff --git a/src/asm/charmap.cpp b/src/asm/charmap.cpp index e92301b7..7a626acc 100644 --- a/src/asm/charmap.cpp +++ b/src/asm/charmap.cpp @@ -1,29 +1,30 @@ /* SPDX-License-Identifier: MIT */ +#include "asm/charmap.hpp" + #include -#include #include +#include #include #include -#include #include -#include +#include #include +#include #include -#include "asm/charmap.hpp" +#include "util.hpp" + #include "asm/main.hpp" #include "asm/output.hpp" #include "asm/warning.hpp" -#include "util.hpp" - // Charmaps are stored using a structure known as "trie". // Essentially a tree, where each nodes stores a single character's worth of info: // whether there exists a mapping that ends at the current character, struct CharmapNode { bool isTerminal; // Whether there exists a mapping that ends here - uint8_t value; // If the above is true, its corresponding value + uint8_t value; // If the above is true, its corresponding value // This MUST be indexes and not pointers, because pointers get invalidated by reallocation! size_t next[255]; // Indexes of where to go next, 0 = nowhere }; @@ -38,8 +39,7 @@ static std::map charmaps; static Charmap *currentCharmap; std::stack charmapStack; -void charmap_New(char const *name, char const *baseName) -{ +void charmap_New(char const *name, char const *baseName) { Charmap *base = nullptr; if (baseName != nullptr) { @@ -68,8 +68,7 @@ void charmap_New(char const *name, char const *baseName) currentCharmap = &charmap; } -void charmap_Set(char const *name) -{ +void charmap_Set(char const *name) { auto search = charmaps.find(name); if (search == charmaps.end()) @@ -78,13 +77,11 @@ void charmap_Set(char const *name) currentCharmap = &search->second; } -void charmap_Push() -{ +void charmap_Push() { charmapStack.push(currentCharmap); } -void charmap_Pop() -{ +void charmap_Pop() { if (charmapStack.empty()) { error("No entries in the charmap stack\n"); return; @@ -94,8 +91,7 @@ void charmap_Pop() charmapStack.pop(); } -void charmap_Add(char *mapping, uint8_t value) -{ +void charmap_Add(char *mapping, uint8_t value) { Charmap &charmap = *currentCharmap; size_t nodeIdx = 0; @@ -124,8 +120,7 @@ void charmap_Add(char *mapping, uint8_t value) node.value = value; } -bool charmap_HasChar(char const *input) -{ +bool charmap_HasChar(char const *input) { Charmap const &charmap = *currentCharmap; size_t nodeIdx = 0; @@ -139,14 +134,12 @@ bool charmap_HasChar(char const *input) return charmap.nodes[nodeIdx].isTerminal; } -void charmap_Convert(char const *input, std::vector &output) -{ +void charmap_Convert(char const *input, std::vector &output) { while (charmap_ConvertNext(input, &output)) ; } -size_t charmap_ConvertNext(char const *&input, std::vector *output) -{ +size_t charmap_ConvertNext(char const *&input, std::vector *output) { // The goal is to match the longest mapping possible. // For that, advance through the trie with each character read. // If that would lead to a dead end, rewind characters until the last match, and output. @@ -194,11 +187,13 @@ size_t charmap_ConvertNext(char const *&input, std::vector *output) // Warn if this character is not mapped but any others are if (charmap.nodes.size() > 1) - warning(WARNING_UNMAPPED_CHAR_1, "Unmapped character %s\n", - printChar(firstChar)); + warning(WARNING_UNMAPPED_CHAR_1, "Unmapped character %s\n", printChar(firstChar)); else if (charmap.name != DEFAULT_CHARMAP_NAME) - warning(WARNING_UNMAPPED_CHAR_2, "Unmapped character %s not in " - DEFAULT_CHARMAP_NAME " charmap\n", printChar(firstChar)); + warning( + WARNING_UNMAPPED_CHAR_2, + "Unmapped character %s not in " DEFAULT_CHARMAP_NAME " charmap\n", + printChar(firstChar) + ); return codepointLen; diff --git a/src/asm/fixpoint.cpp b/src/asm/fixpoint.cpp index 766c144c..2ff336d8 100644 --- a/src/asm/fixpoint.cpp +++ b/src/asm/fixpoint.cpp @@ -2,20 +2,21 @@ // Fixed-point math routines +#include "asm/fixpoint.hpp" + #include #include #include -#include "asm/fixpoint.hpp" #include "asm/symbol.hpp" #include "asm/warning.hpp" #ifndef M_PI -#define M_PI 3.14159265358979323846 + #define M_PI 3.14159265358979323846 #endif #define fix2double(i, q) ((double)((i) / pow(2.0, q))) -#define double2fix(d, q) ((int32_t)round((d) * pow(2.0, q))) +#define double2fix(d, q) ((int32_t)round((d)*pow(2.0, q))) // 2*pi radians == 1 turn #define turn2rad(f) ((f) * (M_PI * 2)) @@ -23,87 +24,70 @@ uint8_t fixPrecision; -uint8_t fix_Precision() -{ +uint8_t fix_Precision() { return fixPrecision; } -double fix_PrecisionFactor() -{ +double fix_PrecisionFactor() { return pow(2.0, fixPrecision); } -int32_t fix_Sin(int32_t i, int32_t q) -{ +int32_t fix_Sin(int32_t i, int32_t q) { return double2fix(sin(turn2rad(fix2double(i, q))), q); } -int32_t fix_Cos(int32_t i, int32_t q) -{ +int32_t fix_Cos(int32_t i, int32_t q) { return double2fix(cos(turn2rad(fix2double(i, q))), q); } -int32_t fix_Tan(int32_t i, int32_t q) -{ +int32_t fix_Tan(int32_t i, int32_t q) { return double2fix(tan(turn2rad(fix2double(i, q))), q); } -int32_t fix_ASin(int32_t i, int32_t q) -{ +int32_t fix_ASin(int32_t i, int32_t q) { return double2fix(rad2turn(asin(fix2double(i, q))), q); } -int32_t fix_ACos(int32_t i, int32_t q) -{ +int32_t fix_ACos(int32_t i, int32_t q) { return double2fix(rad2turn(acos(fix2double(i, q))), q); } -int32_t fix_ATan(int32_t i, int32_t q) -{ +int32_t fix_ATan(int32_t i, int32_t q) { return double2fix(rad2turn(atan(fix2double(i, q))), q); } -int32_t fix_ATan2(int32_t i, int32_t j, int32_t q) -{ +int32_t fix_ATan2(int32_t i, int32_t j, int32_t q) { return double2fix(rad2turn(atan2(fix2double(i, q), fix2double(j, q))), q); } -int32_t fix_Mul(int32_t i, int32_t j, int32_t q) -{ +int32_t fix_Mul(int32_t i, int32_t j, int32_t q) { return double2fix(fix2double(i, q) * fix2double(j, q), q); } -int32_t fix_Div(int32_t i, int32_t j, int32_t q) -{ +int32_t fix_Div(int32_t i, int32_t j, int32_t q) { return double2fix(fix2double(i, q) / fix2double(j, q), q); } -int32_t fix_Mod(int32_t i, int32_t j, int32_t q) -{ +int32_t fix_Mod(int32_t i, int32_t j, int32_t q) { return double2fix(fmod(fix2double(i, q), fix2double(j, q)), q); } -int32_t fix_Pow(int32_t i, int32_t j, int32_t q) -{ +int32_t fix_Pow(int32_t i, int32_t j, int32_t q) { return double2fix(pow(fix2double(i, q), fix2double(j, q)), q); } -int32_t fix_Log(int32_t i, int32_t j, int32_t q) -{ +int32_t fix_Log(int32_t i, int32_t j, int32_t q) { return double2fix(log(fix2double(i, q)) / log(fix2double(j, q)), q); } -int32_t fix_Round(int32_t i, int32_t q) -{ +int32_t fix_Round(int32_t i, int32_t q) { return double2fix(round(fix2double(i, q)), q); } -int32_t fix_Ceil(int32_t i, int32_t q) -{ +int32_t fix_Ceil(int32_t i, int32_t q) { return double2fix(ceil(fix2double(i, q)), q); } -int32_t fix_Floor(int32_t i, int32_t q) -{ +int32_t fix_Floor(int32_t i, int32_t q) { return double2fix(floor(fix2double(i, q)), q); } diff --git a/src/asm/format.cpp b/src/asm/format.cpp index c60e27af..12d0046a 100644 --- a/src/asm/format.cpp +++ b/src/asm/format.cpp @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: MIT */ +#include "asm/format.hpp" + #include #include #include @@ -9,11 +11,9 @@ #include #include "asm/fixpoint.hpp" -#include "asm/format.hpp" #include "asm/warning.hpp" -void FormatSpec::useCharacter(int c) -{ +void FormatSpec::useCharacter(int c) { if (state == FORMAT_INVALID) return; @@ -99,14 +99,12 @@ invalid: } } -void FormatSpec::finishCharacters() -{ +void FormatSpec::finishCharacters() { if (!isValid()) state = FORMAT_INVALID; } -void FormatSpec::printString(char *buf, size_t bufLen, char const *value) -{ +void FormatSpec::printString(char *buf, size_t bufLen, char const *value) { if (isEmpty()) { // No format was specified type = 's'; @@ -149,8 +147,7 @@ void FormatSpec::printString(char *buf, size_t bufLen, char const *value) buf[totalLen] = '\0'; } -void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value) -{ +void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value) { if (isEmpty()) { // No format was specified; default to uppercase $hex type = 'X'; @@ -175,12 +172,12 @@ void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value) } } - char prefixChar = !prefix ? 0 - : type == 'X' ? '$' - : type == 'x' ? '$' - : type == 'b' ? '%' - : type == 'o' ? '&' - : 0; + char prefixChar = !prefix ? 0 + : type == 'X' ? '$' + : type == 'x' ? '$' + : type == 'b' ? '%' + : type == 'o' ? '&' + : 0; char valueBuf[262]; // Max 5 digits + decimal + 255 fraction digits + terminator @@ -215,15 +212,16 @@ void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value) cappedFracWidth = 255; } - snprintf(valueBuf, sizeof(valueBuf), "%.*f", (int)cappedFracWidth, - value / fix_PrecisionFactor()); + snprintf( + valueBuf, sizeof(valueBuf), "%.*f", (int)cappedFracWidth, value / fix_PrecisionFactor() + ); } else { - char const *spec = type == 'd' ? "%" PRId32 - : type == 'u' ? "%" PRIu32 - : type == 'X' ? "%" PRIX32 - : type == 'x' ? "%" PRIx32 - : type == 'o' ? "%" PRIo32 - : "%" PRId32; + char const *spec = type == 'd' ? "%" PRId32 + : type == 'u' ? "%" PRIu32 + : type == 'X' ? "%" PRIX32 + : type == 'x' ? "%" PRIx32 + : type == 'o' ? "%" PRIo32 + : "%" PRId32; snprintf(valueBuf, sizeof(valueBuf), spec, value); } diff --git a/src/asm/fstack.cpp b/src/asm/fstack.cpp index 249ab735..f6be7cfd 100644 --- a/src/asm/fstack.cpp +++ b/src/asm/fstack.cpp @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: MIT */ #include -#include + #include #include #include @@ -15,13 +15,14 @@ #include #include +#include "error.hpp" +#include "platform.hpp" // S_ISDIR (stat macro) + #include "asm/fstack.hpp" #include "asm/macro.hpp" #include "asm/main.hpp" #include "asm/symbol.hpp" #include "asm/warning.hpp" -#include "error.hpp" -#include "platform.hpp" // S_ISDIR (stat macro) struct Context { FileStackNode *fileInfo; @@ -39,7 +40,7 @@ static std::stack contextStack; size_t maxRecursionDepth; // The first include path for `fstk_FindFile` to try is none at all -static std::vector includePaths = { "" }; +static std::vector includePaths = {""}; static const char *preIncludeName; @@ -63,8 +64,7 @@ std::string const &FileStackNode::name() const { return std::get(data); } -static const char *dumpNodeAndParents(FileStackNode const &node) -{ +static const char *dumpNodeAndParents(FileStackNode const &node) { char const *name; if (node.type == NODE_REPT) { @@ -73,7 +73,7 @@ static const char *dumpNodeAndParents(FileStackNode const &node) name = dumpNodeAndParents(*node.parent); fprintf(stderr, "(%" PRIu32 ") -> %s", node.lineNo, name); - for (uint32_t i = nodeIters.size(); i--; ) + for (uint32_t i = nodeIters.size(); i--;) fprintf(stderr, "::REPT~%" PRIu32, nodeIters[i]); } else { name = node.name().c_str(); @@ -87,14 +87,12 @@ static const char *dumpNodeAndParents(FileStackNode const &node) return name; } -void FileStackNode::dump(uint32_t curLineNo) const -{ +void FileStackNode::dump(uint32_t curLineNo) const { dumpNodeAndParents(*this); fprintf(stderr, "(%" PRIu32 ")", curLineNo); } -void fstk_DumpCurrent() -{ +void fstk_DumpCurrent() { if (contextStack.empty()) { fputs("at top level", stderr); return; @@ -102,8 +100,7 @@ void fstk_DumpCurrent() contextStack.top().fileInfo->dump(lexer_GetLineNo()); } -FileStackNode *fstk_GetFileStack() -{ +FileStackNode *fstk_GetFileStack() { if (contextStack.empty()) return nullptr; @@ -117,8 +114,7 @@ FileStackNode *fstk_GetFileStack() return topNode; } -char const *fstk_GetFileName() -{ +char const *fstk_GetFileName() { // Iterating via the nodes themselves skips nested REPTs FileStackNode const *node = contextStack.top().fileInfo; @@ -127,8 +123,7 @@ char const *fstk_GetFileName() return node->name().c_str(); } -void fstk_AddIncludePath(char const *path) -{ +void fstk_AddIncludePath(char const *path) { if (path[0] == '\0') return; @@ -138,8 +133,7 @@ void fstk_AddIncludePath(char const *path) str += '/'; } -void fstk_SetPreIncludeFile(char const *path) -{ +void fstk_SetPreIncludeFile(char const *path) { if (preIncludeName) warnx("Overriding pre-included filename %s", preIncludeName); preIncludeName = path; @@ -147,8 +141,7 @@ void fstk_SetPreIncludeFile(char const *path) printf("Pre-included filename %s\n", preIncludeName); } -static void printDep(char const *path) -{ +static void printDep(char const *path) { if (dependfile) { fprintf(dependfile, "%s: %s\n", targetFileName.c_str(), path); if (generatePhonyDeps) @@ -156,8 +149,7 @@ static void printDep(char const *path) } } -static bool isPathValid(char const *path) -{ +static bool isPathValid(char const *path) { struct stat statbuf; if (stat(path, &statbuf) != 0) @@ -167,9 +159,8 @@ static bool isPathValid(char const *path) return !S_ISDIR(statbuf.st_mode); } -std::string *fstk_FindFile(char const *path) -{ - std::string *fullPath = new(std::nothrow) std::string(); +std::string *fstk_FindFile(char const *path) { + std::string *fullPath = new (std::nothrow) std::string(); if (!fullPath) { error("Failed to allocate string during include path search: %s\n", strerror(errno)); @@ -189,20 +180,22 @@ std::string *fstk_FindFile(char const *path) return nullptr; } -bool yywrap() -{ +bool yywrap() { uint32_t ifDepth = lexer_GetIFDepth(); if (ifDepth != 0) - fatalerror("Ended block with %" PRIu32 " unterminated IF construct%s\n", - ifDepth, ifDepth == 1 ? "" : "s"); + fatalerror( + "Ended block with %" PRIu32 " unterminated IF construct%s\n", + ifDepth, + ifDepth == 1 ? "" : "s" + ); if (Context &context = contextStack.top(); context.fileInfo->type == NODE_REPT) { // The context is a REPT or FOR block, which may loop // If the node is referenced, we can't edit it; duplicate it if (context.fileInfo->referenced) { - context.fileInfo = new(std::nothrow) FileStackNode(*context.fileInfo); + context.fileInfo = new (std::nothrow) FileStackNode(*context.fileInfo); if (!context.fileInfo) fatalerror("Failed to duplicate REPT file node: %s\n", strerror(errno)); // Copy all info but the referencing @@ -255,8 +248,7 @@ bool yywrap() // Make sure not to switch the lexer state before calling this, so the saved line no is correct. // BE CAREFUL! This modifies the file stack directly, you should have set up the file info first. // Callers should set `contextStack.top().lexerState` after this so it is not `nullptr`. -static Context &newContext(FileStackNode &fileInfo) -{ +static Context &newContext(FileStackNode &fileInfo) { if (contextStack.size() > maxRecursionDepth) fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth); @@ -277,15 +269,13 @@ static Context &newContext(FileStackNode &fileInfo) return context; } -void fstk_RunInclude(char const *path) -{ +void fstk_RunInclude(char const *path) { std::string *fullPath = fstk_FindFile(path); if (!fullPath) { if (generatedMissingIncludes) { if (verbose) - printf("Aborting (-MG) on INCLUDE file '%s' (%s)\n", - path, strerror(errno)); + printf("Aborting (-MG) on INCLUDE file '%s' (%s)\n", path, strerror(errno)); failedOnMissingInclude = true; } else { error("Unable to open included file '%s': %s\n", path, strerror(errno)); @@ -293,7 +283,7 @@ void fstk_RunInclude(char const *path) return; } - FileStackNode *fileInfo = new(std::nothrow) FileStackNode(); + FileStackNode *fileInfo = new (std::nothrow) FileStackNode(); if (!fileInfo) { error("Failed to alloc file info for INCLUDE: %s\n", strerror(errno)); @@ -317,8 +307,7 @@ void fstk_RunInclude(char const *path) // Similar to `fstk_RunInclude`, but not subject to `-MG`, and // calling `lexer_SetState` instead of `lexer_SetStateAtEOL`. -static void runPreIncludeFile() -{ +static void runPreIncludeFile() { if (!preIncludeName) return; @@ -329,7 +318,7 @@ static void runPreIncludeFile() return; } - FileStackNode *fileInfo = new(std::nothrow) FileStackNode(); + FileStackNode *fileInfo = new (std::nothrow) FileStackNode(); if (!fileInfo) { error("Failed to alloc file info for pre-include: %s\n", strerror(errno)); @@ -348,8 +337,7 @@ static void runPreIncludeFile() context.uniqueID = macro_UndefUniqueID(); } -void fstk_RunMacro(char const *macroName, MacroArgs &args) -{ +void fstk_RunMacro(char const *macroName, MacroArgs &args) { Symbol *macro = sym_FindExactSymbol(macroName); if (!macro) { @@ -362,7 +350,7 @@ void fstk_RunMacro(char const *macroName, MacroArgs &args) } contextStack.top().macroArgs = macro_GetCurrentArgs(); - FileStackNode *fileInfo = new(std::nothrow) FileStackNode(); + FileStackNode *fileInfo = new (std::nothrow) FileStackNode(); if (!fileInfo) { error("Failed to alloc file info for \"%s\": %s\n", macro->name, strerror(errno)); @@ -383,12 +371,11 @@ void fstk_RunMacro(char const *macroName, MacroArgs &args) if (macro->src->type == NODE_REPT) { std::vector const &srcIters = macro->src->iters(); - for (uint32_t i = srcIters.size(); i--; ) { + for (uint32_t i = srcIters.size(); i--;) { char buf[sizeof("::REPT~4294967295")]; // UINT32_MAX if (sprintf(buf, "::REPT~%" PRIu32, srcIters[i]) < 0) - fatalerror("Failed to write macro invocation info: %s\n", - strerror(errno)); + fatalerror("Failed to write macro invocation info: %s\n", strerror(errno)); fileInfoName.append(buf); } } @@ -398,19 +385,19 @@ void fstk_RunMacro(char const *macroName, MacroArgs &args) Context &context = newContext(*fileInfo); std::string_view *macroView = macro->getMacro(); - lexer_OpenFileView(context.lexerState, "MACRO", macroView->data(), macroView->size(), - macro->fileLine); + lexer_OpenFileView( + context.lexerState, "MACRO", macroView->data(), macroView->size(), macro->fileLine + ); lexer_SetStateAtEOL(&context.lexerState); context.uniqueID = macro_UseNewUniqueID(); macro_UseNewArgs(&args); } -static bool newReptContext(int32_t reptLineNo, char const *body, size_t size) -{ +static bool newReptContext(int32_t reptLineNo, char const *body, size_t size) { uint32_t reptDepth = contextStack.top().fileInfo->type == NODE_REPT - ? contextStack.top().fileInfo->iters().size() - : 0; - FileStackNode *fileInfo = new(std::nothrow) FileStackNode(); + ? contextStack.top().fileInfo->iters().size() + : 0; + FileStackNode *fileInfo = new (std::nothrow) FileStackNode(); if (!fileInfo) { error("Failed to alloc file info for REPT: %s\n", strerror(errno)); @@ -420,7 +407,9 @@ static bool newReptContext(int32_t reptLineNo, char const *body, size_t size) fileInfo->data = std::vector{1}; if (reptDepth) { // Append all parent iter counts - fileInfo->iters().insert(fileInfo->iters().end(), RANGE(contextStack.top().fileInfo->iters())); + fileInfo->iters().insert( + fileInfo->iters().end(), RANGE(contextStack.top().fileInfo->iters()) + ); } Context &context = newContext(*fileInfo); @@ -434,8 +423,7 @@ static bool newReptContext(int32_t reptLineNo, char const *body, size_t size) return true; } -void fstk_RunRept(uint32_t count, int32_t reptLineNo, char const *body, size_t size) -{ +void fstk_RunRept(uint32_t count, int32_t reptLineNo, char const *body, size_t size) { if (count == 0) return; if (!newReptContext(reptLineNo, body, size)) @@ -444,9 +432,15 @@ void fstk_RunRept(uint32_t count, int32_t reptLineNo, char const *body, size_t s contextStack.top().nbReptIters = count; } -void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step, - int32_t reptLineNo, char const *body, size_t size) -{ +void fstk_RunFor( + char const *symName, + int32_t start, + int32_t stop, + int32_t step, + int32_t reptLineNo, + char const *body, + size_t size +) { Symbol *sym = sym_AddVar(symName, start); if (sym->type != SYM_VAR) @@ -462,8 +456,9 @@ void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step, error("FOR cannot have a step value of 0\n"); if ((step > 0 && start > stop) || (step < 0 && start < stop)) - warning(WARNING_BACKWARDS_FOR, "FOR goes backwards from %d to %d by %d\n", - start, stop, step); + warning( + WARNING_BACKWARDS_FOR, "FOR goes backwards from %d to %d by %d\n", start, stop, step + ); if (count == 0) return; @@ -479,14 +474,12 @@ void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step, context.forName = symName; } -void fstk_StopRept() -{ +void fstk_StopRept() { // Prevent more iterations contextStack.top().nbReptIters = 0; } -bool fstk_Break() -{ +bool fstk_Break() { if (contextStack.top().fileInfo->type != NODE_REPT) { error("BREAK can only be used inside a REPT/FOR block\n"); return false; @@ -496,22 +489,20 @@ bool fstk_Break() return true; } -void fstk_NewRecursionDepth(size_t newDepth) -{ +void fstk_NewRecursionDepth(size_t newDepth) { if (contextStack.size() > newDepth + 1) fatalerror("Recursion limit (%zu) exceeded\n", newDepth); maxRecursionDepth = newDepth; } -void fstk_Init(char const *mainPath, size_t maxDepth) -{ +void fstk_Init(char const *mainPath, size_t maxDepth) { Context &context = contextStack.emplace(); if (!lexer_OpenFile(context.lexerState, mainPath)) fatalerror("Failed to open main file\n"); lexer_SetState(&context.lexerState); - FileStackNode *fileInfo = new(std::nothrow) FileStackNode(); + FileStackNode *fileInfo = new (std::nothrow) FileStackNode(); if (!fileInfo) fatalerror("Failed to allocate memory for main file info: %s\n", strerror(errno)); diff --git a/src/asm/lexer.cpp b/src/asm/lexer.cpp index 0230acb2..94cfe365 100644 --- a/src/asm/lexer.cpp +++ b/src/asm/lexer.cpp @@ -1,7 +1,8 @@ /* SPDX-License-Identifier: MIT */ -#include #include +#include + #include #include #include @@ -14,22 +15,22 @@ #include #include #include -#include #include +#include #include #include #include #ifndef _MSC_VER -#include + #include #endif #include "platform.hpp" // For `ssize_t` and `AT` #include "util.hpp" -#include "asm/lexer.hpp" #include "asm/fixpoint.hpp" #include "asm/format.hpp" #include "asm/fstack.hpp" +#include "asm/lexer.hpp" #include "asm/macro.hpp" #include "asm/main.hpp" #include "asm/rpn.hpp" @@ -40,46 +41,57 @@ // Neither MSVC nor MinGW provide `mmap` #if defined(_MSC_VER) || defined(__MINGW32__) -# define WIN32_LEAN_AND_MEAN // include less from windows.h -# include // target architecture -# include // CreateFileA -# include // CreateFileMappingA -# include // MapViewOfFile -# include // CloseHandle -# define MAP_FAILED nullptr -# define mapFile(ptr, fd, path, size) do { \ - (ptr) = MAP_FAILED; \ - HANDLE file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, \ - FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_RANDOM_ACCESS, nullptr); \ - HANDLE mappingObj; \ - \ - if (file == INVALID_HANDLE_VALUE) \ - break; \ - mappingObj = CreateFileMappingA(file, nullptr, PAGE_READONLY, 0, 0, nullptr); \ - if (mappingObj != INVALID_HANDLE_VALUE) \ - (ptr) = MapViewOfFile(mappingObj, FILE_MAP_READ, 0, 0, 0); \ - CloseHandle(mappingObj); \ - CloseHandle(file); \ -} while (0) -# define munmap(ptr, size) UnmapViewOfFile((ptr)) + // clang-format off + // (we need these `include`s in this order) + #define WIN32_LEAN_AND_MEAN // include less from windows.h + #include // target architecture + #include // CreateFileA + #include // CreateFileMappingA + #include // MapViewOfFile + #include // CloseHandle + // clang-format on + #define MAP_FAILED nullptr + #define mapFile(ptr, fd, path, size) \ + do { \ + (ptr) = MAP_FAILED; \ + HANDLE file = CreateFileA( \ + path, \ + GENERIC_READ, \ + FILE_SHARE_READ, \ + nullptr, \ + OPEN_EXISTING, \ + FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_RANDOM_ACCESS, \ + nullptr \ + ); \ + HANDLE mappingObj; \ + if (file == INVALID_HANDLE_VALUE) \ + break; \ + mappingObj = CreateFileMappingA(file, nullptr, PAGE_READONLY, 0, 0, nullptr); \ + if (mappingObj != INVALID_HANDLE_VALUE) \ + (ptr) = MapViewOfFile(mappingObj, FILE_MAP_READ, 0, 0, 0); \ + CloseHandle(mappingObj); \ + CloseHandle(file); \ + } while (0) + #define munmap(ptr, size) UnmapViewOfFile((ptr)) #else // defined(_MSC_VER) || defined(__MINGW32__) -# include -# define mapFile(ptr, fd, path, size) do { \ - (ptr) = mmap(nullptr, (size), PROT_READ, MAP_PRIVATE, (fd), 0); \ - \ - if ((ptr) == MAP_FAILED && errno == ENOTSUP) { \ - /* - * The implementation may not support MAP_PRIVATE; try again with MAP_SHARED - * instead, offering, I believe, weaker guarantees about external modifications to - * the file while reading it. That's still better than not opening it at all, though - */ \ - if (verbose) \ - printf("mmap(%s, MAP_PRIVATE) failed, retrying with MAP_SHARED\n", path); \ - (ptr) = mmap(nullptr, (size), PROT_READ, MAP_SHARED, (fd), 0); \ - } \ -} while (0) + #include + #define mapFile(ptr, fd, path, size) \ + do { \ + (ptr) = mmap(nullptr, (size), PROT_READ, MAP_PRIVATE, (fd), 0); \ + if ((ptr) == MAP_FAILED && errno == ENOTSUP) { \ + /* \ + * The implementation may not support MAP_PRIVATE; try again with MAP_SHARED \ + * instead, offering, I believe, weaker guarantees about external modifications to \ + * the file while reading it. That's still better than not opening it at all, \ + * though \ + */ \ + if (verbose) \ + printf("mmap(%s, MAP_PRIVATE) failed, retrying with MAP_SHARED\n", path); \ + (ptr) = mmap(nullptr, (size), PROT_READ, MAP_SHARED, (fd), 0); \ + } \ + } while (0) #endif // !( defined(_MSC_VER) || defined(__MINGW32__) ) struct CaseInsensitive { @@ -106,207 +118,205 @@ struct CaseInsensitive { // Tokens / keywords not handled here are handled in `yylex_NORMAL`'s switch. // This assumes that no two keywords have the same name. static std::unordered_map keywordDict = { - {"ADC", T_Z80_ADC}, - {"ADD", T_Z80_ADD}, - {"AND", T_Z80_AND}, - {"BIT", T_Z80_BIT}, - {"CALL", T_Z80_CALL}, - {"CCF", T_Z80_CCF}, - {"CPL", T_Z80_CPL}, - {"CP", T_Z80_CP}, - {"DAA", T_Z80_DAA}, - {"DEC", T_Z80_DEC}, - {"DI", T_Z80_DI}, - {"EI", T_Z80_EI}, - {"HALT", T_Z80_HALT}, - {"INC", T_Z80_INC}, - {"JP", T_Z80_JP}, - {"JR", T_Z80_JR}, - {"LD", T_Z80_LD}, - {"LDI", T_Z80_LDI}, - {"LDD", T_Z80_LDD}, - {"LDIO", T_Z80_LDH}, - {"LDH", T_Z80_LDH}, - {"NOP", T_Z80_NOP}, - {"OR", T_Z80_OR}, - {"POP", T_Z80_POP}, - {"PUSH", T_Z80_PUSH}, - {"RES", T_Z80_RES}, - {"RETI", T_Z80_RETI}, - {"RET", T_Z80_RET}, - {"RLCA", T_Z80_RLCA}, - {"RLC", T_Z80_RLC}, - {"RLA", T_Z80_RLA}, - {"RL", T_Z80_RL}, - {"RRC", T_Z80_RRC}, - {"RRCA", T_Z80_RRCA}, - {"RRA", T_Z80_RRA}, - {"RR", T_Z80_RR}, - {"RST", T_Z80_RST}, - {"SBC", T_Z80_SBC}, - {"SCF", T_Z80_SCF}, - {"SET", T_Z80_SET}, - {"SLA", T_Z80_SLA}, - {"SRA", T_Z80_SRA}, - {"SRL", T_Z80_SRL}, - {"STOP", T_Z80_STOP}, - {"SUB", T_Z80_SUB}, - {"SWAP", T_Z80_SWAP}, - {"XOR", T_Z80_XOR}, + {"ADC", T_Z80_ADC }, + {"ADD", T_Z80_ADD }, + {"AND", T_Z80_AND }, + {"BIT", T_Z80_BIT }, + {"CALL", T_Z80_CALL }, + {"CCF", T_Z80_CCF }, + {"CPL", T_Z80_CPL }, + {"CP", T_Z80_CP }, + {"DAA", T_Z80_DAA }, + {"DEC", T_Z80_DEC }, + {"DI", T_Z80_DI }, + {"EI", T_Z80_EI }, + {"HALT", T_Z80_HALT }, + {"INC", T_Z80_INC }, + {"JP", T_Z80_JP }, + {"JR", T_Z80_JR }, + {"LD", T_Z80_LD }, + {"LDI", T_Z80_LDI }, + {"LDD", T_Z80_LDD }, + {"LDIO", T_Z80_LDH }, + {"LDH", T_Z80_LDH }, + {"NOP", T_Z80_NOP }, + {"OR", T_Z80_OR }, + {"POP", T_Z80_POP }, + {"PUSH", T_Z80_PUSH }, + {"RES", T_Z80_RES }, + {"RETI", T_Z80_RETI }, + {"RET", T_Z80_RET }, + {"RLCA", T_Z80_RLCA }, + {"RLC", T_Z80_RLC }, + {"RLA", T_Z80_RLA }, + {"RL", T_Z80_RL }, + {"RRC", T_Z80_RRC }, + {"RRCA", T_Z80_RRCA }, + {"RRA", T_Z80_RRA }, + {"RR", T_Z80_RR }, + {"RST", T_Z80_RST }, + {"SBC", T_Z80_SBC }, + {"SCF", T_Z80_SCF }, + {"SET", T_Z80_SET }, + {"SLA", T_Z80_SLA }, + {"SRA", T_Z80_SRA }, + {"SRL", T_Z80_SRL }, + {"STOP", T_Z80_STOP }, + {"SUB", T_Z80_SUB }, + {"SWAP", T_Z80_SWAP }, + {"XOR", T_Z80_XOR }, - {"NZ", T_CC_NZ}, - {"Z", T_CC_Z}, - {"NC", T_CC_NC}, - // Handled after as T_TOKEN_C - // { "C", T_CC_C }, + {"NZ", T_CC_NZ }, + {"Z", T_CC_Z }, + {"NC", T_CC_NC }, + // Handled after as T_TOKEN_C + // { "C", T_CC_C }, - {"AF", T_MODE_AF}, - {"BC", T_MODE_BC}, - {"DE", T_MODE_DE}, - {"HL", T_MODE_HL}, - {"SP", T_MODE_SP}, - {"HLD", T_MODE_HL_DEC}, - {"HLI", T_MODE_HL_INC}, + {"AF", T_MODE_AF }, + {"BC", T_MODE_BC }, + {"DE", T_MODE_DE }, + {"HL", T_MODE_HL }, + {"SP", T_MODE_SP }, + {"HLD", T_MODE_HL_DEC }, + {"HLI", T_MODE_HL_INC }, - {"A", T_TOKEN_A}, - {"B", T_TOKEN_B}, - {"C", T_TOKEN_C}, - {"D", T_TOKEN_D}, - {"E", T_TOKEN_E}, - {"H", T_TOKEN_H}, - {"L", T_TOKEN_L}, + {"A", T_TOKEN_A }, + {"B", T_TOKEN_B }, + {"C", T_TOKEN_C }, + {"D", T_TOKEN_D }, + {"E", T_TOKEN_E }, + {"H", T_TOKEN_H }, + {"L", T_TOKEN_L }, - {"DEF", T_OP_DEF}, + {"DEF", T_OP_DEF }, - {"FRAGMENT", T_POP_FRAGMENT}, - {"BANK", T_OP_BANK}, - {"ALIGN", T_OP_ALIGN}, + {"FRAGMENT", T_POP_FRAGMENT }, + {"BANK", T_OP_BANK }, + {"ALIGN", T_OP_ALIGN }, - {"SIZEOF", T_OP_SIZEOF}, - {"STARTOF", T_OP_STARTOF}, + {"SIZEOF", T_OP_SIZEOF }, + {"STARTOF", T_OP_STARTOF }, - {"ROUND", T_OP_ROUND}, - {"CEIL", T_OP_CEIL}, - {"FLOOR", T_OP_FLOOR}, - {"DIV", T_OP_FDIV}, - {"MUL", T_OP_FMUL}, - {"FMOD", T_OP_FMOD}, - {"POW", T_OP_POW}, - {"LOG", T_OP_LOG}, - {"SIN", T_OP_SIN}, - {"COS", T_OP_COS}, - {"TAN", T_OP_TAN}, - {"ASIN", T_OP_ASIN}, - {"ACOS", T_OP_ACOS}, - {"ATAN", T_OP_ATAN}, - {"ATAN2", T_OP_ATAN2}, + {"ROUND", T_OP_ROUND }, + {"CEIL", T_OP_CEIL }, + {"FLOOR", T_OP_FLOOR }, + {"DIV", T_OP_FDIV }, + {"MUL", T_OP_FMUL }, + {"FMOD", T_OP_FMOD }, + {"POW", T_OP_POW }, + {"LOG", T_OP_LOG }, + {"SIN", T_OP_SIN }, + {"COS", T_OP_COS }, + {"TAN", T_OP_TAN }, + {"ASIN", T_OP_ASIN }, + {"ACOS", T_OP_ACOS }, + {"ATAN", T_OP_ATAN }, + {"ATAN2", T_OP_ATAN2 }, - {"HIGH", T_OP_HIGH}, - {"LOW", T_OP_LOW}, - {"ISCONST", T_OP_ISCONST}, + {"HIGH", T_OP_HIGH }, + {"LOW", T_OP_LOW }, + {"ISCONST", T_OP_ISCONST }, - {"STRCMP", T_OP_STRCMP}, - {"STRIN", T_OP_STRIN}, - {"STRRIN", T_OP_STRRIN}, - {"STRSUB", T_OP_STRSUB}, - {"STRLEN", T_OP_STRLEN}, - {"STRCAT", T_OP_STRCAT}, - {"STRUPR", T_OP_STRUPR}, - {"STRLWR", T_OP_STRLWR}, - {"STRRPL", T_OP_STRRPL}, - {"STRFMT", T_OP_STRFMT}, + {"STRCMP", T_OP_STRCMP }, + {"STRIN", T_OP_STRIN }, + {"STRRIN", T_OP_STRRIN }, + {"STRSUB", T_OP_STRSUB }, + {"STRLEN", T_OP_STRLEN }, + {"STRCAT", T_OP_STRCAT }, + {"STRUPR", T_OP_STRUPR }, + {"STRLWR", T_OP_STRLWR }, + {"STRRPL", T_OP_STRRPL }, + {"STRFMT", T_OP_STRFMT }, - {"CHARLEN", T_OP_CHARLEN}, - {"CHARSUB", T_OP_CHARSUB}, - {"INCHARMAP", T_OP_INCHARMAP}, + {"CHARLEN", T_OP_CHARLEN }, + {"CHARSUB", T_OP_CHARSUB }, + {"INCHARMAP", T_OP_INCHARMAP }, - {"INCLUDE", T_POP_INCLUDE}, - {"PRINT", T_POP_PRINT}, - {"PRINTLN", T_POP_PRINTLN}, - {"EXPORT", T_POP_EXPORT}, - {"DS", T_POP_DS}, - {"DB", T_POP_DB}, - {"DW", T_POP_DW}, - {"DL", T_POP_DL}, - {"SECTION", T_POP_SECTION}, - {"ENDSECTION", T_POP_ENDSECTION}, - {"PURGE", T_POP_PURGE}, + {"INCLUDE", T_POP_INCLUDE }, + {"PRINT", T_POP_PRINT }, + {"PRINTLN", T_POP_PRINTLN }, + {"EXPORT", T_POP_EXPORT }, + {"DS", T_POP_DS }, + {"DB", T_POP_DB }, + {"DW", T_POP_DW }, + {"DL", T_POP_DL }, + {"SECTION", T_POP_SECTION }, + {"ENDSECTION", T_POP_ENDSECTION }, + {"PURGE", T_POP_PURGE }, - {"RSRESET", T_POP_RSRESET}, - {"RSSET", T_POP_RSSET}, + {"RSRESET", T_POP_RSRESET }, + {"RSSET", T_POP_RSSET }, - {"INCBIN", T_POP_INCBIN}, - {"CHARMAP", T_POP_CHARMAP}, - {"NEWCHARMAP", T_POP_NEWCHARMAP}, - {"SETCHARMAP", T_POP_SETCHARMAP}, - {"PUSHC", T_POP_PUSHC}, - {"POPC", T_POP_POPC}, + {"INCBIN", T_POP_INCBIN }, + {"CHARMAP", T_POP_CHARMAP }, + {"NEWCHARMAP", T_POP_NEWCHARMAP }, + {"SETCHARMAP", T_POP_SETCHARMAP }, + {"PUSHC", T_POP_PUSHC }, + {"POPC", T_POP_POPC }, - {"FAIL", T_POP_FAIL}, - {"WARN", T_POP_WARN}, - {"FATAL", T_POP_FATAL}, - {"ASSERT", T_POP_ASSERT}, - {"STATIC_ASSERT", T_POP_STATIC_ASSERT}, + {"FAIL", T_POP_FAIL }, + {"WARN", T_POP_WARN }, + {"FATAL", T_POP_FATAL }, + {"ASSERT", T_POP_ASSERT }, + {"STATIC_ASSERT", T_POP_STATIC_ASSERT}, - {"MACRO", T_POP_MACRO}, - {"ENDM", T_POP_ENDM}, - {"SHIFT", T_POP_SHIFT}, + {"MACRO", T_POP_MACRO }, + {"ENDM", T_POP_ENDM }, + {"SHIFT", T_POP_SHIFT }, - {"REPT", T_POP_REPT}, - {"FOR", T_POP_FOR}, - {"ENDR", T_POP_ENDR}, - {"BREAK", T_POP_BREAK}, + {"REPT", T_POP_REPT }, + {"FOR", T_POP_FOR }, + {"ENDR", T_POP_ENDR }, + {"BREAK", T_POP_BREAK }, - {"LOAD", T_POP_LOAD}, - {"ENDL", T_POP_ENDL}, + {"LOAD", T_POP_LOAD }, + {"ENDL", T_POP_ENDL }, - {"IF", T_POP_IF}, - {"ELSE", T_POP_ELSE}, - {"ELIF", T_POP_ELIF}, - {"ENDC", T_POP_ENDC}, + {"IF", T_POP_IF }, + {"ELSE", T_POP_ELSE }, + {"ELIF", T_POP_ELIF }, + {"ENDC", T_POP_ENDC }, - {"UNION", T_POP_UNION}, - {"NEXTU", T_POP_NEXTU}, - {"ENDU", T_POP_ENDU}, + {"UNION", T_POP_UNION }, + {"NEXTU", T_POP_NEXTU }, + {"ENDU", T_POP_ENDU }, - {"WRAM0", T_SECT_WRAM0}, - {"VRAM", T_SECT_VRAM}, - {"ROMX", T_SECT_ROMX}, - {"ROM0", T_SECT_ROM0}, - {"HRAM", T_SECT_HRAM}, - {"WRAMX", T_SECT_WRAMX}, - {"SRAM", T_SECT_SRAM}, - {"OAM", T_SECT_OAM}, + {"WRAM0", T_SECT_WRAM0 }, + {"VRAM", T_SECT_VRAM }, + {"ROMX", T_SECT_ROMX }, + {"ROM0", T_SECT_ROM0 }, + {"HRAM", T_SECT_HRAM }, + {"WRAMX", T_SECT_WRAMX }, + {"SRAM", T_SECT_SRAM }, + {"OAM", T_SECT_OAM }, - {"RB", T_POP_RB}, - {"RW", T_POP_RW}, - // Handled before as T_Z80_RL - // {"RL", T_POP_RL}, + {"RB", T_POP_RB }, + {"RW", T_POP_RW }, + // Handled before as T_Z80_RL + // {"RL", T_POP_RL}, - {"EQU", T_POP_EQU}, - {"EQUS", T_POP_EQUS}, - {"REDEF", T_POP_REDEF}, + {"EQU", T_POP_EQU }, + {"EQUS", T_POP_EQUS }, + {"REDEF", T_POP_REDEF }, - {"PUSHS", T_POP_PUSHS}, - {"POPS", T_POP_POPS}, - {"PUSHO", T_POP_PUSHO}, - {"POPO", T_POP_POPO}, + {"PUSHS", T_POP_PUSHS }, + {"POPS", T_POP_POPS }, + {"PUSHO", T_POP_PUSHO }, + {"POPO", T_POP_POPO }, - {"OPT", T_POP_OPT}, + {"OPT", T_POP_OPT }, - {".", T_PERIOD}, + {".", T_PERIOD }, }; -static bool isWhitespace(int c) -{ +static bool isWhitespace(int c) { return c == ' ' || c == '\t'; } LexerState *lexerState = nullptr; LexerState *lexerStateEOL = nullptr; -static void initState(LexerState &state) -{ +static void initState(LexerState &state) { state.mode = LEXER_NORMAL; state.atLineStart = true; // yylex() will init colNo due to this state.lastToken = T_EOF; @@ -324,60 +334,46 @@ static void initState(LexerState &state) state.expansions.clear(); } -static void nextLine() -{ +static void nextLine() { lexerState->lineNo++; lexerState->colNo = 1; } -uint32_t lexer_GetIFDepth() -{ +uint32_t lexer_GetIFDepth() { return lexerState->ifStack.size(); } -void lexer_IncIFDepth() -{ - lexerState->ifStack.push_front({ .ranIfBlock = false, .reachedElseBlock = false }); +void lexer_IncIFDepth() { + lexerState->ifStack.push_front({.ranIfBlock = false, .reachedElseBlock = false}); } -void lexer_DecIFDepth() -{ +void lexer_DecIFDepth() { if (lexerState->ifStack.empty()) fatalerror("Found ENDC outside an IF construct\n"); lexerState->ifStack.pop_front(); } -bool lexer_RanIFBlock() -{ +bool lexer_RanIFBlock() { return lexerState->ifStack.front().ranIfBlock; } -bool lexer_ReachedELSEBlock() -{ +bool lexer_ReachedELSEBlock() { return lexerState->ifStack.front().reachedElseBlock; } -void lexer_RunIFBlock() -{ +void lexer_RunIFBlock() { lexerState->ifStack.front().ranIfBlock = true; } -void lexer_ReachELSEBlock() -{ +void lexer_ReachELSEBlock() { lexerState->ifStack.front().reachedElseBlock = true; } -bool lexer_OpenFile(LexerState &state, char const *path) -{ +bool lexer_OpenFile(LexerState &state, char const *path) { if (!strcmp(path, "-")) { state.path = ""; - state.content = BufferedLexerState{ - .fd = STDIN_FILENO, - .index = 0, - .buf = {}, - .nbChars = 0 - }; + state.content = BufferedLexerState{.fd = STDIN_FILENO, .index = 0, .buf = {}, .nbChars = 0}; if (verbose) printf("Opening stdin\n"); } else { @@ -404,10 +400,10 @@ bool lexer_OpenFile(LexerState &state, char const *path) if (mappingAddr != MAP_FAILED) { close(fd); state.content = MmappedLexerState{ - .ptr = (char *)mappingAddr, - .size = (size_t)fileInfo.st_size, - .offset = 0, - .isReferenced = false + .ptr = (char *)mappingAddr, + .size = (size_t)fileInfo.st_size, + .offset = 0, + .isReferenced = false, }; if (verbose) printf("File \"%s\" is mmap()ped\n", path); @@ -417,18 +413,12 @@ bool lexer_OpenFile(LexerState &state, char const *path) if (!isMmapped) { // Sometimes mmap() fails or isn't available, so have a fallback - state.content = BufferedLexerState{ - .fd = fd, - .index = 0, - .buf = {}, - .nbChars = 0 - }; + state.content = BufferedLexerState{.fd = fd, .index = 0, .buf = {}, .nbChars = 0}; if (verbose) { if (fileInfo.st_size == 0) { printf("File \"%s\" is empty\n", path); } else { - printf("File \"%s\" is opened; errno reports: %s\n", - path, strerror(errno)); + printf("File \"%s\" is opened; errno reports: %s\n", path, strerror(errno)); } } } @@ -439,32 +429,29 @@ bool lexer_OpenFile(LexerState &state, char const *path) return true; } -void lexer_OpenFileView(LexerState &state, char const *path, char const *buf, size_t size, - uint32_t lineNo) -{ +void lexer_OpenFileView( + LexerState &state, char const *path, char const *buf, size_t size, uint32_t lineNo +) { state.path = path; // Used to report read errors in `peekInternal` - state.content = ViewedLexerState{ - .ptr = buf, - .size = size, - .offset = 0 - }; + state.content = ViewedLexerState{.ptr = buf, .size = size, .offset = 0}; initState(state); state.lineNo = lineNo; // Will be incremented at first line start } -void lexer_RestartRept(uint32_t lineNo) -{ - std::visit(Visitor{ - [](MmappedLexerState &mmap) { mmap.offset = 0; }, - [](ViewedLexerState &view) { view.offset = 0; }, - [](auto &) {}, - }, lexerState->content); +void lexer_RestartRept(uint32_t lineNo) { + std::visit( + Visitor{ + [](MmappedLexerState &mmap) { mmap.offset = 0; }, + [](ViewedLexerState &view) { view.offset = 0; }, + [](auto &) {}, + }, + lexerState->content + ); initState(*lexerState); lexerState->lineNo = lineNo; } -void lexer_CleanupState(LexerState &state) -{ +void lexer_CleanupState(LexerState &state) { // A big chunk of the lexer state soundness is the file stack ("fstack"). // Each context in the fstack has its own *unique* lexer state; thus, we always guarantee // that lexer states lifetimes are always properly managed, since they're handled solely @@ -478,32 +465,30 @@ void lexer_CleanupState(LexerState &state) // `lexerStateEOL`, but there's currently no situation in which this should happen. assert(&state != lexerStateEOL); - std::visit(Visitor{ - [](MmappedLexerState &mmap) { - if (!mmap.isReferenced) - munmap(mmap.ptr, mmap.size); - }, - [](BufferedLexerState &cbuf) { - close(cbuf.fd); - }, - [](auto &) {}, - }, state.content); + std::visit( + Visitor{ + [](MmappedLexerState &mmap) { + if (!mmap.isReferenced) + munmap(mmap.ptr, mmap.size); + }, + [](BufferedLexerState &cbuf) { close(cbuf.fd); }, + [](auto &) {}, + }, + state.content + ); } -void lexer_SetMode(enum LexerMode mode) -{ +void lexer_SetMode(enum LexerMode mode) { lexerState->mode = mode; } -void lexer_ToggleStringExpansion(bool enable) -{ +void lexer_ToggleStringExpansion(bool enable) { lexerState->expandStrings = enable; } // Functions for the actual lexer to obtain characters -static void beginExpansion(char const *str, bool owned, char const *name) -{ +static void beginExpansion(char const *str, bool owned, char const *name) { size_t size = strlen(str); // Do not expand empty strings @@ -514,28 +499,25 @@ static void beginExpansion(char const *str, bool owned, char const *name) lexer_CheckRecursionDepth(); lexerState->expansions.push_front({ - .name = name ? std::optional(name) : std::nullopt, - .contents = { .unowned = str }, - .size = size, - .offset = 0, - .owned = owned, + .name = name ? std::optional(name) : std::nullopt, + .contents = {.unowned = str}, + .size = size, + .offset = 0, + .owned = owned, }); } -void lexer_CheckRecursionDepth() -{ +void lexer_CheckRecursionDepth() { if (lexerState->expansions.size() > maxRecursionDepth + 1) fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth); } -static void freeExpansion(Expansion &expansion) -{ +static void freeExpansion(Expansion &expansion) { if (expansion.owned) - delete [] expansion.contents.owned; + delete[] expansion.contents.owned; } -static bool isMacroChar(char c) -{ +static bool isMacroChar(char c) { return c == '@' || c == '#' || c == '<' || (c >= '0' && c <= '9'); } @@ -546,8 +528,7 @@ static uint32_t readNumber(int radix, uint32_t baseValue); static bool startsIdentifier(int c); static bool continuesIdentifier(int c); -static uint32_t readBracketedMacroArgNum() -{ +static uint32_t readBracketedMacroArgNum() { bool disableMacroArgs = lexerState->disableMacroArgs; bool disableInterpolation = lexerState->disableInterpolation; @@ -612,8 +593,7 @@ static uint32_t readBracketedMacroArgNum() return num; } -static char const *readMacroArg(char name) -{ +static char const *readMacroArg(char name) { char const *str = nullptr; if (name == '@') { @@ -642,8 +622,7 @@ static char const *readMacroArg(char name) return str; } -static size_t readInternal(BufferedLexerState &cbuf, size_t bufIndex, size_t nbChars) -{ +static size_t readInternal(BufferedLexerState &cbuf, size_t bufIndex, size_t nbChars) { // This buffer overflow made me lose WEEKS of my life. Never again. assert(bufIndex + nbChars <= LEXER_BUF_SIZE); ssize_t nbReadChars = read(cbuf.fd, &cbuf.buf[bufIndex], nbChars); @@ -656,8 +635,7 @@ static size_t readInternal(BufferedLexerState &cbuf, size_t bufIndex, size_t nbC } // We only need one character of lookahead, for macro arguments -static int peekInternal(uint8_t distance) -{ +static int peekInternal(uint8_t distance) { for (Expansion &exp : lexerState->expansions) { // An expansion that has reached its end will have `exp->offset` == `exp->size`, // and `peekInternal` will continue with its parent @@ -668,67 +646,70 @@ static int peekInternal(uint8_t distance) } if (distance >= LEXER_BUF_SIZE) - fatalerror("Internal lexer error: buffer has insufficient size for peeking (%" - PRIu8 " >= %u)\n", distance, LEXER_BUF_SIZE); + fatalerror( + "Internal lexer error: buffer has insufficient size for peeking (%" PRIu8 " >= %u)\n", + distance, + LEXER_BUF_SIZE + ); - return std::visit(Visitor{ - [&distance](MmappedLexerState &mmap) -> int { - if (size_t idx = mmap.offset + distance; idx < mmap.size) - return (uint8_t)mmap.ptr[idx]; - return EOF; - }, - [&distance](ViewedLexerState &view) -> int { - if (size_t idx = view.offset + distance; idx < view.size) - return (uint8_t)view.ptr[idx]; - return EOF; - }, - [&distance](BufferedLexerState &cbuf) -> int { - if (cbuf.nbChars > distance) - return (uint8_t)cbuf.buf[(cbuf.index + distance) % LEXER_BUF_SIZE]; + return std::visit( + Visitor{ + [&distance](MmappedLexerState &mmap) -> int { + if (size_t idx = mmap.offset + distance; idx < mmap.size) + return (uint8_t)mmap.ptr[idx]; + return EOF; + }, + [&distance](ViewedLexerState &view) -> int { + if (size_t idx = view.offset + distance; idx < view.size) + return (uint8_t)view.ptr[idx]; + return EOF; + }, + [&distance](BufferedLexerState &cbuf) -> int { + if (cbuf.nbChars > distance) + return (uint8_t)cbuf.buf[(cbuf.index + distance) % LEXER_BUF_SIZE]; - // Buffer isn't full enough, read some chars in - size_t target = LEXER_BUF_SIZE - cbuf.nbChars; // Aim: making the buf full + // Buffer isn't full enough, read some chars in + size_t target = LEXER_BUF_SIZE - cbuf.nbChars; // Aim: making the buf full - // Compute the index we'll start writing to - size_t writeIndex = (cbuf.index + cbuf.nbChars) % LEXER_BUF_SIZE; + // Compute the index we'll start writing to + size_t writeIndex = (cbuf.index + cbuf.nbChars) % LEXER_BUF_SIZE; - // If the range to fill passes over the buffer wrapping point, we need two reads - if (writeIndex + target > LEXER_BUF_SIZE) { - size_t nbExpectedChars = LEXER_BUF_SIZE - writeIndex; - size_t nbReadChars = readInternal(cbuf, writeIndex, nbExpectedChars); + // If the range to fill passes over the buffer wrapping point, we need two reads + if (writeIndex + target > LEXER_BUF_SIZE) { + size_t nbExpectedChars = LEXER_BUF_SIZE - writeIndex; + size_t nbReadChars = readInternal(cbuf, writeIndex, nbExpectedChars); - cbuf.nbChars += nbReadChars; + cbuf.nbChars += nbReadChars; - writeIndex += nbReadChars; - if (writeIndex == LEXER_BUF_SIZE) - writeIndex = 0; + writeIndex += nbReadChars; + if (writeIndex == LEXER_BUF_SIZE) + writeIndex = 0; - // If the read was incomplete, don't perform a second read - target -= nbReadChars; - if (nbReadChars < nbExpectedChars) - target = 0; - } - if (target != 0) - cbuf.nbChars += readInternal(cbuf, writeIndex, target); + // If the read was incomplete, don't perform a second read + target -= nbReadChars; + if (nbReadChars < nbExpectedChars) + target = 0; + } + if (target != 0) + cbuf.nbChars += readInternal(cbuf, writeIndex, target); - if (cbuf.nbChars > distance) - return (uint8_t)cbuf.buf[(cbuf.index + distance) % LEXER_BUF_SIZE]; + if (cbuf.nbChars > distance) + return (uint8_t)cbuf.buf[(cbuf.index + distance) % LEXER_BUF_SIZE]; - // If there aren't enough chars even after refilling, give up - return EOF; - }, - [](std::monostate) -> int { - return EOF; - } - }, lexerState->content); + // If there aren't enough chars even after refilling, give up + return EOF; + }, + [](std::monostate) -> int { return EOF; }, + }, + lexerState->content + ); } // forward declarations for peek static void shiftChar(); static char const *readInterpolation(size_t depth); -static int peek() -{ +static int peek() { int c = peekInternal(0); if (lexerState->macroArgScanDistance > 0) @@ -773,8 +754,7 @@ static int peek() return c; } -static void shiftChar() -{ +static void shiftChar() { if (lexerState->capturing) { if (lexerState->captureBuf) lexerState->captureBuf->push_back(peek()); @@ -800,28 +780,26 @@ restart: } else { // Advance within the file contents lexerState->colNo++; - std::visit(Visitor{ - [](MmappedLexerState &mmap) { - mmap.offset++; - }, - [](ViewedLexerState &view) { - view.offset++; - }, - [](BufferedLexerState &cbuf) { - assert(cbuf.index < LEXER_BUF_SIZE); - cbuf.index++; - if (cbuf.index == LEXER_BUF_SIZE) - cbuf.index = 0; // Wrap around if necessary - assert(cbuf.nbChars > 0); - cbuf.nbChars--; - }, - [](std::monostate) {} - }, lexerState->content); + std::visit( + Visitor{ + [](MmappedLexerState &mmap) { mmap.offset++; }, + [](ViewedLexerState &view) { view.offset++; }, + [](BufferedLexerState &cbuf) { + assert(cbuf.index < LEXER_BUF_SIZE); + cbuf.index++; + if (cbuf.index == LEXER_BUF_SIZE) + cbuf.index = 0; // Wrap around if necessary + assert(cbuf.nbChars > 0); + cbuf.nbChars--; + }, + [](std::monostate) {}, + }, + lexerState->content + ); } } -static int nextChar() -{ +static int nextChar() { int c = peek(); // If not at EOF, advance read position @@ -830,31 +808,26 @@ static int nextChar() return c; } -static void handleCRLF(int c) -{ +static void handleCRLF(int c) { if (c == '\r' && peek() == '\n') shiftChar(); } // "Services" provided by the lexer to the rest of the program -char const *lexer_GetFileName() -{ +char const *lexer_GetFileName() { return lexerState ? lexerState->path : nullptr; } -uint32_t lexer_GetLineNo() -{ +uint32_t lexer_GetLineNo() { return lexerState->lineNo; } -uint32_t lexer_GetColNo() -{ +uint32_t lexer_GetColNo() { return lexerState->colNo; } -void lexer_DumpStringExpansions() -{ +void lexer_DumpStringExpansions() { if (!lexerState) return; @@ -866,8 +839,7 @@ void lexer_DumpStringExpansions() } // Discards a block comment -static void discardBlockComment() -{ +static void discardBlockComment() { lexerState->disableMacroArgs = true; lexerState->disableInterpolation = true; for (;;) { @@ -887,8 +859,7 @@ static void discardBlockComment() continue; case '/': if (peek() == '*') { - warning(WARNING_NESTED_COMMENT, - "/* in block comment\n"); + warning(WARNING_NESTED_COMMENT, "/* in block comment\n"); } continue; case '*': @@ -908,8 +879,7 @@ finish: // Function to discard all of a line's comments -static void discardComment() -{ +static void discardComment() { lexerState->disableMacroArgs = true; lexerState->disableInterpolation = true; for (;; shiftChar()) { @@ -924,8 +894,7 @@ static void discardComment() // Function to read a line continuation -static void readLineContinuation() -{ +static void readLineContinuation() { for (;;) { int c = peek(); @@ -941,8 +910,7 @@ static void readLineContinuation() } else if (c == ';') { discardComment(); } else { - error("Begun line continuation, but encountered character %s\n", - printChar(c)); + error("Begun line continuation, but encountered character %s\n", printChar(c)); break; } } @@ -950,8 +918,7 @@ static void readLineContinuation() // Function to read an anonymous label ref -static void readAnonLabelRef(char c) -{ +static void readAnonLabelRef(char c) { uint32_t n = 0; // We come here having already peeked at one char, so no need to do it again @@ -965,8 +932,7 @@ static void readAnonLabelRef(char c) // Functions to lex numbers of various radixes -static uint32_t readNumber(int radix, uint32_t baseValue) -{ +static uint32_t readNumber(int radix, uint32_t baseValue) { uint32_t value = baseValue; for (;; shiftChar()) { @@ -984,8 +950,7 @@ static uint32_t readNumber(int radix, uint32_t baseValue) return value; } -static uint32_t readFractionalPart(uint32_t integer) -{ +static uint32_t readFractionalPart(uint32_t integer) { uint32_t value = 0, divisor = 1; uint8_t precision = 0; enum { @@ -1007,8 +972,7 @@ static uint32_t readFractionalPart(uint32_t integer) break; } if (divisor > (UINT32_MAX - (c - '0')) / 10) { - warning(WARNING_LARGE_CONSTANT, - "Precision of fixed-point constant is too large\n"); + warning(WARNING_LARGE_CONSTANT, "Precision of fixed-point constant is too large\n"); // Discard any additional digits shiftChar(); while (c = peek(), (c >= '0' && c <= '9') || c == '_') @@ -1048,8 +1012,7 @@ static uint32_t readFractionalPart(uint32_t integer) char binDigits[2]; -static uint32_t readBinaryNumber() -{ +static uint32_t readBinaryNumber() { uint32_t value = 0; for (;; shiftChar()) { @@ -1073,8 +1036,7 @@ static uint32_t readBinaryNumber() return value; } -static uint32_t readHexNumber() -{ +static uint32_t readHexNumber() { uint32_t value = 0; bool empty = true; @@ -1107,8 +1069,7 @@ static uint32_t readHexNumber() char gfxDigits[4]; -static uint32_t readGfxConstant() -{ +static uint32_t readGfxConstant() { uint32_t bitPlaneLower = 0, bitPlaneUpper = 0; uint8_t width = 0; @@ -1141,27 +1102,26 @@ static uint32_t readGfxConstant() if (width == 0) error("Invalid graphics constant, no digits after '`'\n"); else if (width == 9) - warning(WARNING_LARGE_CONSTANT, - "Graphics constant is too long, only first 8 pixels considered\n"); + warning( + WARNING_LARGE_CONSTANT, + "Graphics constant is too long, only first 8 pixels considered\n" + ); return bitPlaneUpper << 8 | bitPlaneLower; } // Functions to read identifiers & keywords -static bool startsIdentifier(int c) -{ +static bool startsIdentifier(int c) { // Anonymous labels internally start with '!' return (c <= 'Z' && c >= 'A') || (c <= 'z' && c >= 'a') || c == '.' || c == '_'; } -static bool continuesIdentifier(int c) -{ +static bool continuesIdentifier(int c) { return startsIdentifier(c) || (c <= '9' && c >= '0') || c == '#' || c == '@'; } -static int readIdentifier(char firstChar) -{ +static int readIdentifier(char firstChar) { // Lex while checking for a keyword yylval.symName[0] = firstChar; int tokenType = firstChar == '.' ? T_LOCAL_ID : T_ID; @@ -1195,8 +1155,7 @@ static int readIdentifier(char firstChar) // Functions to read strings -static char const *readInterpolation(size_t depth) -{ +static char const *readInterpolation(size_t depth) { if (depth > maxRecursionDepth) fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth); @@ -1273,14 +1232,14 @@ static char const *readInterpolation(size_t depth) return nullptr; } -#define append_yylval_string(c) do { \ - /* Evaluate c exactly once in case it has side effects */ \ - if (char v = (c); i < sizeof(yylval.string)) \ - yylval.string[i++] = v; \ -} while (0) +#define append_yylval_string(c) \ + do { \ + /* Evaluate c exactly once in case it has side effects */ \ + if (char v = (c); i < sizeof(yylval.string)) \ + yylval.string[i++] = v; \ + } while (0) -static size_t appendEscapedSubstring(char const *str, size_t i) -{ +static size_t appendEscapedSubstring(char const *str, size_t i) { // Copy one extra to flag overflow while (*str) { char c = *str++; @@ -1312,8 +1271,7 @@ static size_t appendEscapedSubstring(char const *str, size_t i) return i; } -static void readString(bool raw) -{ +static void readString(bool raw) { lexerState->disableMacroArgs = true; lexerState->disableInterpolation = true; @@ -1449,7 +1407,7 @@ static void readString(bool raw) lexerState->disableMacroArgs = true; continue; // Do not copy an additional character - // Regular characters will just get copied + // Regular characters will just get copied } append_yylval_string(c); @@ -1466,8 +1424,7 @@ finish: lexerState->disableInterpolation = false; } -static size_t appendStringLiteral(size_t i, bool raw) -{ +static size_t appendStringLiteral(size_t i, bool raw) { lexerState->disableMacroArgs = true; lexerState->disableInterpolation = true; @@ -1595,7 +1552,7 @@ static size_t appendStringLiteral(size_t i, bool raw) lexerState->disableMacroArgs = true; continue; // Do not copy an additional character - // Regular characters will just get copied + // Regular characters will just get copied } append_yylval_string(c); @@ -1618,13 +1575,12 @@ finish: static int yylex_SKIP_TO_ENDC(); // forward declaration for yylex_NORMAL -static int yylex_NORMAL() -{ +static int yylex_NORMAL() { for (;;) { int c = nextChar(); switch (c) { - // Ignore whitespace and comments + // Ignore whitespace and comments case ';': discardComment(); @@ -1633,7 +1589,7 @@ static int yylex_NORMAL() case '\t': break; - // Handle unambiguous single-char tokens + // Handle unambiguous single-char tokens case '~': return T_OP_NOT; @@ -1654,7 +1610,7 @@ static int yylex_NORMAL() case ',': return T_COMMA; - // Handle ambiguous 1- or 2-char tokens + // Handle ambiguous 1- or 2-char tokens case '+': // Either += or ADD if (peek() == '=') { @@ -1729,7 +1685,7 @@ static int yylex_NORMAL() } return T_OP_LOGICNOT; - // Handle ambiguous 1-, 2-, or 3-char tokens + // Handle ambiguous 1-, 2-, or 3-char tokens case '<': // Either <<=, LT, LTE, or left shift switch (peek()) { @@ -1782,7 +1738,7 @@ static int yylex_NORMAL() return T_COLON; } - // Handle numbers + // Handle numbers case '0': // Decimal or fixed-point number case '1': @@ -1837,13 +1793,13 @@ static int yylex_NORMAL() yylval.constValue = readGfxConstant(); return T_NUMBER; - // Handle strings + // Handle strings case '"': readString(false); return T_STRING; - // Handle newlines and EOF + // Handle newlines and EOF case '\r': handleCRLF(c); @@ -1854,7 +1810,7 @@ static int yylex_NORMAL() case EOF: return T_EOF; - // Handle line continuations + // Handle line continuations case '\\': // Macro args were handled by `peek`, and character escapes do not exist @@ -1862,7 +1818,7 @@ static int yylex_NORMAL() readLineContinuation(); break; - // Handle raw strings... or fall through if '#' is not followed by '"' + // Handle raw strings... or fall through if '#' is not followed by '"' case '#': if (peek() == '"') { @@ -1872,7 +1828,7 @@ static int yylex_NORMAL() } // fallthrough - // Handle identifiers... or report garbage characters + // Handle identifiers... or report garbage characters default: if (startsIdentifier(c)) { @@ -1880,8 +1836,7 @@ static int yylex_NORMAL() // An ELIF after a taken IF needs to not evaluate its condition if (tokenType == T_POP_ELIF && lexerState->lastToken == T_NEWLINE - && lexer_GetIFDepth() > 0 && lexer_RanIFBlock() - && !lexer_ReachedELSEBlock()) + && lexer_GetIFDepth() > 0 && lexer_RanIFBlock() && !lexer_ReachedELSEBlock()) return yylex_SKIP_TO_ENDC(); // If a keyword, don't try to expand @@ -1919,8 +1874,7 @@ static int yylex_NORMAL() } } -static int yylex_RAW() -{ +static int yylex_RAW() { // This is essentially a modified `appendStringLiteral` size_t parenDepth = 0; size_t i = 0; @@ -2032,8 +1986,8 @@ backslash: c = '\\'; break; - // Macro args were already handled by peek, so '\@', - // '\#', and '\0'-'\9' should not occur here. + // Macro args were already handled by peek, so '\@', + // '\#', and '\0'-'\9' should not occur here. default: error("Illegal character escape %s\n", printChar(c)); @@ -2094,8 +2048,7 @@ finish: // "meaningful" (= at line start) vs. "meaningless" (everything else) tokens. // It's especially important due to macro args not being handled in this // state, and lexing them in "normal" mode potentially producing such tokens. -static int skipIfBlock(bool toEndc) -{ +static int skipIfBlock(bool toEndc) { lexer_SetMode(LEXER_NORMAL); uint32_t startingDepth = lexer_GetIFDepth(); int token; @@ -2133,7 +2086,7 @@ static int skipIfBlock(bool toEndc) fatalerror("Found ELSE after an ELSE block\n"); lexer_ReachELSEBlock(); // fallthrough - maybeFinish: +maybeFinish: if (toEndc) // Ignore ELIF and ELSE, go to ENDC break; // fallthrough @@ -2178,18 +2131,15 @@ finish: return token; } -static int yylex_SKIP_TO_ELIF() -{ +static int yylex_SKIP_TO_ELIF() { return skipIfBlock(false); } -static int yylex_SKIP_TO_ENDC() -{ +static int yylex_SKIP_TO_ENDC() { return skipIfBlock(true); } -static int yylex_SKIP_TO_ENDR() -{ +static int yylex_SKIP_TO_ENDR() { lexer_SetMode(LEXER_NORMAL); int depth = 1; bool atLineStart = lexerState->atLineStart; @@ -2265,8 +2215,7 @@ finish: return T_EOF; } -int yylex() -{ +int yylex() { if (lexerState->atLineStart && lexerStateEOL) { lexer_SetState(lexerStateEOL); lexerStateEOL = nullptr; @@ -2279,11 +2228,11 @@ int yylex() nextLine(); static int (* const lexerModeFuncs[NB_LEXER_MODES])() = { - yylex_NORMAL, - yylex_RAW, - yylex_SKIP_TO_ELIF, - yylex_SKIP_TO_ENDC, - yylex_SKIP_TO_ENDR, + yylex_NORMAL, + yylex_RAW, + yylex_SKIP_TO_ELIF, + yylex_SKIP_TO_ENDC, + yylex_SKIP_TO_ENDR, }; int token = lexerModeFuncs[lexerState->mode](); @@ -2296,8 +2245,7 @@ int yylex() return token; } -static void startCapture(CaptureBody &capture) -{ +static void startCapture(CaptureBody &capture) { assert(!lexerState->capturing); lexerState->capturing = true; lexerState->captureSize = 0; @@ -2305,29 +2253,29 @@ static void startCapture(CaptureBody &capture) lexerState->disableInterpolation = true; capture.lineNo = lexer_GetLineNo(); - capture.body = std::visit(Visitor{ - [](MmappedLexerState &mmap) -> char const * { - return lexerState->expansions.empty() ? &mmap.ptr[mmap.offset] : nullptr; - }, - [](ViewedLexerState &view) -> char const * { - return lexerState->expansions.empty() ? &view.ptr[view.offset] : nullptr; - }, - [](auto &) -> char const * { - return nullptr; - } - }, lexerState->content); + capture.body = std::visit( + Visitor{ + [](MmappedLexerState &mmap) -> char const * { + return lexerState->expansions.empty() ? &mmap.ptr[mmap.offset] : nullptr; + }, + [](ViewedLexerState &view) -> char const * { + return lexerState->expansions.empty() ? &view.ptr[view.offset] : nullptr; + }, + [](auto &) -> char const * { return nullptr; }, + }, + lexerState->content + ); if (capture.body == nullptr) { // Indicates to retrieve the capture buffer when done capturing assert(lexerState->captureBuf == nullptr); - lexerState->captureBuf = new(std::nothrow) std::vector(); + lexerState->captureBuf = new (std::nothrow) std::vector(); if (!lexerState->captureBuf) fatalerror("Failed to allocate capture buffer: %s\n", strerror(errno)); } } -static void endCapture(CaptureBody &capture) -{ +static void endCapture(CaptureBody &capture) { // This being `nullptr` means we're capturing from the capture buf, which is reallocated // during the whole capture process, and so MUST be retrieved at the end if (!capture.body) @@ -2340,8 +2288,7 @@ static void endCapture(CaptureBody &capture) lexerState->disableInterpolation = false; } -bool lexer_CaptureRept(CaptureBody &capture) -{ +bool lexer_CaptureRept(CaptureBody &capture) { startCapture(capture); size_t depth = 0; @@ -2398,8 +2345,7 @@ finish: return c != EOF; } -bool lexer_CaptureMacroBody(CaptureBody &capture) -{ +bool lexer_CaptureMacroBody(CaptureBody &capture) { startCapture(capture); // If the file is `mmap`ed, we need not to unmap it to keep access to the macro diff --git a/src/asm/macro.cpp b/src/asm/macro.cpp index 9bb4862d..187de1f1 100644 --- a/src/asm/macro.cpp +++ b/src/asm/macro.cpp @@ -1,14 +1,15 @@ /* SPDX-License-Identifier: MIT */ +#include "asm/macro.hpp" + #include -#include #include +#include #include #include #include #include -#include "asm/macro.hpp" #include "asm/warning.hpp" #define MAXMACROARGS 99999 @@ -19,8 +20,7 @@ static uint32_t maxUniqueID = 0; static char uniqueIDBuf[sizeof("_u4294967295")] = {}; // UINT32_MAX static char *uniqueIDPtr = nullptr; -void MacroArgs::append(std::string s) -{ +void MacroArgs::append(std::string s) { if (s.empty()) warning(WARNING_EMPTY_MACRO_ARG, "Empty macro argument\n"); if (args.size() == MAXMACROARGS) @@ -28,18 +28,15 @@ void MacroArgs::append(std::string s) args.push_back(s); } -MacroArgs *macro_GetCurrentArgs() -{ +MacroArgs *macro_GetCurrentArgs() { return macroArgs; } -void macro_UseNewArgs(MacroArgs *args) -{ +void macro_UseNewArgs(MacroArgs *args) { macroArgs = args; } -char const *macro_GetArg(uint32_t i) -{ +char const *macro_GetArg(uint32_t i) { if (!macroArgs) return nullptr; @@ -48,8 +45,7 @@ char const *macro_GetArg(uint32_t i) return realIndex >= macroArgs->args.size() ? nullptr : macroArgs->args[realIndex].c_str(); } -char const *macro_GetAllArgs() -{ +char const *macro_GetAllArgs() { if (!macroArgs) return nullptr; @@ -85,13 +81,11 @@ char const *macro_GetAllArgs() return str; } -uint32_t macro_GetUniqueID() -{ +uint32_t macro_GetUniqueID() { return uniqueID; } -char const *macro_GetUniqueIDStr() -{ +char const *macro_GetUniqueIDStr() { // Generate a new unique ID on the first use of `\@` if (uniqueID == 0) macro_SetUniqueID(++maxUniqueID); @@ -99,8 +93,7 @@ char const *macro_GetUniqueIDStr() return uniqueIDPtr; } -void macro_SetUniqueID(uint32_t id) -{ +void macro_SetUniqueID(uint32_t id) { uniqueID = id; if (id == 0 || id == (uint32_t)-1) { uniqueIDPtr = nullptr; @@ -112,26 +105,23 @@ void macro_SetUniqueID(uint32_t id) } } -uint32_t macro_UseNewUniqueID() -{ +uint32_t macro_UseNewUniqueID() { // A new ID will be generated on the first use of `\@` macro_SetUniqueID(0); return uniqueID; } -uint32_t macro_UndefUniqueID() -{ +uint32_t macro_UndefUniqueID() { // No ID will be generated; use of `\@` is an error macro_SetUniqueID((uint32_t)-1); return uniqueID; } -void macro_ShiftCurrentArgs(int32_t count) -{ +void macro_ShiftCurrentArgs(int32_t count) { if (!macroArgs) { error("Cannot shift macro arguments outside of a macro\n"); } else if (size_t nbArgs = macroArgs->args.size(); - count > 0 && ((uint32_t)count > nbArgs || macroArgs->shift > nbArgs - count)) { + count > 0 && ((uint32_t)count > nbArgs || macroArgs->shift > nbArgs - count)) { warning(WARNING_MACRO_SHIFT, "Cannot shift macro arguments past their end\n"); macroArgs->shift = nbArgs; } else if (count < 0 && macroArgs->shift < (uint32_t)-count) { @@ -142,7 +132,6 @@ void macro_ShiftCurrentArgs(int32_t count) } } -uint32_t macro_NbArgs() -{ +uint32_t macro_NbArgs() { return macroArgs->args.size() - macroArgs->shift; } diff --git a/src/asm/main.cpp b/src/asm/main.cpp index e4ff28b0..f4fb8f63 100644 --- a/src/asm/main.cpp +++ b/src/asm/main.cpp @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: MIT */ +#include "asm/main.hpp" + #include #include #include @@ -7,43 +9,43 @@ #include #include #include -#include #include +#include #include -#include #include +#include #include +#include "error.hpp" +#include "extern/getopt.hpp" +#include "helpers.hpp" +#include "parser.hpp" +#include "version.hpp" + #include "asm/charmap.hpp" #include "asm/fixpoint.hpp" #include "asm/format.hpp" #include "asm/fstack.hpp" #include "asm/lexer.hpp" -#include "asm/main.hpp" #include "asm/opt.hpp" #include "asm/output.hpp" #include "asm/rpn.hpp" #include "asm/symbol.hpp" #include "asm/warning.hpp" -#include "parser.hpp" - -#include "extern/getopt.hpp" - -#include "helpers.hpp" -#include "error.hpp" -#include "version.hpp" #ifdef __clang__ -#if __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__) -#define __SANITIZE_ADDRESS__ -#endif // __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__) -#endif // __clang__ + #if __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__) + #define __SANITIZE_ADDRESS__ + #endif // __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__) +#endif // __clang__ #ifdef __SANITIZE_ADDRESS__ // There are known, non-trivial to fix leaks. We would still like to have `make develop' // detect memory corruption, though. extern "C" { -char const *__asan_default_options() { return "detect_leaks=0"; } +char const *__asan_default_options() { + return "detect_leaks=0"; +} } #endif @@ -65,8 +67,7 @@ bool verbose; bool warnings; // True to enable warnings, false to disable them. // Escapes Make-special chars from a string -static std::string make_escape(std::string &str) -{ +static std::string make_escape(std::string &str) { std::string escaped; size_t pos = 0; @@ -98,54 +99,53 @@ static int depType; // Variants of `-M` // This is because long opt matching, even to a single char, is prioritized // over short opt matching static option const longopts[] = { - { "binary-digits", required_argument, nullptr, 'b' }, - { "define", required_argument, nullptr, 'D' }, - { "export-all", no_argument, nullptr, 'E' }, - { "gfx-chars", required_argument, nullptr, 'g' }, - { "nop-after-halt", no_argument, nullptr, 'H' }, - { "halt-without-nop", no_argument, nullptr, 'h' }, - { "include", required_argument, nullptr, 'I' }, - { "preserve-ld", no_argument, nullptr, 'L' }, - { "auto-ldh", no_argument, nullptr, 'l' }, - { "dependfile", required_argument, nullptr, 'M' }, - { "MG", no_argument, &depType, 'G' }, - { "MP", no_argument, &depType, 'P' }, - { "MT", required_argument, &depType, 'T' }, - { "warning", required_argument, nullptr, 'W' }, - { "MQ", required_argument, &depType, 'Q' }, - { "output", required_argument, nullptr, 'o' }, - { "preinclude", required_argument, nullptr, 'P' }, - { "pad-value", required_argument, nullptr, 'p' }, - { "q-precision", required_argument, nullptr, 'Q' }, - { "recursion-depth", required_argument, nullptr, 'r' }, - { "version", no_argument, nullptr, 'V' }, - { "verbose", no_argument, nullptr, 'v' }, - { "warning", required_argument, nullptr, 'W' }, - { "max-errors", required_argument, nullptr, 'X' }, - { nullptr, no_argument, nullptr, 0 } + {"binary-digits", required_argument, nullptr, 'b'}, + {"define", required_argument, nullptr, 'D'}, + {"export-all", no_argument, nullptr, 'E'}, + {"gfx-chars", required_argument, nullptr, 'g'}, + {"nop-after-halt", no_argument, nullptr, 'H'}, + {"halt-without-nop", no_argument, nullptr, 'h'}, + {"include", required_argument, nullptr, 'I'}, + {"preserve-ld", no_argument, nullptr, 'L'}, + {"auto-ldh", no_argument, nullptr, 'l'}, + {"dependfile", required_argument, nullptr, 'M'}, + {"MG", no_argument, &depType, 'G'}, + {"MP", no_argument, &depType, 'P'}, + {"MT", required_argument, &depType, 'T'}, + {"warning", required_argument, nullptr, 'W'}, + {"MQ", required_argument, &depType, 'Q'}, + {"output", required_argument, nullptr, 'o'}, + {"preinclude", required_argument, nullptr, 'P'}, + {"pad-value", required_argument, nullptr, 'p'}, + {"q-precision", required_argument, nullptr, 'Q'}, + {"recursion-depth", required_argument, nullptr, 'r'}, + {"version", no_argument, nullptr, 'V'}, + {"verbose", no_argument, nullptr, 'v'}, + {"warning", required_argument, nullptr, 'W'}, + {"max-errors", required_argument, nullptr, 'X'}, + {nullptr, no_argument, nullptr, 0 } }; -static void printUsage() -{ +static void printUsage() { fputs( -"Usage: rgbasm [-EHhLlVvw] [-b chars] [-D name[=value]] [-g chars] [-I path]\n" -" [-M depend_file] [-MG] [-MP] [-MT target_file] [-MQ target_file]\n" -" [-o out_file] [-P include_file] [-p pad_value] [-Q precision]\n" -" [-r depth] [-W warning] [-X max_errors] \n" -"Useful options:\n" -" -E, --export-all export all labels\n" -" -M, --dependfile set the output dependency file\n" -" -o, --output set the output object file\n" -" -p, --pad-value set the value to use for `ds'\n" -" -V, --version print RGBASM version and exit\n" -" -W, --warning enable or disable warnings\n" -"\n" -"For help, use `man rgbasm' or go to https://rgbds.gbdev.io/docs/\n", - stderr); + "Usage: rgbasm [-EHhLlVvw] [-b chars] [-D name[=value]] [-g chars] [-I path]\n" + " [-M depend_file] [-MG] [-MP] [-MT target_file] [-MQ target_file]\n" + " [-o out_file] [-P include_file] [-p pad_value] [-Q precision]\n" + " [-r depth] [-W warning] [-X max_errors] \n" + "Useful options:\n" + " -E, --export-all export all labels\n" + " -M, --dependfile set the output dependency file\n" + " -o, --output set the output object file\n" + " -p, --pad-value set the value to use for `ds'\n" + " -V, --version print RGBASM version and exit\n" + " -W, --warning enable or disable warnings\n" + "\n" + "For help, use `man rgbasm' or go to https://rgbds.gbdev.io/docs/\n", + stderr + ); } -int main(int argc, char *argv[]) -{ +int main(int argc, char *argv[]) { time_t now = time(nullptr); char const *sourceDateEpoch = getenv("SOURCE_DATE_EPOCH"); @@ -213,8 +213,9 @@ int main(int argc, char *argv[]) case 'H': if (warnOnHaltNop) - warning(WARNING_OBSOLETE, - "Automatic `nop` after `halt` (the `-H` flag) is deprecated\n"); + warning( + WARNING_OBSOLETE, "Automatic `nop` after `halt` (the `-H` flag) is deprecated\n" + ); else errx("`-H` and `-h` don't make sense together"); haltNop = true; @@ -240,8 +241,10 @@ int main(int argc, char *argv[]) break; case 'l': if (warnOnLdOpt) - warning(WARNING_OBSOLETE, - "Automatic `ld` to `ldh` optimization (the `-l` flag) is deprecated\n"); + warning( + WARNING_OBSOLETE, + "Automatic `ld` to `ldh` optimization (the `-l` flag) is deprecated\n" + ); else errx("`-L` and `-l` don't make sense together"); optimizeLoads = true; @@ -371,7 +374,9 @@ int main(int argc, char *argv[]) targetFileName = objectName; if (argc == musl_optind) { - fputs("FATAL: Please specify an input file (pass `-` to read from standard input)\n", stderr); + fputs( + "FATAL: Please specify an input file (pass `-` to read from standard input)\n", stderr + ); printUsage(); exit(1); } else if (argc != musl_optind + 1) { @@ -387,7 +392,8 @@ int main(int argc, char *argv[]) if (dependfile) { if (targetFileName.empty()) - errx("Dependency files can only be created if a target file is specified with either -o, -MQ or -MT"); + errx("Dependency files can only be created if a target file is specified with either " + "-o, -MQ or -MT"); fprintf(dependfile, "%s: %s\n", targetFileName.c_str(), mainFileName); } diff --git a/src/asm/opt.cpp b/src/asm/opt.cpp index 9f7d61e6..abcbb290 100644 --- a/src/asm/opt.cpp +++ b/src/asm/opt.cpp @@ -33,59 +33,48 @@ struct OptStackEntry { static std::stack stack; -void opt_B(char const chars[2]) -{ +void opt_B(char const chars[2]) { lexer_SetBinDigits(chars); } -void opt_G(char const chars[4]) -{ +void opt_G(char const chars[4]) { lexer_SetGfxDigits(chars); } -void opt_P(uint8_t padByte) -{ +void opt_P(uint8_t padByte) { fillByte = padByte; } -void opt_Q(uint8_t precision) -{ +void opt_Q(uint8_t precision) { fixPrecision = precision; } -void opt_R(size_t newDepth) -{ +void opt_R(size_t newDepth) { fstk_NewRecursionDepth(newDepth); lexer_CheckRecursionDepth(); } -void opt_H(bool warn) -{ +void opt_H(bool warn) { warnOnHaltNop = warn; } -void opt_h(bool halt) -{ +void opt_h(bool halt) { haltNop = halt; } -void opt_L(bool optimize) -{ +void opt_L(bool optimize) { optimizeLoads = optimize; } -void opt_l(bool warn) -{ +void opt_l(bool warn) { warnOnLdOpt = warn; } -void opt_W(char *flag) -{ +void opt_W(char *flag) { processWarningFlag(flag); } -void opt_Parse(char *s) -{ +void opt_Parse(char *s) { switch (s[0]) { case 'b': if (strlen(&s[1]) == 2) @@ -239,8 +228,7 @@ void opt_Parse(char *s) } } -void opt_Push() -{ +void opt_Push() { OptStackEntry entry; // Both of these are pulled from lexer.hpp @@ -273,8 +261,7 @@ void opt_Push() stack.push(entry); } -void opt_Pop() -{ +void opt_Pop() { if (stack.empty()) { error("No entries in the option stack\n"); return; diff --git a/src/asm/output.cpp b/src/asm/output.cpp index 0b47b0f6..2bbf7b82 100644 --- a/src/asm/output.cpp +++ b/src/asm/output.cpp @@ -2,30 +2,31 @@ // Outputs an objectfile +#include "asm/output.hpp" + #include #include #include #include #include -#include #include +#include #include -#include #include +#include #include +#include "error.hpp" +#include "linkdefs.hpp" + #include "asm/charmap.hpp" #include "asm/fstack.hpp" #include "asm/main.hpp" -#include "asm/output.hpp" #include "asm/rpn.hpp" #include "asm/section.hpp" #include "asm/symbol.hpp" #include "asm/warning.hpp" -#include "error.hpp" -#include "linkdefs.hpp" - struct Assertion { Patch patch; Section *section; @@ -42,8 +43,7 @@ static std::deque assertions; static std::deque fileStackNodes; // Write a long to a file (little-endian) -static void putlong(uint32_t i, FILE *f) -{ +static void putlong(uint32_t i, FILE *f) { putc(i, f); putc(i >> 8, f); putc(i >> 16, f); @@ -51,15 +51,13 @@ static void putlong(uint32_t i, FILE *f) } // Write a NUL-terminated string to a file -static void putstring(char const *s, FILE *f) -{ +static void putstring(char const *s, FILE *f) { while (*s) putc(*s++, f); putc(0, f); } -void out_RegisterNode(FileStackNode *node) -{ +void out_RegisterNode(FileStackNode *node) { // If node is not already registered, register it (and parents), and give it a unique ID for (; node && node->ID == (uint32_t)-1; node = node->parent) { node->ID = fileStackNodes.size(); @@ -67,8 +65,7 @@ void out_RegisterNode(FileStackNode *node) } } -void out_ReplaceNode(FileStackNode * /* node */) -{ +void out_ReplaceNode(FileStackNode * /* node */) { #if 0 This is code intended to replace a node, which is pretty useless until ref counting is added... @@ -84,8 +81,7 @@ This is code intended to replace a node, which is pretty useless until ref count } // Return a section's ID, or -1 if the section is not in the list -static uint32_t getSectIDIfAny(Section *sect) -{ +static uint32_t getSectIDIfAny(Section *sect) { if (!sect) return (uint32_t)-1; @@ -98,8 +94,7 @@ static uint32_t getSectIDIfAny(Section *sect) } // Write a patch to a file -static void writepatch(Patch const &patch, FILE *f) -{ +static void writepatch(Patch const &patch, FILE *f) { assert(patch.src->ID != (uint32_t)-1); putlong(patch.src->ID, f); putlong(patch.lineNo, f); @@ -112,8 +107,7 @@ static void writepatch(Patch const &patch, FILE *f) } // Write a section to a file -static void writesection(Section const §, FILE *f) -{ +static void writesection(Section const §, FILE *f) { putstring(sect.name.c_str(), f); putlong(sect.size, f); @@ -138,8 +132,7 @@ static void writesection(Section const §, FILE *f) } // Write a symbol to a file -static void writesymbol(Symbol const &sym, FILE *f) -{ +static void writesymbol(Symbol const &sym, FILE *f) { putstring(sym.name, f); if (!sym.isDefined()) { putc(SYMTYPE_IMPORT, f); @@ -154,8 +147,7 @@ static void writesymbol(Symbol const &sym, FILE *f) } } -static void registerSymbol(Symbol &sym) -{ +static void registerSymbol(Symbol &sym) { sym.ID = objectSymbols.size(); objectSymbols.push_back(&sym); out_RegisterNode(sym.src); @@ -163,19 +155,17 @@ static void registerSymbol(Symbol &sym) // Returns a symbol's ID within the object file // If the symbol does not have one, one is assigned by registering the symbol -static uint32_t getSymbolID(Symbol &sym) -{ +static uint32_t getSymbolID(Symbol &sym) { if (sym.ID == (uint32_t)-1 && !sym_IsPC(&sym)) registerSymbol(sym); return sym.ID; } -static void writerpn(std::vector &rpnexpr, const std::vector &rpn) -{ +static void writerpn(std::vector &rpnexpr, const std::vector &rpn) { char symName[512]; size_t rpnptr = 0; - for (size_t offset = 0; offset < rpn.size(); ) { + for (size_t offset = 0; offset < rpn.size();) { uint8_t rpndata = rpn[offset++]; switch (rpndata) { @@ -262,8 +252,7 @@ static void writerpn(std::vector &rpnexpr, const std::vector & } } -static void initpatch(Patch &patch, uint32_t type, Expression const &expr, uint32_t ofs) -{ +static void initpatch(Patch &patch, uint32_t type, Expression const &expr, uint32_t ofs) { FileStackNode *node = fstk_GetFileStack(); patch.type = type; @@ -290,8 +279,7 @@ static void initpatch(Patch &patch, uint32_t type, Expression const &expr, uint3 } // Create a new patch (includes the rpn expr) -void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32_t pcShift) -{ +void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32_t pcShift) { // Add the patch to the list Patch &patch = currentSection->patches.emplace_front(); @@ -304,22 +292,21 @@ void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32 } // Creates an assert that will be written to the object file -void out_CreateAssert(enum AssertionType type, Expression const &expr, char const *message, uint32_t ofs) -{ +void out_CreateAssert( + enum AssertionType type, Expression const &expr, char const *message, uint32_t ofs +) { Assertion &assertion = assertions.emplace_front(); initpatch(assertion.patch, type, expr, ofs); assertion.message = message; } -static void writeassert(Assertion &assert, FILE *f) -{ +static void writeassert(Assertion &assert, FILE *f) { writepatch(assert.patch, f); putstring(assert.message.c_str(), f); } -static void writeFileStackNode(FileStackNode const &node, FILE *f) -{ +static void writeFileStackNode(FileStackNode const &node, FILE *f) { putlong(node.parent ? node.parent->ID : (uint32_t)-1, f); putlong(node.lineNo, f); putc(node.type, f); @@ -330,13 +317,12 @@ static void writeFileStackNode(FileStackNode const &node, FILE *f) putlong(nodeIters.size(), f); // Iters are stored by decreasing depth, so reverse the order for output - for (uint32_t i = nodeIters.size(); i--; ) + for (uint32_t i = nodeIters.size(); i--;) putlong(nodeIters[i], f); } } -static void registerUnregisteredSymbol(Symbol &sym) -{ +static void registerUnregisteredSymbol(Symbol &sym) { // Check for symbol->src, to skip any built-in symbol from rgbasm if (sym.src && sym.ID == (uint32_t)-1) { registerSymbol(sym); @@ -344,8 +330,7 @@ static void registerUnregisteredSymbol(Symbol &sym) } // Write an objectfile -void out_WriteObject() -{ +void out_WriteObject() { FILE *f; if (strcmp(objectName, "-")) { @@ -374,9 +359,12 @@ void out_WriteObject() // The list is supposed to have decrementing IDs if (it + 1 != fileStackNodes.end() && it[1]->ID != node->ID - 1) - fatalerror("Internal error: fstack node #%" PRIu32 " follows #%" PRIu32 - ". Please report this to the developers!\n", - it[1]->ID, node->ID); + fatalerror( + "Internal error: fstack node #%" PRIu32 " follows #%" PRIu32 + ". Please report this to the developers!\n", + it[1]->ID, + node->ID + ); } for (Symbol const *sym : objectSymbols) @@ -394,8 +382,7 @@ void out_WriteObject() } // Set the objectfilename -void out_SetFileName(char *s) -{ +void out_SetFileName(char *s) { if (objectName) warnx("Overriding output filename %s", objectName); objectName = s; diff --git a/src/asm/parser.y b/src/asm/parser.y index 266c55ba..a15d3c5e 100644 --- a/src/asm/parser.y +++ b/src/asm/parser.y @@ -61,36 +61,29 @@ static const char *strrstr(char const *s1, char const *s2); static void errorInvalidUTF8Byte(uint8_t byte, char const *functionName); static size_t strlenUTF8(char const *s); - static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos, - uint32_t len); + static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos, uint32_t len); static size_t charlenUTF8(char const *str); static void charsubUTF8(char *dest, char const *src, uint32_t pos); static uint32_t adjustNegativePos(int32_t pos, size_t len, char const *functionName); - static void strrpl(char *dest, size_t destLen, char const *src, char const *old, - char const *rep); - static void initStrFmtArgList(StrFmtArgList &args); - static void freeStrFmtArgList(StrFmtArgList &args); - static void strfmt(char *dest, size_t destLen, char const *spec, - std::vector> &args); + static void strrpl( + char *dest, size_t destLen, char const *src, char const *old, char const *rep + ); + static void initStrFmtArgList(StrFmtArgList & args); + static void freeStrFmtArgList(StrFmtArgList & args); + static void strfmt( + char *dest, size_t destLen, char const *spec, + std::vector> &args + ); static void compoundAssignment(const char *symName, enum RPNCommand op, int32_t constValue); - static void initDsArgList(std::vector *&args); - static void initPurgeArgList(std::vector *&args); + static void initDsArgList(std::vector * &args); + static void initPurgeArgList(std::vector * &args); static void failAssert(enum AssertionType type); static void failAssertMsg(enum AssertionType type, char const *msg); void yyerror(char const *str); // The CPU encodes instructions in a logical way, so most instructions actually follow patterns. // These enums thus help with bit twiddling to compute opcodes - enum { - REG_B = 0, - REG_C, - REG_D, - REG_E, - REG_H, - REG_L, - REG_HL_IND, - REG_A - }; + enum { REG_B = 0, REG_C, REG_D, REG_E, REG_H, REG_L, REG_HL_IND, REG_A }; enum { REG_BC_IND = 0, @@ -108,12 +101,7 @@ REG_AF = 3 }; - enum { - CC_NZ = 0, - CC_Z, - CC_NC, - CC_C - }; + enum { CC_NZ = 0, CC_Z, CC_NC, CC_C }; } %union @@ -135,199 +123,199 @@ bool captureTerminated; } -%type relocexpr -%type relocexpr_no_str -%type const -%type const_no_str -%type const_8bit -%type uconst -%type rs_uconst -%type const_3bit -%type reloc_8bit -%type reloc_8bit_no_str -%type reloc_8bit_offset -%type reloc_16bit -%type reloc_16bit_no_str -%type sectiontype +%type relocexpr +%type relocexpr_no_str +%type const +%type const_no_str +%type const_8bit +%type uconst +%type rs_uconst +%type const_3bit +%type reloc_8bit +%type reloc_8bit_no_str +%type reloc_8bit_offset +%type reloc_16bit +%type reloc_16bit_no_str +%type sectiontype -%type string -%type strcat_args -%type strfmt_args -%type strfmt_va_args +%type string +%type strcat_args +%type strfmt_args +%type strfmt_va_args -%type sectorg -%type sectattrs +%type sectorg +%type sectattrs -%token T_NUMBER "number" -%token T_STRING "string" +%token T_NUMBER "number" +%token T_STRING "string" -%token T_PERIOD "." -%token T_COMMA "," -%token T_COLON ":" T_DOUBLE_COLON "::" -%token T_LBRACK "[" T_RBRACK "]" -%token T_LPAREN "(" T_RPAREN ")" -%token T_NEWLINE "newline" +%token T_PERIOD "." +%token T_COMMA "," +%token T_COLON ":" T_DOUBLE_COLON "::" +%token T_LBRACK "[" T_RBRACK "]" +%token T_LPAREN "(" T_RPAREN ")" +%token T_NEWLINE "newline" -%token T_OP_LOGICNOT "!" -%token T_OP_LOGICAND "&&" T_OP_LOGICOR "||" -%token T_OP_LOGICGT ">" T_OP_LOGICLT "<" -%token T_OP_LOGICGE ">=" T_OP_LOGICLE "<=" -%token T_OP_LOGICNE "!=" T_OP_LOGICEQU "==" -%token T_OP_ADD "+" T_OP_SUB "-" -%token T_OP_OR "|" T_OP_XOR "^" T_OP_AND "&" -%token T_OP_SHL "<<" T_OP_SHR ">>" T_OP_USHR ">>>" -%token T_OP_MUL "*" T_OP_DIV "/" T_OP_MOD "%" -%token T_OP_NOT "~" -%left T_OP_LOGICOR -%left T_OP_LOGICAND -%left T_OP_LOGICGT T_OP_LOGICLT T_OP_LOGICGE T_OP_LOGICLE T_OP_LOGICNE T_OP_LOGICEQU -%left T_OP_ADD T_OP_SUB -%left T_OP_OR T_OP_XOR T_OP_AND -%left T_OP_SHL T_OP_SHR T_OP_USHR -%left T_OP_MUL T_OP_DIV T_OP_MOD +%token T_OP_LOGICNOT "!" +%token T_OP_LOGICAND "&&" T_OP_LOGICOR "||" +%token T_OP_LOGICGT ">" T_OP_LOGICLT "<" +%token T_OP_LOGICGE ">=" T_OP_LOGICLE "<=" +%token T_OP_LOGICNE "!=" T_OP_LOGICEQU "==" +%token T_OP_ADD "+" T_OP_SUB "-" +%token T_OP_OR "|" T_OP_XOR "^" T_OP_AND "&" +%token T_OP_SHL "<<" T_OP_SHR ">>" T_OP_USHR ">>>" +%token T_OP_MUL "*" T_OP_DIV "/" T_OP_MOD "%" +%token T_OP_NOT "~" +%left T_OP_LOGICOR +%left T_OP_LOGICAND +%left T_OP_LOGICGT T_OP_LOGICLT T_OP_LOGICGE T_OP_LOGICLE T_OP_LOGICNE T_OP_LOGICEQU +%left T_OP_ADD T_OP_SUB +%left T_OP_OR T_OP_XOR T_OP_AND +%left T_OP_SHL T_OP_SHR T_OP_USHR +%left T_OP_MUL T_OP_DIV T_OP_MOD -%precedence NEG // negation -- unary minus +%precedence NEG // negation -- unary minus -%token T_OP_EXP "**" -%left T_OP_EXP +%token T_OP_EXP "**" +%left T_OP_EXP -%token T_OP_DEF "DEF" -%token T_OP_BANK "BANK" -%token T_OP_ALIGN "ALIGN" -%token T_OP_SIZEOF "SIZEOF" T_OP_STARTOF "STARTOF" +%token T_OP_DEF "DEF" +%token T_OP_BANK "BANK" +%token T_OP_ALIGN "ALIGN" +%token T_OP_SIZEOF "SIZEOF" T_OP_STARTOF "STARTOF" -%token T_OP_SIN "SIN" T_OP_COS "COS" T_OP_TAN "TAN" -%token T_OP_ASIN "ASIN" T_OP_ACOS "ACOS" T_OP_ATAN "ATAN" T_OP_ATAN2 "ATAN2" -%token T_OP_FDIV "FDIV" -%token T_OP_FMUL "FMUL" -%token T_OP_FMOD "FMOD" -%token T_OP_POW "POW" -%token T_OP_LOG "LOG" -%token T_OP_ROUND "ROUND" -%token T_OP_CEIL "CEIL" T_OP_FLOOR "FLOOR" -%type opt_q_arg +%token T_OP_SIN "SIN" T_OP_COS "COS" T_OP_TAN "TAN" +%token T_OP_ASIN "ASIN" T_OP_ACOS "ACOS" T_OP_ATAN "ATAN" T_OP_ATAN2 "ATAN2" +%token T_OP_FDIV "FDIV" +%token T_OP_FMUL "FMUL" +%token T_OP_FMOD "FMOD" +%token T_OP_POW "POW" +%token T_OP_LOG "LOG" +%token T_OP_ROUND "ROUND" +%token T_OP_CEIL "CEIL" T_OP_FLOOR "FLOOR" +%type opt_q_arg -%token T_OP_HIGH "HIGH" T_OP_LOW "LOW" -%token T_OP_ISCONST "ISCONST" +%token T_OP_HIGH "HIGH" T_OP_LOW "LOW" +%token T_OP_ISCONST "ISCONST" -%token T_OP_STRCMP "STRCMP" -%token T_OP_STRIN "STRIN" T_OP_STRRIN "STRRIN" -%token T_OP_STRSUB "STRSUB" -%token T_OP_STRLEN "STRLEN" -%token T_OP_STRCAT "STRCAT" -%token T_OP_STRUPR "STRUPR" T_OP_STRLWR "STRLWR" -%token T_OP_STRRPL "STRRPL" -%token T_OP_STRFMT "STRFMT" +%token T_OP_STRCMP "STRCMP" +%token T_OP_STRIN "STRIN" T_OP_STRRIN "STRRIN" +%token T_OP_STRSUB "STRSUB" +%token T_OP_STRLEN "STRLEN" +%token T_OP_STRCAT "STRCAT" +%token T_OP_STRUPR "STRUPR" T_OP_STRLWR "STRLWR" +%token T_OP_STRRPL "STRRPL" +%token T_OP_STRFMT "STRFMT" -%token T_OP_CHARLEN "CHARLEN" -%token T_OP_CHARSUB "CHARSUB" -%token T_OP_INCHARMAP "INCHARMAP" +%token T_OP_CHARLEN "CHARLEN" +%token T_OP_CHARSUB "CHARSUB" +%token T_OP_INCHARMAP "INCHARMAP" -%token T_LABEL "label" -%token T_ID "identifier" -%token T_LOCAL_ID "local identifier" -%token T_ANON "anonymous label" -%type def_id -%type redef_id -%type scoped_id -%type scoped_anon_id -%token T_POP_EQU "EQU" -%token T_POP_EQUAL "=" -%token T_POP_EQUS "EQUS" +%token T_LABEL "label" +%token T_ID "identifier" +%token T_LOCAL_ID "local identifier" +%token T_ANON "anonymous label" +%type def_id +%type redef_id +%type scoped_id +%type scoped_anon_id +%token T_POP_EQU "EQU" +%token T_POP_EQUAL "=" +%token T_POP_EQUS "EQUS" -%token T_POP_ADDEQ "+=" T_POP_SUBEQ "-=" -%token T_POP_MULEQ "*=" T_POP_DIVEQ "/=" T_POP_MODEQ "%=" -%token T_POP_OREQ "|=" T_POP_XOREQ "^=" T_POP_ANDEQ "&=" -%token T_POP_SHLEQ "<<=" T_POP_SHREQ ">>=" -%type compoundeq +%token T_POP_ADDEQ "+=" T_POP_SUBEQ "-=" +%token T_POP_MULEQ "*=" T_POP_DIVEQ "/=" T_POP_MODEQ "%=" +%token T_POP_OREQ "|=" T_POP_XOREQ "^=" T_POP_ANDEQ "&=" +%token T_POP_SHLEQ "<<=" T_POP_SHREQ ">>=" +%type compoundeq -%token T_POP_INCLUDE "INCLUDE" -%token T_POP_PRINT "PRINT" T_POP_PRINTLN "PRINTLN" -%token T_POP_IF "IF" T_POP_ELIF "ELIF" T_POP_ELSE "ELSE" T_POP_ENDC "ENDC" -%token T_POP_EXPORT "EXPORT" -%token T_POP_DB "DB" T_POP_DS "DS" T_POP_DW "DW" T_POP_DL "DL" -%token T_POP_SECTION "SECTION" T_POP_FRAGMENT "FRAGMENT" -%token T_POP_ENDSECTION "ENDSECTION" -%token T_POP_RB "RB" T_POP_RW "RW" // There is no T_POP_RL, only T_Z80_RL -%token T_POP_MACRO "MACRO" -%token T_POP_ENDM "ENDM" -%token T_POP_RSRESET "RSRESET" T_POP_RSSET "RSSET" -%token T_POP_UNION "UNION" T_POP_NEXTU "NEXTU" T_POP_ENDU "ENDU" -%token T_POP_INCBIN "INCBIN" T_POP_REPT "REPT" T_POP_FOR "FOR" -%token T_POP_CHARMAP "CHARMAP" -%token T_POP_NEWCHARMAP "NEWCHARMAP" -%token T_POP_SETCHARMAP "SETCHARMAP" -%token T_POP_PUSHC "PUSHC" -%token T_POP_POPC "POPC" -%token T_POP_SHIFT "SHIFT" -%token T_POP_ENDR "ENDR" -%token T_POP_BREAK "BREAK" -%token T_POP_LOAD "LOAD" T_POP_ENDL "ENDL" -%token T_POP_FAIL "FAIL" -%token T_POP_WARN "WARN" -%token T_POP_FATAL "FATAL" -%token T_POP_ASSERT "ASSERT" T_POP_STATIC_ASSERT "STATIC_ASSERT" -%token T_POP_PURGE "PURGE" -%token T_POP_REDEF "REDEF" -%token T_POP_POPS "POPS" -%token T_POP_PUSHS "PUSHS" -%token T_POP_POPO "POPO" -%token T_POP_PUSHO "PUSHO" -%token T_POP_OPT "OPT" -%token T_SECT_ROM0 "ROM0" T_SECT_ROMX "ROMX" -%token T_SECT_WRAM0 "WRAM0" T_SECT_WRAMX "WRAMX" T_SECT_HRAM "HRAM" -%token T_SECT_VRAM "VRAM" T_SECT_SRAM "SRAM" T_SECT_OAM "OAM" +%token T_POP_INCLUDE "INCLUDE" +%token T_POP_PRINT "PRINT" T_POP_PRINTLN "PRINTLN" +%token T_POP_IF "IF" T_POP_ELIF "ELIF" T_POP_ELSE "ELSE" T_POP_ENDC "ENDC" +%token T_POP_EXPORT "EXPORT" +%token T_POP_DB "DB" T_POP_DS "DS" T_POP_DW "DW" T_POP_DL "DL" +%token T_POP_SECTION "SECTION" T_POP_FRAGMENT "FRAGMENT" +%token T_POP_ENDSECTION "ENDSECTION" +%token T_POP_RB "RB" T_POP_RW "RW" // There is no T_POP_RL, only T_Z80_RL +%token T_POP_MACRO "MACRO" +%token T_POP_ENDM "ENDM" +%token T_POP_RSRESET "RSRESET" T_POP_RSSET "RSSET" +%token T_POP_UNION "UNION" T_POP_NEXTU "NEXTU" T_POP_ENDU "ENDU" +%token T_POP_INCBIN "INCBIN" T_POP_REPT "REPT" T_POP_FOR "FOR" +%token T_POP_CHARMAP "CHARMAP" +%token T_POP_NEWCHARMAP "NEWCHARMAP" +%token T_POP_SETCHARMAP "SETCHARMAP" +%token T_POP_PUSHC "PUSHC" +%token T_POP_POPC "POPC" +%token T_POP_SHIFT "SHIFT" +%token T_POP_ENDR "ENDR" +%token T_POP_BREAK "BREAK" +%token T_POP_LOAD "LOAD" T_POP_ENDL "ENDL" +%token T_POP_FAIL "FAIL" +%token T_POP_WARN "WARN" +%token T_POP_FATAL "FATAL" +%token T_POP_ASSERT "ASSERT" T_POP_STATIC_ASSERT "STATIC_ASSERT" +%token T_POP_PURGE "PURGE" +%token T_POP_REDEF "REDEF" +%token T_POP_POPS "POPS" +%token T_POP_PUSHS "PUSHS" +%token T_POP_POPO "POPO" +%token T_POP_PUSHO "PUSHO" +%token T_POP_OPT "OPT" +%token T_SECT_ROM0 "ROM0" T_SECT_ROMX "ROMX" +%token T_SECT_WRAM0 "WRAM0" T_SECT_WRAMX "WRAMX" T_SECT_HRAM "HRAM" +%token T_SECT_VRAM "VRAM" T_SECT_SRAM "SRAM" T_SECT_OAM "OAM" -%type sectmod -%type macroargs +%type sectmod +%type macroargs -%type align_spec +%type align_spec -%type ds_args -%type purge_args -%type for_args +%type ds_args +%type purge_args +%type for_args -%token T_Z80_ADC "adc" T_Z80_ADD "add" T_Z80_AND "and" -%token T_Z80_BIT "bit" -%token T_Z80_CALL "call" T_Z80_CCF "ccf" T_Z80_CP "cp" T_Z80_CPL "cpl" -%token T_Z80_DAA "daa" T_Z80_DEC "dec" T_Z80_DI "di" -%token T_Z80_EI "ei" -%token T_Z80_HALT "halt" -%token T_Z80_INC "inc" -%token T_Z80_JP "jp" T_Z80_JR "jr" -%token T_Z80_LD "ld" -%token T_Z80_LDI "ldi" -%token T_Z80_LDD "ldd" -%token T_Z80_LDH "ldh" -%token T_Z80_NOP "nop" -%token T_Z80_OR "or" -%token T_Z80_POP "pop" T_Z80_PUSH "push" -%token T_Z80_RES "res" T_Z80_RET "ret" T_Z80_RETI "reti" T_Z80_RST "rst" -%token T_Z80_RL "rl" T_Z80_RLA "rla" T_Z80_RLC "rlc" T_Z80_RLCA "rlca" -%token T_Z80_RR "rr" T_Z80_RRA "rra" T_Z80_RRC "rrc" T_Z80_RRCA "rrca" -%token T_Z80_SBC "sbc" T_Z80_SCF "scf" T_Z80_SET "set" T_Z80_STOP "stop" -%token T_Z80_SLA "sla" T_Z80_SRA "sra" T_Z80_SRL "srl" T_Z80_SUB "sub" -%token T_Z80_SWAP "swap" -%token T_Z80_XOR "xor" +%token T_Z80_ADC "adc" T_Z80_ADD "add" T_Z80_AND "and" +%token T_Z80_BIT "bit" +%token T_Z80_CALL "call" T_Z80_CCF "ccf" T_Z80_CP "cp" T_Z80_CPL "cpl" +%token T_Z80_DAA "daa" T_Z80_DEC "dec" T_Z80_DI "di" +%token T_Z80_EI "ei" +%token T_Z80_HALT "halt" +%token T_Z80_INC "inc" +%token T_Z80_JP "jp" T_Z80_JR "jr" +%token T_Z80_LD "ld" +%token T_Z80_LDI "ldi" +%token T_Z80_LDD "ldd" +%token T_Z80_LDH "ldh" +%token T_Z80_NOP "nop" +%token T_Z80_OR "or" +%token T_Z80_POP "pop" T_Z80_PUSH "push" +%token T_Z80_RES "res" T_Z80_RET "ret" T_Z80_RETI "reti" T_Z80_RST "rst" +%token T_Z80_RL "rl" T_Z80_RLA "rla" T_Z80_RLC "rlc" T_Z80_RLCA "rlca" +%token T_Z80_RR "rr" T_Z80_RRA "rra" T_Z80_RRC "rrc" T_Z80_RRCA "rrca" +%token T_Z80_SBC "sbc" T_Z80_SCF "scf" T_Z80_SET "set" T_Z80_STOP "stop" +%token T_Z80_SLA "sla" T_Z80_SRA "sra" T_Z80_SRL "srl" T_Z80_SUB "sub" +%token T_Z80_SWAP "swap" +%token T_Z80_XOR "xor" -%token T_TOKEN_A "a" -%token T_TOKEN_B "b" T_TOKEN_C "c" -%token T_TOKEN_D "d" T_TOKEN_E "e" -%token T_TOKEN_H "h" T_TOKEN_L "l" -%token T_MODE_AF "af" T_MODE_BC "bc" T_MODE_DE "de" T_MODE_SP "sp" -%token T_MODE_HL "hl" T_MODE_HL_DEC "hld/hl-" T_MODE_HL_INC "hli/hl+" -%token T_CC_NZ "nz" T_CC_Z "z" T_CC_NC "nc" // There is no T_CC_C, only T_TOKEN_C +%token T_TOKEN_A "a" +%token T_TOKEN_B "b" T_TOKEN_C "c" +%token T_TOKEN_D "d" T_TOKEN_E "e" +%token T_TOKEN_H "h" T_TOKEN_L "l" +%token T_MODE_AF "af" T_MODE_BC "bc" T_MODE_DE "de" T_MODE_SP "sp" +%token T_MODE_HL "hl" T_MODE_HL_DEC "hld/hl-" T_MODE_HL_INC "hli/hl+" +%token T_CC_NZ "nz" T_CC_Z "z" T_CC_NC "nc" // There is no T_CC_C, only T_TOKEN_C -%type reg_r -%type reg_ss -%type reg_rr -%type reg_tt -%type ccode_expr -%type ccode -%type op_a_n -%type op_a_r -%type op_mem_ind -%type assert_type +%type reg_r +%type reg_ss +%type reg_rr +%type reg_tt +%type ccode_expr +%type ccode +%type op_a_n +%type op_a_r +%type op_mem_ind +%type assert_type %token T_EOB "end of buffer" %token T_EOF 0 "end of file" @@ -335,1653 +323,2133 @@ %% -asmfile : lines +// Assembly files. + +asmfile: lines ; -lines : %empty - | lines opt_diff_mark line +lines: + %empty + | lines opt_diff_mark line ; -endofline : T_NEWLINE | T_EOB +endofline: T_NEWLINE | T_EOB ; -opt_diff_mark : %empty // OK - | T_OP_ADD { - error("syntax error, unexpected + at the beginning of the line (is it a leftover diff mark?)\n"); - } - | T_OP_SUB { - error("syntax error, unexpected - at the beginning of the line (is it a leftover diff mark?)\n"); - } +opt_diff_mark: + %empty // OK + | T_OP_ADD { + error( + "syntax error, unexpected + at the beginning of the line (is it a leftover diff mark?)\n" + ); + } + | T_OP_SUB { + error( + "syntax error, unexpected - at the beginning of the line (is it a leftover diff mark?)\n" + ); + } ; -line : plain_directive endofline - | line_directive // Directives that manage newlines themselves - // Continue parsing the next line on a syntax error - | error { - lexer_SetMode(LEXER_NORMAL); - lexer_ToggleStringExpansion(true); - } endofline { - fstk_StopRept(); - yyerrok; - } - // Hint about unindented macros parsed as labels - | T_LABEL error { - lexer_SetMode(LEXER_NORMAL); - lexer_ToggleStringExpansion(true); - } endofline { - Symbol *macro = sym_FindExactSymbol($1); +// Lines and line directives. - if (macro && macro->type == SYM_MACRO) - fprintf(stderr, - " To invoke `%s` as a macro it must be indented\n", $1); - fstk_StopRept(); - yyerrok; - } +line: + plain_directive endofline + | line_directive // Directives that manage newlines themselves + // Continue parsing the next line on a syntax error + | error { + lexer_SetMode(LEXER_NORMAL); + lexer_ToggleStringExpansion(true); + } endofline { + fstk_StopRept(); + yyerrok; + } + // Hint about unindented macros parsed as labels + | T_LABEL error { + lexer_SetMode(LEXER_NORMAL); + lexer_ToggleStringExpansion(true); + } endofline { + Symbol *macro = sym_FindExactSymbol($1); + + if (macro && macro->type == SYM_MACRO) + fprintf( + stderr, + " To invoke `%s` as a macro it must be indented\n", + $1 + ); + fstk_StopRept(); + yyerrok; + } ; // For "logistical" reasons, these directives must manage newlines themselves. // This is because we need to switch the lexer's mode *after* the newline has been read, // and to avoid causing some grammar conflicts (token reducing is finicky). // This is DEFINITELY one of the more FRAGILE parts of the codebase, handle with care. -line_directive : macrodef - | rept - | for - | break - | include - | if - // It's important that all of these require being at line start for `skipIfBlock` - | elif - | else +line_directive: + macrodef + | rept + | for + | break + | include + | if + // It's important that all of these require being at line start for `skipIfBlock` + | elif + | else ; -if : T_POP_IF const T_NEWLINE { - lexer_IncIFDepth(); +if: + T_POP_IF const T_NEWLINE { + lexer_IncIFDepth(); - if ($2) - lexer_RunIFBlock(); - else - lexer_SetMode(LEXER_SKIP_TO_ELIF); + if ($2) + lexer_RunIFBlock(); + else + lexer_SetMode(LEXER_SKIP_TO_ELIF); + } +; + +elif: + T_POP_ELIF const T_NEWLINE { + if (lexer_GetIFDepth() == 0) + fatalerror("Found ELIF outside an IF construct\n"); + + if (lexer_RanIFBlock()) { + if (lexer_ReachedELSEBlock()) + fatalerror("Found ELIF after an ELSE block\n"); + + lexer_SetMode(LEXER_SKIP_TO_ENDC); + } else if ($2) { + lexer_RunIFBlock(); + } else { + lexer_SetMode(LEXER_SKIP_TO_ELIF); } + } ; -elif : T_POP_ELIF const T_NEWLINE { - if (lexer_GetIFDepth() == 0) - fatalerror("Found ELIF outside an IF construct\n"); +else: + T_POP_ELSE T_NEWLINE { + if (lexer_GetIFDepth() == 0) + fatalerror("Found ELSE outside an IF construct\n"); - if (lexer_RanIFBlock()) { - if (lexer_ReachedELSEBlock()) - fatalerror("Found ELIF after an ELSE block\n"); + if (lexer_RanIFBlock()) { + if (lexer_ReachedELSEBlock()) + fatalerror("Found ELSE after an ELSE block\n"); - lexer_SetMode(LEXER_SKIP_TO_ENDC); - } else if ($2) { - lexer_RunIFBlock(); - } else { - lexer_SetMode(LEXER_SKIP_TO_ELIF); - } + lexer_SetMode(LEXER_SKIP_TO_ENDC); + } else { + lexer_RunIFBlock(); + lexer_ReachELSEBlock(); } + } ; -else : T_POP_ELSE T_NEWLINE { - if (lexer_GetIFDepth() == 0) - fatalerror("Found ELSE outside an IF construct\n"); +// Directives, labels, functions, and values. - if (lexer_RanIFBlock()) { - if (lexer_ReachedELSEBlock()) - fatalerror("Found ELSE after an ELSE block\n"); - - lexer_SetMode(LEXER_SKIP_TO_ENDC); - } else { - lexer_RunIFBlock(); - lexer_ReachELSEBlock(); - } - } +plain_directive: + label + | label cpu_commands + | label macro + | label directive + | assignment_directive ; -plain_directive : label - | label cpu_commands - | label macro - | label directive - | assignment_directive +endc: + T_POP_ENDC { + lexer_DecIFDepth(); + } ; -endc : T_POP_ENDC { - lexer_DecIFDepth(); - } +def_id: + T_OP_DEF { + lexer_ToggleStringExpansion(false); + } T_ID { + lexer_ToggleStringExpansion(true); + strcpy($$, $3); + } ; -def_id : T_OP_DEF { - lexer_ToggleStringExpansion(false); - } T_ID { - lexer_ToggleStringExpansion(true); - strcpy($$, $3); - } -; - -redef_id : T_POP_REDEF { - lexer_ToggleStringExpansion(false); - } T_ID { - lexer_ToggleStringExpansion(true); - strcpy($$, $3); - } +redef_id: + T_POP_REDEF { + lexer_ToggleStringExpansion(false); + } T_ID { + lexer_ToggleStringExpansion(true); + strcpy($$, $3); + } ; // T_LABEL covers identifiers followed by a double colon (e.g. `call Function::ret`, // to be read as `call Function :: ret`). This should not conflict with anything. -scoped_id : T_ID | T_LOCAL_ID | T_LABEL; -scoped_anon_id : scoped_id | T_ANON; +scoped_id: T_ID | T_LOCAL_ID | T_LABEL; +scoped_anon_id: scoped_id | T_ANON; -label : %empty - | T_COLON { - sym_AddAnonLabel(); - } - | T_LOCAL_ID { - sym_AddLocalLabel($1); - } - | T_LOCAL_ID T_COLON { - sym_AddLocalLabel($1); - } - | T_LABEL T_COLON { - sym_AddLabel($1); - } - | T_LOCAL_ID T_DOUBLE_COLON { - sym_AddLocalLabel($1); - sym_Export($1); - } - | T_LABEL T_DOUBLE_COLON { - sym_AddLabel($1); - sym_Export($1); - } +label: + %empty + | T_COLON { + sym_AddAnonLabel(); + } + | T_LOCAL_ID { + sym_AddLocalLabel($1); + } + | T_LOCAL_ID T_COLON { + sym_AddLocalLabel($1); + } + | T_LABEL T_COLON { + sym_AddLabel($1); + } + | T_LOCAL_ID T_DOUBLE_COLON { + sym_AddLocalLabel($1); + sym_Export($1); + } + | T_LABEL T_DOUBLE_COLON { + sym_AddLabel($1); + sym_Export($1); + } ; -macro : T_ID { - // Parsing 'macroargs' will restore the lexer's normal mode - lexer_SetMode(LEXER_RAW); - } macroargs { - fstk_RunMacro($1, *$3); - } +macro: + T_ID { + // Parsing 'macroargs' will restore the lexer's normal mode + lexer_SetMode(LEXER_RAW); + } macroargs { + fstk_RunMacro($1, *$3); + } ; -macroargs : %empty { - $$ = new(std::nothrow) MacroArgs(); - if (!$$) - fatalerror("Failed to allocate memory for macro arguments: %s\n", - strerror(errno)); - } - | macroargs T_STRING { - $$->append($2); - } +macroargs: + %empty { + $$ = new(std::nothrow) MacroArgs(); + if (!$$) + fatalerror("Failed to allocate memory for macro arguments: %s\n", strerror(errno)); + } + | macroargs T_STRING { + $$->append($2); + } ; // These commands start with a T_LABEL. -assignment_directive : equ - | assignment - | rb - | rw - | rl - | equs -; - -directive : endc - | print - | println - | export - | db - | dw - | dl - | ds - | section - | rsreset - | rsset - | union - | nextu - | endu - | incbin - | charmap - | newcharmap - | setcharmap - | pushc - | popc - | load - | shift - | fail - | warn - | assert - | def_equ - | redef_equ - | def_set - | def_rb - | def_rw - | def_rl - | def_equs - | redef_equs - | purge - | pops - | pushs - | endsection - | popo - | pusho - | opt - | align -; - -trailing_comma : %empty | T_COMMA -; - -compoundeq : T_POP_ADDEQ { $$ = RPN_ADD; } - | T_POP_SUBEQ { $$ = RPN_SUB; } - | T_POP_MULEQ { $$ = RPN_MUL; } - | T_POP_DIVEQ { $$ = RPN_DIV; } - | T_POP_MODEQ { $$ = RPN_MOD; } - | T_POP_XOREQ { $$ = RPN_XOR; } - | T_POP_OREQ { $$ = RPN_OR; } - | T_POP_ANDEQ { $$ = RPN_AND; } - | T_POP_SHLEQ { $$ = RPN_SHL; } - | T_POP_SHREQ { $$ = RPN_SHR; } -; - -equ : T_LABEL T_POP_EQU const { - warning(WARNING_OBSOLETE, "`%s EQU` is deprecated; use `DEF %s EQU`\n", $1, $1); - sym_AddEqu($1, $3); - } -; - -assignment : T_LABEL T_POP_EQUAL const { - warning(WARNING_OBSOLETE, "`%s =` is deprecated; use `DEF %s =`\n", $1, $1); - sym_AddVar($1, $3); - } - | T_LABEL compoundeq const { - const char *compoundEqOperator = nullptr; - switch ($2) { - case RPN_ADD: compoundEqOperator = "+="; break; - case RPN_SUB: compoundEqOperator = "-="; break; - case RPN_MUL: compoundEqOperator = "*="; break; - case RPN_DIV: compoundEqOperator = "/="; break; - case RPN_MOD: compoundEqOperator = "%="; break; - case RPN_XOR: compoundEqOperator = "^="; break; - case RPN_OR: compoundEqOperator = "|="; break; - case RPN_AND: compoundEqOperator = "&="; break; - case RPN_SHL: compoundEqOperator = "<<="; break; - case RPN_SHR: compoundEqOperator = ">>="; break; - default: break; - } - - warning(WARNING_OBSOLETE, "`%s %s` is deprecated; use `DEF %s %s`\n", - $1, compoundEqOperator, $1, compoundEqOperator); - compoundAssignment($1, $2, $3); - } -; - -equs : T_LABEL T_POP_EQUS string { - warning(WARNING_OBSOLETE, "`%s EQUS` is deprecated; use `DEF %s EQUS`\n", $1, $1); - sym_AddString($1, $3); - } -; - -rb : T_LABEL T_POP_RB rs_uconst { - warning(WARNING_OBSOLETE, "`%s RB` is deprecated; use `DEF %s RB`\n", $1, $1); - sym_AddEqu($1, sym_GetConstantValue("_RS")); - sym_AddVar("_RS", sym_GetConstantValue("_RS") + $3); - } -; - -rw : T_LABEL T_POP_RW rs_uconst { - warning(WARNING_OBSOLETE, "`%s RW` is deprecated; use `DEF %s RW`\n", $1, $1); - sym_AddEqu($1, sym_GetConstantValue("_RS")); - sym_AddVar("_RS", sym_GetConstantValue("_RS") + 2 * $3); - } -; - -rl : T_LABEL T_Z80_RL rs_uconst { - warning(WARNING_OBSOLETE, "`%s RL` is deprecated; use `DEF %s RL`\n", $1, $1); - sym_AddEqu($1, sym_GetConstantValue("_RS")); - sym_AddVar("_RS", sym_GetConstantValue("_RS") + 4 * $3); - } -; - -align : T_OP_ALIGN align_spec { sect_AlignPC($2.alignment, $2.alignOfs); } -; - -align_spec : uconst { - if ($1 > 16) { - error("Alignment must be between 0 and 16, not %u\n", $1); - $$.alignment = $$.alignOfs = 0; - } else { - $$.alignment = $1; - $$.alignOfs = 0; - } - } - | uconst T_COMMA const { - if ($1 > 16) { - error("Alignment must be between 0 and 16, not %u\n", $1); - $$.alignment = $$.alignOfs = 0; - } else if ($3 <= -(1 << $1) || $3 >= 1 << $1) { - error("The absolute alignment offset (%" PRIu32 - ") must be less than alignment size (%d)\n", - (uint32_t)($3 < 0 ? -$3 : $3), 1 << $1); - $$.alignment = $$.alignOfs = 0; - } else { - $$.alignment = $1; - $$.alignOfs = $3 < 0 ? (1 << $1) + $3 : $3; - } - } -; - -opt : T_POP_OPT { - // Parsing 'opt_list' will restore the lexer's normal mode - lexer_SetMode(LEXER_RAW); - } opt_list -; - -opt_list : opt_list_entry - | opt_list opt_list_entry -; - -opt_list_entry : T_STRING { opt_Parse($1); } -; - -popo : T_POP_POPO { opt_Pop(); } -; - -pusho : T_POP_PUSHO { opt_Push(); } -; - -pops : T_POP_POPS { sect_PopSection(); } -; - -pushs : T_POP_PUSHS { sect_PushSection(); } -; - -endsection : T_POP_ENDSECTION { sect_EndSection(); } -; - -fail : T_POP_FAIL string { fatalerror("%s\n", $2); } -; - -warn : T_POP_WARN string { warning(WARNING_USER, "%s\n", $2); } -; - -assert_type : %empty { $$ = ASSERT_ERROR; } - | T_POP_WARN T_COMMA { $$ = ASSERT_WARN; } - | T_POP_FAIL T_COMMA { $$ = ASSERT_ERROR; } - | T_POP_FATAL T_COMMA { $$ = ASSERT_FATAL; } -; - -assert : T_POP_ASSERT assert_type relocexpr { - if (!$3.isKnown) { - out_CreateAssert($2, $3, "", sect_GetOutputOffset()); - } else if ($3.val == 0) { - failAssert($2); - } - rpn_Free($3); - } - | T_POP_ASSERT assert_type relocexpr T_COMMA string { - if (!$3.isKnown) { - out_CreateAssert($2, $3, $5, sect_GetOutputOffset()); - } else if ($3.val == 0) { - failAssertMsg($2, $5); - } - rpn_Free($3); - } - | T_POP_STATIC_ASSERT assert_type const { - if ($3 == 0) - failAssert($2); - } - | T_POP_STATIC_ASSERT assert_type const T_COMMA string { - if ($3 == 0) - failAssertMsg($2, $5); - } -; - -shift : T_POP_SHIFT { macro_ShiftCurrentArgs(1); } - | T_POP_SHIFT const { macro_ShiftCurrentArgs($2); } -; - -load : T_POP_LOAD sectmod string T_COMMA sectiontype sectorg sectattrs { - sect_SetLoadSection($3, (enum SectionType)$5, $6, $7, $2); - } - | T_POP_ENDL { sect_EndLoadSection(); } -; - -rept : T_POP_REPT uconst T_NEWLINE { - $$ = lexer_CaptureRept(captureBody); - } endofline { - if ($4) - fstk_RunRept($2, captureBody.lineNo, captureBody.body, - captureBody.size); - } -; - -for : T_POP_FOR { - lexer_ToggleStringExpansion(false); - } T_ID { - lexer_ToggleStringExpansion(true); - } T_COMMA for_args T_NEWLINE { - $$ = lexer_CaptureRept(captureBody); - } endofline { - if ($8) - fstk_RunFor($3, $6.start, $6.stop, $6.step, captureBody.lineNo, - captureBody.body, captureBody.size); - } - -for_args : const { - $$.start = 0; - $$.stop = $1; - $$.step = 1; - } - | const T_COMMA const { - $$.start = $1; - $$.stop = $3; - $$.step = 1; - } - | const T_COMMA const T_COMMA const { - $$.start = $1; - $$.stop = $3; - $$.step = $5; - } -; - -break : label T_POP_BREAK endofline { - if (fstk_Break()) - lexer_SetMode(LEXER_SKIP_TO_ENDR); - } -; - -macrodef : T_POP_MACRO { - lexer_ToggleStringExpansion(false); - } T_ID { - lexer_ToggleStringExpansion(true); - } T_NEWLINE { - $$ = lexer_CaptureMacroBody(captureBody); - } endofline { - if ($6) - sym_AddMacro($3, captureBody.lineNo, captureBody.body, - captureBody.size); - } -; - -rsset : T_POP_RSSET uconst { sym_AddVar("_RS", $2); } -; - -rsreset : T_POP_RSRESET { sym_AddVar("_RS", 0); } -; - -rs_uconst : %empty { $$ = 1; } - | uconst -; - -union : T_POP_UNION { sect_StartUnion(); } -; - -nextu : T_POP_NEXTU { sect_NextUnionMember(); } -; - -endu : T_POP_ENDU { sect_EndUnion(); } -; - -ds : T_POP_DS uconst { sect_Skip($2, true); } - | T_POP_DS uconst T_COMMA ds_args trailing_comma { - sect_RelBytes($2, *$4); - delete $4; - } - | T_POP_DS T_OP_ALIGN T_LBRACK align_spec T_RBRACK trailing_comma { - uint32_t n = sect_GetAlignBytes($4.alignment, $4.alignOfs); - - sect_Skip(n, true); - sect_AlignPC($4.alignment, $4.alignOfs); - } - | T_POP_DS T_OP_ALIGN T_LBRACK align_spec T_RBRACK T_COMMA ds_args trailing_comma { - uint32_t n = sect_GetAlignBytes($4.alignment, $4.alignOfs); - - sect_RelBytes(n, *$7); - sect_AlignPC($4.alignment, $4.alignOfs); - delete $7; - } -; - -ds_args : reloc_8bit { - initDsArgList($$); - $$->push_back($1); - } - | ds_args T_COMMA reloc_8bit { - $1->push_back($3); - $$ = $1; - } -; - -db : T_POP_DB { sect_Skip(1, false); } - | T_POP_DB constlist_8bit trailing_comma -; - -dw : T_POP_DW { sect_Skip(2, false); } - | T_POP_DW constlist_16bit trailing_comma -; - -dl : T_POP_DL { sect_Skip(4, false); } - | T_POP_DL constlist_32bit trailing_comma -; - -def_equ : def_id T_POP_EQU const { sym_AddEqu($1, $3); } -; - -redef_equ : redef_id T_POP_EQU const { sym_RedefEqu($1, $3); } -; - -def_set : def_id T_POP_EQUAL const { sym_AddVar($1, $3); } - | redef_id T_POP_EQUAL const { sym_AddVar($1, $3); } - | def_id compoundeq const { compoundAssignment($1, $2, $3); } - | redef_id compoundeq const { compoundAssignment($1, $2, $3); } -; - -def_rb : def_id T_POP_RB rs_uconst { - sym_AddEqu($1, sym_GetConstantValue("_RS")); - sym_AddVar("_RS", sym_GetConstantValue("_RS") + $3); - } -; - -def_rw : def_id T_POP_RW rs_uconst { - sym_AddEqu($1, sym_GetConstantValue("_RS")); - sym_AddVar("_RS", sym_GetConstantValue("_RS") + 2 * $3); - } -; - -def_rl : def_id T_Z80_RL rs_uconst { - sym_AddEqu($1, sym_GetConstantValue("_RS")); - sym_AddVar("_RS", sym_GetConstantValue("_RS") + 4 * $3); - } -; - -def_equs : def_id T_POP_EQUS string { sym_AddString($1, $3); } -; - -redef_equs : redef_id T_POP_EQUS string { sym_RedefString($1, $3); } -; - -purge : T_POP_PURGE { - lexer_ToggleStringExpansion(false); - } purge_args trailing_comma { - for (std::string &arg : *$3) - sym_Purge(arg); - delete $3; - lexer_ToggleStringExpansion(true); - } -; - -purge_args : scoped_id { - initPurgeArgList($$); - $$->push_back($1); - } - | purge_args T_COMMA scoped_id { - $1->push_back($3); - $$ = $1; - } -; - -export : T_POP_EXPORT export_list trailing_comma -; - -export_list : export_list_entry - | export_list T_COMMA export_list_entry -; - -export_list_entry : scoped_id { sym_Export($1); } -; - -include : label T_POP_INCLUDE string endofline { - fstk_RunInclude($3); - if (failedOnMissingInclude) - YYACCEPT; - } -; - -incbin : T_POP_INCBIN string { - sect_BinaryFile($2, 0); - if (failedOnMissingInclude) - YYACCEPT; - } - | T_POP_INCBIN string T_COMMA const { - sect_BinaryFile($2, $4); - if (failedOnMissingInclude) - YYACCEPT; - } - | T_POP_INCBIN string T_COMMA const T_COMMA const { - sect_BinaryFileSlice($2, $4, $6); - if (failedOnMissingInclude) - YYACCEPT; - } -; - -charmap : T_POP_CHARMAP string T_COMMA const_8bit { - charmap_Add($2, (uint8_t)$4); - } -; - -newcharmap : T_POP_NEWCHARMAP T_ID { charmap_New($2, nullptr); } - | T_POP_NEWCHARMAP T_ID T_COMMA T_ID { charmap_New($2, $4); } -; - -setcharmap : T_POP_SETCHARMAP T_ID { charmap_Set($2); } -; - -pushc : T_POP_PUSHC { charmap_Push(); } -; - -popc : T_POP_POPC { charmap_Pop(); } -; - -print : T_POP_PRINT print_exprs trailing_comma -; - -println : T_POP_PRINTLN { - putchar('\n'); - fflush(stdout); - } - | T_POP_PRINTLN print_exprs trailing_comma { - putchar('\n'); - fflush(stdout); - } -; - -print_exprs : print_expr - | print_exprs T_COMMA print_expr -; - -print_expr : const_no_str { printf("$%" PRIX32, $1); } - | string { printf("%s", $1); } -; - -const_3bit : const { - int32_t value = $1; - - if ((value < 0) || (value > 7)) { - error("Immediate value must be 3-bit\n"); - $$ = 0; - } else { - $$ = value & 0x7; - } - } -; - -constlist_8bit : constlist_8bit_entry - | constlist_8bit T_COMMA constlist_8bit_entry -; - -constlist_8bit_entry : reloc_8bit_no_str { - sect_RelByte($1, 0); - } - | string { - std::vector output; - - charmap_Convert($1, output); - sect_AbsByteGroup(output.data(), output.size()); - } -; - -constlist_16bit : constlist_16bit_entry - | constlist_16bit T_COMMA constlist_16bit_entry -; - -constlist_16bit_entry : reloc_16bit_no_str { - sect_RelWord($1, 0); - } - | string { - std::vector output; - - charmap_Convert($1, output); - sect_AbsWordGroup(output.data(), output.size()); - } -; - -constlist_32bit : constlist_32bit_entry - | constlist_32bit T_COMMA constlist_32bit_entry -; - -constlist_32bit_entry : relocexpr_no_str { - sect_RelLong($1, 0); - } - | string { - std::vector output; - - charmap_Convert($1, output); - sect_AbsLongGroup(output.data(), output.size()); - } -; - -reloc_8bit : relocexpr { - rpn_CheckNBit($1, 8); - $$ = $1; - } -; - -reloc_8bit_no_str : relocexpr_no_str { - rpn_CheckNBit($1, 8); - $$ = $1; - } -; - -reloc_8bit_offset : T_OP_ADD relocexpr { - rpn_CheckNBit($2, 8); - $$ = $2; - } - | T_OP_SUB relocexpr { - rpn_NEG($$, $2); - rpn_CheckNBit($$, 8); - } -; - -reloc_16bit : relocexpr { - rpn_CheckNBit($1, 16); - $$ = $1; - } -; - -reloc_16bit_no_str : relocexpr_no_str { - rpn_CheckNBit($1, 16); - $$ = $1; - } -; - - -relocexpr : relocexpr_no_str - | string { - std::vector output; - - charmap_Convert($1, output); - rpn_Number($$, str2int2(output)); - } -; - -relocexpr_no_str : scoped_anon_id { rpn_Symbol($$, $1); } - | T_NUMBER { rpn_Number($$, $1); } - | T_OP_LOGICNOT relocexpr %prec NEG { - rpn_LOGNOT($$, $2); - } - | relocexpr T_OP_LOGICOR relocexpr { - rpn_BinaryOp(RPN_LOGOR, $$, $1, $3); - } - | relocexpr T_OP_LOGICAND relocexpr { - rpn_BinaryOp(RPN_LOGAND, $$, $1, $3); - } - | relocexpr T_OP_LOGICEQU relocexpr { - rpn_BinaryOp(RPN_LOGEQ, $$, $1, $3); - } - | relocexpr T_OP_LOGICGT relocexpr { - rpn_BinaryOp(RPN_LOGGT, $$, $1, $3); - } - | relocexpr T_OP_LOGICLT relocexpr { - rpn_BinaryOp(RPN_LOGLT, $$, $1, $3); - } - | relocexpr T_OP_LOGICGE relocexpr { - rpn_BinaryOp(RPN_LOGGE, $$, $1, $3); - } - | relocexpr T_OP_LOGICLE relocexpr { - rpn_BinaryOp(RPN_LOGLE, $$, $1, $3); - } - | relocexpr T_OP_LOGICNE relocexpr { - rpn_BinaryOp(RPN_LOGNE, $$, $1, $3); - } - | relocexpr T_OP_ADD relocexpr { - rpn_BinaryOp(RPN_ADD, $$, $1, $3); - } - | relocexpr T_OP_SUB relocexpr { - rpn_BinaryOp(RPN_SUB, $$, $1, $3); - } - | relocexpr T_OP_XOR relocexpr { - rpn_BinaryOp(RPN_XOR, $$, $1, $3); - } - | relocexpr T_OP_OR relocexpr { - rpn_BinaryOp(RPN_OR, $$, $1, $3); - } - | relocexpr T_OP_AND relocexpr { - rpn_BinaryOp(RPN_AND, $$, $1, $3); - } - | relocexpr T_OP_SHL relocexpr { - rpn_BinaryOp(RPN_SHL, $$, $1, $3); - } - | relocexpr T_OP_SHR relocexpr { - rpn_BinaryOp(RPN_SHR, $$, $1, $3); - } - | relocexpr T_OP_USHR relocexpr { - rpn_BinaryOp(RPN_USHR, $$, $1, $3); - } - | relocexpr T_OP_MUL relocexpr { - rpn_BinaryOp(RPN_MUL, $$, $1, $3); - } - | relocexpr T_OP_DIV relocexpr { - rpn_BinaryOp(RPN_DIV, $$, $1, $3); - } - | relocexpr T_OP_MOD relocexpr { - rpn_BinaryOp(RPN_MOD, $$, $1, $3); - } - | relocexpr T_OP_EXP relocexpr { - rpn_BinaryOp(RPN_EXP, $$, $1, $3); - } - | T_OP_ADD relocexpr %prec NEG { $$ = $2; } - | T_OP_SUB relocexpr %prec NEG { rpn_NEG($$, $2); } - | T_OP_NOT relocexpr %prec NEG { rpn_NOT($$, $2); } - | T_OP_HIGH T_LPAREN relocexpr T_RPAREN { rpn_HIGH($$, $3); } - | T_OP_LOW T_LPAREN relocexpr T_RPAREN { rpn_LOW($$, $3); } - | T_OP_ISCONST T_LPAREN relocexpr T_RPAREN { rpn_ISCONST($$, $3); } - | T_OP_BANK T_LPAREN scoped_anon_id T_RPAREN { - // '@' is also a T_ID; it is handled here - rpn_BankSymbol($$, $3); - } - | T_OP_BANK T_LPAREN string T_RPAREN { rpn_BankSection($$, $3); } - | T_OP_SIZEOF T_LPAREN string T_RPAREN { rpn_SizeOfSection($$, $3); } - | T_OP_STARTOF T_LPAREN string T_RPAREN { rpn_StartOfSection($$, $3); } - | T_OP_SIZEOF T_LPAREN sectiontype T_RPAREN { - rpn_SizeOfSectionType($$, (enum SectionType)$3); - } - | T_OP_STARTOF T_LPAREN sectiontype T_RPAREN { - rpn_StartOfSectionType($$, (enum SectionType)$3); - } - | T_OP_DEF { - lexer_ToggleStringExpansion(false); - } T_LPAREN scoped_anon_id T_RPAREN { - rpn_Number($$, sym_FindScopedValidSymbol($4) != nullptr); - - lexer_ToggleStringExpansion(true); - } - | T_OP_ROUND T_LPAREN const opt_q_arg T_RPAREN { - rpn_Number($$, fix_Round($3, $4)); - } - | T_OP_CEIL T_LPAREN const opt_q_arg T_RPAREN { - rpn_Number($$, fix_Ceil($3, $4)); - } - | T_OP_FLOOR T_LPAREN const opt_q_arg T_RPAREN { - rpn_Number($$, fix_Floor($3, $4)); - } - | T_OP_FDIV T_LPAREN const T_COMMA const opt_q_arg T_RPAREN { - rpn_Number($$, fix_Div($3, $5, $6)); - } - | T_OP_FMUL T_LPAREN const T_COMMA const opt_q_arg T_RPAREN { - rpn_Number($$, fix_Mul($3, $5, $6)); - } - | T_OP_FMOD T_LPAREN const T_COMMA const opt_q_arg T_RPAREN { - rpn_Number($$, fix_Mod($3, $5, $6)); - } - | T_OP_POW T_LPAREN const T_COMMA const opt_q_arg T_RPAREN { - rpn_Number($$, fix_Pow($3, $5, $6)); - } - | T_OP_LOG T_LPAREN const T_COMMA const opt_q_arg T_RPAREN { - rpn_Number($$, fix_Log($3, $5, $6)); - } - | T_OP_SIN T_LPAREN const opt_q_arg T_RPAREN { - rpn_Number($$, fix_Sin($3, $4)); - } - | T_OP_COS T_LPAREN const opt_q_arg T_RPAREN { - rpn_Number($$, fix_Cos($3, $4)); - } - | T_OP_TAN T_LPAREN const opt_q_arg T_RPAREN { - rpn_Number($$, fix_Tan($3, $4)); - } - | T_OP_ASIN T_LPAREN const opt_q_arg T_RPAREN { - rpn_Number($$, fix_ASin($3, $4)); - } - | T_OP_ACOS T_LPAREN const opt_q_arg T_RPAREN { - rpn_Number($$, fix_ACos($3, $4)); - } - | T_OP_ATAN T_LPAREN const opt_q_arg T_RPAREN { - rpn_Number($$, fix_ATan($3, $4)); - } - | T_OP_ATAN2 T_LPAREN const T_COMMA const opt_q_arg T_RPAREN { - rpn_Number($$, fix_ATan2($3, $5, $6)); - } - | T_OP_STRCMP T_LPAREN string T_COMMA string T_RPAREN { - rpn_Number($$, strcmp($3, $5)); - } - | T_OP_STRIN T_LPAREN string T_COMMA string T_RPAREN { - char const *p = strstr($3, $5); - - rpn_Number($$, p ? p - $3 + 1 : 0); - } - | T_OP_STRRIN T_LPAREN string T_COMMA string T_RPAREN { - char const *p = strrstr($3, $5); - - rpn_Number($$, p ? p - $3 + 1 : 0); - } - | T_OP_STRLEN T_LPAREN string T_RPAREN { - rpn_Number($$, strlenUTF8($3)); - } - | T_OP_CHARLEN T_LPAREN string T_RPAREN { - rpn_Number($$, charlenUTF8($3)); - } - | T_OP_INCHARMAP T_LPAREN string T_RPAREN { - rpn_Number($$, charmap_HasChar($3)); - } - | T_LPAREN relocexpr T_RPAREN { $$ = $2; } -; - -uconst : const { - if ($1 < 0) - fatalerror("Constant must not be negative: %d\n", $1); - $$ = $1; - } -; - -const : relocexpr { $$ = $1.getConstVal(); } -; - -const_no_str : relocexpr_no_str { $$ = $1.getConstVal(); } -; - -const_8bit : reloc_8bit { $$ = $1.getConstVal(); } -; - -opt_q_arg : %empty { $$ = fix_Precision(); } - | T_COMMA const { - if ($2 >= 1 && $2 <= 31) { - $$ = $2; - } else { - error("Fixed-point precision must be between 1 and 31\n"); - $$ = fix_Precision(); - } - } -; - -string : T_STRING - | T_OP_STRSUB T_LPAREN string T_COMMA const T_COMMA uconst T_RPAREN { - size_t len = strlenUTF8($3); - uint32_t pos = adjustNegativePos($5, len, "STRSUB"); - - strsubUTF8($$, sizeof($$), $3, pos, $7); - } - | T_OP_STRSUB T_LPAREN string T_COMMA const T_RPAREN { - size_t len = strlenUTF8($3); - uint32_t pos = adjustNegativePos($5, len, "STRSUB"); - - strsubUTF8($$, sizeof($$), $3, pos, pos > len ? 0 : len + 1 - pos); - } - | T_OP_CHARSUB T_LPAREN string T_COMMA const T_RPAREN { - size_t len = charlenUTF8($3); - uint32_t pos = adjustNegativePos($5, len, "CHARSUB"); - - charsubUTF8($$, $3, pos); - } - | T_OP_STRCAT T_LPAREN T_RPAREN { - $$[0] = '\0'; - } - | T_OP_STRCAT T_LPAREN strcat_args T_RPAREN { - strcpy($$, $3); - } - | T_OP_STRUPR T_LPAREN string T_RPAREN { - upperstring($$, $3); - } - | T_OP_STRLWR T_LPAREN string T_RPAREN { - lowerstring($$, $3); - } - | T_OP_STRRPL T_LPAREN string T_COMMA string T_COMMA string T_RPAREN { - strrpl($$, sizeof($$), $3, $5, $7); - } - | T_OP_STRFMT T_LPAREN strfmt_args T_RPAREN { - strfmt($$, sizeof($$), $3.format->c_str(), *$3.args); - freeStrFmtArgList($3); - } - | T_POP_SECTION T_LPAREN scoped_anon_id T_RPAREN { - Symbol *sym = sym_FindScopedValidSymbol($3); - - if (!sym) - fatalerror("Unknown symbol \"%s\"\n", $3); - Section const *section = sym->getSection(); - - if (!section) - fatalerror("\"%s\" does not belong to any section\n", sym->name); - // Section names are capped by rgbasm's maximum string length, - // so this currently can't overflow. - strcpy($$, section->name.c_str()); - } -; - -strcat_args : string - | strcat_args T_COMMA string { - int ret = snprintf($$, sizeof($$), "%s%s", $1, $3); - - if (ret == -1) - fatalerror("snprintf error in STRCAT: %s\n", strerror(errno)); - else if ((unsigned int)ret >= sizeof($$)) - warning(WARNING_LONG_STR, "STRCAT: String too long '%s%s'\n", - $1, $3); - } -; - -strfmt_args : string strfmt_va_args { - $$ = $2; - *$$.format = $1; - } -; - -strfmt_va_args : %empty { - initStrFmtArgList($$); - } - | strfmt_va_args T_COMMA const_no_str { - $1.args->push_back((uint32_t)$3); - $$ = $1; - } - | strfmt_va_args T_COMMA string { - $1.args->push_back($3); - $$ = $1; - } -; - -section : T_POP_SECTION sectmod string T_COMMA sectiontype sectorg sectattrs { - sect_NewSection($3, (enum SectionType)$5, $6, $7, $2); - } -; - -sectmod : %empty { $$ = SECTION_NORMAL; } - | T_POP_UNION { $$ = SECTION_UNION; } - | T_POP_FRAGMENT { $$ = SECTION_FRAGMENT; } -; - -sectiontype : T_SECT_WRAM0 { $$ = SECTTYPE_WRAM0; } - | T_SECT_VRAM { $$ = SECTTYPE_VRAM; } - | T_SECT_ROMX { $$ = SECTTYPE_ROMX; } - | T_SECT_ROM0 { $$ = SECTTYPE_ROM0; } - | T_SECT_HRAM { $$ = SECTTYPE_HRAM; } - | T_SECT_WRAMX { $$ = SECTTYPE_WRAMX; } - | T_SECT_SRAM { $$ = SECTTYPE_SRAM; } - | T_SECT_OAM { $$ = SECTTYPE_OAM; } -; - -sectorg : %empty { $$ = -1; } - | T_LBRACK uconst T_RBRACK { - if ($2 < 0 || $2 >= 0x10000) { - error("Address $%x is not 16-bit\n", $2); - $$ = -1; - } else { - $$ = $2; - } - } -; - -sectattrs : %empty { - $$.alignment = 0; +assignment_directive: equ | assignment | rb | rw | rl | equs; + +directive: + endc + | print + | println + | export + | db + | dw + | dl + | ds + | section + | rsreset + | rsset + | union + | nextu + | endu + | incbin + | charmap + | newcharmap + | setcharmap + | pushc + | popc + | load + | shift + | fail + | warn + | assert + | def_equ + | redef_equ + | def_set + | def_rb + | def_rw + | def_rl + | def_equs + | redef_equs + | purge + | pops + | pushs + | endsection + | popo + | pusho + | opt + | align +; + +trailing_comma: %empty | T_COMMA; + +compoundeq: + T_POP_ADDEQ { + $$ = RPN_ADD; + } + | T_POP_SUBEQ { + $$ = RPN_SUB; + } + | T_POP_MULEQ { + $$ = RPN_MUL; + } + | T_POP_DIVEQ { + $$ = RPN_DIV; + } + | T_POP_MODEQ { + $$ = RPN_MOD; + } + | T_POP_XOREQ { + $$ = RPN_XOR; + } + | T_POP_OREQ { + $$ = RPN_OR; + } + | T_POP_ANDEQ { + $$ = RPN_AND; + } + | T_POP_SHLEQ { + $$ = RPN_SHL; + } + | T_POP_SHREQ { + $$ = RPN_SHR; + } +; + +equ: + T_LABEL T_POP_EQU const { + warning(WARNING_OBSOLETE, "`%s EQU` is deprecated; use `DEF %s EQU`\n", $1, $1); + sym_AddEqu($1, $3); + } +; + +assignment: + T_LABEL T_POP_EQUAL const { + warning(WARNING_OBSOLETE, "`%s =` is deprecated; use `DEF %s =`\n", $1, $1); + sym_AddVar($1, $3); + } + | T_LABEL compoundeq const { + const char *compoundEqOperator = nullptr; + switch ($2) { + case RPN_ADD: compoundEqOperator = "+="; break; + case RPN_SUB: compoundEqOperator = "-="; break; + case RPN_MUL: compoundEqOperator = "*="; break; + case RPN_DIV: compoundEqOperator = "/="; break; + case RPN_MOD: compoundEqOperator = "%="; break; + case RPN_XOR: compoundEqOperator = "^="; break; + case RPN_OR: compoundEqOperator = "|="; break; + case RPN_AND: compoundEqOperator = "&="; break; + case RPN_SHL: compoundEqOperator = "<<="; break; + case RPN_SHR: compoundEqOperator = ">>="; break; + default: break; + } + + warning( + WARNING_OBSOLETE, + "`%s %s` is deprecated; use `DEF %s %s`\n", + $1, + compoundEqOperator, + $1, + compoundEqOperator + ); + compoundAssignment($1, $2, $3); + } +; + +equs: + T_LABEL T_POP_EQUS string { + warning(WARNING_OBSOLETE, "`%s EQUS` is deprecated; use `DEF %s EQUS`\n", $1, $1); + sym_AddString($1, $3); + } +; + +rb: + T_LABEL T_POP_RB rs_uconst { + warning(WARNING_OBSOLETE, "`%s RB` is deprecated; use `DEF %s RB`\n", $1, $1); + sym_AddEqu($1, sym_GetConstantValue("_RS")); + sym_AddVar("_RS", sym_GetConstantValue("_RS") + $3); + } +; + +rw: + T_LABEL T_POP_RW rs_uconst { + warning(WARNING_OBSOLETE, "`%s RW` is deprecated; use `DEF %s RW`\n", $1, $1); + sym_AddEqu($1, sym_GetConstantValue("_RS")); + sym_AddVar("_RS", sym_GetConstantValue("_RS") + 2 * $3); + } +; + +rl: + T_LABEL T_Z80_RL rs_uconst { + warning(WARNING_OBSOLETE, "`%s RL` is deprecated; use `DEF %s RL`\n", $1, $1); + sym_AddEqu($1, sym_GetConstantValue("_RS")); + sym_AddVar("_RS", sym_GetConstantValue("_RS") + 4 * $3); + } +; + +align: + T_OP_ALIGN align_spec { + sect_AlignPC($2.alignment, $2.alignOfs); + } +; + +align_spec: + uconst { + if ($1 > 16) { + error("Alignment must be between 0 and 16, not %u\n", $1); + $$.alignment = $$.alignOfs = 0; + } else { + $$.alignment = $1; $$.alignOfs = 0; - $$.bank = -1; } - | sectattrs T_COMMA T_OP_ALIGN T_LBRACK align_spec T_RBRACK { - $$.alignment = $5.alignment; - $$.alignOfs = $5.alignOfs; + } + | uconst T_COMMA const { + if ($1 > 16) { + error("Alignment must be between 0 and 16, not %u\n", $1); + $$.alignment = $$.alignOfs = 0; + } else if ($3 <= -(1 << $1) || $3 >= 1 << $1) { + error( + "The absolute alignment offset (%" PRIu32 ") must be less than alignment size (%d)\n", + (uint32_t)($3 < 0 ? -$3 : $3), + 1 << $1 + ); + $$.alignment = $$.alignOfs = 0; + } else { + $$.alignment = $1; + $$.alignOfs = $3 < 0 ? (1 << $1) + $3 : $3; } - | sectattrs T_COMMA T_OP_BANK T_LBRACK uconst T_RBRACK { - // We cannot check the validity of this now - $$.bank = $5; + } +; + +opt: + T_POP_OPT { + // Parsing 'opt_list' will restore the lexer's normal mode + lexer_SetMode(LEXER_RAW); + } opt_list +; + +opt_list: + opt_list_entry + | opt_list opt_list_entry +; + +opt_list_entry: + T_STRING { + opt_Parse($1); + } +; + +popo: + T_POP_POPO { + opt_Pop(); + } +; + +pusho: + T_POP_PUSHO { + opt_Push(); + } +; + +pops: + T_POP_POPS { + sect_PopSection(); + } +; + +pushs: + T_POP_PUSHS { + sect_PushSection(); + } +; + +endsection: + T_POP_ENDSECTION { + sect_EndSection(); + } +; + +fail: + T_POP_FAIL string { + fatalerror("%s\n", $2); + } +; + +warn: + T_POP_WARN string { + warning(WARNING_USER, "%s\n", $2); + } +; + +assert_type: + %empty { + $$ = ASSERT_ERROR; + } + | T_POP_WARN T_COMMA { + $$ = ASSERT_WARN; + } + | T_POP_FAIL T_COMMA { + $$ = ASSERT_ERROR; + } + | T_POP_FATAL T_COMMA { + $$ = ASSERT_FATAL; + } +; + +assert: + T_POP_ASSERT assert_type relocexpr { + if (!$3.isKnown) { + out_CreateAssert($2, $3, "", sect_GetOutputOffset()); + } else if ($3.val == 0) { + failAssert($2); } -; - -cpu_commands : cpu_command - | cpu_command T_DOUBLE_COLON cpu_commands -; - -cpu_command : z80_adc - | z80_add - | z80_and - | z80_bit - | z80_call - | z80_ccf - | z80_cp - | z80_cpl - | z80_daa - | z80_dec - | z80_di - | z80_ei - | z80_halt - | z80_inc - | z80_jp - | z80_jr - | z80_ld - | z80_ldd - | z80_ldi - | z80_ldio - | z80_nop - | z80_or - | z80_pop - | z80_push - | z80_res - | z80_ret - | z80_reti - | z80_rl - | z80_rla - | z80_rlc - | z80_rlca - | z80_rr - | z80_rra - | z80_rrc - | z80_rrca - | z80_rst - | z80_sbc - | z80_scf - | z80_set - | z80_sla - | z80_sra - | z80_srl - | z80_stop - | z80_sub - | z80_swap - | z80_xor -; - -z80_adc : T_Z80_ADC op_a_n { - sect_AbsByte(0xCE); - sect_RelByte($2, 1); + rpn_Free($3); + } + | T_POP_ASSERT assert_type relocexpr T_COMMA string { + if (!$3.isKnown) { + out_CreateAssert($2, $3, $5, sect_GetOutputOffset()); + } else if ($3.val == 0) { + failAssertMsg($2, $5); } - | T_Z80_ADC op_a_r { sect_AbsByte(0x88 | $2); } + rpn_Free($3); + } + | T_POP_STATIC_ASSERT assert_type const { + if ($3 == 0) + failAssert($2); + } + | T_POP_STATIC_ASSERT assert_type const T_COMMA string { + if ($3 == 0) + failAssertMsg($2, $5); + } ; -z80_add : T_Z80_ADD op_a_n { - sect_AbsByte(0xC6); - sect_RelByte($2, 1); +shift: + T_POP_SHIFT { + macro_ShiftCurrentArgs(1); + } + | T_POP_SHIFT const { + macro_ShiftCurrentArgs($2); + } +; + +load: + T_POP_LOAD sectmod string T_COMMA sectiontype sectorg sectattrs { + sect_SetLoadSection($3, (enum SectionType)$5, $6, $7, $2); + } + | T_POP_ENDL { + sect_EndLoadSection(); + } +; + +rept: + T_POP_REPT uconst T_NEWLINE { + $$ = lexer_CaptureRept(captureBody); + } endofline { + if ($4) + fstk_RunRept($2, captureBody.lineNo, captureBody.body, captureBody.size); + } +; + +for: + T_POP_FOR { + lexer_ToggleStringExpansion(false); + } T_ID { + lexer_ToggleStringExpansion(true); + } T_COMMA for_args T_NEWLINE { + $$ = lexer_CaptureRept(captureBody); + } endofline { + if ($8) + fstk_RunFor( + $3, + $6.start, + $6.stop, + $6.step, + captureBody.lineNo, + captureBody.body, + captureBody.size + ); + } +; + +for_args: + const { + $$.start = 0; + $$.stop = $1; + $$.step = 1; + } + | const T_COMMA const { + $$.start = $1; + $$.stop = $3; + $$.step = 1; + } + | const T_COMMA const T_COMMA const { + $$.start = $1; + $$.stop = $3; + $$.step = $5; + } +; + +break: + label T_POP_BREAK endofline { + if (fstk_Break()) + lexer_SetMode(LEXER_SKIP_TO_ENDR); + } +; + +macrodef: + T_POP_MACRO { + lexer_ToggleStringExpansion(false); + } T_ID { + lexer_ToggleStringExpansion(true); + } T_NEWLINE { + $$ = lexer_CaptureMacroBody(captureBody); + } endofline { + if ($6) + sym_AddMacro($3, captureBody.lineNo, captureBody.body, captureBody.size); + } +; + +rsset: + T_POP_RSSET uconst { + sym_AddVar("_RS", $2); + } +; + +rsreset: + T_POP_RSRESET { + sym_AddVar("_RS", 0); + } +; + +rs_uconst: + %empty { + $$ = 1; + } + | uconst +; + +union: + T_POP_UNION { + sect_StartUnion(); + } +; + +nextu: + T_POP_NEXTU { + sect_NextUnionMember(); + } +; + +endu: + T_POP_ENDU { + sect_EndUnion(); + } +; + +ds: + T_POP_DS uconst { + sect_Skip($2, true); + } + | T_POP_DS uconst T_COMMA ds_args trailing_comma { + sect_RelBytes($2, *$4); + delete $4; + } + | T_POP_DS T_OP_ALIGN T_LBRACK align_spec T_RBRACK trailing_comma { + uint32_t n = sect_GetAlignBytes($4.alignment, $4.alignOfs); + + sect_Skip(n, true); + sect_AlignPC($4.alignment, $4.alignOfs); + } + | T_POP_DS T_OP_ALIGN T_LBRACK align_spec T_RBRACK T_COMMA ds_args trailing_comma { + uint32_t n = sect_GetAlignBytes($4.alignment, $4.alignOfs); + + sect_RelBytes(n, *$7); + sect_AlignPC($4.alignment, $4.alignOfs); + delete $7; + } +; + +ds_args: + reloc_8bit { + initDsArgList($$); + $$->push_back($1); + } + | ds_args T_COMMA reloc_8bit { + $1->push_back($3); + $$ = $1; + } +; + +db: + T_POP_DB { + sect_Skip(1, false); + } + | T_POP_DB constlist_8bit trailing_comma +; + +dw: + T_POP_DW { + sect_Skip(2, false); + } + | T_POP_DW constlist_16bit trailing_comma +; + +dl: + T_POP_DL { + sect_Skip(4, false); + } + | T_POP_DL constlist_32bit trailing_comma +; + +def_equ: + def_id T_POP_EQU const { + sym_AddEqu($1, $3); + } +; + +redef_equ: + redef_id T_POP_EQU const { + sym_RedefEqu($1, $3); + } +; + +def_set: + def_id T_POP_EQUAL const { + sym_AddVar($1, $3); + } + | redef_id T_POP_EQUAL const { + sym_AddVar($1, $3); + } + | def_id compoundeq const { + compoundAssignment($1, $2, $3); + } + | redef_id compoundeq const { + compoundAssignment($1, $2, $3); + } +; + +def_rb: + def_id T_POP_RB rs_uconst { + sym_AddEqu($1, sym_GetConstantValue("_RS")); + sym_AddVar("_RS", sym_GetConstantValue("_RS") + $3); + } +; + +def_rw: + def_id T_POP_RW rs_uconst { + sym_AddEqu($1, sym_GetConstantValue("_RS")); + sym_AddVar("_RS", sym_GetConstantValue("_RS") + 2 * $3); + } +; + +def_rl: + def_id T_Z80_RL rs_uconst { + sym_AddEqu($1, sym_GetConstantValue("_RS")); + sym_AddVar("_RS", sym_GetConstantValue("_RS") + 4 * $3); + } +; + +def_equs: + def_id T_POP_EQUS string { + sym_AddString($1, $3); + } +; + +redef_equs: + redef_id T_POP_EQUS string { + sym_RedefString($1, $3); + } +; + +purge: + T_POP_PURGE { + lexer_ToggleStringExpansion(false); + } purge_args trailing_comma { + for (std::string &arg : *$3) + sym_Purge(arg); + delete $3; + lexer_ToggleStringExpansion(true); + } +; + +purge_args: + scoped_id { + initPurgeArgList($$); + $$->push_back($1); + } + | purge_args T_COMMA scoped_id { + $1->push_back($3); + $$ = $1; + } +; + +export: T_POP_EXPORT export_list trailing_comma; + +export_list: + export_list_entry + | export_list T_COMMA export_list_entry +; + +export_list_entry: + scoped_id { + sym_Export($1); + } +; + +include: + label T_POP_INCLUDE string endofline { + fstk_RunInclude($3); + if (failedOnMissingInclude) + YYACCEPT; + } +; + +incbin: + T_POP_INCBIN string { + sect_BinaryFile($2, 0); + if (failedOnMissingInclude) + YYACCEPT; + } + | T_POP_INCBIN string T_COMMA const { + sect_BinaryFile($2, $4); + if (failedOnMissingInclude) + YYACCEPT; + } + | T_POP_INCBIN string T_COMMA const T_COMMA const { + sect_BinaryFileSlice($2, $4, $6); + if (failedOnMissingInclude) + YYACCEPT; + } +; + +charmap: + T_POP_CHARMAP string T_COMMA const_8bit { + charmap_Add($2, (uint8_t)$4); + } +; + +newcharmap: + T_POP_NEWCHARMAP T_ID { + charmap_New($2, nullptr); + } + | T_POP_NEWCHARMAP T_ID T_COMMA T_ID { + charmap_New($2, $4); + } +; + +setcharmap: + T_POP_SETCHARMAP T_ID { + charmap_Set($2); + } +; + +pushc: + T_POP_PUSHC { + charmap_Push(); + } +; + +popc: + T_POP_POPC { + charmap_Pop(); + } +; + +print: T_POP_PRINT print_exprs trailing_comma; + +println: + T_POP_PRINTLN { + putchar('\n'); + fflush(stdout); + } + | T_POP_PRINTLN print_exprs trailing_comma { + putchar('\n'); + fflush(stdout); + } +; + +print_exprs: + print_expr + | print_exprs T_COMMA print_expr +; + +print_expr: + const_no_str { + printf("$%" PRIX32, $1); + } + | string { + printf("%s", $1); + } +; + +const_3bit: + const { + int32_t value = $1; + + if ((value < 0) || (value > 7)) { + error("Immediate value must be 3-bit\n"); + $$ = 0; + } else { + $$ = value & 0x7; } - | T_Z80_ADD op_a_r { sect_AbsByte(0x80 | $2); } - | T_Z80_ADD T_MODE_HL T_COMMA reg_ss { sect_AbsByte(0x09 | ($4 << 4)); } - | T_Z80_ADD T_MODE_SP T_COMMA reloc_8bit { - sect_AbsByte(0xE8); - sect_RelByte($4, 1); + } +; + +constlist_8bit: + constlist_8bit_entry + | constlist_8bit T_COMMA constlist_8bit_entry +; + +constlist_8bit_entry: + reloc_8bit_no_str { + sect_RelByte($1, 0); + } + | string { + std::vector output; + + charmap_Convert($1, output); + sect_AbsByteGroup(output.data(), output.size()); + } +; + +constlist_16bit: + constlist_16bit_entry + | constlist_16bit T_COMMA constlist_16bit_entry +; + +constlist_16bit_entry: + reloc_16bit_no_str { + sect_RelWord($1, 0); + } + | string { + std::vector output; + + charmap_Convert($1, output); + sect_AbsWordGroup(output.data(), output.size()); + } +; + +constlist_32bit: + constlist_32bit_entry + | constlist_32bit T_COMMA constlist_32bit_entry +; + +constlist_32bit_entry: + relocexpr_no_str { + sect_RelLong($1, 0); + } + | string { + std::vector output; + + charmap_Convert($1, output); + sect_AbsLongGroup(output.data(), output.size()); + } +; + +reloc_8bit: + relocexpr { + rpn_CheckNBit($1, 8); + $$ = $1; + } +; + +reloc_8bit_no_str: + relocexpr_no_str { + rpn_CheckNBit($1, 8); + $$ = $1; + } +; + +reloc_8bit_offset: + T_OP_ADD relocexpr { + rpn_CheckNBit($2, 8); + $$ = $2; + } + | T_OP_SUB relocexpr { + rpn_NEG($$, $2); + rpn_CheckNBit($$, 8); + } +; + +reloc_16bit: + relocexpr { + rpn_CheckNBit($1, 16); + $$ = $1; + } +; + +reloc_16bit_no_str: + relocexpr_no_str { + rpn_CheckNBit($1, 16); + $$ = $1; + } +; + +relocexpr: + relocexpr_no_str + | string { + std::vector output; + + charmap_Convert($1, output); + rpn_Number($$, str2int2(output)); + } +; + +relocexpr_no_str: + scoped_anon_id { + rpn_Symbol($$, $1); + } + | T_NUMBER { + rpn_Number($$, $1); + } + | T_OP_LOGICNOT relocexpr %prec NEG { + rpn_LOGNOT($$, $2); + } + | relocexpr T_OP_LOGICOR relocexpr { + rpn_BinaryOp(RPN_LOGOR, $$, $1, $3); + } + | relocexpr T_OP_LOGICAND relocexpr { + rpn_BinaryOp(RPN_LOGAND, $$, $1, $3); + } + | relocexpr T_OP_LOGICEQU relocexpr { + rpn_BinaryOp(RPN_LOGEQ, $$, $1, $3); + } + | relocexpr T_OP_LOGICGT relocexpr { + rpn_BinaryOp(RPN_LOGGT, $$, $1, $3); + } + | relocexpr T_OP_LOGICLT relocexpr { + rpn_BinaryOp(RPN_LOGLT, $$, $1, $3); + } + | relocexpr T_OP_LOGICGE relocexpr { + rpn_BinaryOp(RPN_LOGGE, $$, $1, $3); + } + | relocexpr T_OP_LOGICLE relocexpr { + rpn_BinaryOp(RPN_LOGLE, $$, $1, $3); + } + | relocexpr T_OP_LOGICNE relocexpr { + rpn_BinaryOp(RPN_LOGNE, $$, $1, $3); + } + | relocexpr T_OP_ADD relocexpr { + rpn_BinaryOp(RPN_ADD, $$, $1, $3); + } + | relocexpr T_OP_SUB relocexpr { + rpn_BinaryOp(RPN_SUB, $$, $1, $3); + } + | relocexpr T_OP_XOR relocexpr { + rpn_BinaryOp(RPN_XOR, $$, $1, $3); + } + | relocexpr T_OP_OR relocexpr { + rpn_BinaryOp(RPN_OR, $$, $1, $3); + } + | relocexpr T_OP_AND relocexpr { + rpn_BinaryOp(RPN_AND, $$, $1, $3); + } + | relocexpr T_OP_SHL relocexpr { + rpn_BinaryOp(RPN_SHL, $$, $1, $3); + } + | relocexpr T_OP_SHR relocexpr { + rpn_BinaryOp(RPN_SHR, $$, $1, $3); + } + | relocexpr T_OP_USHR relocexpr { + rpn_BinaryOp(RPN_USHR, $$, $1, $3); + } + | relocexpr T_OP_MUL relocexpr { + rpn_BinaryOp(RPN_MUL, $$, $1, $3); + } + | relocexpr T_OP_DIV relocexpr { + rpn_BinaryOp(RPN_DIV, $$, $1, $3); + } + | relocexpr T_OP_MOD relocexpr { + rpn_BinaryOp(RPN_MOD, $$, $1, $3); + } + | relocexpr T_OP_EXP relocexpr { + rpn_BinaryOp(RPN_EXP, $$, $1, $3); + } + | T_OP_ADD relocexpr %prec NEG { + $$ = $2; + } + | T_OP_SUB relocexpr %prec NEG { + rpn_NEG($$, $2); + } + | T_OP_NOT relocexpr %prec NEG { + rpn_NOT($$, $2); + } + | T_OP_HIGH T_LPAREN relocexpr T_RPAREN { + rpn_HIGH($$, $3); + } + | T_OP_LOW T_LPAREN relocexpr T_RPAREN { + rpn_LOW($$, $3); + } + | T_OP_ISCONST T_LPAREN relocexpr T_RPAREN { + rpn_ISCONST($$, $3); + } + | T_OP_BANK T_LPAREN scoped_anon_id T_RPAREN { + // '@' is also a T_ID; it is handled here + rpn_BankSymbol($$, $3); + } + | T_OP_BANK T_LPAREN string T_RPAREN { + rpn_BankSection($$, $3); + } + | T_OP_SIZEOF T_LPAREN string T_RPAREN { + rpn_SizeOfSection($$, $3); + } + | T_OP_STARTOF T_LPAREN string T_RPAREN { + rpn_StartOfSection($$, $3); + } + | T_OP_SIZEOF T_LPAREN sectiontype T_RPAREN { + rpn_SizeOfSectionType($$, (enum SectionType)$3); + } + | T_OP_STARTOF T_LPAREN sectiontype T_RPAREN { + rpn_StartOfSectionType($$, (enum SectionType)$3); + } + | T_OP_DEF { + lexer_ToggleStringExpansion(false); + } T_LPAREN scoped_anon_id T_RPAREN { + rpn_Number($$, sym_FindScopedValidSymbol($4) != nullptr); + + lexer_ToggleStringExpansion(true); + } + | T_OP_ROUND T_LPAREN const opt_q_arg T_RPAREN { + rpn_Number($$, fix_Round($3, $4)); + } + | T_OP_CEIL T_LPAREN const opt_q_arg T_RPAREN { + rpn_Number($$, fix_Ceil($3, $4)); + } + | T_OP_FLOOR T_LPAREN const opt_q_arg T_RPAREN { + rpn_Number($$, fix_Floor($3, $4)); + } + | T_OP_FDIV T_LPAREN const T_COMMA const opt_q_arg T_RPAREN { + rpn_Number($$, fix_Div($3, $5, $6)); + } + | T_OP_FMUL T_LPAREN const T_COMMA const opt_q_arg T_RPAREN { + rpn_Number($$, fix_Mul($3, $5, $6)); + } + | T_OP_FMOD T_LPAREN const T_COMMA const opt_q_arg T_RPAREN { + rpn_Number($$, fix_Mod($3, $5, $6)); + } + | T_OP_POW T_LPAREN const T_COMMA const opt_q_arg T_RPAREN { + rpn_Number($$, fix_Pow($3, $5, $6)); + } + | T_OP_LOG T_LPAREN const T_COMMA const opt_q_arg T_RPAREN { + rpn_Number($$, fix_Log($3, $5, $6)); + } + | T_OP_SIN T_LPAREN const opt_q_arg T_RPAREN { + rpn_Number($$, fix_Sin($3, $4)); + } + | T_OP_COS T_LPAREN const opt_q_arg T_RPAREN { + rpn_Number($$, fix_Cos($3, $4)); + } + | T_OP_TAN T_LPAREN const opt_q_arg T_RPAREN { + rpn_Number($$, fix_Tan($3, $4)); + } + | T_OP_ASIN T_LPAREN const opt_q_arg T_RPAREN { + rpn_Number($$, fix_ASin($3, $4)); + } + | T_OP_ACOS T_LPAREN const opt_q_arg T_RPAREN { + rpn_Number($$, fix_ACos($3, $4)); + } + | T_OP_ATAN T_LPAREN const opt_q_arg T_RPAREN { + rpn_Number($$, fix_ATan($3, $4)); + } + | T_OP_ATAN2 T_LPAREN const T_COMMA const opt_q_arg T_RPAREN { + rpn_Number($$, fix_ATan2($3, $5, $6)); + } + | T_OP_STRCMP T_LPAREN string T_COMMA string T_RPAREN { + rpn_Number($$, strcmp($3, $5)); + } + | T_OP_STRIN T_LPAREN string T_COMMA string T_RPAREN { + char const *p = strstr($3, $5); + + rpn_Number($$, p ? p - $3 + 1 : 0); + } + | T_OP_STRRIN T_LPAREN string T_COMMA string T_RPAREN { + char const *p = strrstr($3, $5); + + rpn_Number($$, p ? p - $3 + 1 : 0); + } + | T_OP_STRLEN T_LPAREN string T_RPAREN { + rpn_Number($$, strlenUTF8($3)); + } + | T_OP_CHARLEN T_LPAREN string T_RPAREN { + rpn_Number($$, charlenUTF8($3)); + } + | T_OP_INCHARMAP T_LPAREN string T_RPAREN { + rpn_Number($$, charmap_HasChar($3)); + } + | T_LPAREN relocexpr T_RPAREN { + $$ = $2; + } +; + +uconst: + const { + if ($1 < 0) + fatalerror("Constant must not be negative: %d\n", $1); + $$ = $1; + } +; + +const: + relocexpr { + $$ = $1.getConstVal(); + } +; + +const_no_str: + relocexpr_no_str { + $$ = $1.getConstVal(); + } +; + +const_8bit: + reloc_8bit { + $$ = $1.getConstVal(); + } +; + +opt_q_arg: + %empty { + $$ = fix_Precision(); + } + | T_COMMA const { + if ($2 >= 1 && $2 <= 31) { + $$ = $2; + } else { + error("Fixed-point precision must be between 1 and 31\n"); + $$ = fix_Precision(); } - + } ; -z80_and : T_Z80_AND op_a_n { - sect_AbsByte(0xE6); - sect_RelByte($2, 1); +string: + T_STRING + | T_OP_STRSUB T_LPAREN string T_COMMA const T_COMMA uconst T_RPAREN { + size_t len = strlenUTF8($3); + uint32_t pos = adjustNegativePos($5, len, "STRSUB"); + + strsubUTF8($$, sizeof($$), $3, pos, $7); + } + | T_OP_STRSUB T_LPAREN string T_COMMA const T_RPAREN { + size_t len = strlenUTF8($3); + uint32_t pos = adjustNegativePos($5, len, "STRSUB"); + + strsubUTF8($$, sizeof($$), $3, pos, pos > len ? 0 : len + 1 - pos); + } + | T_OP_CHARSUB T_LPAREN string T_COMMA const T_RPAREN { + size_t len = charlenUTF8($3); + uint32_t pos = adjustNegativePos($5, len, "CHARSUB"); + + charsubUTF8($$, $3, pos); + } + | T_OP_STRCAT T_LPAREN T_RPAREN { + $$[0] = '\0'; + } + | T_OP_STRCAT T_LPAREN strcat_args T_RPAREN { + strcpy($$, $3); + } + | T_OP_STRUPR T_LPAREN string T_RPAREN { + upperstring($$, $3); + } + | T_OP_STRLWR T_LPAREN string T_RPAREN { + lowerstring($$, $3); + } + | T_OP_STRRPL T_LPAREN string T_COMMA string T_COMMA string T_RPAREN { + strrpl($$, sizeof($$), $3, $5, $7); + } + | T_OP_STRFMT T_LPAREN strfmt_args T_RPAREN { + strfmt($$, sizeof($$), $3.format->c_str(), *$3.args); + freeStrFmtArgList($3); + } + | T_POP_SECTION T_LPAREN scoped_anon_id T_RPAREN { + Symbol *sym = sym_FindScopedValidSymbol($3); + + if (!sym) + fatalerror("Unknown symbol \"%s\"\n", $3); + Section const *section = sym->getSection(); + + if (!section) + fatalerror("\"%s\" does not belong to any section\n", sym->name); + // Section names are capped by rgbasm's maximum string length, + // so this currently can't overflow. + strcpy($$, section->name.c_str()); + } +; + +strcat_args: + string + | strcat_args T_COMMA string { + int ret = snprintf($$, sizeof($$), "%s%s", $1, $3); + + if (ret == -1) + fatalerror("snprintf error in STRCAT: %s\n", strerror(errno)); + else if ((unsigned int)ret >= sizeof($$)) + warning(WARNING_LONG_STR, "STRCAT: String too long '%s%s'\n", $1, $3); + } +; + +strfmt_args: + string strfmt_va_args { + $$ = $2; + *$$.format = $1; + } +; + +strfmt_va_args: + %empty { + initStrFmtArgList($$); + } + | strfmt_va_args T_COMMA const_no_str { + $1.args->push_back((uint32_t)$3); + $$ = $1; + } + | strfmt_va_args T_COMMA string { + $1.args->push_back($3); + $$ = $1; + } +; + +section: + T_POP_SECTION sectmod string T_COMMA sectiontype sectorg sectattrs { + sect_NewSection($3, (enum SectionType)$5, $6, $7, $2); + } +; + +sectmod: + %empty { + $$ = SECTION_NORMAL; + } + | T_POP_UNION { + $$ = SECTION_UNION; + } + | T_POP_FRAGMENT { + $$ = SECTION_FRAGMENT; + } +; + +sectiontype: + T_SECT_WRAM0 { + $$ = SECTTYPE_WRAM0; + } + | T_SECT_VRAM { + $$ = SECTTYPE_VRAM; + } + | T_SECT_ROMX { + $$ = SECTTYPE_ROMX; + } + | T_SECT_ROM0 { + $$ = SECTTYPE_ROM0; + } + | T_SECT_HRAM { + $$ = SECTTYPE_HRAM; + } + | T_SECT_WRAMX { + $$ = SECTTYPE_WRAMX; + } + | T_SECT_SRAM { + $$ = SECTTYPE_SRAM; + } + | T_SECT_OAM { + $$ = SECTTYPE_OAM; + } +; + +sectorg: + %empty { + $$ = -1; + } + | T_LBRACK uconst T_RBRACK { + if ($2 < 0 || $2 >= 0x10000) { + error("Address $%x is not 16-bit\n", $2); + $$ = -1; + } else { + $$ = $2; } - | T_Z80_AND op_a_r { sect_AbsByte(0xA0 | $2); } + } ; -z80_bit : T_Z80_BIT const_3bit T_COMMA reg_r { - sect_AbsByte(0xCB); - sect_AbsByte(0x40 | ($2 << 3) | $4); - } +sectattrs: + %empty { + $$.alignment = 0; + $$.alignOfs = 0; + $$.bank = -1; + } + | sectattrs T_COMMA T_OP_ALIGN T_LBRACK align_spec T_RBRACK { + $$.alignment = $5.alignment; + $$.alignOfs = $5.alignOfs; + } + | sectattrs T_COMMA T_OP_BANK T_LBRACK uconst T_RBRACK { + // We cannot check the validity of this now + $$.bank = $5; + } ; -z80_call : T_Z80_CALL reloc_16bit { - sect_AbsByte(0xCD); - sect_RelWord($2, 1); - } - | T_Z80_CALL ccode_expr T_COMMA reloc_16bit { - sect_AbsByte(0xC4 | ($2 << 3)); - sect_RelWord($4, 1); - } +// CPU commands. + +cpu_commands: + cpu_command + | cpu_command T_DOUBLE_COLON cpu_commands ; -z80_ccf : T_Z80_CCF { sect_AbsByte(0x3F); } +cpu_command: + z80_adc + | z80_add + | z80_and + | z80_bit + | z80_call + | z80_ccf + | z80_cp + | z80_cpl + | z80_daa + | z80_dec + | z80_di + | z80_ei + | z80_halt + | z80_inc + | z80_jp + | z80_jr + | z80_ld + | z80_ldd + | z80_ldi + | z80_ldio + | z80_nop + | z80_or + | z80_pop + | z80_push + | z80_res + | z80_ret + | z80_reti + | z80_rl + | z80_rla + | z80_rlc + | z80_rlca + | z80_rr + | z80_rra + | z80_rrc + | z80_rrca + | z80_rst + | z80_sbc + | z80_scf + | z80_set + | z80_sla + | z80_sra + | z80_srl + | z80_stop + | z80_sub + | z80_swap + | z80_xor ; -z80_cp : T_Z80_CP op_a_n { - sect_AbsByte(0xFE); - sect_RelByte($2, 1); - } - | T_Z80_CP op_a_r { sect_AbsByte(0xB8 | $2); } +z80_adc: + T_Z80_ADC op_a_n { + sect_AbsByte(0xCE); + sect_RelByte($2, 1); + } + | T_Z80_ADC op_a_r { + sect_AbsByte(0x88 | $2); + } ; -z80_cpl : T_Z80_CPL { sect_AbsByte(0x2F); } +z80_add: + T_Z80_ADD op_a_n { + sect_AbsByte(0xC6); + sect_RelByte($2, 1); + } + | T_Z80_ADD op_a_r { + sect_AbsByte(0x80 | $2); + } + | T_Z80_ADD T_MODE_HL T_COMMA reg_ss { + sect_AbsByte(0x09 | ($4 << 4)); + } + | T_Z80_ADD T_MODE_SP T_COMMA reloc_8bit { + sect_AbsByte(0xE8); + sect_RelByte($4, 1); + } ; -z80_daa : T_Z80_DAA { sect_AbsByte(0x27); } +z80_and: + T_Z80_AND op_a_n { + sect_AbsByte(0xE6); + sect_RelByte($2, 1); + } + | T_Z80_AND op_a_r { + sect_AbsByte(0xA0 | $2); + } ; -z80_dec : T_Z80_DEC reg_r { sect_AbsByte(0x05 | ($2 << 3)); } - | T_Z80_DEC reg_ss { sect_AbsByte(0x0B | ($2 << 4)); } +z80_bit: + T_Z80_BIT const_3bit T_COMMA reg_r { + sect_AbsByte(0xCB); + sect_AbsByte(0x40 | ($2 << 3) | $4); + } ; -z80_di : T_Z80_DI { sect_AbsByte(0xF3); } +z80_call: + T_Z80_CALL reloc_16bit { + sect_AbsByte(0xCD); + sect_RelWord($2, 1); + } + | T_Z80_CALL ccode_expr T_COMMA reloc_16bit { + sect_AbsByte(0xC4 | ($2 << 3)); + sect_RelWord($4, 1); + } ; -z80_ei : T_Z80_EI { sect_AbsByte(0xFB); } +z80_ccf: + T_Z80_CCF { + sect_AbsByte(0x3F); + } ; -z80_halt : T_Z80_HALT { - sect_AbsByte(0x76); - if (haltNop) { - if (warnOnHaltNop) { - warnOnHaltNop = false; - warning(WARNING_OBSOLETE, - "Automatic `nop` after `halt` (option 'H') is deprecated\n"); - } - sect_AbsByte(0x00); +z80_cp: + T_Z80_CP op_a_n { + sect_AbsByte(0xFE); + sect_RelByte($2, 1); + } + | T_Z80_CP op_a_r { + sect_AbsByte(0xB8 | $2); + } +; + +z80_cpl: + T_Z80_CPL { + sect_AbsByte(0x2F); + } +; + +z80_daa: + T_Z80_DAA { + sect_AbsByte(0x27); + } +; + +z80_dec: + T_Z80_DEC reg_r { + sect_AbsByte(0x05 | ($2 << 3)); + } + | T_Z80_DEC reg_ss { + sect_AbsByte(0x0B | ($2 << 4)); + } +; + +z80_di: + T_Z80_DI { + sect_AbsByte(0xF3); + } +; + +z80_ei: + T_Z80_EI { + sect_AbsByte(0xFB); + } +; + +z80_halt: + T_Z80_HALT { + sect_AbsByte(0x76); + if (haltNop) { + if (warnOnHaltNop) { + warnOnHaltNop = false; + warning( + WARNING_OBSOLETE, + "Automatic `nop` after `halt` (option 'H') is deprecated\n" + ); } - } -; - -z80_inc : T_Z80_INC reg_r { sect_AbsByte(0x04 | ($2 << 3)); } - | T_Z80_INC reg_ss { sect_AbsByte(0x03 | ($2 << 4)); } -; - -z80_jp : T_Z80_JP reloc_16bit { - sect_AbsByte(0xC3); - sect_RelWord($2, 1); - } - | T_Z80_JP ccode_expr T_COMMA reloc_16bit { - sect_AbsByte(0xC2 | ($2 << 3)); - sect_RelWord($4, 1); - } - | T_Z80_JP T_MODE_HL { - sect_AbsByte(0xE9); - } -; - -z80_jr : T_Z80_JR reloc_16bit { - sect_AbsByte(0x18); - sect_PCRelByte($2, 1); - } - | T_Z80_JR ccode_expr T_COMMA reloc_16bit { - sect_AbsByte(0x20 | ($2 << 3)); - sect_PCRelByte($4, 1); - } -; - -z80_ldi : T_Z80_LDI T_LBRACK T_MODE_HL T_RBRACK T_COMMA T_MODE_A { - sect_AbsByte(0x02 | (2 << 4)); - } - | T_Z80_LDI T_MODE_A T_COMMA T_LBRACK T_MODE_HL T_RBRACK { - sect_AbsByte(0x0A | (2 << 4)); - } -; - -z80_ldd : T_Z80_LDD T_LBRACK T_MODE_HL T_RBRACK T_COMMA T_MODE_A { - sect_AbsByte(0x02 | (3 << 4)); - } - | T_Z80_LDD T_MODE_A T_COMMA T_LBRACK T_MODE_HL T_RBRACK { - sect_AbsByte(0x0A | (3 << 4)); - } -; - -z80_ldio : T_Z80_LDH T_MODE_A T_COMMA op_mem_ind { - rpn_CheckHRAM($4, $4); - - sect_AbsByte(0xF0); - sect_RelByte($4, 1); - } - | T_Z80_LDH op_mem_ind T_COMMA T_MODE_A { - rpn_CheckHRAM($2, $2); - - sect_AbsByte(0xE0); - sect_RelByte($2, 1); - } - | T_Z80_LDH T_MODE_A T_COMMA c_ind { - sect_AbsByte(0xF2); - } - | T_Z80_LDH c_ind T_COMMA T_MODE_A { - sect_AbsByte(0xE2); - } -; - -c_ind : T_LBRACK T_MODE_C T_RBRACK - | T_LBRACK relocexpr T_OP_ADD T_MODE_C T_RBRACK { - if (!$2.isKnown || $2.val != 0xFF00) - error("Expected constant expression equal to $FF00 for \"$ff00+c\"\n"); - } -; - -z80_ld : z80_ld_mem - | z80_ld_cind - | z80_ld_rr - | z80_ld_ss - | z80_ld_hl - | z80_ld_sp - | z80_ld_r - | z80_ld_a -; - -z80_ld_hl : T_Z80_LD T_MODE_HL T_COMMA T_MODE_SP reloc_8bit_offset { - sect_AbsByte(0xF8); - sect_RelByte($5, 1); - } - | T_Z80_LD T_MODE_HL T_COMMA reloc_16bit { - sect_AbsByte(0x01 | (REG_HL << 4)); - sect_RelWord($4, 1); - } -; - -z80_ld_sp : T_Z80_LD T_MODE_SP T_COMMA T_MODE_HL { sect_AbsByte(0xF9); } - | T_Z80_LD T_MODE_SP T_COMMA reloc_16bit { - sect_AbsByte(0x01 | (REG_SP << 4)); - sect_RelWord($4, 1); - } -; - -z80_ld_mem : T_Z80_LD op_mem_ind T_COMMA T_MODE_SP { - sect_AbsByte(0x08); - sect_RelWord($2, 1); - } - | T_Z80_LD op_mem_ind T_COMMA T_MODE_A { - if (optimizeLoads && $2.isKnown - && $2.val >= 0xFF00) { - if (warnOnLdOpt) { - warnOnLdOpt = false; - warning(WARNING_OBSOLETE, - "Automatic `ld` to `ldh` optimization (option 'l') is deprecated\n"); - } - sect_AbsByte(0xE0); - sect_AbsByte($2.val & 0xFF); - rpn_Free($2); - } else { - sect_AbsByte(0xEA); - sect_RelWord($2, 1); - } - } -; - -z80_ld_cind : T_Z80_LD c_ind T_COMMA T_MODE_A { - sect_AbsByte(0xE2); - } -; - -z80_ld_rr : T_Z80_LD reg_rr T_COMMA T_MODE_A { - sect_AbsByte(0x02 | ($2 << 4)); - } -; - -z80_ld_r : T_Z80_LD reg_r T_COMMA reloc_8bit { - sect_AbsByte(0x06 | ($2 << 3)); - sect_RelByte($4, 1); - } - | T_Z80_LD reg_r T_COMMA reg_r { - if (($2 == REG_HL_IND) && ($4 == REG_HL_IND)) - error("LD [HL],[HL] not a valid instruction\n"); - else - sect_AbsByte(0x40 | ($2 << 3) | $4); - } -; - -z80_ld_a : T_Z80_LD reg_r T_COMMA c_ind { - if ($2 == REG_A) - sect_AbsByte(0xF2); - else - error("Destination operand must be A\n"); - } - | T_Z80_LD reg_r T_COMMA reg_rr { - if ($2 == REG_A) - sect_AbsByte(0x0A | ($4 << 4)); - else - error("Destination operand must be A\n"); - } - | T_Z80_LD reg_r T_COMMA op_mem_ind { - if ($2 == REG_A) { - if (optimizeLoads && $4.isKnown && $4.val >= 0xFF00) { - if (warnOnLdOpt) { - warnOnLdOpt = false; - warning(WARNING_OBSOLETE, - "Automatic `ld` to `ldh` optimization (option 'l') is deprecated\n"); - } - sect_AbsByte(0xF0); - sect_AbsByte($4.val & 0xFF); - rpn_Free($4); - } else { - sect_AbsByte(0xFA); - sect_RelWord($4, 1); - } - } else { - error("Destination operand must be A\n"); - rpn_Free($4); - } - } -; - -z80_ld_ss : T_Z80_LD T_MODE_BC T_COMMA reloc_16bit { - sect_AbsByte(0x01 | (REG_BC << 4)); - sect_RelWord($4, 1); - } - | T_Z80_LD T_MODE_DE T_COMMA reloc_16bit { - sect_AbsByte(0x01 | (REG_DE << 4)); - sect_RelWord($4, 1); - } - // HL is taken care of in z80_ld_hl - // SP is taken care of in z80_ld_sp -; - -z80_nop : T_Z80_NOP { sect_AbsByte(0x00); } -; - -z80_or : T_Z80_OR op_a_n { - sect_AbsByte(0xF6); - sect_RelByte($2, 1); - } - | T_Z80_OR op_a_r { sect_AbsByte(0xB0 | $2); } -; - -z80_pop : T_Z80_POP reg_tt { sect_AbsByte(0xC1 | ($2 << 4)); } -; - -z80_push : T_Z80_PUSH reg_tt { sect_AbsByte(0xC5 | ($2 << 4)); } -; - -z80_res : T_Z80_RES const_3bit T_COMMA reg_r { - sect_AbsByte(0xCB); - sect_AbsByte(0x80 | ($2 << 3) | $4); - } -; - -z80_ret : T_Z80_RET { sect_AbsByte(0xC9); } - | T_Z80_RET ccode_expr { sect_AbsByte(0xC0 | ($2 << 3)); } -; - -z80_reti : T_Z80_RETI { sect_AbsByte(0xD9); } -; - -z80_rl : T_Z80_RL reg_r { - sect_AbsByte(0xCB); - sect_AbsByte(0x10 | $2); - } -; - -z80_rla : T_Z80_RLA { sect_AbsByte(0x17); } -; - -z80_rlc : T_Z80_RLC reg_r { - sect_AbsByte(0xCB); - sect_AbsByte(0x00 | $2); - } -; - -z80_rlca : T_Z80_RLCA { sect_AbsByte(0x07); } -; - -z80_rr : T_Z80_RR reg_r { - sect_AbsByte(0xCB); - sect_AbsByte(0x18 | $2); - } -; - -z80_rra : T_Z80_RRA { sect_AbsByte(0x1F); } -; - -z80_rrc : T_Z80_RRC reg_r { - sect_AbsByte(0xCB); - sect_AbsByte(0x08 | $2); - } -; - -z80_rrca : T_Z80_RRCA { sect_AbsByte(0x0F); } -; - -z80_rst : T_Z80_RST reloc_8bit { - rpn_CheckRST($2, $2); - if (!$2.isKnown) - sect_RelByte($2, 0); - else - sect_AbsByte(0xC7 | $2.val); - rpn_Free($2); - } -; - -z80_sbc : T_Z80_SBC op_a_n { - sect_AbsByte(0xDE); - sect_RelByte($2, 1); - } - | T_Z80_SBC op_a_r { sect_AbsByte(0x98 | $2); } -; - -z80_scf : T_Z80_SCF { sect_AbsByte(0x37); } -; - -z80_set : T_Z80_SET const_3bit T_COMMA reg_r { - sect_AbsByte(0xCB); - sect_AbsByte(0xC0 | ($2 << 3) | $4); - } -; - -z80_sla : T_Z80_SLA reg_r { - sect_AbsByte(0xCB); - sect_AbsByte(0x20 | $2); - } -; - -z80_sra : T_Z80_SRA reg_r { - sect_AbsByte(0xCB); - sect_AbsByte(0x28 | $2); - } -; - -z80_srl : T_Z80_SRL reg_r { - sect_AbsByte(0xCB); - sect_AbsByte(0x38 | $2); - } -; - -z80_stop : T_Z80_STOP { - sect_AbsByte(0x10); sect_AbsByte(0x00); } - | T_Z80_STOP reloc_8bit { - sect_AbsByte(0x10); - sect_RelByte($2, 1); + } +; + +z80_inc: + T_Z80_INC reg_r { + sect_AbsByte(0x04 | ($2 << 3)); + } + | T_Z80_INC reg_ss { + sect_AbsByte(0x03 | ($2 << 4)); + } +; + +z80_jp: + T_Z80_JP reloc_16bit { + sect_AbsByte(0xC3); + sect_RelWord($2, 1); + } + | T_Z80_JP ccode_expr T_COMMA reloc_16bit { + sect_AbsByte(0xC2 | ($2 << 3)); + sect_RelWord($4, 1); + } + | T_Z80_JP T_MODE_HL { + sect_AbsByte(0xE9); + } +; + +z80_jr: + T_Z80_JR reloc_16bit { + sect_AbsByte(0x18); + sect_PCRelByte($2, 1); + } + | T_Z80_JR ccode_expr T_COMMA reloc_16bit { + sect_AbsByte(0x20 | ($2 << 3)); + sect_PCRelByte($4, 1); + } +; + +z80_ldi: + T_Z80_LDI T_LBRACK T_MODE_HL T_RBRACK T_COMMA T_MODE_A { + sect_AbsByte(0x02 | (2 << 4)); + } + | T_Z80_LDI T_MODE_A T_COMMA T_LBRACK T_MODE_HL T_RBRACK { + sect_AbsByte(0x0A | (2 << 4)); + } +; + +z80_ldd: + T_Z80_LDD T_LBRACK T_MODE_HL T_RBRACK T_COMMA T_MODE_A { + sect_AbsByte(0x02 | (3 << 4)); + } + | T_Z80_LDD T_MODE_A T_COMMA T_LBRACK T_MODE_HL T_RBRACK { + sect_AbsByte(0x0A | (3 << 4)); + } +; + +z80_ldio: + T_Z80_LDH T_MODE_A T_COMMA op_mem_ind { + rpn_CheckHRAM($4, $4); + + sect_AbsByte(0xF0); + sect_RelByte($4, 1); + } + | T_Z80_LDH op_mem_ind T_COMMA T_MODE_A { + rpn_CheckHRAM($2, $2); + + sect_AbsByte(0xE0); + sect_RelByte($2, 1); + } + | T_Z80_LDH T_MODE_A T_COMMA c_ind { + sect_AbsByte(0xF2); + } + | T_Z80_LDH c_ind T_COMMA T_MODE_A { + sect_AbsByte(0xE2); + } +; + +c_ind: + T_LBRACK T_MODE_C T_RBRACK + | T_LBRACK relocexpr T_OP_ADD T_MODE_C T_RBRACK { + if (!$2.isKnown || $2.val != 0xFF00) + error("Expected constant expression equal to $FF00 for \"$ff00+c\"\n"); + } +; + +z80_ld: + z80_ld_mem + | z80_ld_cind + | z80_ld_rr + | z80_ld_ss + | z80_ld_hl + | z80_ld_sp + | z80_ld_r + | z80_ld_a +; + +z80_ld_hl: + T_Z80_LD T_MODE_HL T_COMMA T_MODE_SP reloc_8bit_offset { + sect_AbsByte(0xF8); + sect_RelByte($5, 1); + } + | T_Z80_LD T_MODE_HL T_COMMA reloc_16bit { + sect_AbsByte(0x01 | (REG_HL << 4)); + sect_RelWord($4, 1); + } +; + +z80_ld_sp: + T_Z80_LD T_MODE_SP T_COMMA T_MODE_HL { + sect_AbsByte(0xF9); + } + | T_Z80_LD T_MODE_SP T_COMMA reloc_16bit { + sect_AbsByte(0x01 | (REG_SP << 4)); + sect_RelWord($4, 1); + } +; + +z80_ld_mem: + T_Z80_LD op_mem_ind T_COMMA T_MODE_SP { + sect_AbsByte(0x08); + sect_RelWord($2, 1); + } + | T_Z80_LD op_mem_ind T_COMMA T_MODE_A { + if (optimizeLoads && $2.isKnown && $2.val >= 0xFF00) { + if (warnOnLdOpt) { + warnOnLdOpt = false; + warning( + WARNING_OBSOLETE, + "Automatic `ld` to `ldh` optimization (option 'l') is deprecated\n" + ); + } + sect_AbsByte(0xE0); + sect_AbsByte($2.val & 0xFF); + rpn_Free($2); + } else { + sect_AbsByte(0xEA); + sect_RelWord($2, 1); } + } ; -z80_sub : T_Z80_SUB op_a_n { - sect_AbsByte(0xD6); - sect_RelByte($2, 1); +z80_ld_cind: + T_Z80_LD c_ind T_COMMA T_MODE_A { + sect_AbsByte(0xE2); + } +; + +z80_ld_rr: + T_Z80_LD reg_rr T_COMMA T_MODE_A { + sect_AbsByte(0x02 | ($2 << 4)); + } +; + +z80_ld_r: + T_Z80_LD reg_r T_COMMA reloc_8bit { + sect_AbsByte(0x06 | ($2 << 3)); + sect_RelByte($4, 1); + } + | T_Z80_LD reg_r T_COMMA reg_r { + if (($2 == REG_HL_IND) && ($4 == REG_HL_IND)) + error("LD [HL],[HL] not a valid instruction\n"); + else + sect_AbsByte(0x40 | ($2 << 3) | $4); + } +; + +z80_ld_a: + T_Z80_LD reg_r T_COMMA c_ind { + if ($2 == REG_A) + sect_AbsByte(0xF2); + else + error("Destination operand must be A\n"); + } + | T_Z80_LD reg_r T_COMMA reg_rr { + if ($2 == REG_A) + sect_AbsByte(0x0A | ($4 << 4)); + else + error("Destination operand must be A\n"); + } + | T_Z80_LD reg_r T_COMMA op_mem_ind { + if ($2 == REG_A) { + if (optimizeLoads && $4.isKnown && $4.val >= 0xFF00) { + if (warnOnLdOpt) { + warnOnLdOpt = false; + warning( + WARNING_OBSOLETE, + "Automatic `ld` to `ldh` optimization (option 'l') is deprecated\n" + ); + } + sect_AbsByte(0xF0); + sect_AbsByte($4.val & 0xFF); + rpn_Free($4); + } else { + sect_AbsByte(0xFA); + sect_RelWord($4, 1); + } + } else { + error("Destination operand must be A\n"); + rpn_Free($4); } - | T_Z80_SUB op_a_r { sect_AbsByte(0x90 | $2); } + } ; -z80_swap : T_Z80_SWAP reg_r { - sect_AbsByte(0xCB); - sect_AbsByte(0x30 | $2); - } +z80_ld_ss: + T_Z80_LD T_MODE_BC T_COMMA reloc_16bit { + sect_AbsByte(0x01 | (REG_BC << 4)); + sect_RelWord($4, 1); + } + | T_Z80_LD T_MODE_DE T_COMMA reloc_16bit { + sect_AbsByte(0x01 | (REG_DE << 4)); + sect_RelWord($4, 1); + } + // HL is taken care of in z80_ld_hl + // SP is taken care of in z80_ld_sp ; -z80_xor : T_Z80_XOR op_a_n { - sect_AbsByte(0xEE); - sect_RelByte($2, 1); - } - | T_Z80_XOR op_a_r { sect_AbsByte(0xA8 | $2); } +z80_nop: + T_Z80_NOP { + sect_AbsByte(0x00); + } ; -op_mem_ind : T_LBRACK reloc_16bit T_RBRACK { $$ = $2; } +z80_or: + T_Z80_OR op_a_n { + sect_AbsByte(0xF6); + sect_RelByte($2, 1); + } + | T_Z80_OR op_a_r { + sect_AbsByte(0xB0 | $2); + } ; -op_a_r : reg_r - | T_MODE_A T_COMMA reg_r { $$ = $3; } +z80_pop: + T_Z80_POP reg_tt { + sect_AbsByte(0xC1 | ($2 << 4)); + } ; -op_a_n : reloc_8bit - | T_MODE_A T_COMMA reloc_8bit { $$ = $3; } +z80_push: + T_Z80_PUSH reg_tt { + sect_AbsByte(0xC5 | ($2 << 4)); + } ; -T_MODE_A : T_TOKEN_A - | T_OP_HIGH T_LPAREN T_MODE_AF T_RPAREN +z80_res: + T_Z80_RES const_3bit T_COMMA reg_r { + sect_AbsByte(0xCB); + sect_AbsByte(0x80 | ($2 << 3) | $4); + } ; -T_MODE_B : T_TOKEN_B - | T_OP_HIGH T_LPAREN T_MODE_BC T_RPAREN +z80_ret: + T_Z80_RET { + sect_AbsByte(0xC9); + } + | T_Z80_RET ccode_expr { + sect_AbsByte(0xC0 | ($2 << 3)); + } ; -T_MODE_C : T_TOKEN_C - | T_OP_LOW T_LPAREN T_MODE_BC T_RPAREN +z80_reti: + T_Z80_RETI { + sect_AbsByte(0xD9); + } ; -T_MODE_D : T_TOKEN_D - | T_OP_HIGH T_LPAREN T_MODE_DE T_RPAREN +z80_rl: + T_Z80_RL reg_r { + sect_AbsByte(0xCB); + sect_AbsByte(0x10 | $2); + } ; -T_MODE_E : T_TOKEN_E - | T_OP_LOW T_LPAREN T_MODE_DE T_RPAREN +z80_rla: + T_Z80_RLA { + sect_AbsByte(0x17); + } ; -T_MODE_H : T_TOKEN_H - | T_OP_HIGH T_LPAREN T_MODE_HL T_RPAREN +z80_rlc: + T_Z80_RLC reg_r { + sect_AbsByte(0xCB); + sect_AbsByte(0x00 | $2); + } ; -T_MODE_L : T_TOKEN_L - | T_OP_LOW T_LPAREN T_MODE_HL T_RPAREN +z80_rlca: + T_Z80_RLCA { + sect_AbsByte(0x07); + } ; -ccode_expr : ccode - | T_OP_LOGICNOT ccode_expr { - $$ = $2 ^ 1; - } +z80_rr: + T_Z80_RR reg_r { + sect_AbsByte(0xCB); + sect_AbsByte(0x18 | $2); + } ; -ccode : T_CC_NZ { $$ = CC_NZ; } - | T_CC_Z { $$ = CC_Z; } - | T_CC_NC { $$ = CC_NC; } - | T_TOKEN_C { $$ = CC_C; } +z80_rra: + T_Z80_RRA { + sect_AbsByte(0x1F); + } ; -reg_r : T_MODE_B { $$ = REG_B; } - | T_MODE_C { $$ = REG_C; } - | T_MODE_D { $$ = REG_D; } - | T_MODE_E { $$ = REG_E; } - | T_MODE_H { $$ = REG_H; } - | T_MODE_L { $$ = REG_L; } - | T_LBRACK T_MODE_HL T_RBRACK { $$ = REG_HL_IND; } - | T_MODE_A { $$ = REG_A; } +z80_rrc: + T_Z80_RRC reg_r { + sect_AbsByte(0xCB); + sect_AbsByte(0x08 | $2); + } ; -reg_tt : T_MODE_BC { $$ = REG_BC; } - | T_MODE_DE { $$ = REG_DE; } - | T_MODE_HL { $$ = REG_HL; } - | T_MODE_AF { $$ = REG_AF; } +z80_rrca: + T_Z80_RRCA { + sect_AbsByte(0x0F); + } ; -reg_ss : T_MODE_BC { $$ = REG_BC; } - | T_MODE_DE { $$ = REG_DE; } - | T_MODE_HL { $$ = REG_HL; } - | T_MODE_SP { $$ = REG_SP; } +z80_rst: + T_Z80_RST reloc_8bit { + rpn_CheckRST($2, $2); + if (!$2.isKnown) + sect_RelByte($2, 0); + else + sect_AbsByte(0xC7 | $2.val); + rpn_Free($2); + } ; -reg_rr : T_LBRACK T_MODE_BC T_RBRACK { $$ = REG_BC_IND; } - | T_LBRACK T_MODE_DE T_RBRACK { $$ = REG_DE_IND; } - | hl_ind_inc { $$ = REG_HL_INDINC; } - | hl_ind_dec { $$ = REG_HL_INDDEC; } +z80_sbc: + T_Z80_SBC op_a_n { + sect_AbsByte(0xDE); + sect_RelByte($2, 1); + } + | T_Z80_SBC op_a_r { + sect_AbsByte(0x98 | $2); + } ; -hl_ind_inc : T_LBRACK T_MODE_HL_INC T_RBRACK - | T_LBRACK T_MODE_HL T_OP_ADD T_RBRACK +z80_scf: + T_Z80_SCF { + sect_AbsByte(0x37); + } ; -hl_ind_dec : T_LBRACK T_MODE_HL_DEC T_RBRACK - | T_LBRACK T_MODE_HL T_OP_SUB T_RBRACK +z80_set: + T_Z80_SET const_3bit T_COMMA reg_r { + sect_AbsByte(0xCB); + sect_AbsByte(0xC0 | ($2 << 3) | $4); + } +; + +z80_sla: + T_Z80_SLA reg_r { + sect_AbsByte(0xCB); + sect_AbsByte(0x20 | $2); + } +; + +z80_sra: + T_Z80_SRA reg_r { + sect_AbsByte(0xCB); + sect_AbsByte(0x28 | $2); + } +; + +z80_srl: + T_Z80_SRL reg_r { + sect_AbsByte(0xCB); + sect_AbsByte(0x38 | $2); + } +; + +z80_stop: + T_Z80_STOP { + sect_AbsByte(0x10); + sect_AbsByte(0x00); + } + | T_Z80_STOP reloc_8bit { + sect_AbsByte(0x10); + sect_RelByte($2, 1); + } +; + +z80_sub: + T_Z80_SUB op_a_n { + sect_AbsByte(0xD6); + sect_RelByte($2, 1); + } + | T_Z80_SUB op_a_r { + sect_AbsByte(0x90 | $2); + } +; + +z80_swap: + T_Z80_SWAP reg_r { + sect_AbsByte(0xCB); + sect_AbsByte(0x30 | $2); + } +; + +z80_xor: + T_Z80_XOR op_a_n { + sect_AbsByte(0xEE); + sect_RelByte($2, 1); + } + | T_Z80_XOR op_a_r { + sect_AbsByte(0xA8 | $2); + } +; + +// Registers or values. + +op_mem_ind: + T_LBRACK reloc_16bit T_RBRACK { + $$ = $2; + } +; + +op_a_r: + reg_r + | T_MODE_A T_COMMA reg_r { + $$ = $3; + } +; + +op_a_n: + reloc_8bit + | T_MODE_A T_COMMA reloc_8bit { + $$ = $3; + } +; + +// Registers and condition codes. + +T_MODE_A: + T_TOKEN_A + | T_OP_HIGH T_LPAREN T_MODE_AF T_RPAREN +; + +T_MODE_B: + T_TOKEN_B + | T_OP_HIGH T_LPAREN T_MODE_BC T_RPAREN +; + +T_MODE_C: + T_TOKEN_C + | T_OP_LOW T_LPAREN T_MODE_BC T_RPAREN +; + +T_MODE_D: + T_TOKEN_D + | T_OP_HIGH T_LPAREN T_MODE_DE T_RPAREN +; + +T_MODE_E: + T_TOKEN_E + | T_OP_LOW T_LPAREN T_MODE_DE T_RPAREN +; + +T_MODE_H: + T_TOKEN_H + | T_OP_HIGH T_LPAREN T_MODE_HL T_RPAREN +; + +T_MODE_L: + T_TOKEN_L + | T_OP_LOW T_LPAREN T_MODE_HL T_RPAREN +; + +ccode_expr: + ccode + | T_OP_LOGICNOT ccode_expr { + $$ = $2 ^ 1; + } +; + +ccode: + T_CC_NZ { + $$ = CC_NZ; + } + | T_CC_Z { + $$ = CC_Z; + } + | T_CC_NC { + $$ = CC_NC; + } + | T_TOKEN_C { + $$ = CC_C; + } +; + +reg_r: + T_MODE_B { + $$ = REG_B; + } + | T_MODE_C { + $$ = REG_C; + } + | T_MODE_D { + $$ = REG_D; + } + | T_MODE_E { + $$ = REG_E; + } + | T_MODE_H { + $$ = REG_H; + } + | T_MODE_L { + $$ = REG_L; + } + | T_LBRACK T_MODE_HL T_RBRACK { + $$ = REG_HL_IND; + } + | T_MODE_A { + $$ = REG_A; + } +; + +reg_tt: + T_MODE_BC { + $$ = REG_BC; + } + | T_MODE_DE { + $$ = REG_DE; + } + | T_MODE_HL { + $$ = REG_HL; + } + | T_MODE_AF { + $$ = REG_AF; + } +; + +reg_ss: + T_MODE_BC { + $$ = REG_BC; + } + | T_MODE_DE { + $$ = REG_DE; + } + | T_MODE_HL { + $$ = REG_HL; + } + | T_MODE_SP { + $$ = REG_SP; + } +; + +reg_rr: + T_LBRACK T_MODE_BC T_RBRACK { + $$ = REG_BC_IND; + } + | T_LBRACK T_MODE_DE T_RBRACK { + $$ = REG_DE_IND; + } + | hl_ind_inc { + $$ = REG_HL_INDINC; + } + | hl_ind_dec { + $$ = REG_HL_INDDEC; + } +; + +hl_ind_inc: + T_LBRACK T_MODE_HL_INC T_RBRACK + | T_LBRACK T_MODE_HL T_OP_ADD T_RBRACK +; + +hl_ind_dec: + T_LBRACK T_MODE_HL_DEC T_RBRACK + | T_LBRACK T_MODE_HL T_OP_SUB T_RBRACK ; %% -static void upperstring(char *dest, char const *src) -{ +// Semantic actions. + +static void upperstring(char *dest, char const *src) { while (*src) *dest++ = toupper(*src++); *dest = '\0'; } -static void lowerstring(char *dest, char const *src) -{ +static void lowerstring(char *dest, char const *src) { while (*src) *dest++ = tolower(*src++); *dest = '\0'; } -static uint32_t str2int2(std::vector const &s) -{ +static uint32_t str2int2(std::vector const &s) { uint32_t length = s.size(); if (length > 4) - warning(WARNING_NUMERIC_STRING_1, - "Treating string as a number ignores first %" PRIu32 " character%s\n", - length - 4, length == 5 ? "" : "s"); + warning( + WARNING_NUMERIC_STRING_1, + "Treating string as a number ignores first %" PRIu32 " character%s\n", length - 4, + length == 5 ? "" : "s" + ); else if (length > 1) - warning(WARNING_NUMERIC_STRING_2, - "Treating %" PRIu32 "-character string as a number\n", length); + warning( + WARNING_NUMERIC_STRING_2, "Treating %" PRIu32 "-character string as a number\n", length + ); uint32_t r = 0; @@ -1993,8 +2461,7 @@ static uint32_t str2int2(std::vector const &s) return r; } -static const char *strrstr(char const *s1, char const *s2) -{ +static const char *strrstr(char const *s1, char const *s2) { size_t len1 = strlen(s1); size_t len2 = strlen(s2); @@ -2008,13 +2475,11 @@ static const char *strrstr(char const *s1, char const *s2) return nullptr; } -static void errorInvalidUTF8Byte(uint8_t byte, char const *functionName) -{ +static void errorInvalidUTF8Byte(uint8_t byte, char const *functionName) { error("%s: Invalid UTF-8 byte 0x%02hhX\n", functionName, byte); } -static size_t strlenUTF8(char const *s) -{ +static size_t strlenUTF8(char const *s) { size_t len = 0; uint32_t state = 0; @@ -2039,8 +2504,7 @@ static size_t strlenUTF8(char const *s) return len; } -static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos, uint32_t len) -{ +static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos, uint32_t len) { size_t srcIndex = 0; size_t destIndex = 0; uint32_t state = 0; @@ -2065,8 +2529,9 @@ static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos // A position 1 past the end of the string is allowed, but will trigger the // "Length too big" warning below if the length is nonzero. if (!src[srcIndex] && pos > curPos) - warning(WARNING_BUILTIN_ARG, - "STRSUB: Position %" PRIu32 " is past the end of the string\n", pos); + warning( + WARNING_BUILTIN_ARG, "STRSUB: Position %" PRIu32 " is past the end of the string\n", pos + ); // Copy from source to destination. while (src[srcIndex] && destIndex < destLen - 1 && curLen < len) { @@ -2092,8 +2557,7 @@ static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos dest[destIndex] = '\0'; } -static size_t charlenUTF8(char const *str) -{ +static size_t charlenUTF8(char const *str) { size_t len; for (len = 0; charmap_ConvertNext(str, nullptr); len++) @@ -2102,8 +2566,7 @@ static size_t charlenUTF8(char const *str) return len; } -static void charsubUTF8(char *dest, char const *src, uint32_t pos) -{ +static void charsubUTF8(char *dest, char const *src, uint32_t pos) { size_t charLen = 1; // Advance to starting position in source string. @@ -2113,8 +2576,10 @@ static void charsubUTF8(char *dest, char const *src, uint32_t pos) char const *start = src; if (!charmap_ConvertNext(src, nullptr)) - warning(WARNING_BUILTIN_ARG, - "CHARSUB: Position %" PRIu32 " is past the end of the string\n", pos); + warning( + WARNING_BUILTIN_ARG, "CHARSUB: Position %" PRIu32 " is past the end of the string\n", + pos + ); // Copy from source to destination. memcpy(dest, start, src - start); @@ -2122,8 +2587,7 @@ static void charsubUTF8(char *dest, char const *src, uint32_t pos) dest[src - start] = '\0'; } -static uint32_t adjustNegativePos(int32_t pos, size_t len, char const *functionName) -{ +static uint32_t adjustNegativePos(int32_t pos, size_t len, char const *functionName) { // STRSUB and CHARSUB adjust negative `pos` arguments the same way, // such that position -1 is the last character of a string. if (pos < 0) @@ -2135,8 +2599,7 @@ static uint32_t adjustNegativePos(int32_t pos, size_t len, char const *functionN return (uint32_t)pos; } -static void strrpl(char *dest, size_t destLen, char const *src, char const *old, char const *rep) -{ +static void strrpl(char *dest, size_t destLen, char const *src, char const *old, char const *rep) { size_t oldLen = strlen(old); size_t repLen = strlen(rep); size_t i = 0; @@ -2180,27 +2643,24 @@ static void strrpl(char *dest, size_t destLen, char const *src, char const *old, dest[i] = '\0'; } -static void initStrFmtArgList(StrFmtArgList &args) -{ - args.format = new(std::nothrow) std::string(); +static void initStrFmtArgList(StrFmtArgList &args) { + args.format = new (std::nothrow) std::string(); if (!args.format) - fatalerror("Failed to allocate memory for STRFMT format string: %s\n", - strerror(errno)); - args.args = new(std::nothrow) std::vector>(); + fatalerror("Failed to allocate memory for STRFMT format string: %s\n", strerror(errno)); + args.args = new (std::nothrow) std::vector>(); if (!args.args) - fatalerror("Failed to allocate memory for STRFMT arg list: %s\n", - strerror(errno)); + fatalerror("Failed to allocate memory for STRFMT arg list: %s\n", strerror(errno)); } -static void freeStrFmtArgList(StrFmtArgList &args) -{ +static void freeStrFmtArgList(StrFmtArgList &args) { delete args.format; delete args.args; } -static void strfmt(char *dest, size_t destLen, char const *spec, - std::vector> &args) -{ +static void strfmt( + char *dest, size_t destLen, char const *spec, + std::vector> &args +) { size_t a = 0; size_t i = 0; @@ -2249,10 +2709,13 @@ static void strfmt(char *dest, size_t destLen, char const *spec, std::variant &arg = args[a++]; static char buf[MAXSTRLEN + 1]; - std::visit(Visitor{ - [&](uint32_t num) { fmt.printNumber(buf, sizeof(buf), num); }, - [&](std::string &str) { fmt.printString(buf, sizeof(buf), str.c_str()); }, - }, arg); + std::visit( + Visitor{ + [&](uint32_t num) { fmt.printNumber(buf, sizeof(buf), num); }, + [&](std::string &str) { fmt.printString(buf, sizeof(buf), str.c_str()); }, + }, + arg + ); i += snprintf(&dest[i], destLen - i, "%s", buf); } @@ -2260,8 +2723,9 @@ static void strfmt(char *dest, size_t destLen, char const *spec, if (a < args.size()) error("STRFMT: %zu unformatted argument(s)\n", args.size() - a); else if (a > args.size()) - error("STRFMT: Not enough arguments for format spec, got: %zu, need: %zu\n", - args.size(), a); + error( + "STRFMT: Not enough arguments for format spec, got: %zu, need: %zu\n", args.size(), a + ); if (i > destLen - 1) { warning(WARNING_LONG_STR, "STRFMT: String too long, got truncated\n"); @@ -2270,8 +2734,7 @@ static void strfmt(char *dest, size_t destLen, char const *spec, dest[i] = '\0'; } -static void compoundAssignment(const char *symName, enum RPNCommand op, int32_t constValue) -{ +static void compoundAssignment(const char *symName, enum RPNCommand op, int32_t constValue) { Expression oldExpr, constExpr, newExpr; int32_t newValue; @@ -2282,49 +2745,44 @@ static void compoundAssignment(const char *symName, enum RPNCommand op, int32_t sym_AddVar(symName, newValue); } -static void initDsArgList(std::vector *&args) -{ - args = new(std::nothrow) std::vector(); +static void initDsArgList(std::vector *&args) { + args = new (std::nothrow) std::vector(); if (!args) fatalerror("Failed to allocate memory for ds arg list: %s\n", strerror(errno)); } -static void initPurgeArgList(std::vector *&args) -{ - args = new(std::nothrow) std::vector(); +static void initPurgeArgList(std::vector *&args) { + args = new (std::nothrow) std::vector(); if (!args) fatalerror("Failed to allocate memory for purge arg list: %s\n", strerror(errno)); } -static void failAssert(enum AssertionType type) -{ +static void failAssert(enum AssertionType type) { switch (type) { - case ASSERT_FATAL: - fatalerror("Assertion failed\n"); - case ASSERT_ERROR: - error("Assertion failed\n"); - break; - case ASSERT_WARN: - warning(WARNING_ASSERT, "Assertion failed\n"); - break; + case ASSERT_FATAL: + fatalerror("Assertion failed\n"); + case ASSERT_ERROR: + error("Assertion failed\n"); + break; + case ASSERT_WARN: + warning(WARNING_ASSERT, "Assertion failed\n"); + break; } } -static void failAssertMsg(enum AssertionType type, char const *msg) -{ +static void failAssertMsg(enum AssertionType type, char const *msg) { switch (type) { - case ASSERT_FATAL: - fatalerror("Assertion failed: %s\n", msg); - case ASSERT_ERROR: - error("Assertion failed: %s\n", msg); - break; - case ASSERT_WARN: - warning(WARNING_ASSERT, "Assertion failed: %s\n", msg); - break; + case ASSERT_FATAL: + fatalerror("Assertion failed: %s\n", msg); + case ASSERT_ERROR: + error("Assertion failed: %s\n", msg); + break; + case ASSERT_WARN: + warning(WARNING_ASSERT, "Assertion failed: %s\n", msg); + break; } } -void yyerror(char const *str) -{ +void yyerror(char const *str) { error("%s\n", str); } diff --git a/src/asm/rpn.cpp b/src/asm/rpn.cpp index 3c8fc1cd..bad0d5c1 100644 --- a/src/asm/rpn.cpp +++ b/src/asm/rpn.cpp @@ -2,6 +2,8 @@ // Controls RPN expressions for objectfiles +#include "asm/rpn.hpp" + #include #include #include @@ -12,18 +14,16 @@ #include #include +#include "opmath.hpp" + #include "asm/main.hpp" #include "asm/output.hpp" -#include "asm/rpn.hpp" #include "asm/section.hpp" #include "asm/symbol.hpp" #include "asm/warning.hpp" -#include "opmath.hpp" - // Init a RPN expression -static void initExpression(Expression &expr) -{ +static void initExpression(Expression &expr) { expr.reason = nullptr; expr.isKnown = true; expr.isSymbol = false; @@ -33,8 +33,7 @@ static void initExpression(Expression &expr) // Makes an expression "not known", also setting its error message template -static void makeUnknown(Expression &expr, Ts ...parts) -{ +static void makeUnknown(Expression &expr, Ts... parts) { expr.isKnown = false; expr.reason = new std::string(); if (!expr.reason) @@ -42,10 +41,9 @@ static void makeUnknown(Expression &expr, Ts ...parts) (expr.reason->append(parts), ...); } -static uint8_t *reserveSpace(Expression &expr, uint32_t size) -{ +static uint8_t *reserveSpace(Expression &expr, uint32_t size) { if (!expr.rpn) { - expr.rpn = new(std::nothrow) std::vector(); + expr.rpn = new (std::nothrow) std::vector(); if (!expr.rpn) fatalerror("Failed to allocate RPN expression: %s\n", strerror(errno)); } @@ -57,22 +55,19 @@ static uint8_t *reserveSpace(Expression &expr, uint32_t size) } // Free the RPN expression -void rpn_Free(Expression &expr) -{ +void rpn_Free(Expression &expr) { delete expr.rpn; delete expr.reason; initExpression(expr); } // Add symbols, constants and operators to expression -void rpn_Number(Expression &expr, uint32_t val) -{ +void rpn_Number(Expression &expr, uint32_t val) { initExpression(expr); expr.val = val; } -void rpn_Symbol(Expression &expr, char const *symName) -{ +void rpn_Symbol(Expression &expr, char const *symName) { Symbol *sym = sym_FindScopedSymbol(symName); if (sym_IsPC(sym) && !sect_GetSymbolSection()) { @@ -98,8 +93,7 @@ void rpn_Symbol(Expression &expr, char const *symName) } } -static void bankSelf(Expression &expr) -{ +static void bankSelf(Expression &expr) { initExpression(expr); if (!currentSection) { @@ -114,8 +108,7 @@ static void bankSelf(Expression &expr) } } -void rpn_BankSymbol(Expression &expr, char const *symName) -{ +void rpn_BankSymbol(Expression &expr, char const *symName) { Symbol const *sym = sym_FindScopedSymbol(symName); // The @ symbol is treated differently. @@ -147,8 +140,7 @@ void rpn_BankSymbol(Expression &expr, char const *symName) } } -void rpn_BankSection(Expression &expr, char const *sectionName) -{ +void rpn_BankSection(Expression &expr, char const *sectionName) { initExpression(expr); Section *section = sect_FindSectionByName(sectionName); @@ -167,8 +159,7 @@ void rpn_BankSection(Expression &expr, char const *sectionName) } } -void rpn_SizeOfSection(Expression &expr, char const *sectionName) -{ +void rpn_SizeOfSection(Expression &expr, char const *sectionName) { initExpression(expr); Section *section = sect_FindSectionByName(sectionName); @@ -187,8 +178,7 @@ void rpn_SizeOfSection(Expression &expr, char const *sectionName) } } -void rpn_StartOfSection(Expression &expr, char const *sectionName) -{ +void rpn_StartOfSection(Expression &expr, char const *sectionName) { initExpression(expr); Section *section = sect_FindSectionByName(sectionName); @@ -207,8 +197,7 @@ void rpn_StartOfSection(Expression &expr, char const *sectionName) } } -void rpn_SizeOfSectionType(Expression &expr, enum SectionType type) -{ +void rpn_SizeOfSectionType(Expression &expr, enum SectionType type) { initExpression(expr); makeUnknown(expr, "Section type's size is not known"); @@ -219,8 +208,7 @@ void rpn_SizeOfSectionType(Expression &expr, enum SectionType type) *ptr++ = type; } -void rpn_StartOfSectionType(Expression &expr, enum SectionType type) -{ +void rpn_StartOfSectionType(Expression &expr, enum SectionType type) { initExpression(expr); makeUnknown(expr, "Section type's start is not known"); @@ -231,8 +219,7 @@ void rpn_StartOfSectionType(Expression &expr, enum SectionType type) *ptr++ = type; } -void rpn_CheckHRAM(Expression &expr, const Expression &src) -{ +void rpn_CheckHRAM(Expression &expr, const Expression &src) { expr = src; expr.isSymbol = false; @@ -247,8 +234,7 @@ void rpn_CheckHRAM(Expression &expr, const Expression &src) } } -void rpn_CheckRST(Expression &expr, const Expression &src) -{ +void rpn_CheckRST(Expression &expr, const Expression &src) { expr = src; if (expr.isKnown) { @@ -264,9 +250,8 @@ void rpn_CheckRST(Expression &expr, const Expression &src) } // Checks that an RPN expression's value fits within N bits (signed or unsigned) -void rpn_CheckNBit(Expression const &expr, uint8_t n) -{ - assert(n != 0); // That doesn't make sense +void rpn_CheckNBit(Expression const &expr, uint8_t n) { + assert(n != 0); // That doesn't make sense assert(n < CHAR_BIT * sizeof(int)); // Otherwise `1 << n` is UB if (expr.isKnown) { @@ -279,8 +264,7 @@ void rpn_CheckNBit(Expression const &expr, uint8_t n) } } -int32_t Expression::getConstVal() const -{ +int32_t Expression::getConstVal() const { if (!isKnown) { error("Expected constant expression: %s\n", reason->c_str()); return 0; @@ -288,8 +272,7 @@ int32_t Expression::getConstVal() const return val; } -void rpn_LOGNOT(Expression &expr, const Expression &src) -{ +void rpn_LOGNOT(Expression &expr, const Expression &src) { expr = src; expr.isSymbol = false; @@ -301,15 +284,13 @@ void rpn_LOGNOT(Expression &expr, const Expression &src) } } -Symbol const *Expression::symbolOf() const -{ +Symbol const *Expression::symbolOf() const { if (!isSymbol) return nullptr; return sym_FindScopedSymbol((char const *)&(*rpn)[1]); } -bool Expression::isDiffConstant(Symbol const *sym) const -{ +bool Expression::isDiffConstant(Symbol const *sym) const { // Check if both expressions only refer to a single symbol Symbol const *sym1 = symbolOf(); @@ -328,8 +309,7 @@ bool Expression::isDiffConstant(Symbol const *sym) const * * @return The constant result if it can be computed, or -1 otherwise. */ -static int32_t tryConstMask(Expression const &lhs, Expression const &rhs) -{ +static int32_t tryConstMask(Expression const &lhs, Expression const &rhs) { Symbol const *lhsSymbol = lhs.symbolOf(); Symbol const *rhsSymbol = lhsSymbol ? nullptr : rhs.symbolOf(); bool lhsIsSymbol = lhsSymbol && lhsSymbol->getSection(); @@ -362,8 +342,9 @@ static int32_t tryConstMask(Expression const &lhs, Expression const &rhs) return (symbolOfs + sect.alignOfs) & ~unknownBits; } -void rpn_BinaryOp(enum RPNCommand op, Expression &expr, const Expression &src1, const Expression &src2) -{ +void rpn_BinaryOp( + enum RPNCommand op, Expression &expr, const Expression &src1, const Expression &src2 +) { expr.isSymbol = false; int32_t constMaskVal; @@ -417,43 +398,47 @@ void rpn_BinaryOp(enum RPNCommand op, Expression &expr, const Expression &src1, break; case RPN_SHL: if (src2.val < 0) - warning(WARNING_SHIFT_AMOUNT, - "Shifting left by negative amount %" PRId32 "\n", - src2.val); + warning( + WARNING_SHIFT_AMOUNT, "Shifting left by negative amount %" PRId32 "\n", src2.val + ); if (src2.val >= 32) - warning(WARNING_SHIFT_AMOUNT, - "Shifting left by large amount %" PRId32 "\n", src2.val); + warning( + WARNING_SHIFT_AMOUNT, "Shifting left by large amount %" PRId32 "\n", src2.val + ); expr.val = op_shift_left(src1.val, src2.val); break; case RPN_SHR: if (src1.val < 0) - warning(WARNING_SHIFT, - "Shifting right negative value %" PRId32 "\n", src1.val); + warning(WARNING_SHIFT, "Shifting right negative value %" PRId32 "\n", src1.val); if (src2.val < 0) - warning(WARNING_SHIFT_AMOUNT, - "Shifting right by negative amount %" PRId32 "\n", - src2.val); + warning( + WARNING_SHIFT_AMOUNT, + "Shifting right by negative amount %" PRId32 "\n", + src2.val + ); if (src2.val >= 32) - warning(WARNING_SHIFT_AMOUNT, - "Shifting right by large amount %" PRId32 "\n", - src2.val); + warning( + WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32 "\n", src2.val + ); expr.val = op_shift_right(src1.val, src2.val); break; case RPN_USHR: if (src2.val < 0) - warning(WARNING_SHIFT_AMOUNT, - "Shifting right by negative amount %" PRId32 "\n", - src2.val); + warning( + WARNING_SHIFT_AMOUNT, + "Shifting right by negative amount %" PRId32 "\n", + src2.val + ); if (src2.val >= 32) - warning(WARNING_SHIFT_AMOUNT, - "Shifting right by large amount %" PRId32 "\n", - src2.val); + warning( + WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32 "\n", src2.val + ); expr.val = op_shift_right_unsigned(src1.val, src2.val); break; @@ -465,9 +450,12 @@ void rpn_BinaryOp(enum RPNCommand op, Expression &expr, const Expression &src1, fatalerror("Division by zero\n"); if (src1.val == INT32_MIN && src2.val == -1) { - warning(WARNING_DIV, - "Division of %" PRId32 " by -1 yields %" PRId32 "\n", - INT32_MIN, INT32_MIN); + warning( + WARNING_DIV, + "Division of %" PRId32 " by -1 yields %" PRId32 "\n", + INT32_MIN, + INT32_MIN + ); expr.val = INT32_MIN; } else { expr.val = op_divide(src1.val, src2.val); @@ -521,8 +509,13 @@ void rpn_BinaryOp(enum RPNCommand op, Expression &expr, const Expression &src1, // Convert the left-hand expression if it's constant if (src1.isKnown) { uint32_t lval = src1.val; - uint8_t bytes[] = {RPN_CONST, (uint8_t)lval, (uint8_t)(lval >> 8), - (uint8_t)(lval >> 16), (uint8_t)(lval >> 24)}; + uint8_t bytes[] = { + RPN_CONST, + (uint8_t)lval, + (uint8_t)(lval >> 8), + (uint8_t)(lval >> 16), + (uint8_t)(lval >> 24), + }; expr.rpnPatchSize = sizeof(bytes); expr.rpn = nullptr; memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes)); @@ -545,8 +538,13 @@ void rpn_BinaryOp(enum RPNCommand op, Expression &expr, const Expression &src1, // If the right expression is constant, merge a shim instead uint32_t rval = src2.val; - uint8_t bytes[] = {RPN_CONST, (uint8_t)rval, (uint8_t)(rval >> 8), - (uint8_t)(rval >> 16), (uint8_t)(rval >> 24)}; + uint8_t bytes[] = { + RPN_CONST, + (uint8_t)rval, + (uint8_t)(rval >> 8), + (uint8_t)(rval >> 16), + (uint8_t)(rval >> 24), + }; if (src2.isKnown) { ptr = bytes; len = sizeof(bytes); @@ -569,23 +567,20 @@ void rpn_BinaryOp(enum RPNCommand op, Expression &expr, const Expression &src1, } } -void rpn_HIGH(Expression &expr, const Expression &src) -{ +void rpn_HIGH(Expression &expr, const Expression &src) { expr = src; expr.isSymbol = false; if (expr.isKnown) { expr.val = (uint32_t)expr.val >> 8 & 0xFF; } else { - uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR, - RPN_CONST, 0xFF, 0, 0, 0, RPN_AND}; + uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR, RPN_CONST, 0xFF, 0, 0, 0, RPN_AND}; expr.rpnPatchSize += sizeof(bytes); memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes)); } } -void rpn_LOW(Expression &expr, const Expression &src) -{ +void rpn_LOW(Expression &expr, const Expression &src) { expr = src; expr.isSymbol = false; @@ -599,16 +594,14 @@ void rpn_LOW(Expression &expr, const Expression &src) } } -void rpn_ISCONST(Expression &expr, const Expression &src) -{ +void rpn_ISCONST(Expression &expr, const Expression &src) { initExpression(expr); expr.val = src.isKnown; expr.isKnown = true; expr.isSymbol = false; } -void rpn_NEG(Expression &expr, const Expression &src) -{ +void rpn_NEG(Expression &expr, const Expression &src) { expr = src; expr.isSymbol = false; @@ -620,8 +613,7 @@ void rpn_NEG(Expression &expr, const Expression &src) } } -void rpn_NOT(Expression &expr, const Expression &src) -{ +void rpn_NOT(Expression &expr, const Expression &src) { expr = src; expr.isSymbol = false; diff --git a/src/asm/section.cpp b/src/asm/section.cpp index 9bf89dcc..183fb89f 100644 --- a/src/asm/section.cpp +++ b/src/asm/section.cpp @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: MIT */ +#include "asm/section.hpp" + #include #include #include @@ -9,21 +11,20 @@ #include #include #include -#include #include +#include #include +#include "error.hpp" +#include "linkdefs.hpp" + #include "asm/fstack.hpp" #include "asm/main.hpp" #include "asm/output.hpp" #include "asm/rpn.hpp" -#include "asm/section.hpp" #include "asm/symbol.hpp" #include "asm/warning.hpp" -#include "error.hpp" -#include "linkdefs.hpp" - uint8_t fillByte; struct UnionStackEntry { @@ -50,8 +51,7 @@ char const *currentLoadScope = nullptr; int32_t loadOffset; // Offset into the LOAD section's parent (see sect_GetOutputOffset) // A quick check to see if we have an initialized section -attr_(warn_unused_result) static bool checksection() -{ +attr_(warn_unused_result) static bool checksection() { if (currentSection) return true; @@ -61,35 +61,38 @@ attr_(warn_unused_result) static bool checksection() // A quick check to see if we have an initialized section that can contain // this much initialized data -attr_(warn_unused_result) static bool checkcodesection() -{ +attr_(warn_unused_result) static bool checkcodesection() { if (!checksection()) return false; if (sect_HasData(currentSection->type)) return true; - error("Section '%s' cannot contain code or data (not ROM0 or ROMX)\n", - currentSection->name.c_str()); + error( + "Section '%s' cannot contain code or data (not ROM0 or ROMX)\n", + currentSection->name.c_str() + ); return false; } -attr_(warn_unused_result) static bool checkSectionSize(Section const §, uint32_t size) -{ +attr_(warn_unused_result) static bool checkSectionSize(Section const §, uint32_t size) { uint32_t maxSize = sectionTypeInfo[sect.type].size; // If the new size is reasonable, keep going if (size <= maxSize) return true; - error("Section '%s' grew too big (max size = 0x%" PRIX32 - " bytes, reached 0x%" PRIX32 ").\n", sect.name.c_str(), maxSize, size); + error( + "Section '%s' grew too big (max size = 0x%" PRIX32 " bytes, reached 0x%" PRIX32 ").\n", + sect.name.c_str(), + maxSize, + size + ); return false; } // Check if the section has grown too much. -attr_(warn_unused_result) static bool reserveSpace(uint32_t delta_size) -{ +attr_(warn_unused_result) static bool reserveSpace(uint32_t delta_size) { // This check is here to trap broken code that generates sections that are too big and to // prevent the assembler from generating huge object files or trying to allocate too much // memory. @@ -97,20 +100,19 @@ attr_(warn_unused_result) static bool reserveSpace(uint32_t delta_size) // If the section has already overflowed, skip the check to avoid erroring out ad nauseam if (currentSection->size != UINT32_MAX - && !checkSectionSize(*currentSection, curOffset + loadOffset + delta_size)) + && !checkSectionSize(*currentSection, curOffset + loadOffset + delta_size)) // Mark the section as overflowed, to avoid repeating the error currentSection->size = UINT32_MAX; if (currentLoadSection && currentLoadSection->size != UINT32_MAX - && !checkSectionSize(*currentLoadSection, curOffset + delta_size)) + && !checkSectionSize(*currentLoadSection, curOffset + delta_size)) currentLoadSection->size = UINT32_MAX; return currentSection->size != UINT32_MAX - && (!currentLoadSection || currentLoadSection->size != UINT32_MAX); + && (!currentLoadSection || currentLoadSection->size != UINT32_MAX); } -Section *sect_FindSectionByName(char const *name) -{ +Section *sect_FindSectionByName(char const *name) { for (Section § : sectionList) { if (sect.name == name) return § @@ -119,14 +121,15 @@ Section *sect_FindSectionByName(char const *name) } #define mask(align) ((1U << (align)) - 1) -#define fail(...) do { \ - error(__VA_ARGS__); \ - nbSectErrors++; \ -} while (0) +#define fail(...) \ + do { \ + error(__VA_ARGS__); \ + nbSectErrors++; \ + } while (0) -static unsigned int mergeSectUnion(Section §, enum SectionType type, uint32_t org, - uint8_t alignment, uint16_t alignOffset) -{ +static unsigned int mergeSectUnion( + Section §, enum SectionType type, uint32_t org, uint8_t alignment, uint16_t alignOffset +) { assert(alignment < 16); // Should be ensured by the caller unsigned int nbSectErrors = 0; @@ -138,11 +141,15 @@ static unsigned int mergeSectUnion(Section §, enum SectionType type, uint32_ if (org != (uint32_t)-1) { // If both are fixed, they must be the same if (sect.org != (uint32_t)-1 && sect.org != org) - fail("Section already declared as fixed at different address $%04" - PRIx32 "\n", sect.org); + fail( + "Section already declared as fixed at different address $%04" PRIx32 "\n", sect.org + ); else if (sect.align != 0 && (mask(sect.align) & (org - sect.alignOfs))) - fail("Section already declared as aligned to %u bytes (offset %" - PRIu16 ")\n", 1U << sect.align, sect.alignOfs); + fail( + "Section already declared as aligned to %u bytes (offset %" PRIu16 ")\n", + 1U << sect.align, + sect.alignOfs + ); else // Otherwise, just override sect.org = org; @@ -151,13 +158,18 @@ static unsigned int mergeSectUnion(Section §, enum SectionType type, uint32_ // Make sure any fixed address given is compatible if (sect.org != (uint32_t)-1) { if ((sect.org - alignOffset) & mask(alignment)) - fail("Section already declared as fixed at incompatible address $%04" - PRIx32 "\n", sect.org); - // Check if alignment offsets are compatible + fail( + "Section already declared as fixed at incompatible address $%04" PRIx32 "\n", + sect.org + ); + // Check if alignment offsets are compatible } else if ((alignOffset & mask(sect.align)) != (sect.alignOfs & mask(alignment))) { - fail("Section already declared with incompatible %u" - "-byte alignment (offset %" PRIu16 ")\n", - 1U << sect.align, sect.alignOfs); + fail( + "Section already declared with incompatible %u" + "-byte alignment (offset %" PRIu16 ")\n", + 1U << sect.align, + sect.alignOfs + ); } else if (alignment > sect.align) { // If the section is not fixed, its alignment is the largest of both sect.align = alignment; @@ -168,8 +180,8 @@ static unsigned int mergeSectUnion(Section §, enum SectionType type, uint32_ return nbSectErrors; } -static unsigned int mergeFragments(Section §, uint32_t org, uint8_t alignment, uint16_t alignOffset) -{ +static unsigned int + mergeFragments(Section §, uint32_t org, uint8_t alignment, uint16_t alignOffset) { assert(alignment < 16); // Should be ensured by the caller unsigned int nbSectErrors = 0; @@ -181,11 +193,16 @@ static unsigned int mergeFragments(Section §, uint32_t org, uint8_t alignmen // If both are fixed, they must be the same if (sect.org != (uint32_t)-1 && sect.org != curOrg) - fail("Section already declared as fixed at incompatible address $%04" - PRIx32 "\n", sect.org); + fail( + "Section already declared as fixed at incompatible address $%04" PRIx32 "\n", + sect.org + ); else if (sect.align != 0 && (mask(sect.align) & (curOrg - sect.alignOfs))) - fail("Section already declared as aligned to %u bytes (offset %" - PRIu16 ")\n", 1U << sect.align, sect.alignOfs); + fail( + "Section already declared as aligned to %u bytes (offset %" PRIu16 ")\n", + 1U << sect.align, + sect.alignOfs + ); else // Otherwise, just override sect.org = curOrg; @@ -199,13 +216,18 @@ static unsigned int mergeFragments(Section §, uint32_t org, uint8_t alignmen // Make sure any fixed address given is compatible if (sect.org != (uint32_t)-1) { if ((sect.org - curOfs) & mask(alignment)) - fail("Section already declared as fixed at incompatible address $%04" - PRIx32 "\n", sect.org); - // Check if alignment offsets are compatible + fail( + "Section already declared as fixed at incompatible address $%04" PRIx32 "\n", + sect.org + ); + // Check if alignment offsets are compatible } else if ((curOfs & mask(sect.align)) != (sect.alignOfs & mask(alignment))) { - fail("Section already declared with incompatible %u" - "-byte alignment (offset %" PRIu16 ")\n", - 1U << sect.align, sect.alignOfs); + fail( + "Section already declared with incompatible %u" + "-byte alignment (offset %" PRIu16 ")\n", + 1U << sect.align, + sect.alignOfs + ); } else if (alignment > sect.align) { // If the section is not fixed, its alignment is the largest of both sect.align = alignment; @@ -216,9 +238,15 @@ static unsigned int mergeFragments(Section §, uint32_t org, uint8_t alignmen return nbSectErrors; } -static void mergeSections(Section §, enum SectionType type, uint32_t org, uint32_t bank, - uint8_t alignment, uint16_t alignOffset, enum SectionModifier mod) -{ +static void mergeSections( + Section §, + enum SectionType type, + uint32_t org, + uint32_t bank, + uint8_t alignment, + uint16_t alignOffset, + enum SectionModifier mod +) { unsigned int nbSectErrors = 0; if (type != sect.type) @@ -230,9 +258,9 @@ static void mergeSections(Section §, enum SectionType type, uint32_t org, ui switch (mod) { case SECTION_UNION: case SECTION_FRAGMENT: - nbSectErrors += mod == SECTION_UNION ? - mergeSectUnion(sect, type, org, alignment, alignOffset) : - mergeFragments(sect, org, alignment, alignOffset); + nbSectErrors += mod == SECTION_UNION + ? mergeSectUnion(sect, type, org, alignment, alignOffset) + : mergeFragments(sect, org, alignment, alignOffset); // Common checks @@ -241,8 +269,7 @@ static void mergeSections(Section §, enum SectionType type, uint32_t org, ui sect.bank = bank; // If both specify a bank, it must be the same one else if (bank != (uint32_t)-1 && sect.bank != bank) - fail("Section already declared with different bank %" PRIu32 "\n", - sect.bank); + fail("Section already declared with different bank %" PRIu32 "\n", sect.bank); break; case SECTION_NORMAL: @@ -254,16 +281,26 @@ static void mergeSections(Section §, enum SectionType type, uint32_t org, ui } if (nbSectErrors) - fatalerror("Cannot create section \"%s\" (%u error%s)\n", - sect.name.c_str(), nbSectErrors, nbSectErrors == 1 ? "" : "s"); + fatalerror( + "Cannot create section \"%s\" (%u error%s)\n", + sect.name.c_str(), + nbSectErrors, + nbSectErrors == 1 ? "" : "s" + ); } #undef fail // Create a new section, not yet in the list. -static Section *createSection(char const *name, enum SectionType type, uint32_t org, uint32_t bank, - uint8_t alignment, uint16_t alignOffset, enum SectionModifier mod) -{ +static Section *createSection( + char const *name, + enum SectionType type, + uint32_t org, + uint32_t bank, + uint8_t alignment, + uint16_t alignOffset, + enum SectionModifier mod +) { // Add the new section to the list (order doesn't matter) Section § = sectionList.emplace_front(); @@ -286,9 +323,13 @@ static Section *createSection(char const *name, enum SectionType type, uint32_t } // Find a section by name and type. If it doesn't exist, create it. -static Section *getSection(char const *name, enum SectionType type, uint32_t org, - SectionSpec const &attrs, enum SectionModifier mod) -{ +static Section *getSection( + char const *name, + enum SectionType type, + uint32_t org, + SectionSpec const &attrs, + enum SectionModifier mod +) { uint32_t bank = attrs.bank; uint8_t alignment = attrs.alignment; uint16_t alignOffset = attrs.alignOfs; @@ -296,29 +337,41 @@ static Section *getSection(char const *name, enum SectionType type, uint32_t org // First, validate parameters, and normalize them if applicable if (bank != (uint32_t)-1) { - if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM - && type != SECTTYPE_SRAM && type != SECTTYPE_WRAMX) + if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM && type != SECTTYPE_SRAM + && type != SECTTYPE_WRAMX) error("BANK only allowed for ROMX, WRAMX, SRAM, or VRAM sections\n"); else if (bank < sectionTypeInfo[type].firstBank || bank > sectionTypeInfo[type].lastBank) - error("%s bank value $%04" PRIx32 " out of range ($%04" PRIx32 " to $%04" - PRIx32 ")\n", sectionTypeInfo[type].name.c_str(), bank, - sectionTypeInfo[type].firstBank, sectionTypeInfo[type].lastBank); + error( + "%s bank value $%04" PRIx32 " out of range ($%04" PRIx32 " to $%04" PRIx32 ")\n", + sectionTypeInfo[type].name.c_str(), + bank, + sectionTypeInfo[type].firstBank, + sectionTypeInfo[type].lastBank + ); } else if (nbbanks(type) == 1) { // If the section type only has a single bank, implicitly force it bank = sectionTypeInfo[type].firstBank; } if (alignOffset >= 1 << alignment) { - error("Alignment offset (%" PRIu16 ") must be smaller than alignment size (%u)\n", - alignOffset, 1U << alignment); + error( + "Alignment offset (%" PRIu16 ") must be smaller than alignment size (%u)\n", + alignOffset, + 1U << alignment + ); alignOffset = 0; } if (org != (uint32_t)-1) { if (org < sectionTypeInfo[type].startAddr || org > endaddr(type)) - error("Section \"%s\"'s fixed address $%04" PRIx32 - " is outside of range [$%04" PRIx16 "; $%04" PRIx16 "]\n", - name, org, sectionTypeInfo[type].startAddr, endaddr(type)); + error( + "Section \"%s\"'s fixed address $%04" PRIx32 " is outside of range [$%04" PRIx16 + "; $%04" PRIx16 "]\n", + name, + org, + sectionTypeInfo[type].startAddr, + endaddr(type) + ); } if (alignment != 0) { @@ -331,12 +384,14 @@ static Section *getSection(char const *name, enum SectionType type, uint32_t org if (org != (uint32_t)-1) { if ((org - alignOffset) & mask) - error("Section \"%s\"'s fixed address doesn't match its alignment\n", - name); + error("Section \"%s\"'s fixed address doesn't match its alignment\n", name); alignment = 0; // Ignore it if it's satisfied } else if (sectionTypeInfo[type].startAddr & mask) { - error("Section \"%s\"'s alignment cannot be attained in %s\n", - name, sectionTypeInfo[type].name.c_str()); + error( + "Section \"%s\"'s alignment cannot be attained in %s\n", + name, + sectionTypeInfo[type].name.c_str() + ); alignment = 0; // Ignore it if it's unattainable org = 0; } else if (alignment == 16) { @@ -361,16 +416,14 @@ static Section *getSection(char const *name, enum SectionType type, uint32_t org } // Set the current section -static void changeSection() -{ +static void changeSection() { if (!currentUnionStack.empty()) fatalerror("Cannot change the section within a UNION\n"); sym_SetCurrentSymbolScope(nullptr); } -bool Section::isSizeKnown() const -{ +bool Section::isSizeKnown() const { // SECTION UNION and SECTION FRAGMENT can still grow if (modifier != SECTION_NORMAL) return false; @@ -389,9 +442,13 @@ bool Section::isSizeKnown() const } // Set the current section by name and type -void sect_NewSection(char const *name, enum SectionType type, uint32_t org, - SectionSpec const &attrs, enum SectionModifier mod) -{ +void sect_NewSection( + char const *name, + enum SectionType type, + uint32_t org, + SectionSpec const &attrs, + enum SectionModifier mod +) { if (currentLoadSection) fatalerror("Cannot change the section within a `LOAD` block\n"); @@ -409,9 +466,13 @@ void sect_NewSection(char const *name, enum SectionType type, uint32_t org, } // Set the current section by name and type -void sect_SetLoadSection(char const *name, enum SectionType type, uint32_t org, - SectionSpec const &attrs, enum SectionModifier mod) -{ +void sect_SetLoadSection( + char const *name, + enum SectionType type, + uint32_t org, + SectionSpec const &attrs, + enum SectionModifier mod +) { // Important info: currently, UNION and LOAD cannot interact, since UNION is prohibited in // "code" sections, whereas LOAD is restricted to them. // Therefore, any interactions are NOT TESTED, so lift either of those restrictions at @@ -444,8 +505,7 @@ void sect_SetLoadSection(char const *name, enum SectionType type, uint32_t org, currentLoadSection = sect; } -void sect_EndLoadSection() -{ +void sect_EndLoadSection() { if (!currentLoadSection) { error("Found `ENDL` outside of a `LOAD` block\n"); return; @@ -458,25 +518,21 @@ void sect_EndLoadSection() sym_SetCurrentSymbolScope(currentLoadScope); } -Section *sect_GetSymbolSection() -{ +Section *sect_GetSymbolSection() { return currentLoadSection ? currentLoadSection : currentSection; } // The offset into the section above -uint32_t sect_GetSymbolOffset() -{ +uint32_t sect_GetSymbolOffset() { return curOffset; } -uint32_t sect_GetOutputOffset() -{ +uint32_t sect_GetOutputOffset() { return curOffset + loadOffset; } // Returns how many bytes need outputting for the specified alignment and offset to succeed -uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset) -{ +uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset) { Section *sect = sect_GetSymbolSection(); if (!sect) return 0; @@ -492,11 +548,10 @@ uint32_t sect_GetAlignBytes(uint8_t alignment, uint16_t offset) // We need `(pcValue + curOffset + return value) % (1 << alignment) == offset` uint16_t pcValue = isFixed ? sect->org : sect->alignOfs; return static_cast(offset - curOffset - pcValue) - % (1u << std::min(alignment, curAlignment)); + % (1u << std::min(alignment, curAlignment)); } -void sect_AlignPC(uint8_t alignment, uint16_t offset) -{ +void sect_AlignPC(uint8_t alignment, uint16_t offset) { if (!checksection()) return; @@ -505,12 +560,16 @@ void sect_AlignPC(uint8_t alignment, uint16_t offset) if (sect->org != (uint32_t)-1) { if ((sect->org + curOffset - offset) % alignSize) - error("Section's fixed address fails required alignment (PC = $%04" PRIx32 - ")\n", sect->org + curOffset); - } else if (sect->align != 0 && (((sect->alignOfs + curOffset) % (1u << sect->align)) - - offset) % alignSize) { - error("Section's alignment fails required alignment (offset from section start = $%04" - PRIx32 ")\n", curOffset); + error( + "Section's fixed address fails required alignment (PC = $%04" PRIx32 ")\n", + sect->org + curOffset + ); + } else if (sect->align != 0 && (((sect->alignOfs + curOffset) % (1u << sect->align)) - offset) % alignSize) { + error( + "Section's alignment fails required alignment (offset from section start = $%04" PRIx32 + ")\n", + curOffset + ); } else if (alignment >= 16) { // Treat an alignment large enough as fixing the address. // Note that this also ensures that a section's alignment never becomes 16 or greater. @@ -526,8 +585,7 @@ void sect_AlignPC(uint8_t alignment, uint16_t offset) } } -static void growSection(uint32_t growth) -{ +static void growSection(uint32_t growth) { curOffset += growth; if (curOffset + loadOffset > currentSection->size) currentSection->size = curOffset + loadOffset; @@ -535,33 +593,28 @@ static void growSection(uint32_t growth) currentLoadSection->size = curOffset; } -static void writebyte(uint8_t byte) -{ +static void writebyte(uint8_t byte) { currentSection->data[sect_GetOutputOffset()] = byte; growSection(1); } -static void writeword(uint16_t b) -{ +static void writeword(uint16_t b) { writebyte(b & 0xFF); writebyte(b >> 8); } -static void writelong(uint32_t b) -{ +static void writelong(uint32_t b) { writebyte(b & 0xFF); writebyte(b >> 8); writebyte(b >> 16); writebyte(b >> 24); } -static void createPatch(enum PatchType type, Expression const &expr, uint32_t pcShift) -{ +static void createPatch(enum PatchType type, Expression const &expr, uint32_t pcShift) { out_CreatePatch(type, expr, sect_GetOutputOffset(), pcShift); } -void sect_StartUnion() -{ +void sect_StartUnion() { // Important info: currently, UNION and LOAD cannot interact, since UNION is prohibited in // "code" sections, whereas LOAD is restricted to them. // Therefore, any interactions are NOT TESTED, so lift either of those restrictions at @@ -576,11 +629,10 @@ void sect_StartUnion() return; } - currentUnionStack.push({ .start = curOffset, .size = 0 }); + currentUnionStack.push({.start = curOffset, .size = 0}); } -static void endUnionMember() -{ +static void endUnionMember() { UnionStackEntry &member = currentUnionStack.top(); uint32_t memberSize = curOffset - member.start; @@ -589,8 +641,7 @@ static void endUnionMember() curOffset = member.start; } -void sect_NextUnionMember() -{ +void sect_NextUnionMember() { if (currentUnionStack.empty()) { error("Found NEXTU outside of a UNION construct\n"); return; @@ -598,8 +649,7 @@ void sect_NextUnionMember() endUnionMember(); } -void sect_EndUnion() -{ +void sect_EndUnion() { if (currentUnionStack.empty()) { error("Found ENDU outside of a UNION construct\n"); return; @@ -609,15 +659,13 @@ void sect_EndUnion() currentUnionStack.pop(); } -void sect_CheckUnionClosed() -{ +void sect_CheckUnionClosed() { if (!currentUnionStack.empty()) error("Unterminated UNION construct\n"); } // Output an absolute byte -void sect_AbsByte(uint8_t b) -{ +void sect_AbsByte(uint8_t b) { if (!checkcodesection()) return; if (!reserveSpace(1)) @@ -626,8 +674,7 @@ void sect_AbsByte(uint8_t b) writebyte(b); } -void sect_AbsByteGroup(uint8_t const *s, size_t length) -{ +void sect_AbsByteGroup(uint8_t const *s, size_t length) { if (!checkcodesection()) return; if (!reserveSpace(length)) @@ -637,8 +684,7 @@ void sect_AbsByteGroup(uint8_t const *s, size_t length) writebyte(*s++); } -void sect_AbsWordGroup(uint8_t const *s, size_t length) -{ +void sect_AbsWordGroup(uint8_t const *s, size_t length) { if (!checkcodesection()) return; if (!reserveSpace(length * 2)) @@ -648,8 +694,7 @@ void sect_AbsWordGroup(uint8_t const *s, size_t length) writeword(*s++); } -void sect_AbsLongGroup(uint8_t const *s, size_t length) -{ +void sect_AbsLongGroup(uint8_t const *s, size_t length) { if (!checkcodesection()) return; if (!reserveSpace(length * 4)) @@ -660,8 +705,7 @@ void sect_AbsLongGroup(uint8_t const *s, size_t length) } // Skip this many bytes -void sect_Skip(uint32_t skip, bool ds) -{ +void sect_Skip(uint32_t skip, bool ds) { if (!checksection()) return; if (!reserveSpace(skip)) @@ -671,8 +715,13 @@ void sect_Skip(uint32_t skip, bool ds) growSection(skip); } else { if (!ds) - warning(WARNING_EMPTY_DATA_DIRECTIVE, "%s directive without data in ROM\n", - (skip == 4) ? "DL" : (skip == 2) ? "DW" : "DB"); + warning( + WARNING_EMPTY_DATA_DIRECTIVE, + "%s directive without data in ROM\n", + (skip == 4) ? "DL" + : (skip == 2) ? "DW" + : "DB" + ); // We know we're in a code SECTION while (skip--) writebyte(fillByte); @@ -681,8 +730,7 @@ void sect_Skip(uint32_t skip, bool ds) // Output a relocatable byte. Checking will be done to see if it // is an absolute value in disguise. -void sect_RelByte(Expression &expr, uint32_t pcShift) -{ +void sect_RelByte(Expression &expr, uint32_t pcShift) { if (!checkcodesection()) return; if (!reserveSpace(1)) @@ -699,8 +747,7 @@ void sect_RelByte(Expression &expr, uint32_t pcShift) // Output several copies of a relocatable byte. Checking will be done to see if // it is an absolute value in disguise. -void sect_RelBytes(uint32_t n, std::vector &exprs) -{ +void sect_RelBytes(uint32_t n, std::vector &exprs) { if (!checkcodesection()) return; if (!reserveSpace(n)) @@ -723,8 +770,7 @@ void sect_RelBytes(uint32_t n, std::vector &exprs) // Output a relocatable word. Checking will be done to see if // it's an absolute value in disguise. -void sect_RelWord(Expression &expr, uint32_t pcShift) -{ +void sect_RelWord(Expression &expr, uint32_t pcShift) { if (!checkcodesection()) return; if (!reserveSpace(2)) @@ -741,8 +787,7 @@ void sect_RelWord(Expression &expr, uint32_t pcShift) // Output a relocatable longword. Checking will be done to see if // is an absolute value in disguise. -void sect_RelLong(Expression &expr, uint32_t pcShift) -{ +void sect_RelLong(Expression &expr, uint32_t pcShift) { if (!checkcodesection()) return; if (!reserveSpace(2)) @@ -759,8 +804,7 @@ void sect_RelLong(Expression &expr, uint32_t pcShift) // Output a PC-relative relocatable byte. Checking will be done to see if it // is an absolute value in disguise. -void sect_PCRelByte(Expression &expr, uint32_t pcShift) -{ +void sect_PCRelByte(Expression &expr, uint32_t pcShift) { if (!checkcodesection()) return; if (!reserveSpace(1)) @@ -782,8 +826,7 @@ void sect_PCRelByte(Expression &expr, uint32_t pcShift) offset = sym->getValue() - (pc->getValue() + 1); if (offset < -128 || offset > 127) { - error("jr target out of reach (expected -129 < %" PRId16 " < 128)\n", - offset); + error("jr target out of reach (expected -129 < %" PRId16 " < 128)\n", offset); writebyte(0); } else { writebyte(offset); @@ -793,8 +836,7 @@ void sect_PCRelByte(Expression &expr, uint32_t pcShift) } // Output a binary file -void sect_BinaryFile(char const *s, int32_t startPos) -{ +void sect_BinaryFile(char const *s, int32_t startPos) { if (startPos < 0) { error("Start position cannot be negative (%" PRId32 ")\n", startPos); startPos = 0; @@ -834,8 +876,7 @@ void sect_BinaryFile(char const *s, int32_t startPos) goto cleanup; } else { if (errno != ESPIPE) - error("Error determining size of INCBIN file '%s': %s\n", - s, strerror(errno)); + error("Error determining size of INCBIN file '%s': %s\n", s, strerror(errno)); // The file isn't seekable, so we'll just skip bytes while (startPos--) (void)fgetc(f); @@ -854,8 +895,7 @@ cleanup: fclose(f); } -void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length) -{ +void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length) { if (start_pos < 0) { error("Start position cannot be negative (%" PRId32 ")\n", start_pos); start_pos = 0; @@ -900,16 +940,20 @@ void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length) } if ((start_pos + length) > fsize) { - error("Specified range in INCBIN is out of bounds (%" PRIu32 " + %" PRIu32 - " > %" PRIu32 ")\n", start_pos, length, fsize); + error( + "Specified range in INCBIN is out of bounds (%" PRIu32 " + %" PRIu32 " > %" PRIu32 + ")\n", + start_pos, + length, + fsize + ); goto cleanup; } fseek(f, start_pos, SEEK_SET); } else { if (errno != ESPIPE) - error("Error determining size of INCBIN file '%s': %s\n", - s, strerror(errno)); + error("Error determining size of INCBIN file '%s': %s\n", s, strerror(errno)); // The file isn't seekable, so we'll just skip bytes while (start_pos--) (void)fgetc(f); @@ -923,8 +967,7 @@ void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length) } else if (ferror(f)) { error("Error reading INCBIN file '%s': %s\n", s, strerror(errno)); } else { - error("Premature end of file (%" PRId32 " bytes left to read)\n", - length + 1); + error("Premature end of file (%" PRId32 " bytes left to read)\n", length + 1); } } @@ -933,15 +976,14 @@ cleanup: } // Section stack routines -void sect_PushSection() -{ +void sect_PushSection() { sectionStack.push_front({ - .section = currentSection, - .loadSection = currentLoadSection, - .scope = sym_GetCurrentSymbolScope(), - .offset = curOffset, - .loadOffset = loadOffset, - .unionStack = {}, + .section = currentSection, + .loadSection = currentLoadSection, + .scope = sym_GetCurrentSymbolScope(), + .offset = curOffset, + .loadOffset = loadOffset, + .unionStack = {}, }); // Reset the section scope @@ -951,8 +993,7 @@ void sect_PushSection() std::swap(currentUnionStack, sectionStack.front().unionStack); } -void sect_PopSection() -{ +void sect_PopSection() { if (sectionStack.empty()) fatalerror("No entries in the section stack\n"); @@ -971,8 +1012,7 @@ void sect_PopSection() std::swap(currentUnionStack, entry.unionStack); } -void sect_EndSection() -{ +void sect_EndSection() { if (!currentSection) fatalerror("Cannot end the section outside of a SECTION\n"); diff --git a/src/asm/symbol.cpp b/src/asm/symbol.cpp index 22020607..04210008 100644 --- a/src/asm/symbol.cpp +++ b/src/asm/symbol.cpp @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: MIT */ +#include "asm/symbol.hpp" + #include #include #include @@ -7,26 +9,25 @@ #include #include #include -#include #include +#include #include #include #include +#include "error.hpp" +#include "helpers.hpp" +#include "util.hpp" +#include "version.hpp" + #include "asm/fixpoint.hpp" #include "asm/fstack.hpp" #include "asm/macro.hpp" #include "asm/main.hpp" #include "asm/output.hpp" #include "asm/section.hpp" -#include "asm/symbol.hpp" -#include "util.hpp" #include "asm/warning.hpp" -#include "error.hpp" -#include "helpers.hpp" -#include "version.hpp" - std::map symbols; static const char *labelScope; // Current section's label scope @@ -38,19 +39,16 @@ static char savedTIMESTAMP_ISO8601_LOCAL[256]; static char savedTIMESTAMP_ISO8601_UTC[256]; static bool exportAll; -bool sym_IsPC(Symbol const *sym) -{ +bool sym_IsPC(Symbol const *sym) { return sym == PCSymbol; } -void sym_ForEach(void (*callback)(Symbol &)) -{ +void sym_ForEach(void (*callback)(Symbol &)) { for (auto &it : symbols) callback(it.second); } -static int32_t Callback_NARG() -{ +static int32_t Callback_NARG() { if (!macro_GetCurrentArgs()) { error("_NARG does not make sense outside of a macro\n"); return 0; @@ -58,15 +56,13 @@ static int32_t Callback_NARG() return macro_NbArgs(); } -static int32_t CallbackPC() -{ +static int32_t CallbackPC() { Section const *section = sect_GetSymbolSection(); return section ? section->org + sect_GetSymbolOffset() : 0; } -int32_t Symbol::getValue() const -{ +int32_t Symbol::getValue() const { assert(std::holds_alternative(data) || std::holds_alternative(data)); if (int32_t const *value = std::get_if(&data); value) { // TODO: do not use section's org directly @@ -75,29 +71,28 @@ int32_t Symbol::getValue() const return getOutputValue(); } -int32_t Symbol::getOutputValue() const -{ - return std::visit(Visitor{ - [](int32_t value) -> int32_t { return value; }, - [](int32_t (*callback)()) -> int32_t { return callback(); }, - [](auto &) -> int32_t { return 0; } - }, data); +int32_t Symbol::getOutputValue() const { + return std::visit( + Visitor{ + [](int32_t value) -> int32_t { return value; }, + [](int32_t (*callback)()) -> int32_t { return callback(); }, + [](auto &) -> int32_t { return 0; }, + }, + data + ); } -std::string_view *Symbol::getMacro() const -{ +std::string_view *Symbol::getMacro() const { assert(std::holds_alternative(data)); return std::get(data); } -std::string *Symbol::getEqus() const -{ +std::string *Symbol::getEqus() const { assert(std::holds_alternative(data)); return std::get(data); } -static void dumpFilename(Symbol const &sym) -{ +static void dumpFilename(Symbol const &sym) { if (sym.src) sym.src->dump(sym.fileLine); else if (sym.fileLine == 0) @@ -107,15 +102,13 @@ static void dumpFilename(Symbol const &sym) } // Set a symbol's definition filename and line -static void setSymbolFilename(Symbol &sym) -{ - sym.src = fstk_GetFileStack(); // This is `nullptr` for built-ins +static void setSymbolFilename(Symbol &sym) { + sym.src = fstk_GetFileStack(); // This is `nullptr` for built-ins sym.fileLine = sym.src ? lexer_GetLineNo() : 0; // This is 1 for built-ins } // Update a symbol's definition filename and line -static void updateSymbolFilename(Symbol &sym) -{ +static void updateSymbolFilename(Symbol &sym) { FileStackNode *oldSrc = sym.src; setSymbolFilename(sym); @@ -126,8 +119,7 @@ static void updateSymbolFilename(Symbol &sym) } // Create a new symbol by name -static Symbol &createsymbol(char const *symName) -{ +static Symbol &createsymbol(char const *symName) { Symbol &sym = symbols[symName]; if (snprintf(sym.name, MAXSYMLEN + 1, "%s", symName) > MAXSYMLEN) @@ -144,9 +136,8 @@ static Symbol &createsymbol(char const *symName) // Creates the full name of a local symbol in a given scope, by prepending // the name with the parent symbol's name. -static void fullSymbolName(char *output, size_t outputSize, - char const *localName, char const *scopeName) -{ +static void + fullSymbolName(char *output, size_t outputSize, char const *localName, char const *scopeName) { int ret = snprintf(output, outputSize, "%s%s", scopeName, localName); if (ret < 0) @@ -155,27 +146,23 @@ static void fullSymbolName(char *output, size_t outputSize, fatalerror("Symbol name is too long: '%s%s'\n", scopeName, localName); } -static void assignStringSymbol(Symbol &sym, char const *value) -{ - std::string *equs = new(std::nothrow) std::string(value); +static void assignStringSymbol(Symbol &sym, char const *value) { + std::string *equs = new (std::nothrow) std::string(value); if (!equs) fatalerror("No memory for string equate: %s\n", strerror(errno)); sym.type = SYM_EQUS; sym.data = equs; } -Symbol *sym_FindExactSymbol(char const *symName) -{ +Symbol *sym_FindExactSymbol(char const *symName) { auto search = symbols.find(symName); return search != symbols.end() ? &search->second : nullptr; } -Symbol *sym_FindScopedSymbol(char const *symName) -{ +Symbol *sym_FindScopedSymbol(char const *symName) { if (char const *localName = strchr(symName, '.'); localName) { if (strchr(localName + 1, '.')) - fatalerror("'%s' is a nonsensical reference to a nested local symbol\n", - symName); + fatalerror("'%s' is a nonsensical reference to a nested local symbol\n", symName); // If auto-scoped local label, expand the name if (localName == symName) { // Meaning, the name begins with the dot char fullName[MAXSYMLEN + 1]; @@ -187,8 +174,7 @@ Symbol *sym_FindScopedSymbol(char const *symName) return sym_FindExactSymbol(symName); } -Symbol *sym_FindScopedValidSymbol(char const *symName) -{ +Symbol *sym_FindScopedValidSymbol(char const *symName) { Symbol *sym = sym_FindScopedSymbol(symName); // `@` has no value outside a section @@ -202,14 +188,12 @@ Symbol *sym_FindScopedValidSymbol(char const *symName) return sym; } -Symbol const *sym_GetPC() -{ +Symbol const *sym_GetPC() { return PCSymbol; } // Purge a symbol -void sym_Purge(std::string const &symName) -{ +void sym_Purge(std::string const &symName) { Symbol *sym = sym_FindScopedValidSymbol(symName.c_str()); if (!sym) { @@ -230,8 +214,7 @@ void sym_Purge(std::string const &symName) } } -uint32_t sym_GetPCValue() -{ +uint32_t sym_GetPCValue() { Section const *sect = sect_GetSymbolSection(); if (!sect) @@ -244,8 +227,7 @@ uint32_t sym_GetPCValue() } // Return a constant symbol's value, assuming it's defined -uint32_t Symbol::getConstantValue() const -{ +uint32_t Symbol::getConstantValue() const { if (sym_IsPC(this)) return sym_GetPCValue(); @@ -257,8 +239,7 @@ uint32_t Symbol::getConstantValue() const } // Return a constant symbol's value -uint32_t sym_GetConstantValue(char const *symName) -{ +uint32_t sym_GetConstantValue(char const *symName) { if (Symbol const *sym = sym_FindScopedSymbol(symName); sym) return sym->getConstantValue(); @@ -266,13 +247,11 @@ uint32_t sym_GetConstantValue(char const *symName) return 0; } -char const *sym_GetCurrentSymbolScope() -{ +char const *sym_GetCurrentSymbolScope() { return labelScope; } -void sym_SetCurrentSymbolScope(char const *newScope) -{ +void sym_SetCurrentSymbolScope(char const *newScope) { labelScope = newScope; } @@ -283,8 +262,7 @@ void sym_SetCurrentSymbolScope(char const *newScope) * @param symName The name of the symbol to create * @param numeric If false, the symbol may not have been referenced earlier */ -static Symbol *createNonrelocSymbol(char const *symName, bool numeric) -{ +static Symbol *createNonrelocSymbol(char const *symName, bool numeric) { Symbol *sym = sym_FindExactSymbol(symName); if (!sym) { @@ -306,8 +284,7 @@ static Symbol *createNonrelocSymbol(char const *symName, bool numeric) } // Add an equated symbol -Symbol *sym_AddEqu(char const *symName, int32_t value) -{ +Symbol *sym_AddEqu(char const *symName, int32_t value) { Symbol *sym = createNonrelocSymbol(symName, true); if (!sym) @@ -319,8 +296,7 @@ Symbol *sym_AddEqu(char const *symName, int32_t value) return sym; } -Symbol *sym_RedefEqu(char const *symName, int32_t value) -{ +Symbol *sym_RedefEqu(char const *symName, int32_t value) { Symbol *sym = sym_FindExactSymbol(symName); if (!sym) @@ -355,8 +331,7 @@ Symbol *sym_RedefEqu(char const *symName, int32_t value) * of the string are enough: sym_AddString("M_PI", "3.1415"). This is the same * as ``` M_PI EQUS "3.1415" ``` */ -Symbol *sym_AddString(char const *symName, char const *value) -{ +Symbol *sym_AddString(char const *symName, char const *value) { Symbol *sym = createNonrelocSymbol(symName, false); if (!sym) @@ -366,8 +341,7 @@ Symbol *sym_AddString(char const *symName, char const *value) return sym; } -Symbol *sym_RedefString(char const *symName, char const *value) -{ +Symbol *sym_RedefString(char const *symName, char const *value) { Symbol *sym = sym_FindExactSymbol(symName); if (!sym) @@ -395,15 +369,15 @@ Symbol *sym_RedefString(char const *symName, char const *value) } // Alter a mutable symbol's value -Symbol *sym_AddVar(char const *symName, int32_t value) -{ +Symbol *sym_AddVar(char const *symName, int32_t value) { Symbol *sym = sym_FindExactSymbol(symName); if (!sym) { sym = &createsymbol(symName); } else if (sym->isDefined() && sym->type != SYM_VAR) { - error("'%s' already defined as %s at ", - symName, sym->type == SYM_LABEL ? "label" : "constant"); + error( + "'%s' already defined as %s at ", symName, sym->type == SYM_LABEL ? "label" : "constant" + ); dumpFilename(*sym); putc('\n', stderr); return sym; @@ -422,8 +396,7 @@ Symbol *sym_AddVar(char const *symName, int32_t value) * @param symName The label's full name (so `.name` is invalid) * @return The created symbol */ -static Symbol *addLabel(char const *symName) -{ +static Symbol *addLabel(char const *symName) { assert(symName[0] != '.'); // The symbol name must have been expanded prior Symbol *sym = sym_FindExactSymbol(symName); @@ -452,8 +425,7 @@ static Symbol *addLabel(char const *symName) } // Add a local (`.name` or `Parent.name`) relocatable symbol -Symbol *sym_AddLocalLabel(char const *symName) -{ +Symbol *sym_AddLocalLabel(char const *symName) { // Assuming no dots in `labelScope` if defined assert(!labelScope || !strchr(labelScope, '.')); @@ -464,13 +436,11 @@ Symbol *sym_AddLocalLabel(char const *symName) // Check for something after the dot in `localName` if (localName[1] == '\0') { - fatalerror("'%s' is a nonsensical reference to an empty local label\n", - symName); + fatalerror("'%s' is a nonsensical reference to an empty local label\n", symName); } // Check for more than one dot in `localName` if (strchr(localName + 1, '.')) - fatalerror("'%s' is a nonsensical reference to a nested local label\n", - symName); + fatalerror("'%s' is a nonsensical reference to a nested local label\n", symName); if (localName == symName) { if (!labelScope) { @@ -486,8 +456,7 @@ Symbol *sym_AddLocalLabel(char const *symName) } // Add a relocatable symbol -Symbol *sym_AddLabel(char const *symName) -{ +Symbol *sym_AddLabel(char const *symName) { Symbol *sym = addLabel(symName); // Set the symbol as the new scope @@ -499,8 +468,7 @@ Symbol *sym_AddLabel(char const *symName) static uint32_t anonLabelID; // Add an anonymous label -Symbol *sym_AddAnonLabel() -{ +Symbol *sym_AddAnonLabel() { if (anonLabelID == UINT32_MAX) { error("Only %" PRIu32 " anonymous labels can be created!", anonLabelID); return nullptr; @@ -513,22 +481,29 @@ Symbol *sym_AddAnonLabel() } // Write an anonymous label's name to a buffer -void sym_WriteAnonLabelName(char buf[MAXSYMLEN + 1], uint32_t ofs, bool neg) -{ +void sym_WriteAnonLabelName(char buf[MAXSYMLEN + 1], uint32_t ofs, bool neg) { uint32_t id = 0; if (neg) { if (ofs > anonLabelID) - error("Reference to anonymous label %" PRIu32 " before, when only %" PRIu32 - " ha%s been created so far\n", - ofs, anonLabelID, anonLabelID == 1 ? "s" : "ve"); + error( + "Reference to anonymous label %" PRIu32 " before, when only %" PRIu32 + " ha%s been created so far\n", + ofs, + anonLabelID, + anonLabelID == 1 ? "s" : "ve" + ); else id = anonLabelID - ofs; } else { ofs--; // We're referencing symbols that haven't been created yet... if (ofs > UINT32_MAX - anonLabelID) - error("Reference to anonymous label %" PRIu32 " after, when only %" PRIu32 - " may still be created\n", ofs + 1, UINT32_MAX - anonLabelID); + error( + "Reference to anonymous label %" PRIu32 " after, when only %" PRIu32 + " may still be created\n", + ofs + 1, + UINT32_MAX - anonLabelID + ); else id = anonLabelID + ofs; } @@ -537,8 +512,7 @@ void sym_WriteAnonLabelName(char buf[MAXSYMLEN + 1], uint32_t ofs, bool neg) } // Export a symbol -void sym_Export(char const *symName) -{ +void sym_Export(char const *symName) { if (symName[0] == '!') { error("Anonymous labels cannot be exported\n"); return; @@ -553,14 +527,13 @@ void sym_Export(char const *symName) } // Add a macro definition -Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char const *body, size_t size) -{ +Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char const *body, size_t size) { Symbol *sym = createNonrelocSymbol(symName, false); if (!sym) return nullptr; - std::string_view *macro = new(std::nothrow) std::string_view(body, size); + std::string_view *macro = new (std::nothrow) std::string_view(body, size); if (!macro) fatalerror("No memory for macro: %s\n", strerror(errno)); sym->type = SYM_MACRO; @@ -576,8 +549,7 @@ Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char const *body, s // Flag that a symbol is referenced in an RPN expression // and create it if it doesn't exist yet -Symbol *sym_Ref(char const *symName) -{ +Symbol *sym_Ref(char const *symName) { Symbol *sym = sym_FindScopedSymbol(symName); if (!sym) { @@ -598,13 +570,11 @@ Symbol *sym_Ref(char const *symName) } // Set whether to export all relocatable symbols by default -void sym_SetExportAll(bool set) -{ +void sym_SetExportAll(bool set) { exportAll = set; } -static Symbol *createBuiltinSymbol(char const *symName) -{ +static Symbol *createBuiltinSymbol(char const *symName) { Symbol *sym = &createsymbol(symName); sym->isBuiltin = true; @@ -615,8 +585,7 @@ static Symbol *createBuiltinSymbol(char const *symName) } // Initialize the symboltable -void sym_Init(time_t now) -{ +void sym_Init(time_t now) { PCSymbol = createBuiltinSymbol("@"); PCSymbol->type = SYM_LABEL; PCSymbol->data = CallbackPC; @@ -627,11 +596,12 @@ void sym_Init(time_t now) sym_AddVar("_RS", 0)->isBuiltin = true; -#define addSym(fn, name, val) do { \ - Symbol *sym = fn(name, val); \ - assert(sym); \ - sym->isBuiltin = true; \ -} while (0) +#define addSym(fn, name, val) \ + do { \ + Symbol *sym = fn(name, val); \ + assert(sym); \ + sym->isBuiltin = true; \ + } while (0) #define addNumber(name, val) addSym(sym_AddEqu, name, val) #define addString(name, val) addSym(sym_AddString, name, val) @@ -653,15 +623,21 @@ void sym_Init(time_t now) strftime(savedTIME, sizeof(savedTIME), "\"%H:%M:%S\"", time_local); strftime(savedDATE, sizeof(savedDATE), "\"%d %B %Y\"", time_local); - strftime(savedTIMESTAMP_ISO8601_LOCAL, - sizeof(savedTIMESTAMP_ISO8601_LOCAL), "\"%Y-%m-%dT%H:%M:%S%z\"", - time_local); + strftime( + savedTIMESTAMP_ISO8601_LOCAL, + sizeof(savedTIMESTAMP_ISO8601_LOCAL), + "\"%Y-%m-%dT%H:%M:%S%z\"", + time_local + ); const tm *time_utc = gmtime(&now); - strftime(savedTIMESTAMP_ISO8601_UTC, - sizeof(savedTIMESTAMP_ISO8601_UTC), "\"%Y-%m-%dT%H:%M:%SZ\"", - time_utc); + strftime( + savedTIMESTAMP_ISO8601_UTC, + sizeof(savedTIMESTAMP_ISO8601_UTC), + "\"%Y-%m-%dT%H:%M:%SZ\"", + time_utc + ); addString("__TIME__", savedTIME); addString("__DATE__", savedDATE); diff --git a/src/asm/warning.cpp b/src/asm/warning.cpp index 50b913cb..bc49ec69 100644 --- a/src/asm/warning.cpp +++ b/src/asm/warning.cpp @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: MIT */ +#include "asm/warning.hpp" + #include #include #include @@ -8,48 +10,46 @@ #include #include -#include "asm/fstack.hpp" -#include "asm/main.hpp" -#include "asm/warning.hpp" - #include "error.hpp" #include "itertools.hpp" +#include "asm/fstack.hpp" +#include "asm/main.hpp" + unsigned int nbErrors = 0; unsigned int maxErrors = 0; static const enum WarningState defaultWarnings[ARRAY_SIZE(warningStates)] = { - WARNING_ENABLED, // WARNING_ASSERT - WARNING_DISABLED, // WARNING_BACKWARDS_FOR - WARNING_DISABLED, // WARNING_BUILTIN_ARG - WARNING_DISABLED, // WARNING_CHARMAP_REDEF - WARNING_DISABLED, // WARNING_DIV - WARNING_DISABLED, // WARNING_EMPTY_DATA_DIRECTIVE - WARNING_DISABLED, // WARNING_EMPTY_MACRO_ARG - WARNING_DISABLED, // WARNING_EMPTY_STRRPL - WARNING_DISABLED, // WARNING_LARGE_CONSTANT - WARNING_DISABLED, // WARNING_LONG_STR - WARNING_DISABLED, // WARNING_MACRO_SHIFT - WARNING_ENABLED, // WARNING_NESTED_COMMENT - WARNING_ENABLED, // WARNING_OBSOLETE - WARNING_DISABLED, // WARNING_SHIFT - WARNING_DISABLED, // WARNING_SHIFT_AMOUNT - WARNING_ENABLED, // WARNING_USER + WARNING_ENABLED, // WARNING_ASSERT + WARNING_DISABLED, // WARNING_BACKWARDS_FOR + WARNING_DISABLED, // WARNING_BUILTIN_ARG + WARNING_DISABLED, // WARNING_CHARMAP_REDEF + WARNING_DISABLED, // WARNING_DIV + WARNING_DISABLED, // WARNING_EMPTY_DATA_DIRECTIVE + WARNING_DISABLED, // WARNING_EMPTY_MACRO_ARG + WARNING_DISABLED, // WARNING_EMPTY_STRRPL + WARNING_DISABLED, // WARNING_LARGE_CONSTANT + WARNING_DISABLED, // WARNING_LONG_STR + WARNING_DISABLED, // WARNING_MACRO_SHIFT + WARNING_ENABLED, // WARNING_NESTED_COMMENT + WARNING_ENABLED, // WARNING_OBSOLETE + WARNING_DISABLED, // WARNING_SHIFT + WARNING_DISABLED, // WARNING_SHIFT_AMOUNT + WARNING_ENABLED, // WARNING_USER - WARNING_ENABLED, // WARNING_NUMERIC_STRING_1 - WARNING_DISABLED, // WARNING_NUMERIC_STRING_2 - WARNING_ENABLED, // WARNING_TRUNCATION_1 - WARNING_DISABLED, // WARNING_TRUNCATION_2 - WARNING_ENABLED, // WARNING_UNMAPPED_CHAR_1 - WARNING_DISABLED, // WARNING_UNMAPPED_CHAR_2 + WARNING_ENABLED, // WARNING_NUMERIC_STRING_1 + WARNING_DISABLED, // WARNING_NUMERIC_STRING_2 + WARNING_ENABLED, // WARNING_TRUNCATION_1 + WARNING_DISABLED, // WARNING_TRUNCATION_2 + WARNING_ENABLED, // WARNING_UNMAPPED_CHAR_1 + WARNING_DISABLED, // WARNING_UNMAPPED_CHAR_2 }; enum WarningState warningStates[ARRAY_SIZE(warningStates)]; bool warningsAreErrors; // Set if `-Werror` was specified -static enum WarningState warningState(enum WarningID id) -{ +static enum WarningState warningState(enum WarningID id) { // Check if warnings are globally disabled if (!warnings) return WARNING_DISABLED; @@ -68,35 +68,35 @@ static enum WarningState warningState(enum WarningID id) } static const char * const warningFlags[NB_WARNINGS] = { - "assert", - "backwards-for", - "builtin-args", - "charmap-redef", - "div", - "empty-data-directive", - "empty-macro-arg", - "empty-strrpl", - "large-constant", - "long-string", - "macro-shift", - "nested-comment", - "obsolete", - "shift", - "shift-amount", - "user", + "assert", + "backwards-for", + "builtin-args", + "charmap-redef", + "div", + "empty-data-directive", + "empty-macro-arg", + "empty-strrpl", + "large-constant", + "long-string", + "macro-shift", + "nested-comment", + "obsolete", + "shift", + "shift-amount", + "user", - // Parametric warnings - "numeric-string", - "numeric-string", - "truncation", - "truncation", - "unmapped-char", - "unmapped-char", + // Parametric warnings + "numeric-string", + "numeric-string", + "truncation", + "truncation", + "unmapped-char", + "unmapped-char", - // Meta warnings - "all", - "extra", - "everything", // Especially useful for testing + // Meta warnings + "all", + "extra", + "everything", // Especially useful for testing }; static const struct { @@ -104,13 +104,12 @@ static const struct { uint8_t nbLevels; uint8_t defaultLevel; } paramWarnings[] = { - { "numeric-string", 2, 1 }, - { "truncation", 2, 2 }, - { "unmapped-char", 2, 1 }, + {"numeric-string", 2, 1}, + {"truncation", 2, 2}, + {"unmapped-char", 2, 1}, }; -static bool tryProcessParamWarning(char const *flag, uint8_t param, enum WarningState state) -{ +static bool tryProcessParamWarning(char const *flag, uint8_t param, enum WarningState state) { enum WarningID baseID = PARAM_WARNINGS_START; for (size_t i = 0; i < ARRAY_SIZE(paramWarnings); i++) { @@ -126,17 +125,19 @@ static bool tryProcessParamWarning(char const *flag, uint8_t param, enum Warning param = paramWarnings[i].defaultLevel; } else if (param > maxParam) { if (param != 255) // Don't warn if already capped - warnx("Got parameter %" PRIu8 - " for warning flag \"%s\", but the maximum is %" - PRIu8 "; capping.\n", - param, flag, maxParam); + warnx( + "Got parameter %" PRIu8 + " for warning flag \"%s\", but the maximum is %" PRIu8 "; capping.\n", + param, + flag, + maxParam + ); param = maxParam; } // Set the first to enabled/error, and disable the rest for (uint8_t ofs = 0; ofs < maxParam; ofs++) { - warningStates[baseID + ofs] = - ofs < param ? state : WARNING_DISABLED; + warningStates[baseID + ofs] = ofs < param ? state : WARNING_DISABLED; } return true; } @@ -146,73 +147,70 @@ static bool tryProcessParamWarning(char const *flag, uint8_t param, enum Warning return false; } -enum MetaWarningCommand { - META_WARNING_DONE = NB_WARNINGS -}; +enum MetaWarningCommand { META_WARNING_DONE = NB_WARNINGS }; // Warnings that probably indicate an error static uint8_t const _wallCommands[] = { - WARNING_BACKWARDS_FOR, - WARNING_BUILTIN_ARG, - WARNING_CHARMAP_REDEF, - WARNING_EMPTY_DATA_DIRECTIVE, - WARNING_EMPTY_STRRPL, - WARNING_LARGE_CONSTANT, - WARNING_LONG_STR, - WARNING_NESTED_COMMENT, - WARNING_OBSOLETE, - WARNING_NUMERIC_STRING_1, - WARNING_UNMAPPED_CHAR_1, - META_WARNING_DONE + WARNING_BACKWARDS_FOR, + WARNING_BUILTIN_ARG, + WARNING_CHARMAP_REDEF, + WARNING_EMPTY_DATA_DIRECTIVE, + WARNING_EMPTY_STRRPL, + WARNING_LARGE_CONSTANT, + WARNING_LONG_STR, + WARNING_NESTED_COMMENT, + WARNING_OBSOLETE, + WARNING_NUMERIC_STRING_1, + WARNING_UNMAPPED_CHAR_1, + META_WARNING_DONE, }; // Warnings that are less likely to indicate an error static uint8_t const _wextraCommands[] = { - WARNING_EMPTY_MACRO_ARG, - WARNING_MACRO_SHIFT, - WARNING_NESTED_COMMENT, - WARNING_OBSOLETE, - WARNING_NUMERIC_STRING_2, - WARNING_TRUNCATION_1, - WARNING_TRUNCATION_2, - WARNING_UNMAPPED_CHAR_1, - WARNING_UNMAPPED_CHAR_2, - META_WARNING_DONE + WARNING_EMPTY_MACRO_ARG, + WARNING_MACRO_SHIFT, + WARNING_NESTED_COMMENT, + WARNING_OBSOLETE, + WARNING_NUMERIC_STRING_2, + WARNING_TRUNCATION_1, + WARNING_TRUNCATION_2, + WARNING_UNMAPPED_CHAR_1, + WARNING_UNMAPPED_CHAR_2, + META_WARNING_DONE, }; // Literally everything. Notably useful for testing static uint8_t const _weverythingCommands[] = { - WARNING_BACKWARDS_FOR, - WARNING_BUILTIN_ARG, - WARNING_DIV, - WARNING_EMPTY_DATA_DIRECTIVE, - WARNING_EMPTY_MACRO_ARG, - WARNING_EMPTY_STRRPL, - WARNING_LARGE_CONSTANT, - WARNING_LONG_STR, - WARNING_MACRO_SHIFT, - WARNING_NESTED_COMMENT, - WARNING_OBSOLETE, - WARNING_SHIFT, - WARNING_SHIFT_AMOUNT, - WARNING_NUMERIC_STRING_1, - WARNING_NUMERIC_STRING_2, - WARNING_TRUNCATION_1, - WARNING_TRUNCATION_2, - WARNING_UNMAPPED_CHAR_1, - WARNING_UNMAPPED_CHAR_2, - // WARNING_USER, - META_WARNING_DONE + WARNING_BACKWARDS_FOR, + WARNING_BUILTIN_ARG, + WARNING_DIV, + WARNING_EMPTY_DATA_DIRECTIVE, + WARNING_EMPTY_MACRO_ARG, + WARNING_EMPTY_STRRPL, + WARNING_LARGE_CONSTANT, + WARNING_LONG_STR, + WARNING_MACRO_SHIFT, + WARNING_NESTED_COMMENT, + WARNING_OBSOLETE, + WARNING_SHIFT, + WARNING_SHIFT_AMOUNT, + WARNING_NUMERIC_STRING_1, + WARNING_NUMERIC_STRING_2, + WARNING_TRUNCATION_1, + WARNING_TRUNCATION_2, + WARNING_UNMAPPED_CHAR_1, + WARNING_UNMAPPED_CHAR_2, + // WARNING_USER, + META_WARNING_DONE, }; static uint8_t const *metaWarningCommands[NB_META_WARNINGS] = { - _wallCommands, - _wextraCommands, - _weverythingCommands + _wallCommands, + _wextraCommands, + _weverythingCommands, }; -void processWarningFlag(char *flag) -{ +void processWarningFlag(char *flag) { static bool setError = false; // First, try to match against a "meta" warning @@ -221,11 +219,11 @@ void processWarningFlag(char *flag) if (!strcmp(flag, warningFlags[id])) { // We got a match! if (setError) - errx("Cannot make meta warning \"%s\" into an error", - flag); + errx("Cannot make meta warning \"%s\" into an error", flag); for (uint8_t const *ptr = metaWarningCommands[id - META_WARNINGS_START]; - *ptr != META_WARNING_DONE; ptr++) { + *ptr != META_WARNING_DONE; + ptr++) { // Warning flag, set without override if (warningStates[*ptr] == WARNING_DEFAULT) warningStates[*ptr] = WARNING_ENABLED; @@ -252,16 +250,16 @@ void processWarningFlag(char *flag) setError = false; return; - // Otherwise, allow parsing as another flag + // Otherwise, allow parsing as another flag } } // Well, it's either a normal warning or a mistake enum WarningState state = setError ? WARNING_ERROR - // Not an error, then check if this is a negation - : strncmp(flag, "no-", strlen("no-")) ? WARNING_ENABLED - : WARNING_DISABLED; + // Not an error, then check if this is a negation + : strncmp(flag, "no-", strlen("no-")) ? WARNING_ENABLED + : WARNING_DISABLED; char *rootFlag = state == WARNING_DISABLED ? flag + strlen("no-") : flag; // Is this a "parametric" warning? @@ -284,8 +282,7 @@ void processWarningFlag(char *flag) // Avoid overflowing! if (param > UINT8_MAX - (*ptr - '0')) { if (!warned) - warnx("Invalid warning flag \"%s\": capping parameter at 255\n", - flag); + warnx("Invalid warning flag \"%s\": capping parameter at 255\n", flag); warned = true; // Only warn once, cap always param = 255; continue; @@ -303,8 +300,7 @@ void processWarningFlag(char *flag) return; } *equals = '\0'; // Truncate the param at the '=' - if (tryProcessParamWarning(rootFlag, param, - param == 0 ? WARNING_DISABLED : state)) + if (tryProcessParamWarning(rootFlag, param, param == 0 ? WARNING_DISABLED : state)) return; } } @@ -327,9 +323,9 @@ void processWarningFlag(char *flag) warnx("Unknown warning `%s`", flag); } -void printDiag(char const *fmt, va_list args, char const *type, - char const *flagfmt, char const *flag) -{ +void printDiag( + char const *fmt, va_list args, char const *type, char const *flagfmt, char const *flag +) { fputs(type, stderr); fputs(": ", stderr); fstk_DumpCurrent(); @@ -339,8 +335,7 @@ void printDiag(char const *fmt, va_list args, char const *type, lexer_DumpStringExpansions(); } -void error(char const *fmt, ...) -{ +void error(char const *fmt, ...) { va_list args; va_start(args, fmt); @@ -350,12 +345,15 @@ void error(char const *fmt, ...) // This intentionally makes 0 act as "unlimited" (or at least "limited to sizeof(unsigned)") nbErrors++; if (nbErrors == maxErrors) - errx("The maximum of %u error%s was reached (configure with \"-X/--max-errors\"); assembly aborted!", - maxErrors, maxErrors == 1 ? "" : "s"); + errx( + "The maximum of %u error%s was reached (configure with \"-X/--max-errors\"); assembly " + "aborted!", + maxErrors, + maxErrors == 1 ? "" : "s" + ); } -[[noreturn]] void fatalerror(char const *fmt, ...) -{ +[[noreturn]] void fatalerror(char const *fmt, ...) { va_list args; va_start(args, fmt); @@ -365,8 +363,7 @@ void error(char const *fmt, ...) exit(1); } -void warning(enum WarningID id, char const *fmt, ...) -{ +void warning(enum WarningID id, char const *fmt, ...) { char const *flag = warningFlags[id]; va_list args; diff --git a/src/error.cpp b/src/error.cpp index 5d05b002..64c6e1dc 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -1,15 +1,14 @@ /* SPDX-License-Identifier: MIT */ +#include "error.hpp" + #include #include #include #include #include -#include "error.hpp" - -static void vwarn(char const *fmt, va_list ap) -{ +static void vwarn(char const *fmt, va_list ap) { const char *error = strerror(errno); fprintf(stderr, "warning: "); @@ -17,15 +16,13 @@ static void vwarn(char const *fmt, va_list ap) fprintf(stderr, ": %s\n", error); } -static void vwarnx(char const *fmt, va_list ap) -{ +static void vwarnx(char const *fmt, va_list ap) { fprintf(stderr, "warning: "); vfprintf(stderr, fmt, ap); putc('\n', stderr); } -[[noreturn]] static void verr(char const *fmt, va_list ap) -{ +[[noreturn]] static void verr(char const *fmt, va_list ap) { const char *error = strerror(errno); fprintf(stderr, "error: "); @@ -35,8 +32,7 @@ static void vwarnx(char const *fmt, va_list ap) exit(1); } -[[noreturn]] static void verrx(char const *fmt, va_list ap) -{ +[[noreturn]] static void verrx(char const *fmt, va_list ap) { fprintf(stderr, "error: "); vfprintf(stderr, fmt, ap); putc('\n', stderr); @@ -44,8 +40,7 @@ static void vwarnx(char const *fmt, va_list ap) exit(1); } -void warn(char const *fmt, ...) -{ +void warn(char const *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -53,8 +48,7 @@ void warn(char const *fmt, ...) va_end(ap); } -void warnx(char const *fmt, ...) -{ +void warnx(char const *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -62,16 +56,14 @@ void warnx(char const *fmt, ...) va_end(ap); } -[[noreturn]] void err(char const *fmt, ...) -{ +[[noreturn]] void err(char const *fmt, ...) { va_list ap; va_start(ap, fmt); verr(fmt, ap); } -[[noreturn]] void errx(char const *fmt, ...) -{ +[[noreturn]] void errx(char const *fmt, ...) { va_list ap; va_start(ap, fmt); diff --git a/src/extern/getopt.cpp b/src/extern/getopt.cpp index 112ca3ee..d9b3c856 100644 --- a/src/extern/getopt.cpp +++ b/src/extern/getopt.cpp @@ -2,32 +2,28 @@ /* This implementation was taken from musl and modified for RGBDS */ -#include -#include +#include "extern/getopt.hpp" + #include +#include #include +#include #include #include -#include "extern/getopt.hpp" - char *musl_optarg; int musl_optind = 1, musl_opterr = 1, musl_optopt; int musl_optreset = 0; static int musl_optpos; -static void musl_getopt_msg(char const *a, char const *b, char const *c, size_t l) -{ +static void musl_getopt_msg(char const *a, char const *b, char const *c, size_t l) { FILE *f = stderr; - if (fputs(a, f) >= 0 && - fwrite(b, strlen(b), 1, f) && - fwrite(c, 1, l, f) == l) + if (fputs(a, f) >= 0 && fwrite(b, strlen(b), 1, f) && fwrite(c, 1, l, f) == l) putc('\n', f); } -static int getopt(int argc, char *argv[], char const *optstring) -{ +static int getopt(int argc, char *argv[], char const *optstring) { int i; wchar_t c, d; int k, l; @@ -77,7 +73,7 @@ static int getopt(int argc, char *argv[], char const *optstring) i = 0; d = 0; do { - l = mbtowc(&d, optstring+i, MB_LEN_MAX); + l = mbtowc(&d, optstring + i, MB_LEN_MAX); if (l > 0) i += l; else @@ -101,30 +97,29 @@ static int getopt(int argc, char *argv[], char const *optstring) if (optstring[0] == ':') return ':'; if (musl_opterr) - musl_getopt_msg(argv[0], ": option requires an argument: ", - optchar, k); + musl_getopt_msg(argv[0], ": option requires an argument: ", optchar, k); return '?'; } } return c; } -static void permute(char **argv, int dest, int src) -{ +static void permute(char **argv, int dest, int src) { char *tmp = argv[src]; int i; for (i = src; i > dest; i--) - argv[i] = argv[i-1]; + argv[i] = argv[i - 1]; argv[dest] = tmp; } -static int musl_getopt_long_core(int argc, char **argv, char const *optstring, - const option *longopts, int *idx, int longonly); +static int musl_getopt_long_core( + int argc, char **argv, char const *optstring, const option *longopts, int *idx, int longonly +); -static int musl_getopt_long(int argc, char **argv, char const *optstring, - const option *longopts, int *idx, int longonly) -{ +static int musl_getopt_long( + int argc, char **argv, char const *optstring, const option *longopts, int *idx, int longonly +) { int ret, skipped, resumed; if (!musl_optind || musl_optreset) { @@ -139,7 +134,7 @@ static int musl_getopt_long(int argc, char **argv, char const *optstring, skipped = musl_optind; if (optstring[0] != '+' && optstring[0] != '-') { int i; - for (i = musl_optind; ; i++) { + for (i = musl_optind;; i++) { if (i >= argc || !argv[i]) return -1; if (argv[i][0] == '-' && argv[i][1]) @@ -159,13 +154,13 @@ static int musl_getopt_long(int argc, char **argv, char const *optstring, return ret; } -static int musl_getopt_long_core(int argc, char **argv, char const *optstring, - const option *longopts, int *idx, int longonly) -{ +static int musl_getopt_long_core( + int argc, char **argv, char const *optstring, const option *longopts, int *idx, int longonly +) { musl_optarg = 0; - if (longopts && argv[musl_optind][0] == '-' && - ((longonly && argv[musl_optind][1] && argv[musl_optind][1] != '-') || - (argv[musl_optind][1] == '-' && argv[musl_optind][2]))) { + if (longopts && argv[musl_optind][0] == '-' + && ((longonly && argv[musl_optind][1] && argv[musl_optind][1] != '-') + || (argv[musl_optind][1] == '-' && argv[musl_optind][2]))) { int colon = optstring[optstring[0] == '+' || optstring[0] == '-'] == ':'; int i, cnt, match = 0; char *arg = 0, *opt, *start = argv[musl_optind] + 1; @@ -213,10 +208,12 @@ static int musl_getopt_long_core(int argc, char **argv, char const *optstring, musl_optopt = longopts[i].val; if (colon || !musl_opterr) return '?'; - musl_getopt_msg(argv[0], - ": option does not take an argument: ", - longopts[i].name, - strlen(longopts[i].name)); + musl_getopt_msg( + argv[0], + ": option does not take an argument: ", + longopts[i].name, + strlen(longopts[i].name) + ); return '?'; } musl_optarg = opt + 1; @@ -228,10 +225,12 @@ static int musl_getopt_long_core(int argc, char **argv, char const *optstring, return ':'; if (!musl_opterr) return '?'; - musl_getopt_msg(argv[0], - ": option requires an argument: ", - longopts[i].name, - strlen(longopts[i].name)); + musl_getopt_msg( + argv[0], + ": option requires an argument: ", + longopts[i].name, + strlen(longopts[i].name) + ); return '?'; } musl_optind++; @@ -247,11 +246,12 @@ static int musl_getopt_long_core(int argc, char **argv, char const *optstring, if (argv[musl_optind][1] == '-') { musl_optopt = 0; if (!colon && musl_opterr) - musl_getopt_msg(argv[0], cnt ? - ": option is ambiguous: " : - ": unrecognized option: ", - argv[musl_optind] + 2, - strlen(argv[musl_optind] + 2)); + musl_getopt_msg( + argv[0], + cnt ? ": option is ambiguous: " : ": unrecognized option: ", + argv[musl_optind] + 2, + strlen(argv[musl_optind] + 2) + ); musl_optind++; return '?'; } @@ -259,8 +259,8 @@ static int musl_getopt_long_core(int argc, char **argv, char const *optstring, return getopt(argc, argv, optstring); } -int musl_getopt_long_only(int argc, char **argv, char const *optstring, - const option *longopts, int *idx) -{ +int musl_getopt_long_only( + int argc, char **argv, char const *optstring, const option *longopts, int *idx +) { return musl_getopt_long(argc, argv, optstring, longopts, idx, 1); } diff --git a/src/extern/utf8decoder.cpp b/src/extern/utf8decoder.cpp index 0898dd4f..c509efde 100644 --- a/src/extern/utf8decoder.cpp +++ b/src/extern/utf8decoder.cpp @@ -5,40 +5,37 @@ #include static const uint8_t utf8d[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00..0f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10..1f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20..2f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30..3f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40..4f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50..5f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60..6f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70..7f */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80..8f */ - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, /* 90..9f */ - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* a0..af */ - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* b0..bf */ - 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* c0..cf */ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* d0..df */ - 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, /* e0..ef */ - 11, 6, 6, 6, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* f0..ff */ - 0, 1, 2, 3, 5, 8, 7, 1, 1, 1, 4, 6, 1, 1, 1, 1, /* s0 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* s1 */ - 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, /* s1 */ - 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, /* s3 */ - 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, /* s4 */ - 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, /* s5 */ - 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, /* s6 */ - 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, /* s7 */ - 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* s8 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00..0f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10..1f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20..2f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30..3f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40..4f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50..5f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60..6f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70..7f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80..8f */ + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, /* 90..9f */ + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* a0..af */ + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* b0..bf */ + 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* c0..cf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* d0..df */ + 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, /* e0..ef */ + 11, 6, 6, 6, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* f0..ff */ + 0, 1, 2, 3, 5, 8, 7, 1, 1, 1, 4, 6, 1, 1, 1, 1, /* s0 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* s1 */ + 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, /* s1 */ + 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, /* s3 */ + 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, /* s4 */ + 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, /* s5 */ + 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, /* s6 */ + 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, /* s7 */ + 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* s8 */ }; -uint32_t decode(uint32_t *state, uint32_t *codep, uint8_t byte) -{ +uint32_t decode(uint32_t *state, uint32_t *codep, uint8_t byte) { uint32_t type = utf8d[byte]; - *codep = (*state != 0) ? - (byte & 0x3FU) | (*codep << 6) : - (0xFF >> type) & (byte); + *codep = (*state != 0) ? (byte & 0x3FU) | (*codep << 6) : (0xFF >> type) & (byte); *state = utf8d[256 + *state * 16 + type]; return *state; diff --git a/src/fix/main.cpp b/src/fix/main.cpp index 938fac78..6fd4ad31 100644 --- a/src/fix/main.cpp +++ b/src/fix/main.cpp @@ -1,7 +1,8 @@ /* SPDX-License-Identifier: MIT */ -#include #include +#include + #include #include #include @@ -14,7 +15,6 @@ #include #include "extern/getopt.hpp" - #include "helpers.hpp" #include "platform.hpp" #include "version.hpp" @@ -37,47 +37,46 @@ static const char *optstring = "Ccf:i:jk:l:m:n:Op:r:st:Vv"; * over short opt matching */ static option const longopts[] = { - { "color-only", no_argument, nullptr, 'C' }, - { "color-compatible", no_argument, nullptr, 'c' }, - { "fix-spec", required_argument, nullptr, 'f' }, - { "game-id", required_argument, nullptr, 'i' }, - { "non-japanese", no_argument, nullptr, 'j' }, - { "new-licensee", required_argument, nullptr, 'k' }, - { "old-licensee", required_argument, nullptr, 'l' }, - { "mbc-type", required_argument, nullptr, 'm' }, - { "rom-version", required_argument, nullptr, 'n' }, - { "overwrite", no_argument, nullptr, 'O' }, - { "pad-value", required_argument, nullptr, 'p' }, - { "ram-size", required_argument, nullptr, 'r' }, - { "sgb-compatible", no_argument, nullptr, 's' }, - { "title", required_argument, nullptr, 't' }, - { "version", no_argument, nullptr, 'V' }, - { "validate", no_argument, nullptr, 'v' }, - { nullptr, no_argument, nullptr, 0 } + {"color-only", no_argument, nullptr, 'C'}, + {"color-compatible", no_argument, nullptr, 'c'}, + {"fix-spec", required_argument, nullptr, 'f'}, + {"game-id", required_argument, nullptr, 'i'}, + {"non-japanese", no_argument, nullptr, 'j'}, + {"new-licensee", required_argument, nullptr, 'k'}, + {"old-licensee", required_argument, nullptr, 'l'}, + {"mbc-type", required_argument, nullptr, 'm'}, + {"rom-version", required_argument, nullptr, 'n'}, + {"overwrite", no_argument, nullptr, 'O'}, + {"pad-value", required_argument, nullptr, 'p'}, + {"ram-size", required_argument, nullptr, 'r'}, + {"sgb-compatible", no_argument, nullptr, 's'}, + {"title", required_argument, nullptr, 't'}, + {"version", no_argument, nullptr, 'V'}, + {"validate", no_argument, nullptr, 'v'}, + {nullptr, no_argument, nullptr, 0 } }; -static void printUsage() -{ +static void printUsage() { fputs( -"Usage: rgbfix [-jOsVv] [-C | -c] [-f ] [-i ] [-k ]\n" -" [-l ] [-m ] [-n ]\n" -" [-p ] [-r ] [-t ] ...\n" -"Useful options:\n" -" -m, --mbc-type set the MBC type byte to this value; refer\n" -" to the man page for a list of values\n" -" -p, --pad-value pad to the next valid size using this value\n" -" -r, --ram-size set the cart RAM size byte to this value\n" -" -V, --version print RGBFIX version and exit\n" -" -v, --validate fix the header logo and both checksums (-f lhg)\n" -"\n" -"For help, use `man rgbfix' or go to https://rgbds.gbdev.io/docs/\n", - stderr); + "Usage: rgbfix [-jOsVv] [-C | -c] [-f ] [-i ] [-k ]\n" + " [-l ] [-m ] [-n ]\n" + " [-p ] [-r ] [-t ] ...\n" + "Useful options:\n" + " -m, --mbc-type set the MBC type byte to this value; refer\n" + " to the man page for a list of values\n" + " -p, --pad-value pad to the next valid size using this value\n" + " -r, --ram-size set the cart RAM size byte to this value\n" + " -V, --version print RGBFIX version and exit\n" + " -v, --validate fix the header logo and both checksums (-f lhg)\n" + "\n" + "For help, use `man rgbfix' or go to https://rgbds.gbdev.io/docs/\n", + stderr + ); } static uint8_t nbErrors; -static format_(printf, 1, 2) void report(char const *fmt, ...) -{ +static format_(printf, 1, 2) void report(char const *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -89,7 +88,7 @@ static format_(printf, 1, 2) void report(char const *fmt, ...) } enum MbcType { - ROM = 0x00, + ROM = 0x00, ROM_RAM = 0x08, ROM_RAM_BATTERY = 0x09, @@ -153,13 +152,12 @@ enum MbcType { // Error values MBC_NONE = UNSPECIFIED, // No MBC specified, do not act on it - MBC_BAD, // Specified MBC does not exist / syntax error - MBC_WRONG_FEATURES, // MBC incompatible with specified features - MBC_BAD_RANGE, // MBC number out of range + MBC_BAD, // Specified MBC does not exist / syntax error + MBC_WRONG_FEATURES, // MBC incompatible with specified features + MBC_BAD_RANGE, // MBC number out of range }; -static void printAcceptedMBCNames() -{ +static void printAcceptedMBCNames() { fputs("\tROM ($00) [aka ROM_ONLY]\n", stderr); fputs("\tMBC1 ($01), MBC1+RAM ($02), MBC1+RAM+BATTERY ($03)\n", stderr); fputs("\tMBC2 ($05), MBC2+BATTERY ($06)\n", stderr); @@ -188,8 +186,7 @@ static uint8_t tpp1Rev[2]; /* * @return False on failure */ -static bool readMBCSlice(char const *&name, char const *expected) -{ +static bool readMBCSlice(char const *&name, char const *expected) { while (*expected) { char c = *name++; @@ -207,8 +204,7 @@ static bool readMBCSlice(char const *&name, char const *expected) return true; } -static enum MbcType parseMBC(char const *name) -{ +static enum MbcType parseMBC(char const *name) { if (!strcasecmp(name, "help")) { fputs("Accepted MBC names:\n", stderr); printAcceptedMBCNames(); @@ -242,10 +238,10 @@ static enum MbcType parseMBC(char const *name) ptr++; #define tryReadSlice(expected) \ -do { \ - if (!readMBCSlice(ptr, expected)) \ - return MBC_BAD; \ -} while (0) + do { \ + if (!readMBCSlice(ptr, expected)) \ + return MBC_BAD; \ + } while (0) switch (*ptr++) { case 'R': // ROM / ROM_ONLY @@ -386,11 +382,11 @@ do { \ // Read "additional features" uint8_t features = 0; -#define RAM 0x80 -#define BATTERY 0x40 -#define TIMER 0x20 -#define RUMBLE 0x10 -#define SENSOR 0x08 +#define RAM 0x80 +#define BATTERY 0x40 +#define TIMER 0x20 +#define RUMBLE 0x10 +#define SENSOR 0x08 #define MULTIRUMBLE 0x04 for (;;) { @@ -498,8 +494,9 @@ do { \ } static_assert(MBC3 + 1 == MBC3_RAM, "Enum sanity check failed!"); static_assert(MBC3 + 2 == MBC3_RAM_BATTERY, "Enum sanity check failed!"); - static_assert(MBC3_TIMER_BATTERY + 1 == MBC3_TIMER_RAM_BATTERY, - "Enum sanity check failed!"); + static_assert( + MBC3_TIMER_BATTERY + 1 == MBC3_TIMER_RAM_BATTERY, "Enum sanity check failed!" + ); if (features == RAM) mbc++; else if (features == (RAM | BATTERY)) @@ -516,8 +513,7 @@ do { \ static_assert(MBC5 + 1 == MBC5_RAM, "Enum sanity check failed!"); static_assert(MBC5 + 2 == MBC5_RAM_BATTERY, "Enum sanity check failed!"); static_assert(MBC5_RUMBLE + 1 == MBC5_RUMBLE_RAM, "Enum sanity check failed!"); - static_assert(MBC5_RUMBLE + 2 == MBC5_RUMBLE_RAM_BATTERY, - "Enum sanity check failed!"); + static_assert(MBC5_RUMBLE + 2 == MBC5_RUMBLE_RAM_BATTERY, "Enum sanity check failed!"); if (features == RAM) mbc++; else if (features == (RAM | BATTERY)) @@ -547,8 +543,9 @@ do { \ case TPP1: if (features & RAM) - fprintf(stderr, - "warning: TPP1 requests RAM implicitly if given a non-zero RAM size"); + fprintf( + stderr, "warning: TPP1 requests RAM implicitly if given a non-zero RAM size" + ); if (features & BATTERY) mbc |= 0x08; if (features & TIMER) @@ -574,8 +571,7 @@ do { \ } } -static char const *mbcName(enum MbcType type) -{ +static char const *mbcName(enum MbcType type) { switch (type) { case ROM: return "ROM"; @@ -673,8 +669,7 @@ static char const *mbcName(enum MbcType type) unreachable_(); } -static bool hasRAM(enum MbcType type) -{ +static bool hasRAM(enum MbcType type) { switch (type) { case ROM: case MBC1: @@ -685,7 +680,7 @@ static bool hasRAM(enum MbcType type) case MBC3_TIMER_BATTERY: case MBC5: case MBC5_RUMBLE: - case MBC6: // TODO: not sure + case MBC6: // TODO: not sure case BANDAI_TAMA5: // TODO: not sure case MBC_NONE: case MBC_BAD: @@ -736,30 +731,28 @@ static bool hasRAM(enum MbcType type) } static const uint8_t ninLogo[] = { - 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, - 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, - 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, - 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99, - 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, - 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E + 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, + 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99, + 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E, }; static const uint8_t trashLogo[] = { - 0xFF^0xCE, 0xFF^0xED, 0xFF^0x66, 0xFF^0x66, 0xFF^0xCC, 0xFF^0x0D, 0xFF^0x00, 0xFF^0x0B, - 0xFF^0x03, 0xFF^0x73, 0xFF^0x00, 0xFF^0x83, 0xFF^0x00, 0xFF^0x0C, 0xFF^0x00, 0xFF^0x0D, - 0xFF^0x00, 0xFF^0x08, 0xFF^0x11, 0xFF^0x1F, 0xFF^0x88, 0xFF^0x89, 0xFF^0x00, 0xFF^0x0E, - 0xFF^0xDC, 0xFF^0xCC, 0xFF^0x6E, 0xFF^0xE6, 0xFF^0xDD, 0xFF^0xDD, 0xFF^0xD9, 0xFF^0x99, - 0xFF^0xBB, 0xFF^0xBB, 0xFF^0x67, 0xFF^0x63, 0xFF^0x6E, 0xFF^0x0E, 0xFF^0xEC, 0xFF^0xCC, - 0xFF^0xDD, 0xFF^0xDC, 0xFF^0x99, 0xFF^0x9F, 0xFF^0xBB, 0xFF^0xB9, 0xFF^0x33, 0xFF^0x3E + 0xFF ^ 0xCE, 0xFF ^ 0xED, 0xFF ^ 0x66, 0xFF ^ 0x66, 0xFF ^ 0xCC, 0xFF ^ 0x0D, 0xFF ^ 0x00, + 0xFF ^ 0x0B, 0xFF ^ 0x03, 0xFF ^ 0x73, 0xFF ^ 0x00, 0xFF ^ 0x83, 0xFF ^ 0x00, 0xFF ^ 0x0C, + 0xFF ^ 0x00, 0xFF ^ 0x0D, 0xFF ^ 0x00, 0xFF ^ 0x08, 0xFF ^ 0x11, 0xFF ^ 0x1F, 0xFF ^ 0x88, + 0xFF ^ 0x89, 0xFF ^ 0x00, 0xFF ^ 0x0E, 0xFF ^ 0xDC, 0xFF ^ 0xCC, 0xFF ^ 0x6E, 0xFF ^ 0xE6, + 0xFF ^ 0xDD, 0xFF ^ 0xDD, 0xFF ^ 0xD9, 0xFF ^ 0x99, 0xFF ^ 0xBB, 0xFF ^ 0xBB, 0xFF ^ 0x67, + 0xFF ^ 0x63, 0xFF ^ 0x6E, 0xFF ^ 0x0E, 0xFF ^ 0xEC, 0xFF ^ 0xCC, 0xFF ^ 0xDD, 0xFF ^ 0xDC, + 0xFF ^ 0x99, 0xFF ^ 0x9F, 0xFF ^ 0xBB, 0xFF ^ 0xB9, 0xFF ^ 0x33, 0xFF ^ 0x3E, }; static enum { DMG, BOTH, CGB } model = DMG; // If DMG, byte is left alone -#define FIX_LOGO 0x80 -#define TRASH_LOGO 0x40 -#define FIX_HEADER_SUM 0x20 -#define TRASH_HEADER_SUM 0x10 -#define FIX_GLOBAL_SUM 0x08 -#define TRASH_GLOBAL_SUM 0x04 +#define FIX_LOGO 0x80 +#define TRASH_LOGO 0x40 +#define FIX_HEADER_SUM 0x20 +#define TRASH_HEADER_SUM 0x10 +#define FIX_GLOBAL_SUM 0x08 +#define TRASH_GLOBAL_SUM 0x04 static uint8_t fixSpec = 0; static const char *gameID = nullptr; static uint8_t gameIDLen; @@ -776,13 +769,11 @@ static bool sgb = false; // If false, SGB flags are left alone static const char *title = nullptr; static uint8_t titleLen; -static uint8_t maxTitleLen() -{ +static uint8_t maxTitleLen() { return gameID ? 11 : model != DMG ? 15 : 16; } -static ssize_t readBytes(int fd, uint8_t *buf, size_t len) -{ +static ssize_t readBytes(int fd, uint8_t *buf, size_t len) { // POSIX specifies that lengths greater than SSIZE_MAX yield implementation-defined results assert(len <= SSIZE_MAX); @@ -807,8 +798,7 @@ static ssize_t readBytes(int fd, uint8_t *buf, size_t len) return total; } -static ssize_t writeBytes(int fd, uint8_t *buf, size_t len) -{ +static ssize_t writeBytes(int fd, uint8_t *buf, size_t len) { // POSIX specifies that lengths greater than SSIZE_MAX yield implementation-defined results assert(len <= SSIZE_MAX); @@ -838,8 +828,7 @@ static ssize_t writeBytes(int fd, uint8_t *buf, size_t len) * @param fixedByte The fixed byte at the address * @param areaName Name to be displayed in the warning message */ -static void overwriteByte(uint8_t *rom0, uint16_t addr, uint8_t fixedByte, char const *areaName) -{ +static void overwriteByte(uint8_t *rom0, uint16_t addr, uint8_t fixedByte, char const *areaName) { uint8_t origByte = rom0[addr]; if (!overwriteRom && origByte != 0 && origByte != fixedByte) @@ -855,16 +844,15 @@ static void overwriteByte(uint8_t *rom0, uint16_t addr, uint8_t fixedByte, char * @param size How many bytes to check * @param areaName Name to be displayed in the warning message */ -static void overwriteBytes(uint8_t *rom0, uint16_t startAddr, uint8_t const *fixed, uint8_t size, - char const *areaName) -{ +static void overwriteBytes( + uint8_t *rom0, uint16_t startAddr, uint8_t const *fixed, uint8_t size, char const *areaName +) { if (!overwriteRom) { for (uint8_t i = 0; i < size; i++) { uint8_t origByte = rom0[i + startAddr]; if (origByte != 0 && origByte != fixed[i]) { - fprintf(stderr, "warning: Overwrote a non-zero byte in the %s\n", - areaName); + fprintf(stderr, "warning: Overwrote a non-zero byte in the %s\n", areaName); break; } } @@ -879,8 +867,7 @@ static void overwriteBytes(uint8_t *rom0, uint16_t startAddr, uint8_t const *fix * @param name The file's name, to be displayed for error output * @param fileSize The file's size if known, 0 if not. */ -static void processFile(int input, int output, char const *name, off_t fileSize) -{ +static void processFile(int input, int output, char const *name, off_t fileSize) { // Both of these should be true for seekable files, and neither otherwise if (input == output) assert(fileSize != 0); @@ -896,8 +883,13 @@ static void processFile(int input, int output, char const *name, off_t fileSize) report("FATAL: Failed to read \"%s\"'s header: %s\n", name, strerror(errno)); return; } else if (rom0Len < headerSize) { - report("FATAL: \"%s\" too short, expected at least %jd ($%jx) bytes, got only %jd\n", - name, (intmax_t)headerSize, (intmax_t)headerSize, (intmax_t)rom0Len); + report( + "FATAL: \"%s\" too short, expected at least %jd ($%jx) bytes, got only %jd\n", + name, + (intmax_t)headerSize, + (intmax_t)headerSize, + (intmax_t)rom0Len + ); return; } // Accept partial reads if the file contains at least the header @@ -919,8 +911,9 @@ static void processFile(int input, int output, char const *name, off_t fileSize) overwriteByte(rom0, 0x143, model == BOTH ? 0x80 : 0xC0, "CGB flag"); if (newLicensee) - overwriteBytes(rom0, 0x144, (uint8_t const *)newLicensee, newLicenseeLen, - "new licensee code"); + overwriteBytes( + rom0, 0x144, (uint8_t const *)newLicensee, newLicenseeLen, "new licensee code" + ); if (sgb) overwriteByte(rom0, 0x146, 0x03, "SGB flag"); @@ -963,9 +956,11 @@ static void processFile(int input, int output, char const *name, off_t fileSize) if (oldLicensee != UNSPECIFIED) overwriteByte(rom0, 0x14B, oldLicensee, "old licensee code"); else if (sgb && rom0[0x14B] != 0x33) - fprintf(stderr, - "warning: SGB compatibility enabled, but old licensee was 0x%02x, not 0x33\n", - rom0[0x14B]); + fprintf( + stderr, + "warning: SGB compatibility enabled, but old licensee was 0x%02x, not 0x33\n", + rom0[0x14B] + ); if (romVersion != UNSPECIFIED) overwriteByte(rom0, 0x14C, romVersion, "mask ROM version number"); @@ -981,9 +976,9 @@ static void processFile(int input, int output, char const *name, off_t fileSize) // 65536 banks = 1 GiB. // This should be reasonable for the time being, and may be extended later. std::vector romx; // Buffer of ROMX bank data - uint32_t nbBanks = 1; // Number of banks *targeted*, including ROM0 - size_t totalRomxLen = 0; // *Actual* size of ROMX data - uint8_t bank[BANK_SIZE]; // Temp buffer used to store a whole bank's worth of data + uint32_t nbBanks = 1; // Number of banks *targeted*, including ROM0 + size_t totalRomxLen = 0; // *Actual* size of ROMX data + uint8_t bank[BANK_SIZE]; // Temp buffer used to store a whole bank's worth of data // Handle ROMX if (input == output) { @@ -1006,7 +1001,9 @@ static void processFile(int input, int output, char const *name, off_t fileSize) // Update bank count, ONLY IF at least one byte was read if (bankLen) { // We're gonna read another bank, check that it won't be too much - static_assert(0x10000 * BANK_SIZE <= SSIZE_MAX, "Max input file size too large for OS"); + static_assert( + 0x10000 * BANK_SIZE <= SSIZE_MAX, "Max input file size too large for OS" + ); if (nbBanks == 0x10000) { report("FATAL: \"%s\" has more than 65536 banks\n", name); return; @@ -1062,8 +1059,7 @@ static void processFile(int input, int output, char const *name, off_t fileSize) for (uint16_t i = 0x134; i < 0x14D; i++) sum -= rom0[i] + 1; - overwriteByte(rom0, 0x14D, fixSpec & TRASH_HEADER_SUM ? ~sum : sum, - "header checksum"); + overwriteByte(rom0, 0x14D, fixSpec & TRASH_HEADER_SUM ? ~sum : sum, "header checksum"); } if (fixSpec & (FIX_GLOBAL_SUM | TRASH_GLOBAL_SUM)) { @@ -1113,8 +1109,12 @@ static void processFile(int input, int output, char const *name, off_t fileSize) report("FATAL: Failed to write \"%s\"'s ROM0: %s\n", name, strerror(errno)); return; } else if (writeLen < rom0Len) { - report("FATAL: Could only write %jd of \"%s\"'s %jd ROM0 bytes\n", - (intmax_t)writeLen, name, (intmax_t)rom0Len); + report( + "FATAL: Could only write %jd of \"%s\"'s %jd ROM0 bytes\n", + (intmax_t)writeLen, + name, + (intmax_t)rom0Len + ); return; } @@ -1127,8 +1127,12 @@ static void processFile(int input, int output, char const *name, off_t fileSize) report("FATAL: Failed to write \"%s\"'s ROMX: %s\n", name, strerror(errno)); return; } else if ((size_t)writeLen < totalRomxLen) { - report("FATAL: Could only write %jd of \"%s\"'s %zu ROMX bytes\n", - (intmax_t)writeLen, name, totalRomxLen); + report( + "FATAL: Could only write %jd of \"%s\"'s %zu ROMX bytes\n", + (intmax_t)writeLen, + name, + totalRomxLen + ); return; } } @@ -1137,8 +1141,7 @@ static void processFile(int input, int output, char const *name, off_t fileSize) if (padValue != UNSPECIFIED) { if (input == output) { if (lseek(output, 0, SEEK_END) == (off_t)-1) { - report("FATAL: Failed to seek to end of \"%s\": %s\n", - name, strerror(errno)); + report("FATAL: Failed to seek to end of \"%s\": %s\n", name, strerror(errno)); return; } } @@ -1153,8 +1156,7 @@ static void processFile(int input, int output, char const *name, off_t fileSize) // The return value is either -1, or at most `thisLen`, // so it's fine to cast to `size_t` if ((size_t)ret != thisLen) { - report("FATAL: Failed to write \"%s\"'s padding: %s\n", - name, strerror(errno)); + report("FATAL: Failed to write \"%s\"'s padding: %s\n", name, strerror(errno)); break; } len -= thisLen; @@ -1162,8 +1164,7 @@ static void processFile(int input, int output, char const *name, off_t fileSize) } } -static bool processFilename(char const *name) -{ +static bool processFilename(char const *name) { nbErrors = 0; if (!strcmp(name, "-")) { (void)setmode(STDIN_FILENO, O_BINARY); @@ -1181,21 +1182,24 @@ static bool processFilename(char const *name) struct stat stat; if (input == -1) { - report("FATAL: Failed to open \"%s\" for reading+writing: %s\n", - name, strerror(errno)); + report("FATAL: Failed to open \"%s\" for reading+writing: %s\n", name, strerror(errno)); goto finish; } if (fstat(input, &stat) == -1) { report("FATAL: Failed to stat \"%s\": %s\n", name, strerror(errno)); } else if (!S_ISREG(stat.st_mode)) { // TODO: Do we want to support other types? - report("FATAL: \"%s\" is not a regular file, and thus cannot be modified in-place\n", - name); + report( + "FATAL: \"%s\" is not a regular file, and thus cannot be modified in-place\n", name + ); } else if (stat.st_size < 0x150) { // This check is in theory redundant with the one in `processFile`, but it // prevents passing a file size of 0, which usually indicates pipes - report("FATAL: \"%s\" too short, expected at least 336 ($150) bytes, got only %jd\n", - name, (intmax_t)stat.st_size); + report( + "FATAL: \"%s\" too short, expected at least 336 ($150) bytes, got only %jd\n", + name, + (intmax_t)stat.st_size + ); } else { processFile(input, input, name, stat.st_size); } @@ -1204,48 +1208,53 @@ static bool processFilename(char const *name) } finish: if (nbErrors) - fprintf(stderr, "Fixing \"%s\" failed with %u error%s\n", - name, nbErrors, nbErrors == 1 ? "" : "s"); + fprintf( + stderr, + "Fixing \"%s\" failed with %u error%s\n", + name, + nbErrors, + nbErrors == 1 ? "" : "s" + ); return nbErrors; } -int main(int argc, char *argv[]) -{ +int main(int argc, char *argv[]) { nbErrors = 0; for (int ch; (ch = musl_getopt_long_only(argc, argv, optstring, longopts, nullptr)) != -1;) { switch (ch) { size_t len; #define parseByte(output, name) \ -do { \ - char *endptr; \ - unsigned long tmp; \ - \ - if (musl_optarg[0] == 0) { \ - report("error: Argument to option '" name "' may not be empty\n"); \ - } else { \ - if (musl_optarg[0] == '$') { \ - tmp = strtoul(&musl_optarg[1], &endptr, 16); \ + do { \ + char *endptr; \ + unsigned long tmp; \ +\ + if (musl_optarg[0] == 0) { \ + report("error: Argument to option '" name "' may not be empty\n"); \ } else { \ - tmp = strtoul(musl_optarg, &endptr, 0); \ + if (musl_optarg[0] == '$') { \ + tmp = strtoul(&musl_optarg[1], &endptr, 16); \ + } else { \ + tmp = strtoul(musl_optarg, &endptr, 0); \ + } \ + if (*endptr) \ + report( \ + "error: Expected number as argument to option '" name "', got %s\n", \ + musl_optarg \ + ); \ + else if (tmp > 0xFF) \ + report("error: Argument to option '" name "' is larger than 255: %lu\n", tmp); \ + else \ + output = tmp; \ } \ - if (*endptr) \ - report("error: Expected number as argument to option '" name "', got %s\n", \ - musl_optarg); \ - else if (tmp > 0xFF) \ - report("error: Argument to option '" name "' is larger than 255: %lu\n", tmp); \ - else \ - output = tmp; \ - } \ -} while (0) + } while (0) case 'C': case 'c': model = ch == 'c' ? BOTH : CGB; if (titleLen > 15) { titleLen = 15; - fprintf(stderr, "warning: Truncating title \"%s\" to 15 chars\n", - title); + fprintf(stderr, "warning: Truncating title \"%s\" to 15 chars\n", title); } break; @@ -1260,12 +1269,11 @@ do { \ #define SPEC_g FIX_GLOBAL_SUM #define SPEC_G TRASH_GLOBAL_SUM #define overrideSpec(cur, bad) \ -do { \ - if (fixSpec & SPEC_##bad) \ - fprintf(stderr, \ - "warning: '" #cur "' overriding '" #bad "' in fix spec\n"); \ - fixSpec = (fixSpec & ~SPEC_##bad) | SPEC_##cur; \ -} while (0) + do { \ + if (fixSpec & SPEC_##bad) \ + fprintf(stderr, "warning: '" #cur "' overriding '" #bad "' in fix spec\n"); \ + fixSpec = (fixSpec & ~SPEC_##bad) | SPEC_##cur; \ + } while (0) case 'l': overrideSpec(l, L); break; @@ -1288,8 +1296,7 @@ do { \ break; default: - fprintf(stderr, "warning: Ignoring '%c' in fix spec\n", - *musl_optarg); + fprintf(stderr, "warning: Ignoring '%c' in fix spec\n", *musl_optarg); #undef overrideSpec } musl_optarg++; @@ -1301,14 +1308,12 @@ do { \ len = strlen(gameID); if (len > 4) { len = 4; - fprintf(stderr, "warning: Truncating game ID \"%s\" to 4 chars\n", - gameID); + fprintf(stderr, "warning: Truncating game ID \"%s\" to 4 chars\n", gameID); } gameIDLen = len; if (titleLen > 11) { titleLen = 11; - fprintf(stderr, "warning: Truncating title \"%s\" to 11 chars\n", - title); + fprintf(stderr, "warning: Truncating title \"%s\" to 11 chars\n", title); } break; @@ -1321,9 +1326,9 @@ do { \ len = strlen(newLicensee); if (len > 2) { len = 2; - fprintf(stderr, - "warning: Truncating new licensee \"%s\" to 2 chars\n", - newLicensee); + fprintf( + stderr, "warning: Truncating new licensee \"%s\" to 2 chars\n", newLicensee + ); } newLicenseeLen = len; break; @@ -1335,18 +1340,22 @@ do { \ case 'm': cartridgeType = parseMBC(musl_optarg); if (cartridgeType == MBC_BAD) { - report("error: Unknown MBC \"%s\"\nAccepted MBC names:\n", - musl_optarg); + report("error: Unknown MBC \"%s\"\nAccepted MBC names:\n", musl_optarg); printAcceptedMBCNames(); } else if (cartridgeType == MBC_WRONG_FEATURES) { - report("error: Features incompatible with MBC (\"%s\")\nAccepted combinations:\n", - musl_optarg); + report( + "error: Features incompatible with MBC (\"%s\")\nAccepted combinations:\n", + musl_optarg + ); printAcceptedMBCNames(); } else if (cartridgeType == MBC_BAD_RANGE) { - report("error: Specified MBC ID out of range 0-255: %s\n", - musl_optarg); + report("error: Specified MBC ID out of range 0-255: %s\n", musl_optarg); } else if (cartridgeType == ROM_RAM || cartridgeType == ROM_RAM_BATTERY) { - fprintf(stderr, "warning: ROM+RAM / ROM+RAM+BATTERY are under-specified and poorly supported\n"); + fprintf( + stderr, + "warning: ROM+RAM / ROM+RAM+BATTERY are under-specified and poorly " + "supported\n" + ); } break; @@ -1377,8 +1386,7 @@ do { \ if (len > maxLen) { len = maxLen; - fprintf(stderr, "warning: Truncating title \"%s\" to %u chars\n", - title, maxLen); + fprintf(stderr, "warning: Truncating title \"%s\" to %u chars\n", title, maxLen); } titleLen = len; break; @@ -1401,42 +1409,58 @@ do { \ } if ((cartridgeType & 0xFF00) == TPP1 && !japanese) - fprintf(stderr, "warning: TPP1 overwrites region flag for its identification code, ignoring `-j`\n"); + fprintf( + stderr, + "warning: TPP1 overwrites region flag for its identification code, ignoring `-j`\n" + ); // Check that RAM size is correct for "standard" mappers if (ramSize != UNSPECIFIED && (cartridgeType & 0xFF00) == 0) { if (cartridgeType == ROM_RAM || cartridgeType == ROM_RAM_BATTERY) { if (ramSize != 1) - fprintf(stderr, "warning: MBC \"%s\" should have 2 KiB of RAM (-r 1)\n", - mbcName(cartridgeType)); + fprintf( + stderr, + "warning: MBC \"%s\" should have 2 KiB of RAM (-r 1)\n", + mbcName(cartridgeType) + ); } else if (hasRAM(cartridgeType)) { if (!ramSize) { - fprintf(stderr, - "warning: MBC \"%s\" has RAM, but RAM size was set to 0\n", - mbcName(cartridgeType)); + fprintf( + stderr, + "warning: MBC \"%s\" has RAM, but RAM size was set to 0\n", + mbcName(cartridgeType) + ); } else if (ramSize == 1) { - fprintf(stderr, - "warning: RAM size 1 (2 KiB) was specified for MBC \"%s\"\n", - mbcName(cartridgeType)); + fprintf( + stderr, + "warning: RAM size 1 (2 KiB) was specified for MBC \"%s\"\n", + mbcName(cartridgeType) + ); } // TODO: check possible values? } else if (ramSize) { - fprintf(stderr, - "warning: MBC \"%s\" has no RAM, but RAM size was set to %u\n", - mbcName(cartridgeType), ramSize); + fprintf( + stderr, + "warning: MBC \"%s\" has no RAM, but RAM size was set to %u\n", + mbcName(cartridgeType), + ramSize + ); } } if (sgb && oldLicensee != UNSPECIFIED && oldLicensee != 0x33) - fprintf(stderr, - "warning: SGB compatibility enabled, but old licensee is 0x%02x, not 0x33\n", - oldLicensee); + fprintf( + stderr, + "warning: SGB compatibility enabled, but old licensee is 0x%02x, not 0x33\n", + oldLicensee + ); argv += musl_optind; bool failed = nbErrors; if (!*argv) { - fputs("FATAL: Please specify an input file (pass `-` to read from standard input)\n", - stderr); + fputs( + "FATAL: Please specify an input file (pass `-` to read from standard input)\n", stderr + ); printUsage(); exit(1); } diff --git a/src/gfx/main.cpp b/src/gfx/main.cpp index ace00a38..2f9e7671 100644 --- a/src/gfx/main.cpp +++ b/src/gfx/main.cpp @@ -118,52 +118,54 @@ static char const *optstring = "-Aa:b:Cc:Dd:FfhL:mN:n:Oo:Pp:Qq:r:s:Tt:U:uVvx:Z"; * over short opt matching */ static option const longopts[] = { - {"auto-attr-map", no_argument, nullptr, 'A'}, - {"output-attr-map", no_argument, nullptr, -'A'}, // Deprecated - {"attr-map", required_argument, nullptr, 'a'}, - {"base-tiles", required_argument, nullptr, 'b'}, - {"color-curve", no_argument, nullptr, 'C'}, - {"colors", required_argument, nullptr, 'c'}, - {"depth", required_argument, nullptr, 'd'}, - {"slice", required_argument, nullptr, 'L'}, - {"mirror-tiles", no_argument, nullptr, 'm'}, - {"nb-tiles", required_argument, nullptr, 'N'}, - {"nb-palettes", required_argument, nullptr, 'n'}, - {"group-outputs", no_argument, nullptr, 'O'}, - {"output", required_argument, nullptr, 'o'}, - {"auto-palette", no_argument, nullptr, 'P'}, - {"output-palette", no_argument, nullptr, -'P'}, // Deprecated - {"palette", required_argument, nullptr, 'p'}, - {"auto-palette-map", no_argument, nullptr, 'Q'}, - {"output-palette-map", no_argument, nullptr, -'Q'}, // Deprecated - {"palette-map", required_argument, nullptr, 'q'}, - {"reverse", required_argument, nullptr, 'r'}, - {"auto-tilemap", no_argument, nullptr, 'T'}, - {"output-tilemap", no_argument, nullptr, -'T'}, // Deprecated - {"tilemap", required_argument, nullptr, 't'}, - {"unit-size", required_argument, nullptr, 'U'}, - {"unique-tiles", no_argument, nullptr, 'u'}, - {"version", no_argument, nullptr, 'V'}, - {"verbose", no_argument, nullptr, 'v'}, - {"trim-end", required_argument, nullptr, 'x'}, - {"columns", no_argument, nullptr, 'Z'}, - {nullptr, no_argument, nullptr, 0 } + {"auto-attr-map", no_argument, nullptr, 'A' }, + {"output-attr-map", no_argument, nullptr, -'A'}, // Deprecated + {"attr-map", required_argument, nullptr, 'a' }, + {"base-tiles", required_argument, nullptr, 'b' }, + {"color-curve", no_argument, nullptr, 'C' }, + {"colors", required_argument, nullptr, 'c' }, + {"depth", required_argument, nullptr, 'd' }, + {"slice", required_argument, nullptr, 'L' }, + {"mirror-tiles", no_argument, nullptr, 'm' }, + {"nb-tiles", required_argument, nullptr, 'N' }, + {"nb-palettes", required_argument, nullptr, 'n' }, + {"group-outputs", no_argument, nullptr, 'O' }, + {"output", required_argument, nullptr, 'o' }, + {"auto-palette", no_argument, nullptr, 'P' }, + {"output-palette", no_argument, nullptr, -'P'}, // Deprecated + {"palette", required_argument, nullptr, 'p' }, + {"auto-palette-map", no_argument, nullptr, 'Q' }, + {"output-palette-map", no_argument, nullptr, -'Q'}, // Deprecated + {"palette-map", required_argument, nullptr, 'q' }, + {"reverse", required_argument, nullptr, 'r' }, + {"auto-tilemap", no_argument, nullptr, 'T' }, + {"output-tilemap", no_argument, nullptr, -'T'}, // Deprecated + {"tilemap", required_argument, nullptr, 't' }, + {"unit-size", required_argument, nullptr, 'U' }, + {"unique-tiles", no_argument, nullptr, 'u' }, + {"version", no_argument, nullptr, 'V' }, + {"verbose", no_argument, nullptr, 'v' }, + {"trim-end", required_argument, nullptr, 'x' }, + {"columns", no_argument, nullptr, 'Z' }, + {nullptr, no_argument, nullptr, 0 } }; static void printUsage() { - fputs("Usage: rgbgfx [-r stride] [-CmOuVZ] [-v [-v ...]] [-a | -A]\n" - " [-b ] [-c ] [-d ] [-L ] [-N ]\n" - " [-n ] [-o ] [-p | -P] [-q | -Q]\n" - " [-s ] [-t | -T] [-x ] \n" - "Useful options:\n" - " -m, --mirror-tiles optimize out mirrored tiles\n" - " -o, --output output the tile data to this path\n" - " -t, --tilemap output the tile map to this path\n" - " -u, --unique-tiles optimize out identical tiles\n" - " -V, --version print RGBGFX version and exit\n" - "\n" - "For help, use `man rgbgfx' or go to https://rgbds.gbdev.io/docs/\n", - stderr); + fputs( + "Usage: rgbgfx [-r stride] [-CmOuVZ] [-v [-v ...]] [-a | -A]\n" + " [-b ] [-c ] [-d ] [-L ] [-N ]\n" + " [-n ] [-o ] [-p | -P] [-q | -Q]\n" + " [-s ] [-t | -T] [-x ] \n" + "Useful options:\n" + " -m, --mirror-tiles optimize out mirrored tiles\n" + " -o, --output output the tile data to this path\n" + " -t, --tilemap output the tile map to this path\n" + " -u, --unique-tiles optimize out identical tiles\n" + " -V, --version print RGBGFX version and exit\n" + "\n" + "For help, use `man rgbgfx' or go to https://rgbds.gbdev.io/docs/\n", + stderr + ); } /* @@ -215,8 +217,9 @@ static uint16_t parseNumber(char *&string, char const *errPrefix, uint16_t errVa }; if (charIndex(*string) == 255) { - error("%s: expected digit%s, but found nothing", errPrefix, - base != 10 ? " after base" : ""); + error( + "%s: expected digit%s, but found nothing", errPrefix, base != 10 ? " after base" : "" + ); return errVal; } uint16_t number = 0; @@ -246,10 +249,13 @@ static void skipWhitespace(char *&arg) { static void registerInput(char const *arg) { if (!options.input.empty()) { - fprintf(stderr, - "FATAL: input image specified more than once! (first \"%s\", then " - "\"%s\")\n", - options.input.c_str(), arg); + fprintf( + stderr, + "FATAL: input image specified more than once! (first \"%s\", then " + "\"%s\")\n", + options.input.c_str(), + arg + ); printUsage(); exit(1); } else if (arg[0] == '\0') { // Empty input path @@ -272,8 +278,10 @@ static std::vector readAtFile(std::string const &path, std::vector } // We only filter out `EOF`, but calling `isblank()` on anything else is UB! - static_assert(std::remove_reference_t::traits_type::eof() == EOF, - "isblank(char_traits<...>::eof()) is UB!"); + static_assert( + std::remove_reference_t::traits_type::eof() == EOF, + "isblank(char_traits<...>::eof()) is UB!" + ); std::vector argvOfs; for (;;) { @@ -296,7 +304,7 @@ static std::vector readAtFile(std::string const &path, std::vector } continue; // Start processing the next line // If it's an empty line, ignore it - case '\r': // Assuming CRLF here + case '\r': // Assuming CRLF here file->sbumpc(); // Discard the upcoming '\n' [[fallthrough]]; case '\n': @@ -371,8 +379,10 @@ static char *parseArgv(int argc, char *argv[]) { } skipWhitespace(arg); if (*arg != ',') { - error("Base tile IDs must be one or two comma-separated numbers, not \"%s\"", - musl_optarg); + error( + "Base tile IDs must be one or two comma-separated numbers, not \"%s\"", + musl_optarg + ); break; } ++arg; // Skip comma @@ -384,8 +394,10 @@ static char *parseArgv(int argc, char *argv[]) { options.baseTileIDs[1] = number; } if (*arg != '\0') { - error("Base tile IDs must be one or two comma-separated numbers, not \"%s\"", - musl_optarg); + error( + "Base tile IDs must be one or two comma-separated numbers, not \"%s\"", + musl_optarg + ); break; } break; @@ -474,8 +486,10 @@ static char *parseArgv(int argc, char *argv[]) { } skipWhitespace(arg); if (*arg != ',') { - error("Bank capacity must be one or two comma-separated numbers, not \"%s\"", - musl_optarg); + error( + "Bank capacity must be one or two comma-separated numbers, not \"%s\"", + musl_optarg + ); break; } ++arg; // Skip comma @@ -485,8 +499,10 @@ static char *parseArgv(int argc, char *argv[]) { error("Bank 1 cannot contain more than 256 tiles"); } if (*arg != '\0') { - error("Bank capacity must be one or two comma-separated numbers, not \"%s\"", - musl_optarg); + error( + "Bank capacity must be one or two comma-separated numbers, not \"%s\"", + musl_optarg + ); break; } break; @@ -604,7 +620,7 @@ static char *parseArgv(int argc, char *argv[]) { int main(int argc, char *argv[]) { struct AtFileStackEntry { - int parentInd; // Saved offset into parent argv + int parentInd; // Saved offset into parent argv std::vector argv; // This context's arg pointer vec std::vector argPool; @@ -633,7 +649,7 @@ int main(int argc, char *argv[]) { curArgc = stackEntry.argv.size() - 1; curArgv = stackEntry.argv.data(); musl_optind = 1; // Don't use 0 because we're not scanning a different argv per se - continue; // Begin scanning that arg vector + continue; // Begin scanning that arg vector } if (musl_optind != curArgc) { @@ -665,16 +681,23 @@ int main(int argc, char *argv[]) { if (options.nbColorsPerPal == 0) { options.nbColorsPerPal = 1u << options.bitDepth; } else if (options.nbColorsPerPal > 1u << options.bitDepth) { - error("%" PRIu8 "bpp palettes can only contain %u colors, not %" PRIu8, options.bitDepth, - 1u << options.bitDepth, options.nbColorsPerPal); + error( + "%" PRIu8 "bpp palettes can only contain %u colors, not %" PRIu8, + options.bitDepth, + 1u << options.bitDepth, + options.nbColorsPerPal + ); } auto autoOutPath = [](bool autoOptEnabled, std::string &path, char const *extension) { if (autoOptEnabled) { auto &image = localOptions.groupOutputs ? options.output : options.input; if (image.empty()) { - fprintf(stderr, "FATAL: No %s specified\n", localOptions.groupOutputs - ? "output tile data file" : "input image"); + fprintf( + stderr, + "FATAL: No %s specified\n", + localOptions.groupOutputs ? "output tile data file" : "input image" + ); printUsage(); exit(1); } @@ -723,7 +746,8 @@ int main(int argc, char *argv[]) { static std::array textbox{ " ,----------------------------------------.", " | Augh, dimensional interference again?! |", - " `----------------------------------------'"}; + " `----------------------------------------'", + }; for (size_t i = 0; i < gfx.size(); ++i) { uint16_t row = gfx[i]; for (uint8_t _ = 0; _ < 10; ++_) { @@ -781,15 +805,27 @@ int main(int argc, char *argv[]) { } fputs("\t]\n", stderr); } - fprintf(stderr, - "\tInput image slice: %" PRIu32 "x%" PRIu32 " pixels starting at (%" PRIi32 - ", %" PRIi32 ")\n", - options.inputSlice.width, options.inputSlice.height, options.inputSlice.left, - options.inputSlice.top); - fprintf(stderr, "\tBase tile IDs: [%" PRIu8 ", %" PRIu8 "]\n", options.baseTileIDs[0], - options.baseTileIDs[1]); - fprintf(stderr, "\tMaximum %" PRIu16 " tiles in bank 0, %" PRIu16 " in bank 1\n", - options.maxNbTiles[0], options.maxNbTiles[1]); + fprintf( + stderr, + "\tInput image slice: %" PRIu32 "x%" PRIu32 " pixels starting at (%" PRIi32 ", %" PRIi32 + ")\n", + options.inputSlice.width, + options.inputSlice.height, + options.inputSlice.left, + options.inputSlice.top + ); + fprintf( + stderr, + "\tBase tile IDs: [%" PRIu8 ", %" PRIu8 "]\n", + options.baseTileIDs[0], + options.baseTileIDs[1] + ); + fprintf( + stderr, + "\tMaximum %" PRIu16 " tiles in bank 0, %" PRIu16 " in bank 1\n", + options.maxNbTiles[0], + options.maxNbTiles[1] + ); auto printPath = [](char const *name, std::string const &path) { if (!path.empty()) { fprintf(stderr, "\t%s: %s\n", name, path.c_str()); @@ -814,8 +850,7 @@ int main(int argc, char *argv[]) { } else { process(); } - } else if (!options.palettes.empty() && options.palSpecType == Options::EXPLICIT - && !options.reverse()) { + } else if (!options.palettes.empty() && options.palSpecType == Options::EXPLICIT && !options.reverse()) { processPalettes(); } else { fputs("FATAL: No input image specified\n", stderr); @@ -832,7 +867,7 @@ int main(int argc, char *argv[]) { void Palette::addColor(uint16_t color) { for (size_t i = 0; true; ++i) { assert(i < colors.size()); // The packing should guarantee this - if (colors[i] == color) { // The color is already present + if (colors[i] == color) { // The color is already present break; } else if (colors[i] == UINT16_MAX) { // Empty slot colors[i] = color; @@ -858,9 +893,9 @@ auto Palette::begin() -> decltype(colors)::iterator { auto Palette::end() -> decltype(colors)::iterator { // Return an iterator pointing past the last non-empty element. // Since the palette may contain gaps, we must scan from the end. - return std::find_if(colors.rbegin(), colors.rend(), - [](uint16_t c) { return c != UINT16_MAX; }) - .base(); + return std::find_if( + colors.rbegin(), colors.rend(), [](uint16_t c) { return c != UINT16_MAX; } + ).base(); } auto Palette::begin() const -> decltype(colors)::const_iterator { @@ -870,9 +905,9 @@ auto Palette::begin() const -> decltype(colors)::const_iterator { auto Palette::end() const -> decltype(colors)::const_iterator { // Same as the non-const end(). - return std::find_if(colors.rbegin(), colors.rend(), - [](uint16_t c) { return c != UINT16_MAX; }) - .base(); + return std::find_if( + colors.rbegin(), colors.rend(), [](uint16_t c) { return c != UINT16_MAX; } + ).base(); } uint8_t Palette::size() const { diff --git a/src/gfx/pal_packing.cpp b/src/gfx/pal_packing.cpp index 277aec9f..8d35d226 100644 --- a/src/gfx/pal_packing.cpp +++ b/src/gfx/pal_packing.cpp @@ -140,9 +140,10 @@ public: */ template void assign(Ts &&...args) { - auto freeSlot = std::find_if_not( - RANGE(_assigned), - [](std::optional const &slot) { return slot.has_value(); }); + auto freeSlot = + std::find_if_not(RANGE(_assigned), [](std::optional const &slot) { + return slot.has_value(); + }); if (freeSlot == _assigned.end()) { // We are full, use a new slot _assigned.emplace_back(std::forward(args)...); @@ -158,15 +159,20 @@ public: bool empty() const { return std::find_if( RANGE(_assigned), - [](std::optional const &slot) { return slot.has_value(); }) + [](std::optional const &slot) { return slot.has_value(); } + ) == _assigned.end(); } size_t nbProtoPals() const { return std::distance(RANGE(*this)); } private: template - static void addUniqueColors(std::unordered_set &colors, Iter iter, Iter const &end, - std::vector const &protoPals) { + static void addUniqueColors( + std::unordered_set &colors, + Iter iter, + Iter const &end, + std::vector const &protoPals + ) { for (; iter != end; ++iter) { ProtoPalette const &protoPal = protoPals[iter->protoPalIndex]; colors.insert(RANGE(protoPal)); @@ -226,8 +232,8 @@ public: * Computes the "relative size" of a set of proto-palettes on this palette */ template - auto combinedVolume(Iter &&begin, Iter const &end, - std::vector const &protoPals) const { + auto combinedVolume(Iter &&begin, Iter const &end, std::vector const &protoPals) + const { auto &colors = uniqueColors(); addUniqueColors(colors, std::forward(begin), end, protoPals); return colors.size(); @@ -243,8 +249,9 @@ public: } }; -static void decant(std::vector &assignments, - std::vector const &protoPalettes) { +static void decant( + std::vector &assignments, std::vector const &protoPalettes +) { // "Decanting" is the process of moving all *things* that can fit in a lower index there auto decantOn = [&assignments](auto const &tryDecanting) { // No need to attempt decanting on palette #0, as there are no palettes to decant to @@ -268,8 +275,9 @@ static void decant(std::vector &assignments, } }; - options.verbosePrint(Options::VERB_DEBUG, "%zu palettes before decanting\n", - assignments.size()); + options.verbosePrint( + Options::VERB_DEBUG, "%zu palettes before decanting\n", assignments.size() + ); // Decant on palettes decantOn([&protoPalettes](AssignedProtos &to, AssignedProtos &from) { @@ -281,8 +289,9 @@ static void decant(std::vector &assignments, from.clear(); } }); - options.verbosePrint(Options::VERB_DEBUG, "%zu palettes after decanting on palettes\n", - assignments.size()); + options.verbosePrint( + Options::VERB_DEBUG, "%zu palettes after decanting on palettes\n", assignments.size() + ); // Decant on "components" (= proto-pals sharing colors) decantOn([&protoPalettes](AssignedProtos &to, AssignedProtos &from) { @@ -331,8 +340,9 @@ static void decant(std::vector &assignments, } } }); - options.verbosePrint(Options::VERB_DEBUG, "%zu palettes after decanting on \"components\"\n", - assignments.size()); + options.verbosePrint( + Options::VERB_DEBUG, "%zu palettes after decanting on \"components\"\n", assignments.size() + ); // Decant on individual proto-palettes decantOn([&protoPalettes](AssignedProtos &to, AssignedProtos &from) { @@ -343,14 +353,16 @@ static void decant(std::vector &assignments, } } }); - options.verbosePrint(Options::VERB_DEBUG, "%zu palettes after decanting on proto-palettes\n", - assignments.size()); + options.verbosePrint( + Options::VERB_DEBUG, "%zu palettes after decanting on proto-palettes\n", assignments.size() + ); } std::tuple, size_t> overloadAndRemove(std::vector const &protoPalettes) { - options.verbosePrint(Options::VERB_LOG_ACT, - "Paginating palettes using \"overload-and-remove\" strategy...\n"); + options.verbosePrint( + Options::VERB_LOG_ACT, "Paginating palettes using \"overload-and-remove\" strategy...\n" + ); // Sort the proto-palettes by size, which improves the packing algorithm's efficiency DefaultInitVec sortedProtoPalIDs(protoPalettes.size()); @@ -379,9 +391,14 @@ std::tuple, size_t> continue; } - options.verbosePrint(Options::VERB_DEBUG, "%zu/%zu: Rel size: %f (size = %zu)\n", i + 1, - assignments.size(), assignments[i].relSizeOf(protoPal), - protoPal.size()); + options.verbosePrint( + Options::VERB_DEBUG, + "%zu/%zu: Rel size: %f (size = %zu)\n", + i + 1, + assignments.size(), + assignments[i].relSizeOf(protoPal), + protoPal.size() + ); if (assignments[i].relSizeOf(protoPal) < bestRelSize) { bestPalIndex = i; } @@ -397,21 +414,26 @@ std::tuple, size_t> // If this overloads the palette, get it back to normal (if possible) while (bestPal.volume() > options.maxOpaqueColors()) { - options.verbosePrint(Options::VERB_DEBUG, - "Palette %zu is overloaded! (%zu > %" PRIu8 ")\n", - bestPalIndex, bestPal.volume(), options.maxOpaqueColors()); + options.verbosePrint( + Options::VERB_DEBUG, + "Palette %zu is overloaded! (%zu > %" PRIu8 ")\n", + bestPalIndex, + bestPal.volume(), + options.maxOpaqueColors() + ); // Look for a proto-pal minimizing "efficiency" (size / rel_size) auto efficiency = [&bestPal](ProtoPalette const &pal) { return pal.size() / bestPal.relSizeOf(pal); }; - auto [minEfficiencyIter, maxEfficiencyIter] = - std::minmax_element(RANGE(bestPal), - [&efficiency, &protoPalettes](ProtoPalAttrs const &lhs, - ProtoPalAttrs const &rhs) { - return efficiency(protoPalettes[lhs.protoPalIndex]) - < efficiency(protoPalettes[rhs.protoPalIndex]); - }); + auto [minEfficiencyIter, maxEfficiencyIter] = std::minmax_element( + RANGE(bestPal), + [&efficiency, + &protoPalettes](ProtoPalAttrs const &lhs, ProtoPalAttrs const &rhs) { + return efficiency(protoPalettes[lhs.protoPalIndex]) + < efficiency(protoPalettes[rhs.protoPalIndex]); + } + ); // All efficiencies are identical iff min equals max // TODO: maybe not ideal to re-compute these two? @@ -443,18 +465,24 @@ std::tuple, size_t> while (!queue.empty()) { ProtoPalAttrs const &attrs = queue.front(); ProtoPalette const &protoPal = protoPalettes[attrs.protoPalIndex]; - auto iter = - std::find_if(RANGE(assignments), - [&protoPal](AssignedProtos const &pal) { return pal.canFit(protoPal); }); + auto iter = std::find_if(RANGE(assignments), [&protoPal](AssignedProtos const &pal) { + return pal.canFit(protoPal); + }); if (iter == assignments.end()) { // No such page, create a new one - options.verbosePrint(Options::VERB_DEBUG, - "Adding new palette (%zu) for overflowing proto-pal %zu\n", - assignments.size(), attrs.protoPalIndex); + options.verbosePrint( + Options::VERB_DEBUG, + "Adding new palette (%zu) for overflowing proto-pal %zu\n", + assignments.size(), + attrs.protoPalIndex + ); assignments.emplace_back(protoPalettes, std::move(attrs)); } else { - options.verbosePrint(Options::VERB_DEBUG, - "Assigning overflowing proto-pal %zu to palette %zu\n", - attrs.protoPalIndex, iter - assignments.begin()); + options.verbosePrint( + Options::VERB_DEBUG, + "Assigning overflowing proto-pal %zu to palette %zu\n", + attrs.protoPalIndex, + iter - assignments.begin() + ); iter->assign(std::move(attrs)); } queue.pop(); diff --git a/src/gfx/pal_sorting.cpp b/src/gfx/pal_sorting.cpp index 6d4c6744..a63fbb4f 100644 --- a/src/gfx/pal_sorting.cpp +++ b/src/gfx/pal_sorting.cpp @@ -13,13 +13,20 @@ namespace sorting { -void indexed(std::vector &palettes, int palSize, png_color const *palRGB, - int palAlphaSize, png_byte *palAlpha) { +void indexed( + std::vector &palettes, + int palSize, + png_color const *palRGB, + int palAlphaSize, + png_byte *palAlpha +) { options.verbosePrint(Options::VERB_LOG_ACT, "Sorting palettes using embedded palette...\n"); auto pngToRgb = [&palRGB, &palAlphaSize, &palAlpha](int index) { auto const &c = palRGB[index]; - return Rgba(c.red, c.green, c.blue, palAlpha && index < palAlphaSize ? palAlpha[index] : 0xFF); + return Rgba( + c.red, c.green, c.blue, palAlpha && index < palAlphaSize ? palAlpha[index] : 0xFF + ); }; for (Palette &pal : palettes) { @@ -43,8 +50,9 @@ void indexed(std::vector &palettes, int palSize, png_color const *palRG } } -void grayscale(std::vector &palettes, - std::array, 0x8001> const &colors) { +void grayscale( + std::vector &palettes, std::array, 0x8001> const &colors +) { options.verbosePrint(Options::VERB_LOG_ACT, "Sorting grayscale-only palette...\n"); // This method is only applicable if there are at most as many colors as colors per palette, so diff --git a/src/gfx/pal_spec.cpp b/src/gfx/pal_spec.cpp index e92c18a6..e52c3d1d 100644 --- a/src/gfx/pal_spec.cpp +++ b/src/gfx/pal_spec.cpp @@ -66,10 +66,12 @@ void parseInlinePalSpec(char const * const rawArg) { assert(len <= arg.length()); errorMessage(msg); - fprintf(stderr, - "In inline palette spec: %s\n" - " ", - rawArg); + fprintf( + stderr, + "In inline palette spec: %s\n" + " ", + rawArg + ); for (auto i = ofs; i; --i) { putc(' ', stderr); } @@ -97,12 +99,17 @@ void parseInlinePalSpec(char const * const rawArg) { auto pos = std::min(arg.find_first_not_of("0123456789ABCDEFabcdef"sv, n), arg.length()); switch (pos - n) { case 3: - color = Rgba(singleToHex(arg[n + 0]), singleToHex(arg[n + 1]), singleToHex(arg[n + 2]), - 0xFF); + color = Rgba( + singleToHex(arg[n + 0]), singleToHex(arg[n + 1]), singleToHex(arg[n + 2]), 0xFF + ); break; case 6: - color = Rgba(toHex(arg[n + 0], arg[n + 1]), toHex(arg[n + 2], arg[n + 3]), - toHex(arg[n + 4], arg[n + 5]), 0xFF); + color = Rgba( + toHex(arg[n + 0], arg[n + 1]), + toHex(arg[n + 2], arg[n + 3]), + toHex(arg[n + 4], arg[n + 5]), + 0xFF + ); break; case 0: parseError(n - 1, 1, "Missing color after '#'"); @@ -239,36 +246,31 @@ static std::optional parseDec(std::string const &str, std::string::size_type return std::optional{value}; } -static std::optional parseColor(std::string const &str, std::string::size_type &n, - uint16_t i) { +static std::optional + parseColor(std::string const &str, std::string::size_type &n, uint16_t i) { std::optional r = parseDec(str, n); if (!r) { - error("Failed to parse color #%d (\"%s\"): invalid red component", i + 1, - str.c_str()); + error("Failed to parse color #%d (\"%s\"): invalid red component", i + 1, str.c_str()); return std::nullopt; } skipWhitespace(str, n); if (n == str.length()) { - error("Failed to parse color #%d (\"%s\"): missing green component", i + 1, - str.c_str()); + error("Failed to parse color #%d (\"%s\"): missing green component", i + 1, str.c_str()); return std::nullopt; } std::optional g = parseDec(str, n); if (!g) { - error("Failed to parse color #%d (\"%s\"): invalid green component", i + 1, - str.c_str()); + error("Failed to parse color #%d (\"%s\"): invalid green component", i + 1, str.c_str()); return std::nullopt; } skipWhitespace(str, n); if (n == str.length()) { - error("Failed to parse color #%d (\"%s\"): missing blue component", i + 1, - str.c_str()); + error("Failed to parse color #%d (\"%s\"): missing blue component", i + 1, str.c_str()); return std::nullopt; } std::optional b = parseDec(str, n); if (!b) { - error("Failed to parse color #%d (\"%s\"): invalid blue component", i + 1, - str.c_str()); + error("Failed to parse color #%d (\"%s\"): invalid blue component", i + 1, str.c_str()); return std::nullopt; } @@ -301,10 +303,14 @@ static void parsePSPFile(std::filebuf &file) { return; } - if (uint16_t nbPalColors = options.nbColorsPerPal * options.nbPalettes; *nbColors > nbPalColors) { - warning("PSP file contains %" PRIu16 " colors, but there can only be %" PRIu16 - "; ignoring extra", - *nbColors, nbPalColors); + if (uint16_t nbPalColors = options.nbColorsPerPal * options.nbPalettes; + *nbColors > nbPalColors) { + warning( + "PSP file contains %" PRIu16 " colors, but there can only be %" PRIu16 + "; ignoring extra", + *nbColors, + nbPalColors + ); nbColors = nbPalColors; } @@ -320,8 +326,11 @@ static void parsePSPFile(std::filebuf &file) { return; } if (n != line.length()) { - error("Failed to parse color #%d (\"%s\"): trailing characters after blue component", - i + 1, line.c_str()); + error( + "Failed to parse color #%d (\"%s\"): trailing characters after blue component", + i + 1, + line.c_str() + ); return; } @@ -372,9 +381,12 @@ static void parseGPLFile(std::filebuf &file) { } if (nbColors > maxNbColors) { - warning("GPL file contains %" PRIu16 " colors, but there can only be %" PRIu16 - "; ignoring extra", - nbColors, maxNbColors); + warning( + "GPL file contains %" PRIu16 " colors, but there can only be %" PRIu16 + "; ignoring extra", + nbColors, + maxNbColors + ); } } @@ -393,8 +405,11 @@ static void parseHEXFile(std::filebuf &file) { if (line.length() != 6 || line.find_first_not_of("0123456789ABCDEFabcdef"sv) != std::string::npos) { - error("Failed to parse color #%d (\"%s\"): invalid \"rrggbb\" line", - nbColors + 1, line.c_str()); + error( + "Failed to parse color #%d (\"%s\"): invalid \"rrggbb\" line", + nbColors + 1, + line.c_str() + ); return; } @@ -411,9 +426,12 @@ static void parseHEXFile(std::filebuf &file) { } if (nbColors > maxNbColors) { - warning("HEX file contains %" PRIu16 " colors, but there can only be %" PRIu16 - "; ignoring extra", - nbColors, maxNbColors); + warning( + "HEX file contains %" PRIu16 " colors, but there can only be %" PRIu16 + "; ignoring extra", + nbColors, + maxNbColors + ); } } @@ -436,10 +454,14 @@ static void parseACTFile(std::filebuf &file) { return; } - if (uint16_t nbPalColors = options.nbColorsPerPal * options.nbPalettes; nbColors > nbPalColors) { - warning("ACT file contains %" PRIu16 " colors, but there can only be %" PRIu16 - "; ignoring extra", - nbColors, nbPalColors); + if (uint16_t nbPalColors = options.nbColorsPerPal * options.nbPalettes; + nbColors > nbPalColors) { + warning( + "ACT file contains %" PRIu16 " colors, but there can only be %" PRIu16 + "; ignoring extra", + nbColors, + nbPalColors + ); nbColors = nbPalColors; } @@ -486,10 +508,14 @@ static void parseACOFile(std::filebuf &file) { } uint16_t nbColors = readBE(buf); - if (uint16_t nbPalColors = options.nbColorsPerPal * options.nbPalettes; nbColors > nbPalColors) { - warning("ACO file contains %" PRIu16 " colors, but there can only be %" PRIu16 - "; ignoring extra", - nbColors, nbPalColors); + if (uint16_t nbPalColors = options.nbColorsPerPal * options.nbPalettes; + nbColors > nbPalColors) { + warning( + "ACO file contains %" PRIu16 " colors, but there can only be %" PRIu16 + "; ignoring extra", + nbColors, + nbPalColors + ); nbColors = nbPalColors; } @@ -543,16 +569,22 @@ static void parseGBCFile(std::filebuf &file) { if (len == 0) { break; } else if (len != sizeof(buf)) { - error("GBC palette dump contains %zu 8-byte palette%s, plus %zu byte%s", - options.palSpec.size(), options.palSpec.size() == 1 ? "" : "s", len, - len == 1 ? "" : "s"); + error( + "GBC palette dump contains %zu 8-byte palette%s, plus %zu byte%s", + options.palSpec.size(), + options.palSpec.size() == 1 ? "" : "s", + len, + len == 1 ? "" : "s" + ); break; } - options.palSpec.push_back({Rgba::fromCGBColor(readLE(&buf[0])), - Rgba::fromCGBColor(readLE(&buf[2])), - Rgba::fromCGBColor(readLE(&buf[4])), - Rgba::fromCGBColor(readLE(&buf[6]))}); + options.palSpec.push_back( + {Rgba::fromCGBColor(readLE(&buf[0])), + Rgba::fromCGBColor(readLE(&buf[2])), + Rgba::fromCGBColor(readLE(&buf[4])), + Rgba::fromCGBColor(readLE(&buf[6]))} + ); } } @@ -576,14 +608,16 @@ void parseExternalPalSpec(char const *arg) { std::tuple{"GBC", &parseGBCFile, std::ios::binary}, }; - auto iter = std::find_if(RANGE(parsers), - [&arg, &ptr](decltype(parsers)::value_type const &parser) { - return strncasecmp(arg, std::get<0>(parser), ptr - arg) == 0; - }); + auto iter = + std::find_if(RANGE(parsers), [&arg, &ptr](decltype(parsers)::value_type const &parser) { + return strncasecmp(arg, std::get<0>(parser), ptr - arg) == 0; + }); if (iter == parsers.end()) { - error("Unknown external palette format \"%.*s\"", - static_cast(std::min(ptr - arg, static_cast(INT_MAX))), - arg); + error( + "Unknown external palette format \"%.*s\"", + static_cast(std::min(ptr - arg, static_cast(INT_MAX))), + arg + ); return; } diff --git a/src/gfx/process.cpp b/src/gfx/process.cpp index db93f54c..675a62ed 100644 --- a/src/gfx/process.cpp +++ b/src/gfx/process.cpp @@ -59,10 +59,9 @@ public: } size_t size() const { - return std::count_if(RANGE(_colors), - [](decltype(_colors)::value_type const &slot) { - return slot.has_value() && !slot->isTransparent(); - }); + return std::count_if(RANGE(_colors), [](decltype(_colors)::value_type const &slot) { + return slot.has_value() && !slot->isTransparent(); + }); } decltype(_colors) const &raw() const { return _colors; } @@ -105,10 +104,13 @@ class Png { self->file->sgetn(reinterpret_cast(data), expectedLen); if (nbBytesRead != expectedLen) { - fatal("Error reading input image (\"%s\"): file too short (expected at least %zd more " - "bytes after reading %zu)", - self->c_str(), length - nbBytesRead, - (size_t)self->file->pubseekoff(0, std::ios_base::cur)); + fatal( + "Error reading input image (\"%s\"): file too short (expected at least %zd more " + "bytes after reading %zu)", + self->c_str(), + length - nbBytesRead, + (size_t)self->file->pubseekoff(0, std::ios_base::cur) + ); } } @@ -134,9 +136,12 @@ public: bool isSuitableForGrayscale() const { // Check that all of the grays don't fall into the same "bin" if (colors.size() > options.maxOpaqueColors()) { // Apply the Pigeonhole Principle - options.verbosePrint(Options::VERB_DEBUG, - "Too many colors for grayscale sorting (%zu > %" PRIu8 ")\n", - colors.size(), options.maxOpaqueColors()); + options.verbosePrint( + Options::VERB_DEBUG, + "Too many colors for grayscale sorting (%zu > %" PRIu8 ")\n", + colors.size(), + options.maxOpaqueColors() + ); return false; } uint8_t bins = 0; @@ -145,9 +150,11 @@ public: continue; } if (!color->isGray()) { - options.verbosePrint(Options::VERB_DEBUG, - "Found non-gray color #%08x, not using grayscale sorting\n", - color->toCSS()); + options.verbosePrint( + Options::VERB_DEBUG, + "Found non-gray color #%08x, not using grayscale sorting\n", + color->toCSS() + ); return false; } uint8_t mask = 1 << color->grayIndex(); @@ -155,7 +162,8 @@ public: options.verbosePrint( Options::VERB_DEBUG, "Color #%08x conflicts with another one, not using grayscale sorting\n", - color->toCSS()); + color->toCSS() + ); return false; } bins |= mask; @@ -174,8 +182,7 @@ public: */ explicit Png(std::string const &filePath) : path(filePath), colors() { if (file.open(path, std::ios_base::in | std::ios_base::binary) == nullptr) { - fatal("Failed to open input image (\"%s\"): %s", file.c_str(path), - strerror(errno)); + fatal("Failed to open input image (\"%s\"): %s", file.c_str(path), strerror(errno)); } options.verbosePrint(Options::VERB_LOG_ACT, "Opened input file\n"); @@ -190,8 +197,9 @@ public: options.verbosePrint(Options::VERB_INTERM, "PNG header signature is OK\n"); - png = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)this, handleError, - handleWarning); + png = png_create_read_struct( + PNG_LIBPNG_VER_STRING, (png_voidp)this, handleError, handleWarning + ); if (!png) { fatal("Failed to allocate PNG structure: %s", strerror(errno)); } @@ -215,8 +223,9 @@ public: int bitDepth, interlaceType; //, compressionType, filterMethod; - png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, &interlaceType, nullptr, - nullptr); + png_get_IHDR( + png, info, &width, &height, &bitDepth, &colorType, &interlaceType, nullptr, nullptr + ); if (options.inputSlice.width == 0 && width % 8 != 0) { fatal("Image width (%" PRIu32 " pixels) is not a multiple of 8!", width); @@ -253,23 +262,35 @@ public: fatal("Unknown interlace type %d", interlaceType); } }; - options.verbosePrint(Options::VERB_INTERM, - "Input image: %" PRIu32 "x%" PRIu32 " pixels, %dbpp %s, %s\n", width, - height, bitDepth, colorTypeName(), interlaceTypeName()); + options.verbosePrint( + Options::VERB_INTERM, + "Input image: %" PRIu32 "x%" PRIu32 " pixels, %dbpp %s, %s\n", + width, + height, + bitDepth, + colorTypeName(), + interlaceTypeName() + ); if (png_get_PLTE(png, info, &embeddedPal, &nbColors) != 0) { if (png_get_tRNS(png, info, &transparencyPal, &nbTransparentEntries, nullptr)) { assert(nbTransparentEntries <= nbColors); } - options.verbosePrint(Options::VERB_INTERM, "Embedded palette has %d colors: [", - nbColors); + options.verbosePrint( + Options::VERB_INTERM, "Embedded palette has %d colors: [", nbColors + ); for (int i = 0; i < nbColors; ++i) { auto const &color = embeddedPal[i]; options.verbosePrint( - Options::VERB_INTERM, "#%02x%02x%02x%02x%s", color.red, color.green, color.blue, + Options::VERB_INTERM, + "#%02x%02x%02x%02x%s", + color.red, + color.green, + color.blue, transparencyPal && i < nbTransparentEntries ? transparencyPal[i] : 0xFF, - i != nbColors - 1 ? ", " : "]\n"); + i != nbColors - 1 ? ", " : "]\n" + ); } } else { options.verbosePrint(Options::VERB_INTERM, "No embedded palette\n"); @@ -329,40 +350,51 @@ public: std::vector indeterminates; // Assign a color to the given position, and register it in the image palette as well - auto assignColor = [this, &conflicts, &indeterminates](png_uint_32 x, png_uint_32 y, - Rgba &&color) { - if (!color.isTransparent() && !color.isOpaque()) { - uint32_t css = color.toCSS(); - if (std::find(RANGE(indeterminates), css) - == indeterminates.end()) { - error("Color #%08x is neither transparent (alpha < %u) nor opaque (alpha >= " - "%u) [first seen at x: %" PRIu32 ", y: %" PRIu32 "]", - css, Rgba::transparency_threshold, Rgba::opacity_threshold, x, y); - indeterminates.push_back(css); - } - } else if (Rgba const *other = colors.registerColor(color); other) { - std::tuple conflicting{color.toCSS(), other->toCSS()}; - // Do not report combinations twice - if (std::find(RANGE(conflicts), conflicting) == conflicts.end()) { - warning("Fusing colors #%08x and #%08x into Game Boy color $%04x [first seen " + auto assignColor = + [this, &conflicts, &indeterminates](png_uint_32 x, png_uint_32 y, Rgba &&color) { + if (!color.isTransparent() && !color.isOpaque()) { + uint32_t css = color.toCSS(); + if (std::find(RANGE(indeterminates), css) == indeterminates.end()) { + error( + "Color #%08x is neither transparent (alpha < %u) nor opaque (alpha >= " + "%u) [first seen at x: %" PRIu32 ", y: %" PRIu32 "]", + css, + Rgba::transparency_threshold, + Rgba::opacity_threshold, + x, + y + ); + indeterminates.push_back(css); + } + } else if (Rgba const *other = colors.registerColor(color); other) { + std::tuple conflicting{color.toCSS(), other->toCSS()}; + // Do not report combinations twice + if (std::find(RANGE(conflicts), conflicting) == conflicts.end()) { + warning( + "Fusing colors #%08x and #%08x into Game Boy color $%04x [first seen " "at x: %" PRIu32 ", y: %" PRIu32 "]", - std::get<0>(conflicting), std::get<1>(conflicting), color.cgbColor(), x, - y); - // Do not report this combination again - conflicts.emplace_back(conflicting); - } - } + std::get<0>(conflicting), + std::get<1>(conflicting), + color.cgbColor(), + x, + y + ); + // Do not report this combination again + conflicts.emplace_back(conflicting); + } + } - pixel(x, y) = color; - }; + pixel(x, y) = color; + }; if (interlaceType == PNG_INTERLACE_NONE) { for (png_uint_32 y = 0; y < height; ++y) { png_read_row(png, row.data(), nullptr); for (png_uint_32 x = 0; x < width; ++x) { - assignColor(x, y, - Rgba(row[x * 4], row[x * 4 + 1], row[x * 4 + 2], row[x * 4 + 3])); + assignColor( + x, y, Rgba(row[x * 4], row[x * 4 + 1], row[x * 4 + 2], row[x * 4 + 3]) + ); } } } else { @@ -454,14 +486,17 @@ public: iterator begin() const { return {*this, _limit, 0, 0}; } iterator end() const { iterator it{*this, _limit, _width - 8, _height - 8}; // Last valid one... - return ++it; // ...now one-past-last! + return ++it; // ...now one-past-last! } }; public: TilesVisitor visitAsTiles() const { - return {*this, options.columnMajor, - options.inputSlice.width ? options.inputSlice.width * 8 : width, - options.inputSlice.height ? options.inputSlice.height * 8 : height}; + return { + *this, + options.columnMajor, + options.inputSlice.width ? options.inputSlice.width * 8 : width, + options.inputSlice.height ? options.inputSlice.height * 8 : height, + }; } }; @@ -497,7 +532,7 @@ struct AttrmapEntry { * attrmap entry while correctly handling the above, use `getPalID`. */ size_t protoPaletteID; // Only this field is used when outputting "unoptimized" data - uint8_t tileID; // This is the ID as it will be output to the tilemap + uint8_t tileID; // This is the ID as it will be output to the tilemap bool bank; bool yFlip; bool xFlip; @@ -523,8 +558,12 @@ static void generatePalSpec(Png const &png) { embPalSize = options.maxOpaqueColors(); } for (int i = 0; i < embPalSize; ++i) { - options.palSpec[0][i] = Rgba(embPalRGB[i].red, embPalRGB[i].green, embPalRGB[i].blue, - embPalAlpha && i < embPalAlphaSize ? embPalAlpha[i] : 0xFF); + options.palSpec[0][i] = Rgba( + embPalRGB[i].red, + embPalRGB[i].green, + embPalRGB[i].blue, + embPalAlpha && i < embPalAlphaSize ? embPalAlpha[i] : 0xFF + ); } } @@ -536,8 +575,12 @@ static std::tuple, std::vector> assert(mappings.size() == protoPalettes.size()); if (options.verbosity >= Options::VERB_INTERM) { - fprintf(stderr, "Proto-palette mappings: (%zu palette%s)\n", nbPalettes, - nbPalettes != 1 ? "s" : ""); + fprintf( + stderr, + "Proto-palette mappings: (%zu palette%s)\n", + nbPalettes, + nbPalettes != 1 ? "s" : "" + ); for (size_t i = 0; i < mappings.size(); ++i) { fprintf(stderr, "%zu -> %zu\n", i, mappings[i]); } @@ -615,8 +658,11 @@ static std::tuple, std::vector> mappings[i] = iter - palettes.begin(); // Bogus value, but whatever } if (bad) { - fprintf(stderr, "note: The following palette%s specified:\n", - palettes.size() == 1 ? " was" : "s were"); + fprintf( + stderr, + "note: The following palette%s specified:\n", + palettes.size() == 1 ? " was" : "s were" + ); for (Palette const &pal : palettes) { fprintf(stderr, " [%s]\n", listColors(pal)); } @@ -640,15 +686,17 @@ static void outputPalettes(std::vector const &palettes) { if (palettes.size() > options.nbPalettes) { // If the palette generation is wrong, other (dependee) operations are likely to be // nonsensical, so fatal-error outright - fatal("Generated %zu palettes, over the maximum of %" PRIu8, palettes.size(), - options.nbPalettes); + fatal( + "Generated %zu palettes, over the maximum of %" PRIu8, + palettes.size(), + options.nbPalettes + ); } if (!options.palettes.empty()) { File output; if (!output.open(options.palettes, std::ios_base::out | std::ios_base::binary)) { - fatal("Failed to open \"%s\": %s", output.c_str(options.palettes), - strerror(errno)); + fatal("Failed to open \"%s\": %s", output.c_str(options.palettes), strerror(errno)); } for (Palette const &palette : palettes) { @@ -675,8 +723,8 @@ public: // of altering the element's hash, but the tile ID is not part of it. mutable uint16_t tileID; - static uint16_t rowBitplanes(Png::TilesVisitor::Tile const &tile, Palette const &palette, - uint32_t y) { + static uint16_t + rowBitplanes(Png::TilesVisitor::Tile const &tile, Palette const &palette, uint32_t y) { uint16_t row = 0; for (uint32_t x = 0; x < 8; ++x) { row <<= 1; @@ -734,8 +782,9 @@ public: } // Check if we have horizontal mirroring, which scans the array forward again - if (std::equal(RANGE(_data), other._data.begin(), - [](uint8_t lhs, uint8_t rhs) { return lhs == flipTable[rhs]; })) { + if (std::equal(RANGE(_data), other._data.begin(), [](uint8_t lhs, uint8_t rhs) { + return lhs == flipTable[rhs]; + })) { return MatchType::HFLIP; } @@ -773,16 +822,20 @@ struct std::hash { namespace unoptimized { -static void outputTileData(Png const &png, DefaultInitVec const &attrmap, - std::vector const &palettes, - DefaultInitVec const &mappings) { +static void outputTileData( + Png const &png, + DefaultInitVec const &attrmap, + std::vector const &palettes, + DefaultInitVec const &mappings +) { File output; if (!output.open(options.output, std::ios_base::out | std::ios_base::binary)) { fatal("Failed to open \"%s\": %s", output.c_str(options.output), strerror(errno)); } uint16_t widthTiles = options.inputSlice.width ? options.inputSlice.width : png.getWidth() / 8; - uint16_t heightTiles = options.inputSlice.height ? options.inputSlice.height : png.getHeight() / 8; + uint16_t heightTiles = + options.inputSlice.height ? options.inputSlice.height : png.getHeight() / 8; uint64_t remainingTiles = widthTiles * heightTiles; if (remainingTiles <= options.trim) { return; @@ -808,15 +861,15 @@ static void outputTileData(Png const &png, DefaultInitVec const &a assert(remainingTiles == 0); } -static void outputMaps(DefaultInitVec const &attrmap, - DefaultInitVec const &mappings) { +static void outputMaps( + DefaultInitVec const &attrmap, DefaultInitVec const &mappings +) { std::optional tilemapOutput, attrmapOutput, palmapOutput; auto autoOpenPath = [](std::string const &path, std::optional &file) { if (!path.empty()) { file.emplace(); if (!file->open(path, std::ios_base::out | std::ios_base::binary)) { - fatal("Failed to open \"%s\": %s", file->c_str(options.tilemap), - strerror(errno)); + fatal("Failed to open \"%s\": %s", file->c_str(options.tilemap), strerror(errno)); } } }; @@ -864,8 +917,8 @@ struct UniqueTiles { /* * Adds a tile to the collection, and returns its ID */ - std::tuple addTile(Png::TilesVisitor::Tile const &tile, - Palette const &palette) { + std::tuple + addTile(Png::TilesVisitor::Tile const &tile, Palette const &palette) { TileData newTile(tile, palette); auto [tileData, inserted] = tileset.insert(newTile); @@ -893,9 +946,12 @@ struct UniqueTiles { * 8-bit tile IDs + the bank bit; this will save the work when we output the data later (potentially * twice) */ -static UniqueTiles dedupTiles(Png const &png, DefaultInitVec &attrmap, - std::vector const &palettes, - DefaultInitVec const &mappings) { +static UniqueTiles dedupTiles( + Png const &png, + DefaultInitVec &attrmap, + std::vector const &palettes, + DefaultInitVec const &mappings +) { // Iterate throughout the image, generating tile data as we go // (We don't need the full tile data to be able to dedup tiles, but we don't lose anything // by caching the full tile data anyway, so we might as well.) @@ -941,8 +997,9 @@ static void outputTilemap(DefaultInitVec const &attrmap) { } } -static void outputAttrmap(DefaultInitVec const &attrmap, - DefaultInitVec const &mappings) { +static void outputAttrmap( + DefaultInitVec const &attrmap, DefaultInitVec const &mappings +) { File output; if (!output.open(options.attrmap, std::ios_base::out | std::ios_base::binary)) { fatal("Failed to create \"%s\": %s", output.c_str(options.attrmap), strerror(errno)); @@ -956,8 +1013,9 @@ static void outputAttrmap(DefaultInitVec const &attrmap, } } -static void outputPalmap(DefaultInitVec const &attrmap, - DefaultInitVec const &mappings) { +static void outputPalmap( + DefaultInitVec const &attrmap, DefaultInitVec const &mappings +) { File output; if (!output.open(options.palmap, std::ios_base::out | std::ios_base::binary)) { fatal("Failed to create \"%s\": %s", output.c_str(options.palmap), strerror(errno)); @@ -1063,21 +1121,33 @@ void process() { } if (nbColorsInTile > options.maxOpaqueColors()) { - fatal("Tile at (%" PRIu32 ", %" PRIu32 ") has %" PRIu8 " opaque colors, more than %" PRIu8 "!", - tile.x, tile.y, nbColorsInTile, options.maxOpaqueColors()); + fatal( + "Tile at (%" PRIu32 ", %" PRIu32 ") has %" PRIu8 " opaque colors, more than %" PRIu8 + "!", + tile.x, + tile.y, + nbColorsInTile, + options.maxOpaqueColors() + ); } attrs.protoPaletteID = protoPalettes.size(); if (protoPalettes.size() == AttrmapEntry::transparent) { // Check for overflow - fatal("Reached %zu proto-palettes... sorry, this image is too much for me to handle :(", - AttrmapEntry::transparent); + fatal( + "Reached %zu proto-palettes... sorry, this image is too much for me to handle :(", + AttrmapEntry::transparent + ); } protoPalettes.push_back(tileColors); contained:; } - options.verbosePrint(Options::VERB_INTERM, "Image contains %zu proto-palette%s\n", - protoPalettes.size(), protoPalettes.size() != 1 ? "s" : ""); + options.verbosePrint( + Options::VERB_INTERM, + "Image contains %zu proto-palette%s\n", + protoPalettes.size(), + protoPalettes.size() != 1 ? "s" : "" + ); if (options.verbosity >= Options::VERB_INTERM) { for (auto const &protoPal : protoPalettes) { fputs("[ ", stderr); @@ -1102,8 +1172,12 @@ contained:; // Check the tile count if (nbTilesW * nbTilesH > options.maxNbTiles[0] + options.maxNbTiles[1]) { - fatal("Image contains %" PRIu32 " tiles, exceeding the limit of %" PRIu16 " + %" PRIu16, - nbTilesW * nbTilesH, options.maxNbTiles[0], options.maxNbTiles[1]); + fatal( + "Image contains %" PRIu32 " tiles, exceeding the limit of %" PRIu16 " + %" PRIu16, + nbTilesW * nbTilesH, + options.maxNbTiles[0], + options.maxNbTiles[1] + ); } if (!options.output.empty()) { @@ -1114,7 +1188,8 @@ contained:; if (!options.tilemap.empty() || !options.attrmap.empty() || !options.palmap.empty()) { options.verbosePrint( Options::VERB_LOG_ACT, - "Generating unoptimized tilemap and/or attrmap and/or palmap...\n"); + "Generating unoptimized tilemap and/or attrmap and/or palmap...\n" + ); unoptimized::outputMaps(attrmap, mappings); } } else { @@ -1123,8 +1198,12 @@ contained:; optimized::UniqueTiles tiles = optimized::dedupTiles(png, attrmap, palettes, mappings); if (tiles.size() > options.maxNbTiles[0] + options.maxNbTiles[1]) { - fatal("Image contains %zu tiles, exceeding the limit of %" PRIu16 " + %" PRIu16, - tiles.size(), options.maxNbTiles[0], options.maxNbTiles[1]); + fatal( + "Image contains %zu tiles, exceeding the limit of %" PRIu16 " + %" PRIu16, + tiles.size(), + options.maxNbTiles[0], + options.maxNbTiles[1] + ); } if (!options.output.empty()) { diff --git a/src/gfx/proto_palette.cpp b/src/gfx/proto_palette.cpp index 2a2f97f7..4d01d74d 100644 --- a/src/gfx/proto_palette.cpp +++ b/src/gfx/proto_palette.cpp @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: MIT */ -#include "helpers.hpp" - #include "gfx/proto_palette.hpp" #include @@ -10,6 +8,8 @@ #include #include +#include "helpers.hpp" + bool ProtoPalette::add(uint16_t color) { size_t i = 0; diff --git a/src/gfx/reverse.cpp b/src/gfx/reverse.cpp index 3badc3e3..f4620b2a 100644 --- a/src/gfx/reverse.cpp +++ b/src/gfx/reverse.cpp @@ -53,13 +53,19 @@ static DefaultInitVec readInto(const std::string &path) { } [[noreturn]] static void pngError(png_structp png, char const *msg) { - fatal("Error writing reversed image (\"%s\"): %s", - static_cast(png_get_error_ptr(png)), msg); + fatal( + "Error writing reversed image (\"%s\"): %s", + static_cast(png_get_error_ptr(png)), + msg + ); } static void pngWarning(png_structp png, char const *msg) { - warning("While writing reversed image (\"%s\"): %s", - static_cast(png_get_error_ptr(png)), msg); + warning( + "While writing reversed image (\"%s\"): %s", + static_cast(png_get_error_ptr(png)), + msg + ); } void writePng(png_structp png, png_bytep data, size_t length) { @@ -94,17 +100,23 @@ void reverse() { warning("\"Sliced-off\" pixels are ignored in reverse mode"); } if (options.inputSlice.width != 0 && options.inputSlice.width != options.reversedWidth * 8) { - warning("Specified input slice width (%" PRIu16 - ") doesn't match provided reversing width (%" PRIu16 " * 8)", - options.inputSlice.width, options.reversedWidth); + warning( + "Specified input slice width (%" PRIu16 + ") doesn't match provided reversing width (%" PRIu16 " * 8)", + options.inputSlice.width, + options.reversedWidth + ); } options.verbosePrint(Options::VERB_LOG_ACT, "Reading tiles...\n"); auto const tiles = readInto(options.output); uint8_t tileSize = 8 * options.bitDepth; if (tiles.size() % tileSize != 0) { - fatal("Tile data size (%zu bytes) is not a multiple of %" PRIu8 " bytes", - tiles.size(), tileSize); + fatal( + "Tile data size (%zu bytes) is not a multiple of %" PRIu8 " bytes", + tiles.size(), + tileSize + ); } // By default, assume tiles are not deduplicated, and add the (allegedly) trimmed tiles @@ -121,25 +133,33 @@ void reverse() { fatal("Cannot generate empty image"); } if (nbTileInstances > options.maxNbTiles[0] + options.maxNbTiles[1]) { - warning("Read %zu tiles, more than the limit of %" PRIu16 " + %" PRIu16, - nbTileInstances, options.maxNbTiles[0], options.maxNbTiles[1]); + warning( + "Read %zu tiles, more than the limit of %" PRIu16 " + %" PRIu16, + nbTileInstances, + options.maxNbTiles[0], + options.maxNbTiles[1] + ); } size_t width = options.reversedWidth, height; // In tiles if (nbTileInstances % width != 0) { - fatal("Total number of tiles read (%zu) cannot be divided by image width (%zu tiles)", - nbTileInstances, width); + fatal( + "Total number of tiles read (%zu) cannot be divided by image width (%zu tiles)", + nbTileInstances, + width + ); } height = nbTileInstances / width; - options.verbosePrint(Options::VERB_INTERM, "Reversed image dimensions: %zux%zu tiles\n", width, - height); + options.verbosePrint( + Options::VERB_INTERM, "Reversed image dimensions: %zux%zu tiles\n", width, height + ); // TODO: `-U` to configure tile size beyond 8x8px ("deduplication units") std::vector, 4>> palettes{ {Rgba(0xFFFFFFFF), Rgba(0xAAAAAAFF), Rgba(0x555555FF), Rgba(0x000000FF)} - }; + }; // If a palette file is used as input, it overrides the default colors. if (!options.palettes.empty()) { File file; @@ -155,27 +175,37 @@ void reverse() { if (nbRead == buf.size()) { // Expand the colors auto &palette = palettes.emplace_back(); - std::generate(palette.begin(), palette.begin() + options.nbColorsPerPal, - [&buf, i = 0]() mutable { - i += 2; - return Rgba::fromCGBColor(buf[i - 2] + (buf[i - 1] << 8)); - }); + std::generate( + palette.begin(), + palette.begin() + options.nbColorsPerPal, + [&buf, i = 0]() mutable { + i += 2; + return Rgba::fromCGBColor(buf[i - 2] + (buf[i - 1] << 8)); + } + ); } else if (nbRead != 0) { - fatal("Palette data size (%zu) is not a multiple of %zu bytes!\n", - palettes.size() * buf.size() + nbRead, buf.size()); + fatal( + "Palette data size (%zu) is not a multiple of %zu bytes!\n", + palettes.size() * buf.size() + nbRead, + buf.size() + ); } } while (nbRead != 0); if (palettes.size() > options.nbPalettes) { - warning("Read %zu palettes, more than the specified limit of %" PRIu8, - palettes.size(), options.nbPalettes); + warning( + "Read %zu palettes, more than the specified limit of %" PRIu8, + palettes.size(), + options.nbPalettes + ); } if (options.palSpecType == Options::EXPLICIT && palettes != options.palSpec) { warning("Colors in the palette file do not match those specified with `-c`!"); } } else if (options.palSpecType == Options::EMBEDDED) { - warning("An embedded palette was requested, but no palette file was specified; ignoring request."); + warning("An embedded palette was requested, but no palette file was specified; ignoring " + "request."); } else if (options.palSpecType == Options::EXPLICIT) { palettes = std::move(options.palSpec); // We won't be using it again. } @@ -184,8 +214,11 @@ void reverse() { if (!options.attrmap.empty()) { attrmap = readInto(options.attrmap); if (attrmap->size() != nbTileInstances) { - fatal("Attribute map size (%zu tiles) doesn't match image's (%zu)", attrmap->size(), - nbTileInstances); + fatal( + "Attribute map size (%zu tiles) doesn't match image's (%zu)", + attrmap->size(), + nbTileInstances + ); } // Scan through the attributes for inconsistencies @@ -195,8 +228,9 @@ void reverse() { bool bad = false; for (auto attr : *attrmap) { if ((attr & 0b111) > palettes.size()) { - error("Referencing palette %u, but there are only %zu!", - attr & 0b111, palettes.size()); + error( + "Referencing palette %u, but there are only %zu!", attr & 0b111, palettes.size() + ); bad = true; } if (attr & 0x08 && !tilemap) { @@ -213,16 +247,22 @@ void reverse() { for (auto [id, attr] : zip(*tilemap, *attrmap)) { bool bank = attr & 1 << 3; if (id >= options.maxNbTiles[bank]) { - warning("Tile #%" PRIu8 - " was referenced, but the limit for bank %u is %" PRIu16, - id, bank, options.maxNbTiles[bank]); + warning( + "Tile #%" PRIu8 " was referenced, but the limit for bank %u is %" PRIu16, + id, + bank, + options.maxNbTiles[bank] + ); } } } else { for (auto id : *tilemap) { if (id >= options.maxNbTiles[0]) { - warning("Tile #%" PRIu8 " was referenced, but the limit is %" PRIu16, id, - options.maxNbTiles[0]); + warning( + "Tile #%" PRIu8 " was referenced, but the limit is %" PRIu16, + id, + options.maxNbTiles[0] + ); } } } @@ -232,8 +272,11 @@ void reverse() { if (!options.palmap.empty()) { palmap = readInto(options.palmap); if (palmap->size() != nbTileInstances) { - fatal("Palette map size (%zu tiles) doesn't match image's (%zu)", palmap->size(), - nbTileInstances); + fatal( + "Palette map size (%zu tiles) doesn't match image's (%zu)", + palmap->size(), + nbTileInstances + ); } } @@ -244,8 +287,10 @@ void reverse() { } png_structp png = png_create_write_struct( PNG_LIBPNG_VER_STRING, - const_cast(static_cast(pngFile.c_str(options.input))), pngError, - pngWarning); + const_cast(static_cast(pngFile.c_str(options.input))), + pngError, + pngWarning + ); if (!png) { fatal("Failed to create PNG write struct: %s", strerror(errno)); } @@ -255,8 +300,17 @@ void reverse() { } png_set_write_fn(png, &pngFile, writePng, flushPng); - png_set_IHDR(png, pngInfo, options.reversedWidth * 8, height * 8, 8, PNG_COLOR_TYPE_RGB_ALPHA, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + png_set_IHDR( + png, + pngInfo, + options.reversedWidth * 8, + height * 8, + 8, + PNG_COLOR_TYPE_RGB_ALPHA, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT + ); png_write_info(png, pngInfo); png_color_8 sbitChunk; @@ -270,10 +324,14 @@ void reverse() { size_t const SIZEOF_ROW = options.reversedWidth * 8 * SIZEOF_PIXEL; std::vector tileRow(8 * SIZEOF_ROW, 0xFF); // Data for 8 rows of pixels uint8_t * const rowPtrs[8] = { - &tileRow.data()[0 * SIZEOF_ROW], &tileRow.data()[1 * SIZEOF_ROW], - &tileRow.data()[2 * SIZEOF_ROW], &tileRow.data()[3 * SIZEOF_ROW], - &tileRow.data()[4 * SIZEOF_ROW], &tileRow.data()[5 * SIZEOF_ROW], - &tileRow.data()[6 * SIZEOF_ROW], &tileRow.data()[7 * SIZEOF_ROW], + &tileRow.data()[0 * SIZEOF_ROW], + &tileRow.data()[1 * SIZEOF_ROW], + &tileRow.data()[2 * SIZEOF_ROW], + &tileRow.data()[3 * SIZEOF_ROW], + &tileRow.data()[4 * SIZEOF_ROW], + &tileRow.data()[5 * SIZEOF_ROW], + &tileRow.data()[6 * SIZEOF_ROW], + &tileRow.data()[7 * SIZEOF_ROW], }; for (size_t ty = 0; ty < height; ++ty) { @@ -294,8 +352,22 @@ void reverse() { // We do not have data for tiles trimmed with `-x`, so assume they are "blank" static std::array const trimmedTile{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, }; uint8_t const *tileData = tileID > nbTileInstances - options.trim ? trimmedTile.data() diff --git a/src/gfx/rgba.cpp b/src/gfx/rgba.cpp index 5247aa5e..dbbbcf33 100644 --- a/src/gfx/rgba.cpp +++ b/src/gfx/rgba.cpp @@ -15,11 +15,11 @@ * with gaps in the scale curve filled by polynomial interpolation. */ static std::array reverse_curve{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, // These - 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, // comments - 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, // prevent - 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, // clang-format - 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, // from + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, // These + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, // comments + 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, // prevent + 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, // clang-format + 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, // from 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, // reflowing 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, // these 16, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 19, 19, // sixteen diff --git a/src/link/assign.cpp b/src/link/assign.cpp index 9321d892..bbd7d230 100644 --- a/src/link/assign.cpp +++ b/src/link/assign.cpp @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: MIT */ +#include "link/assign.hpp" + #include #include #include @@ -8,18 +10,17 @@ #include #include -#include "link/assign.hpp" -#include "link/section.hpp" -#include "link/symbol.hpp" -#include "link/object.hpp" -#include "link/main.hpp" -#include "link/output.hpp" - #include "error.hpp" #include "helpers.hpp" #include "itertools.hpp" #include "linkdefs.hpp" +#include "link/main.hpp" +#include "link/object.hpp" +#include "link/output.hpp" +#include "link/section.hpp" +#include "link/symbol.hpp" + struct MemoryLocation { uint16_t address; uint32_t bank; @@ -36,15 +37,13 @@ std::vector> memory[SECTTYPE_INVALID]; uint64_t nbSectionsToAssign; // Init the free space-modelling structs -static void initFreeSpace() -{ +static void initFreeSpace() { for (enum SectionType type : EnumSeq(SECTTYPE_INVALID)) { memory[type].resize(nbbanks(type)); for (std::deque &bankMem : memory[type]) { - bankMem.push_back({ - .address = sectionTypeInfo[type].startAddr, - .size = sectionTypeInfo[type].size - }); + bankMem.push_back( + {.address = sectionTypeInfo[type].startAddr, .size = sectionTypeInfo[type].size} + ); } } } @@ -54,8 +53,7 @@ static void initFreeSpace() * @param section The section to assign * @param location The location to assign the section to */ -static void assignSection(Section §ion, MemoryLocation const &location) -{ +static void assignSection(Section §ion, MemoryLocation const &location) { // Propagate the assigned location to all UNIONs/FRAGMENTs // so `jr` patches in them will have the correct offset for (Section *next = §ion; next != nullptr; next = next->nextu) { @@ -77,9 +75,9 @@ static void assignSection(Section §ion, MemoryLocation const &location) * @param location The location to attempt placing the section at * @return True if the location is suitable, false otherwise. */ -static bool isLocationSuitable(Section const §ion, FreeSpace const &freeSpace, - MemoryLocation const &location) -{ +static bool isLocationSuitable( + Section const §ion, FreeSpace const &freeSpace, MemoryLocation const &location +) { if (section.isAddressFixed && section.org != location.address) return false; @@ -99,8 +97,7 @@ static bool isLocationSuitable(Section const §ion, FreeSpace const &freeSpac * @return The index into `memory[section->type]` of the free space encompassing the location, * or -1 if none was found */ -static ssize_t getPlacement(Section const §ion, MemoryLocation &location) -{ +static ssize_t getPlacement(Section const §ion, MemoryLocation &location) { SectionTypeInfo const &typeInfo = sectionTypeInfo[section.type]; static uint16_t curScrambleROM = 0; @@ -166,16 +163,16 @@ static ssize_t getPlacement(Section const §ion, MemoryLocation &location) // If that location is past the current block's end, // go forwards until that is no longer the case. - while (spaceIdx < bankMem.size() && location.address >= - bankMem[spaceIdx].address + bankMem[spaceIdx].size) + while (spaceIdx < bankMem.size() + && location.address >= bankMem[spaceIdx].address + bankMem[spaceIdx].size) spaceIdx++; // Try again with the new location/free space combo } // Try again in the next bank, if one is available. - // Try scrambled banks in descending order until no bank in the scrambled range is available. - // Otherwise, try in ascending order. + // Try scrambled banks in descending order until no bank in the scrambled range is + // available. Otherwise, try in ascending order. if (section.isBankFixed) { return -1; } else if (scrambleROMX && section.type == SECTTYPE_ROMX && location.bank <= scrambleROMX) { @@ -213,20 +210,17 @@ static ssize_t getPlacement(Section const §ion, MemoryLocation &location) * sections of decreasing size. * @param section The section to place */ -static void placeSection(Section §ion) -{ +static void placeSection(Section §ion) { MemoryLocation location; // Specially handle 0-byte SECTIONs, as they can't overlap anything if (section.size == 0) { // Unless the SECTION's address was fixed, the starting address // is fine for any alignment, as checked in sect_DoSanityChecks. - location.address = section.isAddressFixed - ? section.org - : sectionTypeInfo[section.type].startAddr; - location.bank = section.isBankFixed - ? section.bank - : sectionTypeInfo[section.type].firstBank; + location.address = + section.isAddressFixed ? section.org : sectionTypeInfo[section.type].startAddr; + location.bank = + section.isBankFixed ? section.bank : sectionTypeInfo[section.type].firstBank; assignSection(section, location); return; } @@ -234,14 +228,14 @@ static void placeSection(Section §ion) // Place section using first-fit decreasing algorithm // https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm if (ssize_t spaceIdx = getPlacement(section, location); spaceIdx != -1) { - std::deque &bankMem = memory[section.type][location.bank - - sectionTypeInfo[section.type].firstBank]; + std::deque &bankMem = + memory[section.type][location.bank - sectionTypeInfo[section.type].firstBank]; FreeSpace &freeSpace = bankMem[spaceIdx]; assignSection(section, location); // Update the free space - bool noLeftSpace = freeSpace.address == section.org; + bool noLeftSpace = freeSpace.address == section.org; bool noRightSpace = freeSpace.address + freeSpace.size == section.org + section.size; if (noLeftSpace && noRightSpace) { // The free space is entirely deleted @@ -249,11 +243,12 @@ static void placeSection(Section §ion) } else if (!noLeftSpace && !noRightSpace) { // The free space is split in two // Append the new space after the original one - bankMem.insert(bankMem.begin() + spaceIdx + 1, { - .address = (uint16_t)(section.org + section.size), - .size = (uint16_t)(freeSpace.address + freeSpace.size - - section.org - section.size) - }); + bankMem.insert( + bankMem.begin() + spaceIdx + 1, + {.address = (uint16_t)(section.org + section.size), + .size = + (uint16_t)(freeSpace.address + freeSpace.size - section.org - section.size)} + ); // Resize the original space (address is unmodified) freeSpace.size = section.org - freeSpace.address; } else { @@ -271,41 +266,66 @@ static void placeSection(Section §ion) if (section.isBankFixed && nbbanks(section.type) != 1) { if (section.isAddressFixed) - snprintf(where, sizeof(where), "at $%02" PRIx32 ":%04" PRIx16, - section.bank, section.org); + snprintf( + where, sizeof(where), "at $%02" PRIx32 ":%04" PRIx16, section.bank, section.org + ); else if (section.isAlignFixed) - snprintf(where, sizeof(where), "in bank $%02" PRIx32 " with align mask %" PRIx16, - section.bank, (uint16_t)~section.alignMask); + snprintf( + where, + sizeof(where), + "in bank $%02" PRIx32 " with align mask %" PRIx16, + section.bank, + (uint16_t)~section.alignMask + ); else snprintf(where, sizeof(where), "in bank $%02" PRIx32, section.bank); } else { if (section.isAddressFixed) snprintf(where, sizeof(where), "at address $%04" PRIx16, section.org); else if (section.isAlignFixed) - snprintf(where, sizeof(where), "with align mask %" PRIx16 " and offset %" PRIx16, - (uint16_t)~section.alignMask, section.alignOfs); + snprintf( + where, + sizeof(where), + "with align mask %" PRIx16 " and offset %" PRIx16, + (uint16_t)~section.alignMask, + section.alignOfs + ); else strcpy(where, "anywhere"); } // If a section failed to go to several places, nothing we can report if (!section.isBankFixed || !section.isAddressFixed) - errx("Unable to place \"%s\" (%s section) %s", - section.name.c_str(), sectionTypeInfo[section.type].name.c_str(), where); + errx( + "Unable to place \"%s\" (%s section) %s", + section.name.c_str(), + sectionTypeInfo[section.type].name.c_str(), + where + ); // If the section just can't fit the bank, report that else if (section.org + section.size > endaddr(section.type) + 1) - errx("Unable to place \"%s\" (%s section) %s: section runs past end of region ($%04x > $%04x)", - section.name.c_str(), sectionTypeInfo[section.type].name.c_str(), where, - section.org + section.size, endaddr(section.type) + 1); + errx( + "Unable to place \"%s\" (%s section) %s: section runs past end of region ($%04x > " + "$%04x)", + section.name.c_str(), + sectionTypeInfo[section.type].name.c_str(), + where, + section.org + section.size, + endaddr(section.type) + 1 + ); // Otherwise there is overlap with another section else - errx("Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"", - section.name.c_str(), sectionTypeInfo[section.type].name.c_str(), where, - out_OverlappingSection(section)->name.c_str()); + errx( + "Unable to place \"%s\" (%s section) %s: section overlaps with \"%s\"", + section.name.c_str(), + sectionTypeInfo[section.type].name.c_str(), + where, + out_OverlappingSection(section)->name.c_str() + ); } -#define BANK_CONSTRAINED (1 << 2) -#define ORG_CONSTRAINED (1 << 1) +#define BANK_CONSTRAINED (1 << 2) +#define ORG_CONSTRAINED (1 << 1) #define ALIGN_CONSTRAINED (1 << 0) static std::deque
unassignedSections[1 << 3]; @@ -314,8 +334,7 @@ static std::deque
unassignedSections[1 << 3]; * This is so the most-constrained sections are placed first * @param section The section to categorize */ -static void categorizeSection(Section §ion) -{ +static void categorizeSection(Section §ion) { uint8_t constraints = 0; if (section.isBankFixed) @@ -337,8 +356,7 @@ static void categorizeSection(Section §ion) nbSectionsToAssign++; } -void assign_AssignSections() -{ +void assign_AssignSections() { verbosePrint("Beginning assignment...\n"); // Initialize assignment @@ -368,8 +386,7 @@ void assign_AssignSections() for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED; constraints >= 0; constraints--) { for (Section *section : unassignedSections[constraints]) { - fprintf(stderr, "%c \"%s\"", nbSections == 0 ? ';': ',', - section->name.c_str()); + fprintf(stderr, "%c \"%s\"", nbSections == 0 ? ';' : ',', section->name.c_str()); nbSections++; if (nbSections == 10) goto max_out; @@ -384,7 +401,8 @@ max_out: } // Assign all remaining sections by decreasing constraint order - for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED; constraints >= 0; constraints--) { + for (int8_t constraints = BANK_CONSTRAINED | ALIGN_CONSTRAINED; constraints >= 0; + constraints--) { for (Section *section : unassignedSections[constraints]) placeSection(*section); diff --git a/src/link/main.cpp b/src/link/main.cpp index f18edda0..129f35c2 100644 --- a/src/link/main.cpp +++ b/src/link/main.cpp @@ -1,51 +1,51 @@ /* SPDX-License-Identifier: MIT */ +#include +#include + #include #include #include #include -#include #include +#include #include -#include #include -#include -#include +#include #include #include +#include "error.hpp" +#include "extern/getopt.hpp" +#include "itertools.hpp" +#include "linkdefs.hpp" +#include "platform.hpp" +#include "script.hpp" +#include "version.hpp" + #include "link/assign.hpp" #include "link/object.hpp" #include "link/output.hpp" #include "link/patch.hpp" #include "link/section.hpp" -#include "script.hpp" #include "link/symbol.hpp" -#include "extern/getopt.hpp" - -#include "error.hpp" -#include "itertools.hpp" -#include "linkdefs.hpp" -#include "platform.hpp" -#include "version.hpp" - -bool isDmgMode; // -d -char *linkerScriptName; // -l -char const *mapFileName; // -m -bool noSymInMap; // -M -char const *symFileName; // -n -char const *overlayFileName; // -O -char const *outputFileName; // -o -uint8_t padValue; // -p +bool isDmgMode; // -d +char *linkerScriptName; // -l +char const *mapFileName; // -m +bool noSymInMap; // -M +char const *symFileName; // -n +char const *overlayFileName; // -O +char const *outputFileName; // -o +uint8_t padValue; // -p // Setting these three to 0 disables the functionality -uint16_t scrambleROMX = 0; // -S +uint16_t scrambleROMX = 0; // -S uint8_t scrambleWRAMX = 0; uint8_t scrambleSRAM = 0; -bool is32kMode; // -t -bool beVerbose; // -v -bool isWRAM0Mode; // -w -bool disablePadding; // -x +bool is32kMode; // -t +bool beVerbose; // -v +bool isWRAM0Mode; // -w +bool disablePadding; // -x FILE *linkerScript; @@ -72,8 +72,7 @@ std::string const &FileStackNode::name() const { } // Helper function to dump a file stack to stderr -std::string const *FileStackNode::dumpFileStack() const -{ +std::string const *FileStackNode::dumpFileStack() const { std::string const *lastName; if (parent) { @@ -95,9 +94,9 @@ std::string const *FileStackNode::dumpFileStack() const return lastName; } -void printDiag(char const *fmt, va_list args, char const *type, - FileStackNode const *where, uint32_t lineNo) -{ +void printDiag( + char const *fmt, va_list args, char const *type, FileStackNode const *where, uint32_t lineNo +) { fputs(type, stderr); fputs(": ", stderr); if (where) { @@ -108,8 +107,7 @@ void printDiag(char const *fmt, va_list args, char const *type, putc('\n', stderr); } -void warning(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) -{ +void warning(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) { va_list args; va_start(args, fmt); @@ -117,8 +115,7 @@ void warning(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) va_end(args); } -void error(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) -{ +void error(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) { va_list args; va_start(args, fmt); @@ -129,8 +126,7 @@ void error(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) nbErrors++; } -void argErr(char flag, char const *fmt, ...) -{ +void argErr(char flag, char const *fmt, ...) { va_list args; fprintf(stderr, "error: Invalid argument for option '%c': ", flag); @@ -143,8 +139,7 @@ void argErr(char flag, char const *fmt, ...) nbErrors++; } -[[noreturn]] void fatal(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) -{ +[[noreturn]] void fatal(FileStackNode const *where, uint32_t lineNo, char const *fmt, ...) { va_list args; va_start(args, fmt); @@ -154,8 +149,9 @@ void argErr(char flag, char const *fmt, ...) if (nbErrors != UINT32_MAX) nbErrors++; - fprintf(stderr, "Linking aborted after %" PRIu32 " error%s\n", nbErrors, - nbErrors == 1 ? "" : "s"); + fprintf( + stderr, "Linking aborted after %" PRIu32 " error%s\n", nbErrors, nbErrors == 1 ? "" : "s" + ); exit(1); } @@ -173,41 +169,41 @@ static const char *optstring = "dl:m:Mn:O:o:p:S:s:tVvWwx"; * over short opt matching */ static option const longopts[] = { - { "dmg", no_argument, nullptr, 'd' }, - { "linkerscript", required_argument, nullptr, 'l' }, - { "map", required_argument, nullptr, 'm' }, - { "no-sym-in-map", no_argument, nullptr, 'M' }, - { "sym", required_argument, nullptr, 'n' }, - { "overlay", required_argument, nullptr, 'O' }, - { "output", required_argument, nullptr, 'o' }, - { "pad", required_argument, nullptr, 'p' }, - { "scramble", required_argument, nullptr, 'S' }, - { "smart", required_argument, nullptr, 's' }, - { "tiny", no_argument, nullptr, 't' }, - { "version", no_argument, nullptr, 'V' }, - { "verbose", no_argument, nullptr, 'v' }, - { "wramx", no_argument, nullptr, 'w' }, - { "nopad", no_argument, nullptr, 'x' }, - { nullptr, no_argument, nullptr, 0 } + {"dmg", no_argument, nullptr, 'd'}, + {"linkerscript", required_argument, nullptr, 'l'}, + {"map", required_argument, nullptr, 'm'}, + {"no-sym-in-map", no_argument, nullptr, 'M'}, + {"sym", required_argument, nullptr, 'n'}, + {"overlay", required_argument, nullptr, 'O'}, + {"output", required_argument, nullptr, 'o'}, + {"pad", required_argument, nullptr, 'p'}, + {"scramble", required_argument, nullptr, 'S'}, + {"smart", required_argument, nullptr, 's'}, + {"tiny", no_argument, nullptr, 't'}, + {"version", no_argument, nullptr, 'V'}, + {"verbose", no_argument, nullptr, 'v'}, + {"wramx", no_argument, nullptr, 'w'}, + {"nopad", no_argument, nullptr, 'x'}, + {nullptr, no_argument, nullptr, 0 } }; -static void printUsage() -{ +static void printUsage() { fputs( -"Usage: rgblink [-dMtVvwx] [-l script] [-m map_file] [-n sym_file]\n" -" [-O overlay_file] [-o out_file] [-p pad_value]\n" -" [-S spec] [-s symbol] ...\n" -"Useful options:\n" -" -l, --linkerscript set the input linker script\n" -" -m, --map set the output map file\n" -" -n, --sym set the output symbol list file\n" -" -o, --output set the output file\n" -" -p, --pad set the value to pad between sections with\n" -" -x, --nopad disable padding of output binary\n" -" -V, --version print RGBLINK version and exits\n" -"\n" -"For help, use `man rgblink' or go to https://rgbds.gbdev.io/docs/\n", - stderr); + "Usage: rgblink [-dMtVvwx] [-l script] [-m map_file] [-n sym_file]\n" + " [-O overlay_file] [-o out_file] [-p pad_value]\n" + " [-S spec] [-s symbol] ...\n" + "Useful options:\n" + " -l, --linkerscript set the input linker script\n" + " -m, --map set the output map file\n" + " -n, --sym set the output symbol list file\n" + " -o, --output set the output file\n" + " -p, --pad set the value to pad between sections with\n" + " -x, --nopad disable padding of output binary\n" + " -V, --version print RGBLINK version and exits\n" + "\n" + "For help, use `man rgblink' or go to https://rgbds.gbdev.io/docs/\n", + stderr + ); } enum ScrambledRegion { @@ -222,13 +218,12 @@ struct { char const *name; uint16_t max; } scrambleSpecs[SCRAMBLE_UNK] = { - { "romx", 65535 }, // SCRAMBLE_ROMX - { "sram", 255 }, // SCRAMBLE_SRAM - { "wramx", 7 }, // SCRAMBLE_WRAMX + {"romx", 65535}, // SCRAMBLE_ROMX + {"sram", 255 }, // SCRAMBLE_SRAM + {"wramx", 7 }, // SCRAMBLE_WRAMX }; -static void parseScrambleSpec(char const *spec) -{ +static void parseScrambleSpec(char const *spec) { // Skip any leading whitespace spec += strspn(spec, " \t"); @@ -251,7 +246,7 @@ static void parseScrambleSpec(char const *spec) if (*spec == '\0') break; - if (*spec == '=') // Skip the limit, too + if (*spec == '=') // Skip the limit, too spec = strchr(&spec[1], ','); // Skip to next comma, if any goto next; } @@ -259,8 +254,9 @@ static void parseScrambleSpec(char const *spec) // Find the next non-blank char after the region name's end spec += regionNameLen + strspn(&spec[regionNameLen], " \t"); if (*spec != '\0' && *spec != ',' && *spec != '=') { - argErr('S', "Unexpected '%c' after region name \"%.*s\"", - regionNamePrintLen, regionName); + argErr( + 'S', "Unexpected '%c' after region name \"%.*s\"", regionNamePrintLen, regionName + ); // Skip to next ',' or '=' (or NUL) and keep parsing spec += 1 + strcspn(&spec[1], ",="); } @@ -285,22 +281,30 @@ static void parseScrambleSpec(char const *spec) char *endptr; if (*spec == '\0' || *spec == ',') { - argErr('S', "Empty limit for region \"%.*s\"", - regionNamePrintLen, regionName); + argErr('S', "Empty limit for region \"%.*s\"", regionNamePrintLen, regionName); goto next; } limit = strtoul(spec, &endptr, 10); endptr += strspn(endptr, " \t"); if (*endptr != '\0' && *endptr != ',') { - argErr('S', "Invalid non-numeric limit for region \"%.*s\"", - regionNamePrintLen, regionName); + argErr( + 'S', + "Invalid non-numeric limit for region \"%.*s\"", + regionNamePrintLen, + regionName + ); endptr = strchr(endptr, ','); } spec = endptr; if (region != SCRAMBLE_UNK && limit > scrambleSpecs[region].max) { - argErr('S', "Limit for region \"%.*s\" may not exceed %" PRIu16, - regionNamePrintLen, regionName, scrambleSpecs[region].max); + argErr( + 'S', + "Limit for region \"%.*s\" may not exceed %" PRIu16, + regionNamePrintLen, + regionName, + scrambleSpecs[region].max + ); limit = scrambleSpecs[region].max; } @@ -321,8 +325,7 @@ static void parseScrambleSpec(char const *spec) // Only WRAMX can be implied, since ROMX and SRAM size may vary scrambleWRAMX = 7; } else { - argErr('S', "Cannot imply limit for region \"%.*s\"", - regionNamePrintLen, regionName); + argErr('S', "Cannot imply limit for region \"%.*s\"", regionNamePrintLen, regionName); } next: @@ -337,13 +340,13 @@ next: } [[noreturn]] void reportErrors() { - fprintf(stderr, "Linking failed with %" PRIu32 " error%s\n", - nbErrors, nbErrors == 1 ? "" : "s"); + fprintf( + stderr, "Linking failed with %" PRIu32 " error%s\n", nbErrors, nbErrors == 1 ? "" : "s" + ); exit(1); } -static void freeSection(Section §ion) -{ +static void freeSection(Section §ion) { Section *next = §ion; for (Section *nextu; next; next = nextu) { @@ -352,13 +355,11 @@ static void freeSection(Section §ion) }; } -static void freeSections() -{ +static void freeSections() { sect_ForEach(freeSection); } -int main(int argc, char *argv[]) -{ +int main(int argc, char *argv[]) { // Parse options for (int ch; (ch = musl_getopt_long_only(argc, argv, optstring, longopts, nullptr)) != -1;) { switch (ch) { @@ -444,8 +445,9 @@ int main(int argc, char *argv[]) // If no input files were specified, the user must have screwed up if (curArgIndex == argc) { - fputs("FATAL: Please specify an input file (pass `-` to read from standard input)\n", - stderr); + fputs( + "FATAL: Please specify an input file (pass `-` to read from standard input)\n", stderr + ); printUsage(); exit(1); } diff --git a/src/link/object.cpp b/src/link/object.cpp index 985c7301..20bd7dc6 100644 --- a/src/link/object.cpp +++ b/src/link/object.cpp @@ -1,30 +1,31 @@ /* SPDX-License-Identifier: MIT */ +#include "link/object.hpp" + #include #include #include #include #include #include -#include #include -#include +#include #include +#include #include -#include "link/assign.hpp" -#include "link/main.hpp" -#include "link/object.hpp" -#include "link/patch.hpp" -#include "link/sdas_obj.hpp" -#include "link/section.hpp" -#include "link/symbol.hpp" - #include "error.hpp" #include "helpers.hpp" #include "linkdefs.hpp" #include "version.hpp" +#include "link/assign.hpp" +#include "link/main.hpp" +#include "link/patch.hpp" +#include "link/sdas_obj.hpp" +#include "link/section.hpp" +#include "link/symbol.hpp" + static std::deque> symbolLists; static std::vector> nodes; static std::deque assertions; @@ -33,25 +34,23 @@ static std::deque assertions; // Internal, DO NOT USE. // For helper wrapper macros defined below, such as `tryReadlong` -#define tryRead(func, type, errval, vartype, var, file, ...) do { \ - FILE *tmpFile = file; \ - type tmpVal = func(tmpFile); \ - /* TODO: maybe mark the condition as `unlikely`; how to do that portably? */ \ - if (tmpVal == (errval)) { \ - errx(__VA_ARGS__, feof(tmpFile) \ - ? "Unexpected end of file" \ - : strerror(errno)); \ - } \ - var = (vartype)tmpVal; \ -} while (0) +#define tryRead(func, type, errval, vartype, var, file, ...) \ + do { \ + FILE *tmpFile = file; \ + type tmpVal = func(tmpFile); \ + /* TODO: maybe mark the condition as `unlikely`; how to do that portably? */ \ + if (tmpVal == (errval)) { \ + errx(__VA_ARGS__, feof(tmpFile) ? "Unexpected end of file" : strerror(errno)); \ + } \ + var = (vartype)tmpVal; \ + } while (0) /* * Reads an unsigned long (32-bit) value from a file. * @param file The file to read from. This will read 4 bytes from the file. * @return The value read, cast to a int64_t, or -1 on failure. */ -static int64_t readlong(FILE *file) -{ +static int64_t readlong(FILE *file) { uint32_t value = 0; // Read the little-endian value byte by byte @@ -92,8 +91,7 @@ static int64_t readlong(FILE *file) * @param ... A format string and related arguments; note that an extra string * argument is provided, the reason for failure */ -#define tryGetc(type, var, file, ...) \ - tryRead(getc, int, EOF, type, var, file, __VA_ARGS__) +#define tryGetc(type, var, file, ...) tryRead(getc, int, EOF, type, var, file, __VA_ARGS__) /* * Helper macro for readings '\0'-terminated strings from a file, and errors out if it fails to. @@ -103,19 +101,18 @@ static int64_t readlong(FILE *file) * @param ... A format string and related arguments; note that an extra string * argument is provided, the reason for failure */ -#define tryReadstring(var, file, ...) do { \ - FILE *tmpFile = file; \ - std::string &tmpVal = var; \ - for (int tmpByte = getc(tmpFile); tmpByte != '\0'; tmpByte = getc(tmpFile)) { \ - if (tmpByte == EOF) { \ - errx(__VA_ARGS__, feof(tmpFile) \ - ? "Unexpected end of file" \ - : strerror(errno)); \ - } else { \ - tmpVal.push_back(tmpByte); \ - } \ - }; \ -} while (0) +#define tryReadstring(var, file, ...) \ + do { \ + FILE *tmpFile = file; \ + std::string &tmpVal = var; \ + for (int tmpByte = getc(tmpFile); tmpByte != '\0'; tmpByte = getc(tmpFile)) { \ + if (tmpByte == EOF) { \ + errx(__VA_ARGS__, feof(tmpFile) ? "Unexpected end of file" : strerror(errno)); \ + } else { \ + tmpVal.push_back(tmpByte); \ + } \ + }; \ + } while (0) // Functions to parse object files @@ -126,39 +123,55 @@ static int64_t readlong(FILE *file) * @param i The ID of the node in the array * @param fileName The filename to report in errors */ -static void readFileStackNode(FILE *file, std::vector &fileNodes, uint32_t i, - char const *fileName) -{ +static void readFileStackNode( + FILE *file, std::vector &fileNodes, uint32_t i, char const *fileName +) { FileStackNode &node = fileNodes[i]; uint32_t parentID; - tryReadlong(parentID, file, - "%s: Cannot read node #%" PRIu32 "'s parent ID: %s", fileName, i); + tryReadlong(parentID, file, "%s: Cannot read node #%" PRIu32 "'s parent ID: %s", fileName, i); node.parent = parentID != (uint32_t)-1 ? &fileNodes[parentID] : nullptr; - tryReadlong(node.lineNo, file, - "%s: Cannot read node #%" PRIu32 "'s line number: %s", fileName, i); - tryGetc(enum FileStackNodeType, node.type, file, - "%s: Cannot read node #%" PRIu32 "'s type: %s", fileName, i); + tryReadlong( + node.lineNo, file, "%s: Cannot read node #%" PRIu32 "'s line number: %s", fileName, i + ); + tryGetc( + enum FileStackNodeType, + node.type, + file, + "%s: Cannot read node #%" PRIu32 "'s type: %s", + fileName, + i + ); switch (node.type) { case NODE_FILE: case NODE_MACRO: node.data = ""; - tryReadstring(node.name(), file, - "%s: Cannot read node #%" PRIu32 "'s file name: %s", fileName, i); + tryReadstring( + node.name(), file, "%s: Cannot read node #%" PRIu32 "'s file name: %s", fileName, i + ); break; uint32_t depth; case NODE_REPT: - tryReadlong(depth, file, - "%s: Cannot read node #%" PRIu32 "'s rept depth: %s", fileName, i); + tryReadlong(depth, file, "%s: Cannot read node #%" PRIu32 "'s rept depth: %s", fileName, i); node.data = std::vector(depth); for (uint32_t k = 0; k < depth; k++) - tryReadlong(node.iters()[k], file, - "%s: Cannot read node #%" PRIu32 "'s iter #%" PRIu32 ": %s", - fileName, i, k); + tryReadlong( + node.iters()[k], + file, + "%s: Cannot read node #%" PRIu32 "'s iter #%" PRIu32 ": %s", + fileName, + i, + k + ); if (!node.parent) - fatal(nullptr, 0, "%s is not a valid object file: root node (#%" - PRIu32 ") may not be REPT", fileName, i); + fatal( + nullptr, + 0, + "%s is not a valid object file: root node (#%" PRIu32 ") may not be REPT", + fileName, + i + ); } } @@ -168,34 +181,52 @@ static void readFileStackNode(FILE *file, std::vector &fileNodes, * @param symbol The symbol to fill * @param fileName The filename to report in errors */ -static void readSymbol(FILE *file, Symbol &symbol, char const *fileName, - std::vector const &fileNodes) -{ +static void readSymbol( + FILE *file, Symbol &symbol, char const *fileName, std::vector const &fileNodes +) { tryReadstring(symbol.name, file, "%s: Cannot read symbol name: %s", fileName); - tryGetc(enum ExportLevel, symbol.type, file, "%s: Cannot read \"%s\"'s type: %s", - fileName, symbol.name.c_str()); + tryGetc( + enum ExportLevel, + symbol.type, + file, + "%s: Cannot read \"%s\"'s type: %s", + fileName, + symbol.name.c_str() + ); // If the symbol is defined in this file, read its definition if (symbol.type != SYMTYPE_IMPORT) { symbol.objFileName = fileName; uint32_t nodeID; - tryReadlong(nodeID, file, "%s: Cannot read \"%s\"'s node ID: %s", - fileName, symbol.name.c_str()); + tryReadlong( + nodeID, file, "%s: Cannot read \"%s\"'s node ID: %s", fileName, symbol.name.c_str() + ); symbol.src = &fileNodes[nodeID]; - tryReadlong(symbol.lineNo, file, "%s: Cannot read \"%s\"'s line number: %s", - fileName, symbol.name.c_str()); + tryReadlong( + symbol.lineNo, + file, + "%s: Cannot read \"%s\"'s line number: %s", + fileName, + symbol.name.c_str() + ); int32_t sectionID, value; - tryReadlong(sectionID, file, "%s: Cannot read \"%s\"'s section ID: %s", - fileName, symbol.name.c_str()); - tryReadlong(value, file, "%s: Cannot read \"%s\"'s value: %s", - fileName, symbol.name.c_str()); + tryReadlong( + sectionID, + file, + "%s: Cannot read \"%s\"'s section ID: %s", + fileName, + symbol.name.c_str() + ); + tryReadlong( + value, file, "%s: Cannot read \"%s\"'s value: %s", fileName, symbol.name.c_str() + ); if (sectionID == -1) { symbol.data = value; } else { symbol.data = Label{ - .sectionID = sectionID, - .offset = value, - // Set the `.section` later based on the `.sectionID` - .section = nullptr, + .sectionID = sectionID, + .offset = value, + // Set the `.section` later based on the `.sectionID` + .section = nullptr, }; } } else { @@ -210,53 +241,96 @@ static void readSymbol(FILE *file, Symbol &symbol, char const *fileName, * @param fileName The filename to report in errors * @param i The number of the patch to report in errors */ -static void readPatch(FILE *file, Patch &patch, char const *fileName, std::string const §Name, - uint32_t i, std::vector const &fileNodes) -{ +static void readPatch( + FILE *file, + Patch &patch, + char const *fileName, + std::string const §Name, + uint32_t i, + std::vector const &fileNodes +) { uint32_t nodeID, rpnSize; enum PatchType type; - tryReadlong(nodeID, file, - "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s node ID: %s", - fileName, sectName.c_str(), i); + tryReadlong( + nodeID, + file, + "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s node ID: %s", + fileName, + sectName.c_str(), + i + ); patch.src = &fileNodes[nodeID]; - tryReadlong(patch.lineNo, file, - "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s line number: %s", - fileName, sectName.c_str(), i); - tryReadlong(patch.offset, file, - "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s offset: %s", - fileName, sectName.c_str(), i); - tryReadlong(patch.pcSectionID, file, - "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s", - fileName, sectName.c_str(), i); - tryReadlong(patch.pcOffset, file, - "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s", - fileName, sectName.c_str(), i); - tryGetc(enum PatchType, type, file, - "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s type: %s", - fileName, sectName.c_str(), i); + tryReadlong( + patch.lineNo, + file, + "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s line number: %s", + fileName, + sectName.c_str(), + i + ); + tryReadlong( + patch.offset, + file, + "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s offset: %s", + fileName, + sectName.c_str(), + i + ); + tryReadlong( + patch.pcSectionID, + file, + "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s", + fileName, + sectName.c_str(), + i + ); + tryReadlong( + patch.pcOffset, + file, + "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s", + fileName, + sectName.c_str(), + i + ); + tryGetc( + enum PatchType, + type, + file, + "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s type: %s", + fileName, + sectName.c_str(), + i + ); patch.type = type; - tryReadlong(rpnSize, file, - "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s RPN size: %s", - fileName, sectName.c_str(), i); + tryReadlong( + rpnSize, + file, + "%s: Unable to read \"%s\"'s patch #%" PRIu32 "'s RPN size: %s", + fileName, + sectName.c_str(), + i + ); patch.rpnExpression.resize(rpnSize); size_t nbElementsRead = fread(patch.rpnExpression.data(), 1, rpnSize, file); if (nbElementsRead != rpnSize) - errx("%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s RPN expression: %s", - fileName, sectName.c_str(), i, - feof(file) ? "Unexpected end of file" : strerror(errno)); + errx( + "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s RPN expression: %s", + fileName, + sectName.c_str(), + i, + feof(file) ? "Unexpected end of file" : strerror(errno) + ); } /* * Sets a patch's pcSection from its pcSectionID. * @param patch The patch to fix */ -static void linkPatchToPCSect(Patch &patch, std::vector
const &fileSections) -{ - patch.pcSection = patch.pcSectionID != (uint32_t)-1 ? fileSections[patch.pcSectionID] - : nullptr; +static void linkPatchToPCSect(Patch &patch, std::vector
const &fileSections) { + patch.pcSection = patch.pcSectionID != (uint32_t)-1 ? fileSections[patch.pcSectionID] : nullptr; } /* @@ -265,9 +339,9 @@ static void linkPatchToPCSect(Patch &patch, std::vector
const &fileSe * @param section The section to fill * @param fileName The filename to report in errors */ -static void readSection(FILE *file, Section §ion, char const *fileName, - std::vector const &fileNodes) -{ +static void readSection( + FILE *file, Section §ion, char const *fileName, std::vector const &fileNodes +) { int32_t tmp; uint8_t byte; @@ -277,8 +351,9 @@ static void readSection(FILE *file, Section §ion, char const *fileName, errx("\"%s\"'s section size (%" PRId32 ") is invalid", section.name.c_str(), tmp); section.size = tmp; section.offset = 0; - tryGetc(uint8_t, byte, file, "%s: Cannot read \"%s\"'s type: %s", fileName, - section.name.c_str()); + tryGetc( + uint8_t, byte, file, "%s: Cannot read \"%s\"'s type: %s", fileName, section.name.c_str() + ); section.type = (enum SectionType)(byte & 0x3F); if (byte >> 7) section.modifier = SECTION_UNION; @@ -296,17 +371,29 @@ static void readSection(FILE *file, Section §ion, char const *fileName, tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s bank: %s", fileName, section.name.c_str()); section.isBankFixed = tmp >= 0; section.bank = tmp; - tryGetc(uint8_t, byte, file, "%s: Cannot read \"%s\"'s alignment: %s", fileName, - section.name.c_str()); + tryGetc( + uint8_t, + byte, + file, + "%s: Cannot read \"%s\"'s alignment: %s", + fileName, + section.name.c_str() + ); if (byte > 16) byte = 16; section.isAlignFixed = byte != 0; section.alignMask = (1 << byte) - 1; - tryReadlong(tmp, file, "%s: Cannot read \"%s\"'s alignment offset: %s", fileName, - section.name.c_str()); + tryReadlong( + tmp, file, "%s: Cannot read \"%s\"'s alignment offset: %s", fileName, section.name.c_str() + ); if (tmp > UINT16_MAX) { - error(nullptr, 0, "\"%s\"'s alignment offset is too large (%" PRId32 ")", - section.name.c_str(), tmp); + error( + nullptr, + 0, + "\"%s\"'s alignment offset is too large (%" PRId32 ")", + section.name.c_str(), + tmp + ); tmp = UINT16_MAX; } section.alignOfs = tmp; @@ -316,15 +403,23 @@ static void readSection(FILE *file, Section §ion, char const *fileName, section.data.resize(section.size); if (size_t nbRead = fread(section.data.data(), 1, section.size, file); nbRead != section.size) - errx("%s: Cannot read \"%s\"'s data: %s", fileName, section.name.c_str(), - feof(file) ? "Unexpected end of file" : strerror(errno)); + errx( + "%s: Cannot read \"%s\"'s data: %s", + fileName, + section.name.c_str(), + feof(file) ? "Unexpected end of file" : strerror(errno) + ); } uint32_t nbPatches; - tryReadlong(nbPatches, file, - "%s: Cannot read \"%s\"'s number of patches: %s", fileName, - section.name.c_str()); + tryReadlong( + nbPatches, + file, + "%s: Cannot read \"%s\"'s number of patches: %s", + fileName, + section.name.c_str() + ); section.patches.resize(nbPatches); for (uint32_t i = 0; i < nbPatches; i++) @@ -337,8 +432,7 @@ static void readSection(FILE *file, Section §ion, char const *fileName, * @param symbol The symbol to link * @param section The section to link */ -static void linkSymToSect(Symbol &symbol, Section §ion) -{ +static void linkSymToSect(Symbol &symbol, Section §ion) { uint32_t a = 0, b = section.symbols.size(); int32_t symbolOffset = symbol.label().offset; @@ -361,9 +455,13 @@ static void linkSymToSect(Symbol &symbol, Section §ion) * @param assert The assertion to fill * @param fileName The filename to report in errors */ -static void readAssertion(FILE *file, Assertion &assert, char const *fileName, uint32_t i, - std::vector const &fileNodes) -{ +static void readAssertion( + FILE *file, + Assertion &assert, + char const *fileName, + uint32_t i, + std::vector const &fileNodes +) { char assertName[sizeof("Assertion #4294967295")]; // UINT32_MAX snprintf(assertName, sizeof(assertName), "Assertion #%" PRIu32, i); @@ -372,13 +470,11 @@ static void readAssertion(FILE *file, Assertion &assert, char const *fileName, u tryReadstring(assert.message, file, "%s: Cannot read assertion's message: %s", fileName); } -static Section *getMainSection(Section §ion) -{ +static Section *getMainSection(Section §ion) { return section.modifier != SECTION_NORMAL ? sect_GetSection(section.name) : §ion; } -void obj_ReadFile(char const *fileName, unsigned int fileID) -{ +void obj_ReadFile(char const *fileName, unsigned int fileID) { FILE *file; if (strcmp(fileName, "-")) { @@ -405,12 +501,9 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) default: // This is (probably) a SDCC object file, defer the rest of detection to it // Since SDCC does not provide line info, everything will be reported as coming from the // object file. It's better than nothing. - nodes[fileID].push_back({ - .parent = nullptr, - .lineNo = 0, - .type = NODE_FILE, - .data = fileName - }); + nodes[fileID].push_back( + {.parent = nullptr, .lineNo = 0, .type = NODE_FILE, .data = fileName} + ); std::vector &fileSymbols = symbolLists.emplace_front(); @@ -422,7 +515,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) int matchedElems; if (fscanf(file, RGBDS_OBJECT_VERSION_STRING "%n", &matchedElems) == 1 - && matchedElems != strlen(RGBDS_OBJECT_VERSION_STRING)) + && matchedElems != strlen(RGBDS_OBJECT_VERSION_STRING)) errx("%s: Not a RGBDS object file", fileName); verbosePrint("Reading object file %s\n", fileName); @@ -431,10 +524,16 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) tryReadlong(revNum, file, "%s: Cannot read revision number: %s", fileName); if (revNum != RGBDS_OBJECT_REV) - errx("%s: Unsupported object file for rgblink %s; try rebuilding \"%s\"%s" - " (expected revision %d, got %d)", fileName, get_package_version_string(), - fileName, revNum > RGBDS_OBJECT_REV ? " or updating rgblink" : "", - RGBDS_OBJECT_REV, revNum); + errx( + "%s: Unsupported object file for rgblink %s; try rebuilding \"%s\"%s" + " (expected revision %d, got %d)", + fileName, + get_package_version_string(), + fileName, + revNum > RGBDS_OBJECT_REV ? " or updating rgblink" : "", + RGBDS_OBJECT_REV, + revNum + ); uint32_t nbNodes; uint32_t nbSymbols; @@ -448,7 +547,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) tryReadlong(nbNodes, file, "%s: Cannot read number of nodes: %s", fileName); nodes[fileID].resize(nbNodes); verbosePrint("Reading %u nodes...\n", nbNodes); - for (uint32_t i = nbNodes; i--; ) + for (uint32_t i = nbNodes; i--;) readFileStackNode(file, nodes[fileID], i, fileName); // This file's symbols, kept to link sections to them @@ -474,7 +573,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) verbosePrint("Reading %" PRIu32 " sections...\n", nbSections); for (uint32_t i = 0; i < nbSections; i++) { // Read section - fileSections[i] = new(std::nothrow) Section(); + fileSections[i] = new (std::nothrow) Section(); if (!fileSections[i]) err("%s: Failed to create new section", fileName); @@ -527,12 +626,10 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) fclose(file); } -void obj_CheckAssertions() -{ +void obj_CheckAssertions() { patch_CheckAssertions(assertions); } -void obj_Setup(unsigned int nbFiles) -{ +void obj_Setup(unsigned int nbFiles) { nodes.resize(nbFiles); } diff --git a/src/link/output.cpp b/src/link/output.cpp index 4da596f3..bf743a54 100644 --- a/src/link/output.cpp +++ b/src/link/output.cpp @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: MIT */ +#include "link/output.hpp" + #include #include #include @@ -10,17 +12,15 @@ #include #include -#include "link/output.hpp" +#include "error.hpp" +#include "extern/utf8decoder.hpp" +#include "itertools.hpp" +#include "linkdefs.hpp" + #include "link/main.hpp" #include "link/section.hpp" #include "link/symbol.hpp" -#include "extern/utf8decoder.hpp" - -#include "error.hpp" -#include "itertools.hpp" -#include "linkdefs.hpp" - #define BANK_SIZE 0x4000 FILE *outputFile; @@ -42,42 +42,45 @@ static std::deque sections[SECTTYPE_INVALID]; // Defines the order in which types are output to the sym and map files static enum SectionType typeMap[SECTTYPE_INVALID] = { - SECTTYPE_ROM0, - SECTTYPE_ROMX, - SECTTYPE_VRAM, - SECTTYPE_SRAM, - SECTTYPE_WRAM0, - SECTTYPE_WRAMX, - SECTTYPE_OAM, - SECTTYPE_HRAM + SECTTYPE_ROM0, + SECTTYPE_ROMX, + SECTTYPE_VRAM, + SECTTYPE_SRAM, + SECTTYPE_WRAM0, + SECTTYPE_WRAMX, + SECTTYPE_OAM, + SECTTYPE_HRAM, }; -void out_AddSection(Section const §ion) -{ +void out_AddSection(Section const §ion) { static const uint32_t maxNbBanks[SECTTYPE_INVALID] = { - 1, // SECTTYPE_WRAM0 - 2, // SECTTYPE_VRAM - UINT32_MAX, // SECTTYPE_ROMX - 1, // SECTTYPE_ROM0 - 1, // SECTTYPE_HRAM - 7, // SECTTYPE_WRAMX - UINT32_MAX, // SECTTYPE_SRAM - 1, // SECTTYPE_OAM + 1, // SECTTYPE_WRAM0 + 2, // SECTTYPE_VRAM + UINT32_MAX, // SECTTYPE_ROMX + 1, // SECTTYPE_ROM0 + 1, // SECTTYPE_HRAM + 7, // SECTTYPE_WRAMX + UINT32_MAX, // SECTTYPE_SRAM + 1, // SECTTYPE_OAM }; uint32_t targetBank = section.bank - sectionTypeInfo[section.type].firstBank; uint32_t minNbBanks = targetBank + 1; if (minNbBanks > maxNbBanks[section.type]) - errx("Section \"%s\" has an invalid bank range (%" PRIu32 " > %" PRIu32 ")", - section.name.c_str(), section.bank, maxNbBanks[section.type] - 1); + errx( + "Section \"%s\" has an invalid bank range (%" PRIu32 " > %" PRIu32 ")", + section.name.c_str(), + section.bank, + maxNbBanks[section.type] - 1 + ); for (uint32_t i = sections[section.type].size(); i < minNbBanks; i++) sections[section.type].emplace_back(); - std::deque
&bankSections = section.size - ? sections[section.type][targetBank].sections - : sections[section.type][targetBank].zeroLenSections; + std::deque
&bankSections = + section.size ? sections[section.type][targetBank].sections + : sections[section.type][targetBank].zeroLenSections; auto pos = bankSections.begin(); while (pos != bankSections.end() && (*pos)->org < section.org) @@ -86,8 +89,7 @@ void out_AddSection(Section const §ion) bankSections.insert(pos, §ion); } -Section const *out_OverlappingSection(Section const §ion) -{ +Section const *out_OverlappingSection(Section const §ion) { uint32_t bank = section.bank - sectionTypeInfo[section.type].firstBank; for (Section const *ptr : sections[section.type][bank].sections) { @@ -101,8 +103,7 @@ Section const *out_OverlappingSection(Section const §ion) * Performs sanity checks on the overlay file. * @return The number of ROM banks in the overlay file */ -static uint32_t checkOverlaySize() -{ +static uint32_t checkOverlaySize() { if (!overlayFile) return 0; @@ -136,14 +137,13 @@ static uint32_t checkOverlaySize() * covered by any sections. * @param nbOverlayBanks The number of banks in the overlay file */ -static void coverOverlayBanks(uint32_t nbOverlayBanks) -{ +static void coverOverlayBanks(uint32_t nbOverlayBanks) { // 2 if is32kMode, 1 otherwise uint32_t nbRom0Banks = sectionTypeInfo[SECTTYPE_ROM0].size / BANK_SIZE; // Discount ROM0 banks to avoid outputting too much uint32_t nbUncoveredBanks = nbOverlayBanks - nbRom0Banks > sections[SECTTYPE_ROMX].size() - ? nbOverlayBanks - nbRom0Banks - : 0; + ? nbOverlayBanks - nbRom0Banks + : 0; if (nbUncoveredBanks > sections[SECTTYPE_ROMX].size()) { for (uint32_t i = sections[SECTTYPE_ROMX].size(); i < nbUncoveredBanks; i++) @@ -157,8 +157,8 @@ static void coverOverlayBanks(uint32_t nbOverlayBanks) * @param baseOffset The address of the bank's first byte in GB address space * @param size The size of the bank */ -static void writeBank(std::deque
*bankSections, uint16_t baseOffset, uint16_t size) -{ +static void + writeBank(std::deque
*bankSections, uint16_t baseOffset, uint16_t size) { uint16_t offset = 0; if (bankSections) { @@ -190,8 +190,7 @@ static void writeBank(std::deque
*bankSections, uint16_t baseOf } // Writes a ROM file to the output. -static void writeROM() -{ +static void writeROM() { if (outputFileName) { if (strcmp(outputFileName, "-")) { outputFile = fopen(outputFileName, "wb"); @@ -220,12 +219,18 @@ static void writeROM() coverOverlayBanks(nbOverlayBanks); if (outputFile) { - writeBank(!sections[SECTTYPE_ROM0].empty() ? §ions[SECTTYPE_ROM0][0].sections : nullptr, - sectionTypeInfo[SECTTYPE_ROM0].startAddr, sectionTypeInfo[SECTTYPE_ROM0].size); + writeBank( + !sections[SECTTYPE_ROM0].empty() ? §ions[SECTTYPE_ROM0][0].sections : nullptr, + sectionTypeInfo[SECTTYPE_ROM0].startAddr, + sectionTypeInfo[SECTTYPE_ROM0].size + ); - for (uint32_t i = 0 ; i < sections[SECTTYPE_ROMX].size(); i++) - writeBank(§ions[SECTTYPE_ROMX][i].sections, - sectionTypeInfo[SECTTYPE_ROMX].startAddr, sectionTypeInfo[SECTTYPE_ROMX].size); + for (uint32_t i = 0; i < sections[SECTTYPE_ROMX].size(); i++) + writeBank( + §ions[SECTTYPE_ROMX][i].sections, + sectionTypeInfo[SECTTYPE_ROMX].startAddr, + sectionTypeInfo[SECTTYPE_ROMX].size + ); } if (outputFile) @@ -235,23 +240,20 @@ static void writeROM() } // Checks whether this character is legal as the first character of a symbol's name in a sym file -static bool canStartSymName(char c) -{ +static bool canStartSymName(char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_'; } // Checks whether this character is legal in a symbol's name in a sym file -static bool isLegalForSymName(char c) -{ - return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || - c == '_' || c == '@' || c == '#' || c == '$' || c == '.'; +static bool isLegalForSymName(char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' + || c == '@' || c == '#' || c == '$' || c == '.'; } // Prints a symbol's name to `symFile`, assuming that the first character is legal. // Illegal characters are UTF-8-decoded (errors are replaced by U+FFFD) and emitted as `\u`/`\U`. -static void printSymName(char const *name) -{ - for (char const *ptr = name; *ptr != '\0'; ) { +static void printSymName(char const *name) { + for (char const *ptr = name; *ptr != '\0';) { char c = *ptr; if (isLegalForSymName(c)) { @@ -277,16 +279,14 @@ static void printSymName(char const *name) ++ptr; } while (state != 0); - fprintf(symFile, codepoint <= 0xFFFF ? "\\u%04" PRIx32 : "\\U%08" PRIx32, - codepoint); + fprintf(symFile, codepoint <= 0xFFFF ? "\\u%04" PRIx32 : "\\U%08" PRIx32, codepoint); } } } // Comparator function for `std::stable_sort` to sort symbols // Symbols are ordered by address, then by parentage -static int compareSymbols(SortedSymbol const &sym1, SortedSymbol const &sym2) -{ +static int compareSymbols(SortedSymbol const &sym1, SortedSymbol const &sym2) { if (sym1.addr != sym2.addr) return sym1.addr < sym2.addr ? -1 : 1; @@ -315,24 +315,24 @@ static int compareSymbols(SortedSymbol const &sym1, SortedSymbol const &sym2) * Write a bank's contents to the sym file * @param bankSections The bank's sections */ -static void writeSymBank(SortedSections const &bankSections, enum SectionType type, uint32_t bank) -{ -#define forEachSortedSection(sect, ...) do { \ - for (auto it = bankSections.zeroLenSections.begin(); it != bankSections.zeroLenSections.end(); it++) { \ - for (Section const *sect = *it; sect; sect = sect->nextu) \ - __VA_ARGS__ \ - } \ - for (auto it = bankSections.sections.begin(); it != bankSections.sections.end(); it++) { \ - for (Section const *sect = *it; sect; sect = sect->nextu) \ - __VA_ARGS__ \ - } \ -} while (0) +static void writeSymBank(SortedSections const &bankSections, enum SectionType type, uint32_t bank) { +#define forEachSortedSection(sect, ...) \ + do { \ + for (auto it = bankSections.zeroLenSections.begin(); \ + it != bankSections.zeroLenSections.end(); \ + it++) { \ + for (Section const *sect = *it; sect; sect = sect->nextu) \ + __VA_ARGS__ \ + } \ + for (auto it = bankSections.sections.begin(); it != bankSections.sections.end(); it++) { \ + for (Section const *sect = *it; sect; sect = sect->nextu) \ + __VA_ARGS__ \ + } \ + } while (0) uint32_t nbSymbols = 0; - forEachSortedSection(sect, { - nbSymbols += sect->symbols.size(); - }); + forEachSortedSection(sect, { nbSymbols += sect->symbols.size(); }); if (!nbSymbols) return; @@ -345,10 +345,8 @@ static void writeSymBank(SortedSections const &bankSections, enum SectionType ty for (Symbol const *sym : sect->symbols) { // Don't output symbols that begin with an illegal character if (!sym->name.empty() && canStartSymName(sym->name[0])) - symList.push_back({ - .sym = sym, - .addr = (uint16_t)(sym->label().offset + sect->org) - }); + symList.push_back({.sym = sym, .addr = (uint16_t)(sym->label().offset + sect->org)} + ); } }); @@ -365,23 +363,31 @@ static void writeSymBank(SortedSections const &bankSections, enum SectionType ty } } -static void writeEmptySpace(uint16_t begin, uint16_t end) -{ +static void writeEmptySpace(uint16_t begin, uint16_t end) { if (begin < end) { uint16_t len = end - begin; - fprintf(mapFile, "\tEMPTY: $%04x-$%04x ($%04" PRIx16 " byte%s)\n", - begin, end - 1, len, len == 1 ? "" : "s"); + fprintf( + mapFile, + "\tEMPTY: $%04x-$%04x ($%04" PRIx16 " byte%s)\n", + begin, + end - 1, + len, + len == 1 ? "" : "s" + ); } } /* * Write a bank's contents to the map file */ -static void writeMapBank(SortedSections const §List, enum SectionType type, uint32_t bank) -{ - fprintf(mapFile, "\n%s bank #%" PRIu32 ":\n", sectionTypeInfo[type].name.c_str(), - bank + sectionTypeInfo[type].firstBank); +static void writeMapBank(SortedSections const §List, enum SectionType type, uint32_t bank) { + fprintf( + mapFile, + "\n%s bank #%" PRIu32 ":\n", + sectionTypeInfo[type].name.c_str(), + bank + sectionTypeInfo[type].firstBank + ); uint16_t used = 0; auto section = sectList.sections.begin(); @@ -390,9 +396,10 @@ static void writeMapBank(SortedSections const §List, enum SectionType type, while (section != sectList.sections.end() || zeroLenSection != sectList.zeroLenSections.end()) { // Pick the lowest section by address out of the two - auto &pickedSection = section == sectList.sections.end() ? zeroLenSection - : zeroLenSection == sectList.zeroLenSections.end() ? section - : (*section)->org < (*zeroLenSection)->org ? section : zeroLenSection; + auto &pickedSection = section == sectList.sections.end() ? zeroLenSection + : zeroLenSection == sectList.zeroLenSections.end() ? section + : (*section)->org < (*zeroLenSection)->org ? section + : zeroLenSection; Section const *sect = *pickedSection; used += sect->size; @@ -403,31 +410,41 @@ static void writeMapBank(SortedSections const §List, enum SectionType type, prevEndAddr = sect->org + sect->size; if (sect->size != 0) - fprintf(mapFile, "\tSECTION: $%04" PRIx16 "-$%04x ($%04" PRIx16 - " byte%s) [\"%s\"]\n", - sect->org, prevEndAddr - 1, sect->size, sect->size == 1 ? "" : "s", - sect->name.c_str()); + fprintf( + mapFile, + "\tSECTION: $%04" PRIx16 "-$%04x ($%04" PRIx16 " byte%s) [\"%s\"]\n", + sect->org, + prevEndAddr - 1, + sect->size, + sect->size == 1 ? "" : "s", + sect->name.c_str() + ); else - fprintf(mapFile, "\tSECTION: $%04" PRIx16 " (0 bytes) [\"%s\"]\n", - sect->org, sect->name.c_str()); + fprintf( + mapFile, + "\tSECTION: $%04" PRIx16 " (0 bytes) [\"%s\"]\n", + sect->org, + sect->name.c_str() + ); if (!noSymInMap) { // Also print symbols in the following "pieces" for (uint16_t org = sect->org; sect; sect = sect->nextu) { for (Symbol *sym : sect->symbols) // Space matches "\tSECTION: $xxxx ..." - fprintf(mapFile, "\t $%04" PRIx32 " = %s\n", - sym->label().offset + org, - sym->name.c_str()); + fprintf( + mapFile, + "\t $%04" PRIx32 " = %s\n", + sym->label().offset + org, + sym->name.c_str() + ); if (sect->nextu) { // Announce the following "piece" if (sect->nextu->modifier == SECTION_UNION) - fprintf(mapFile, - "\t ; Next union\n"); + fprintf(mapFile, "\t ; Next union\n"); else if (sect->nextu->modifier == SECTION_FRAGMENT) - fprintf(mapFile, - "\t ; Next fragment\n"); + fprintf(mapFile, "\t ; Next fragment\n"); } } } @@ -444,16 +461,14 @@ static void writeMapBank(SortedSections const §List, enum SectionType type, uint16_t slack = sectionTypeInfo[type].size - used; - fprintf(mapFile, "\tTOTAL EMPTY: $%04" PRIx16 " byte%s\n", slack, - slack == 1 ? "" : "s"); + fprintf(mapFile, "\tTOTAL EMPTY: $%04" PRIx16 " byte%s\n", slack, slack == 1 ? "" : "s"); } } /* * Write the total used and free space by section type to the map file */ -static void writeMapSummary() -{ +static void writeMapSummary() { fputs("SUMMARY:\n", mapFile); for (uint8_t i = 0; i < SECTTYPE_INVALID; i++) { @@ -480,9 +495,9 @@ static void writeMapSummary() || zeroLenSection != sectList.zeroLenSections.end()) { // Pick the lowest section by address out of the two auto &pickedSection = section == sectList.sections.end() ? zeroLenSection - : zeroLenSection == sectList.zeroLenSections.end() ? section - : (*section)->org < (*zeroLenSection)->org ? section - : zeroLenSection; + : zeroLenSection == sectList.zeroLenSections.end() ? section + : (*section)->org < (*zeroLenSection)->org ? section + : zeroLenSection; used += (*pickedSection)->size; pickedSection++; @@ -491,19 +506,22 @@ static void writeMapSummary() usedTotal += used; } - fprintf(mapFile, "\t%s: %" PRId32 " byte%s used / %" PRId32 " free", - sectionTypeInfo[type].name.c_str(), usedTotal, usedTotal == 1 ? "" : "s", - nbBanks * sectionTypeInfo[type].size - usedTotal); - if (sectionTypeInfo[type].firstBank != sectionTypeInfo[type].lastBank - || nbBanks > 1) + fprintf( + mapFile, + "\t%s: %" PRId32 " byte%s used / %" PRId32 " free", + sectionTypeInfo[type].name.c_str(), + usedTotal, + usedTotal == 1 ? "" : "s", + nbBanks * sectionTypeInfo[type].size - usedTotal + ); + if (sectionTypeInfo[type].firstBank != sectionTypeInfo[type].lastBank || nbBanks > 1) fprintf(mapFile, " in %u bank%s", nbBanks, nbBanks == 1 ? "" : "s"); putc('\n', mapFile); } } // Writes the sym file, if applicable. -static void writeSym() -{ +static void writeSym() { if (!symFileName) return; @@ -529,8 +547,7 @@ static void writeSym() } // Writes the map file, if applicable. -static void writeMap() -{ +static void writeMap() { if (!mapFileName) return; @@ -555,8 +572,7 @@ static void writeMap() fclose(mapFile); } -void out_WriteFiles() -{ +void out_WriteFiles() { writeROM(); writeSym(); writeMap(); diff --git a/src/link/patch.cpp b/src/link/patch.cpp index cc536cbf..289a52bf 100644 --- a/src/link/patch.cpp +++ b/src/link/patch.cpp @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: MIT */ +#include "link/patch.hpp" + #include #include #include @@ -8,17 +10,16 @@ #include #include -#include "link/object.hpp" -#include "link/patch.hpp" -#include "link/section.hpp" -#include "link/symbol.hpp" - #include "error.hpp" #include "helpers.hpp" #include "linkdefs.hpp" #include "opmath.hpp" #include "platform.hpp" +#include "link/object.hpp" +#include "link/section.hpp" +#include "link/symbol.hpp" + struct RPNStackEntry { int32_t value; bool errorFlag; // Whether the value is a placeholder inserted for error recovery @@ -26,17 +27,15 @@ struct RPNStackEntry { std::deque rpnStack; -static void pushRPN(int32_t value, bool comesFromError) -{ - rpnStack.push_front({ .value = value, .errorFlag = comesFromError }); +static void pushRPN(int32_t value, bool comesFromError) { + rpnStack.push_front({.value = value, .errorFlag = comesFromError}); } // This flag tracks whether the RPN op that is currently being evaluated // has popped any values with the error flag set. static bool isError = false; -static int32_t popRPN(FileStackNode const *node, uint32_t lineNo) -{ +static int32_t popRPN(FileStackNode const *node, uint32_t lineNo) { if (rpnStack.empty()) fatal(node, lineNo, "Internal error, RPN stack empty"); @@ -49,17 +48,16 @@ static int32_t popRPN(FileStackNode const *node, uint32_t lineNo) // RPN operators -static uint32_t getRPNByte(uint8_t const *&expression, int32_t &size, - FileStackNode const *node, uint32_t lineNo) -{ +static uint32_t getRPNByte( + uint8_t const *&expression, int32_t &size, FileStackNode const *node, uint32_t lineNo +) { if (!size--) fatal(node, lineNo, "Internal error, RPN expression overread"); return *expression++; } -static Symbol const *getSymbol(std::vector const &symbolList, uint32_t index) -{ +static Symbol const *getSymbol(std::vector const &symbolList, uint32_t index) { assert(index != (uint32_t)-1); // PC needs to be handled specially, not here Symbol const &symbol = symbolList[index]; @@ -78,8 +76,7 @@ static Symbol const *getSymbol(std::vector const &symbolList, uint32_t i * @return isError Set if an error occurred during evaluation, and further * errors caused by the value should be suppressed. */ -static int32_t computeRPNExpr(Patch const &patch, std::vector const &fileSymbols) -{ +static int32_t computeRPNExpr(Patch const &patch, std::vector const &fileSymbols) { // Small shortcut to avoid a lot of repetition #define popRPN() popRPN(patch.src, patch.lineNo) @@ -89,8 +86,8 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil rpnStack.clear(); while (size > 0) { - enum RPNCommand command = (enum RPNCommand)getRPNByte(expression, size, - patch.src, patch.lineNo); + enum RPNCommand command = + (enum RPNCommand)getRPNByte(expression, size, patch.src, patch.lineNo); int32_t value; isError = false; @@ -218,22 +215,27 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil case RPN_BANK_SYM: value = 0; for (uint8_t shift = 0; shift < 32; shift += 8) - value |= getRPNByte(expression, size, - patch.src, patch.lineNo) << shift; + value |= getRPNByte(expression, size, patch.src, patch.lineNo) << shift; symbol = getSymbol(fileSymbols, value); if (!symbol) { - error(patch.src, patch.lineNo, - "Requested BANK() of symbol \"%s\", which was not found", - fileSymbols[value].name.c_str()); + error( + patch.src, + patch.lineNo, + "Requested BANK() of symbol \"%s\", which was not found", + fileSymbols[value].name.c_str() + ); isError = true; value = 1; } else if (Label const *label = std::get_if