From 9095c5b320aa462f267c9579a874ecf7db513886 Mon Sep 17 00:00:00 2001 From: Rangi <35663410+Rangi42@users.noreply.github.com> Date: Sat, 3 Oct 2026 13:24:49 -0400 Subject: [PATCH] Do not reuse `Patch` struct for outputting assertions (#2184) --- include/asm/output.hpp | 2 +- include/asm/section.hpp | 2 +- include/link/patch.hpp | 8 +- include/link/section.hpp | 10 +- src/asm/output.cpp | 75 +++++---- src/link/object.cpp | 334 +++++++++++++++++++++++---------------- src/link/patch.cpp | 253 +++++++++++++++-------------- src/link/sdas_obj.cpp | 102 ++++++------ src/link/section.cpp | 2 +- 9 files changed, 427 insertions(+), 361 deletions(-) diff --git a/include/asm/output.hpp b/include/asm/output.hpp index 906c5c4c..7887116c 100644 --- a/include/asm/output.hpp +++ b/include/asm/output.hpp @@ -18,7 +18,7 @@ enum StateFeature { STATE_EQU, STATE_VAR, STATE_EQUS, STATE_CHAR, STATE_MACRO, N void out_RegisterNode(std::shared_ptr node); void out_RegisterSymbol(Symbol &sym); -void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32_t pcShift); +void out_CreatePatch(PatchType type, Expression const &expr, uint32_t ofs, uint32_t pcShift); void out_CreateAssert( AssertionType type, Expression const &expr, std::string const &message, uint32_t ofs ); diff --git a/include/asm/section.hpp b/include/asm/section.hpp index 3421a0c6..ce4b3260 100644 --- a/include/asm/section.hpp +++ b/include/asm/section.hpp @@ -24,7 +24,7 @@ struct Patch { uint32_t offset; Section *pcSection; uint32_t pcOffset; - uint8_t type; + PatchType type; std::vector rpn; }; diff --git a/include/link/patch.hpp b/include/link/patch.hpp index 557e5281..e10ebf1e 100644 --- a/include/link/patch.hpp +++ b/include/link/patch.hpp @@ -11,10 +11,12 @@ struct Symbol; struct Assertion { - Patch patch; // Also used for its `.type` + Expression rpn; + uint32_t offset; + AssertionType type; std::string message; - // This would be redundant with `patch.pcSection->fileSymbols`, but `section` is sometimes - // `nullptr`! + // This would be redundant with `rpn.pcSection->fileSymbols`, + // but `rpn.pcSection` is sometimes `nullptr`! std::vector *fileSymbols; }; diff --git a/include/link/section.hpp b/include/link/section.hpp index b808a25e..4b69dc5a 100644 --- a/include/link/section.hpp +++ b/include/link/section.hpp @@ -15,15 +15,19 @@ struct FileStackNode; struct Section; struct Symbol; -struct Patch { +struct Expression { FileStackNode const *src; uint32_t lineNo; - uint32_t offset; Section const *pcSection; uint32_t pcSectionID; uint32_t pcOffset; + std::vector rpn; +}; + +struct Patch { + Expression rpn; + uint32_t offset; PatchType type; - std::vector rpnExpression; }; struct Section { diff --git a/src/asm/output.cpp b/src/asm/output.cpp index 405d7ae0..3507fdcd 100644 --- a/src/asm/output.cpp +++ b/src/asm/output.cpp @@ -31,8 +31,13 @@ #include "asm/warning.hpp" struct Assertion { - Patch patch; - Section *section; + std::shared_ptr src; + uint32_t lineNo; + uint32_t offset; + Section *pcSection; + uint32_t pcOffset; + AssertionType type; + std::vector rpn; std::string message; }; @@ -66,19 +71,6 @@ void out_RegisterNode(std::shared_ptr node) { } } -static void writePatch(Patch const &patch, FILE *file) { - assume(patch.src->ID != UINT32_MAX); - - putLong(patch.src->ID, file); - putLong(patch.lineNo, file); - putLong(patch.offset, file); - putLong(patch.pcSection ? patch.pcSection->getID() : UINT32_MAX, file); - putLong(patch.pcOffset, file); - putc(patch.type, file); - putLong(patch.rpn.size(), file); - fwrite(patch.rpn.data(), 1, patch.rpn.size(), file); -} - static void writeSection(Section const §, FILE *file) { assume(sect.src->ID != UINT32_MAX); @@ -104,7 +96,16 @@ static void writeSection(Section const §, FILE *file) { putLong(sect.patches.size(), file); for (Patch const &patch : sect.patches) { - writePatch(patch, file); + assume(patch.src->ID != UINT32_MAX); + + putLong(patch.src->ID, file); + putLong(patch.lineNo, file); + putLong(patch.offset, file); + putLong(patch.pcSection ? patch.pcSection->getID() : UINT32_MAX, file); + putLong(patch.pcOffset, file); + putc(patch.type, file); + putLong(patch.rpn.size(), file); + fwrite(patch.rpn.data(), 1, patch.rpn.size(), file); } } } @@ -135,7 +136,11 @@ void out_RegisterSymbol(Symbol &sym) { } } -static void initPatch(Patch &patch, uint32_t type, Expression const &expr, uint32_t ofs) { +void out_CreatePatch(PatchType type, Expression const &expr, uint32_t ofs, uint32_t pcShift) { + assume(sect_GetSymbolSection() != nullptr); + + // Add the patch to the list + Patch &patch = *sect_AddOutputPatch(); patch.type = type; patch.src = fstk_GetFileStack(); // All patches are assumed to eventually be written, so the file stack node is registered @@ -145,18 +150,8 @@ static void initPatch(Patch &patch, uint32_t type, Expression const &expr, uint3 patch.pcSection = sect_GetSymbolSection(); patch.pcOffset = sect_GetSymbolOffset(); expr.encode(patch.rpn); -} - -void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32_t pcShift) { - // Add the patch to the list - assume(sect_GetSymbolSection() != nullptr); - Patch &patch = *sect_AddOutputPatch(); - - initPatch(patch, type, expr, ofs); - - // If the patch had a quantity of bytes output before it, - // PC is not at the patch's location, but at the location - // before those bytes. + // If the patch had a quantity of bytes output before it, PC is not at the patch's location, + // but at the location before those bytes. patch.pcOffset -= pcShift; } @@ -168,13 +163,29 @@ void out_CreateAssert( } Assertion &assertion = assertions.emplace_front(); - - initPatch(assertion.patch, type, expr, ofs); + assertion.type = type; + assertion.src = fstk_GetFileStack(); + // All assertions are assumed to eventually be written, so the file stack node is registered + out_RegisterNode(assertion.src); + assertion.lineNo = lexer_GetLineNo(); + assertion.offset = ofs; + assertion.pcSection = sect_GetSymbolSection(); + assertion.pcOffset = sect_GetSymbolOffset(); + expr.encode(assertion.rpn); assertion.message = message; } static void writeAssert(Assertion const &assert, FILE *file) { - writePatch(assert.patch, file); + assume(assert.src->ID != UINT32_MAX); + + putLong(assert.src->ID, file); + putLong(assert.lineNo, file); + putLong(assert.offset, file); + putLong(assert.pcSection ? assert.pcSection->getID() : UINT32_MAX, file); + putLong(assert.pcOffset, file); + putc(assert.type, file); + putLong(assert.rpn.size(), file); + fwrite(assert.rpn.data(), 1, assert.rpn.size(), file); putString(assert.message, file); } diff --git a/src/link/object.cpp b/src/link/object.cpp index 0ddb97d8..184701f0 100644 --- a/src/link/object.cpp +++ b/src/link/object.cpp @@ -205,111 +205,6 @@ static void readSymbol( } } -// Reads a patch from a file. -static void readPatch( - FILE *file, - Patch &patch, - char const *fileName, - std::string const §Name, - uint32_t patchID, - std::vector const &fileNodes -) { - uint32_t nodeID; - tryReadLong( - nodeID, - file, - "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s node ID: %s", - fileName, - sectName.c_str(), - patchID - ); - if (nodeID >= fileNodes.size()) { - fatal( - "%s: \"%s\"'s patch #%" PRIu32 " has invalid node ID #%" PRIu32, - fileName, - sectName.c_str(), - patchID, - nodeID - ); - } - patch.src = &fileNodes[nodeID]; - - tryReadLong( - patch.lineNo, - file, - "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s line number: %s", - fileName, - sectName.c_str(), - patchID - ); - tryReadLong( - patch.offset, - file, - "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s offset: %s", - fileName, - sectName.c_str(), - patchID - ); - tryReadLong( - patch.pcSectionID, - file, - "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s", - fileName, - sectName.c_str(), - patchID - ); - tryReadLong( - patch.pcOffset, - file, - "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s", - fileName, - sectName.c_str(), - patchID - ); - - uint8_t type; - tryGetc( - type, - file, - "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s type: %s", - fileName, - sectName.c_str(), - patchID - ); - if (type >= PATCHTYPE_INVALID) { - fatal( - "%s: \"%s\"'s patch #%" PRIu32 " has unknown type 0x%02x", - fileName, - sectName.c_str(), - patchID, - type - ); - } else { - patch.type = PatchType(type); - } - - uint32_t rpnSize; - tryReadLong( - rpnSize, - file, - "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s RPN size: %s", - fileName, - sectName.c_str(), - patchID - ); - - patch.rpnExpression.resize(rpnSize); - if (fread(patch.rpnExpression.data(), 1, rpnSize, file) != rpnSize) { - fatal( - "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s RPN expression: %s", - fileName, - sectName.c_str(), - patchID, - feof(file) ? "Unexpected end of file" : strerror(errno) - ); - } -} - // Reads a section from a file. static void readSection( FILE *file, Section §ion, char const *fileName, std::vector const &fileNodes @@ -386,31 +281,127 @@ static void readSection( } section.alignOfs = tmp; - if (sectTypeHasData(section.type)) { - if (section.size) { - section.data.resize(section.size); - if (fread(section.data.data(), 1, section.size, file) != section.size) { - fatal( - "%s: Cannot read \"%s\"'s data: %s", - fileName, - section.name.c_str(), - feof(file) ? "Unexpected end of file" : strerror(errno) - ); - } - } + if (!sectTypeHasData(section.type)) { + return; + } + + if (section.size) { + section.data.resize(section.size); + if (fread(section.data.data(), 1, section.size, file) != section.size) { + fatal( + "%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() + ); + + section.patches.resize(nbPatches); + for (uint32_t patchID = 0; patchID < nbPatches; ++patchID) { + Patch &patch = section.patches[patchID]; - uint32_t nbPatches; tryReadLong( - nbPatches, + nodeID, file, - "%s: Cannot read \"%s\"'s number of patches: %s", + "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s node ID: %s", fileName, - section.name.c_str() + section.name.c_str(), + patchID + ); + if (nodeID >= fileNodes.size()) { + fatal( + "%s: \"%s\"'s patch #%" PRIu32 " has invalid node ID #%" PRIu32, + fileName, + section.name.c_str(), + patchID, + nodeID + ); + } + patch.rpn.src = &fileNodes[nodeID]; + + tryReadLong( + patch.rpn.lineNo, + file, + "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s line number: %s", + fileName, + section.name.c_str(), + patchID + ); + tryReadLong( + patch.offset, + file, + "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s offset: %s", + fileName, + section.name.c_str(), + patchID + ); + tryReadLong( + patch.rpn.pcSectionID, + file, + "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s", + fileName, + section.name.c_str(), + patchID + ); + tryReadLong( + patch.rpn.pcOffset, + file, + "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s PC offset: %s", + fileName, + section.name.c_str(), + patchID ); - section.patches.resize(nbPatches); - for (uint32_t i = 0; i < nbPatches; ++i) { - readPatch(file, section.patches[i], fileName, section.name, i, fileNodes); + uint8_t type; + tryGetc( + type, + file, + "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s type: %s", + fileName, + section.name.c_str(), + patchID + ); + if (type >= PATCHTYPE_INVALID) { + fatal( + "%s: \"%s\"'s patch #%" PRIu32 " has unknown type 0x%02x", + fileName, + section.name.c_str(), + patchID, + type + ); + } else { + patch.type = PatchType(type); + } + + uint32_t rpnSize; + tryReadLong( + rpnSize, + file, + "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s RPN size: %s", + fileName, + section.name.c_str(), + patchID + ); + + patch.rpn.rpn.resize(rpnSize); + if (fread(patch.rpn.rpn.data(), 1, rpnSize, file) != rpnSize) { + fatal( + "%s: Cannot read \"%s\"'s patch #%" PRIu32 "'s RPN expression: %s", + fileName, + section.name.c_str(), + patchID, + feof(file) ? "Unexpected end of file" : strerror(errno) + ); } } } @@ -423,11 +414,76 @@ static void readAssertion( uint32_t assertID, std::vector const &fileNodes ) { - std::string assertName("Assertion #"); + uint32_t nodeID; + tryReadLong( + nodeID, file, "%s: Cannot read assertion #%" PRIu32 "'s node ID: %s", fileName, assertID + ); + if (nodeID >= fileNodes.size()) { + fatal( + "%s: assertion #%" PRIu32 " has invalid node ID #%" PRIu32, fileName, assertID, nodeID + ); + } + assert.rpn.src = &fileNodes[nodeID]; - assertName += std::to_string(assertID); - readPatch(file, assert.patch, fileName, assertName, 0, fileNodes); - tryReadString(assert.message, file, "%s: Cannot read assertion's message: %s", fileName); + tryReadLong( + assert.rpn.lineNo, + file, + "%s: Cannot read assertion #%" PRIu32 "'s line number: %s", + fileName, + assertID + ); + tryReadLong( + assert.offset, + file, + "%s: Cannot read assertion #%" PRIu32 "'s offset: %s", + fileName, + assertID + ); + tryReadLong( + assert.rpn.pcSectionID, + file, + "%s: Cannot read assertion #%" PRIu32 "'s PC offset: %s", + fileName, + assertID + ); + tryReadLong( + assert.rpn.pcOffset, + file, + "%s: Cannot read assertion #%" PRIu32 "'s PC offset: %s", + fileName, + assertID + ); + + uint8_t type; + tryGetc(type, file, "%s: Cannot read assertion #%" PRIu32 "'s type: %s", fileName, assertID); + if (type > ASSERT_FATAL) { + fatal("%s: assertion #%" PRIu32 " has unknown type 0x%02x", fileName, assertID, type); + } else { + assert.type = AssertionType(type); + } + + uint32_t rpnSize; + tryReadLong( + rpnSize, file, "%s: Cannot read assertion #%" PRIu32 "'s RPN size: %s", fileName, assertID + ); + + assert.rpn.rpn.resize(rpnSize); + if (fread(assert.rpn.rpn.data(), 1, rpnSize, file) != rpnSize) { + fatal( + "%s: Cannot read assertion #%" PRIu32 "'s RPN expression: %s", + fileName, + assertID, + feof(file) ? "Unexpected end of file" : strerror(errno) + ); + } + + tryReadString( + assert.message, + file, + "%s: Cannot read assertion #%" PRIu32 "'s message: %s", + fileName, + assertID + ); } void obj_ReadFile(std::string const &filePath, size_t fileID) { @@ -557,17 +613,17 @@ void obj_ReadFile(std::string const &filePath, size_t fileID) { readAssertion(file, assertion, fileName, i, nodes[fileID]); - if (assertion.patch.pcSectionID == UINT32_MAX) { - assertion.patch.pcSection = nullptr; - } else if (assertion.patch.pcSectionID >= fileSections.size()) { + if (assertion.rpn.pcSectionID == UINT32_MAX) { + assertion.rpn.pcSection = nullptr; + } else if (assertion.rpn.pcSectionID >= fileSections.size()) { fatal( - "%s: Assertion #%" PRIu32 "'s patch has invalid section ID #%" PRIu32, + "%s: Assertion #%" PRIu32 " has invalid section ID #%" PRIu32, fileName, i, - assertion.patch.pcSectionID + assertion.rpn.pcSectionID ); } else { - assertion.patch.pcSection = fileSections[assertion.patch.pcSectionID].get(); + assertion.rpn.pcSection = fileSections[assertion.rpn.pcSectionID].get(); } assertion.fileSymbols = &fileSymbols; @@ -579,18 +635,18 @@ void obj_ReadFile(std::string const &filePath, size_t fileID) { continue; } for (size_t i = 0; i < sect->patches.size(); ++i) { - if (Patch &patch = sect->patches[i]; patch.pcSectionID == UINT32_MAX) { - patch.pcSection = nullptr; - } else if (patch.pcSectionID >= fileSections.size()) { + if (Expression &rpn = sect->patches[i].rpn; rpn.pcSectionID == UINT32_MAX) { + rpn.pcSection = nullptr; + } else if (rpn.pcSectionID >= fileSections.size()) { fatal( "%s: \"%s\"'s patch #%zu has invalid section ID #%" PRIu32, fileName, sect->name.c_str(), i, - patch.pcSectionID + rpn.pcSectionID ); } else { - patch.pcSection = fileSections[patch.pcSectionID].get(); + rpn.pcSection = fileSections[rpn.pcSectionID].get(); } } } diff --git a/src/link/patch.cpp b/src/link/patch.cpp index 75729c9d..b6ad398c 100644 --- a/src/link/patch.cpp +++ b/src/link/patch.cpp @@ -36,11 +36,11 @@ static void pushRPN(int32_t value, bool comesFromError) { // has popped any values with the error flag set. static bool isError = false; -#define diagnosticAt(patch, id, ...) \ +#define diagnosticAt(expr, id, ...) \ do { \ bool errorDiag = warnings.getWarningBehavior(id) == WarningBehavior::ERROR; \ if (!isError || !errorDiag) { \ - warningAt(patch, id, __VA_ARGS__); \ + warningAt(expr, id, __VA_ARGS__); \ } \ if (errorDiag) { \ isError = true; \ @@ -60,9 +60,9 @@ static bool isError = false; } \ } while (0) -static int32_t popRPN(Patch const &patch) { +static int32_t popRPN(Expression const &expr) { if (rpnStack.empty()) { - fatalAt(patch, "Internal error, RPN stack empty"); + fatalAt(expr, "Internal error, RPN stack empty"); } RPNStackEntry entry = rpnStack.front(); @@ -74,12 +74,12 @@ static int32_t popRPN(Patch const &patch) { // RPN operators -static uint32_t getRPNByte(uint8_t const *&expression, int32_t &size, Patch const &patch) { +static uint32_t getRPNByte(uint8_t const *&rpnBuffer, int32_t &size, Expression const &expr) { if (!size--) { - fatalAt(patch, "Internal error, RPN expression overread"); + fatalAt(expr, "Internal error, RPN expression overread"); } - return *expression++; + return *rpnBuffer++; } static Symbol const *getSymbol(std::vector const &symbolList, uint32_t index) { @@ -95,15 +95,15 @@ static Symbol const *getSymbol(std::vector const &symbolList, uint32_t i return &symbol; } -// Compute a patch's value from its RPN string. -static int32_t computeRPNExpr(Patch const &patch, std::vector const &fileSymbols) { - uint8_t const *expression = patch.rpnExpression.data(); - int32_t size = static_cast(patch.rpnExpression.size()); +// Compute an Expression's value from its RPN string. +static int32_t computeRPNExpr(Expression const &expr, std::vector const &fileSymbols) { + uint8_t const *rpnBuffer = expr.rpn.data(); + int32_t size = static_cast(expr.rpn.size()); rpnStack.clear(); while (size > 0) { - RPNCommand command = static_cast(getRPNByte(expression, size, patch)); + RPNCommand command = static_cast(getRPNByte(rpnBuffer, size, expr)); isError = false; @@ -114,24 +114,24 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil int32_t value; switch (command) { case RPN_ADD: - value = op_add(popRPN(patch), popRPN(patch)); + value = op_add(popRPN(expr), popRPN(expr)); break; case RPN_SUB: - value = popRPN(patch); - value = op_sub(popRPN(patch), value); + value = popRPN(expr); + value = op_sub(popRPN(expr), value); break; case RPN_MUL: - value = op_mul(popRPN(patch), popRPN(patch)); + value = op_mul(popRPN(expr), popRPN(expr)); break; case RPN_DIV: - value = popRPN(patch); + value = popRPN(expr); if (value == 0) { - firstErrorAt(patch, "Division by 0"); - popRPN(patch); + firstErrorAt(expr, "Division by 0"); + popRPN(expr); value = 0; - } else if (int32_t lval = popRPN(patch); lval == INT32_MIN && value == -1) { + } else if (int32_t lval = popRPN(expr); lval == INT32_MIN && value == -1) { diagnosticAt( - patch, + expr, WARNING_DIV, "Division of %" PRId32 " by -1 yields %" PRId32, INT32_MIN, @@ -143,153 +143,153 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil } break; case RPN_MOD: - value = popRPN(patch); + value = popRPN(expr); if (value == 0) { - firstErrorAt(patch, "Modulo by 0"); - popRPN(patch); + firstErrorAt(expr, "Modulo by 0"); + popRPN(expr); value = 0; - } else if (int32_t lval = popRPN(patch); lval == INT32_MIN && value == -1) { - diagnosticAt(patch, WARNING_DIV, "Modulo of %" PRId32 " by -1 yields 0", INT32_MIN); + } else if (int32_t lval = popRPN(expr); lval == INT32_MIN && value == -1) { + diagnosticAt(expr, WARNING_DIV, "Modulo of %" PRId32 " by -1 yields 0", INT32_MIN); value = 0; } else { value = op_modulo(lval, value); } break; case RPN_NEG: - value = op_neg(popRPN(patch)); + value = op_neg(popRPN(expr)); break; case RPN_EXP: - value = popRPN(patch); + value = popRPN(expr); if (value < 0) { - firstErrorAt(patch, "Exponent by negative value %" PRId32, value); - popRPN(patch); + firstErrorAt(expr, "Exponent by negative value %" PRId32, value); + popRPN(expr); value = 0; } else { - value = op_exponent(popRPN(patch), value); + value = op_exponent(popRPN(expr), value); } break; case RPN_HIGH: - value = op_high(popRPN(patch)); + value = op_high(popRPN(expr)); break; case RPN_LOW: - value = op_low(popRPN(patch)); + value = op_low(popRPN(expr)); break; case RPN_BITWIDTH: - value = op_bitwidth(popRPN(patch)); + value = op_bitwidth(popRPN(expr)); break; case RPN_TZCOUNT: - value = op_tzcount(popRPN(patch)); + value = op_tzcount(popRPN(expr)); break; case RPN_OR: - value = popRPN(patch) | popRPN(patch); + value = popRPN(expr) | popRPN(expr); break; case RPN_AND: - value = popRPN(patch) & popRPN(patch); + value = popRPN(expr) & popRPN(expr); break; case RPN_XOR: - value = popRPN(patch) ^ popRPN(patch); + value = popRPN(expr) ^ popRPN(expr); break; case RPN_NOT: - value = ~popRPN(patch); + value = ~popRPN(expr); break; case RPN_LOGAND: - value = popRPN(patch); - value = popRPN(patch) && value; + value = popRPN(expr); + value = popRPN(expr) && value; break; case RPN_LOGOR: - value = popRPN(patch); - value = popRPN(patch) || value; + value = popRPN(expr); + value = popRPN(expr) || value; break; case RPN_LOGNOT: - value = !popRPN(patch); + value = !popRPN(expr); break; case RPN_LOGEQ: - value = popRPN(patch) == popRPN(patch); + value = popRPN(expr) == popRPN(expr); break; case RPN_LOGNE: - value = popRPN(patch) != popRPN(patch); + value = popRPN(expr) != popRPN(expr); break; case RPN_LOGGT: - value = popRPN(patch); - value = popRPN(patch) > value; + value = popRPN(expr); + value = popRPN(expr) > value; break; case RPN_LOGLT: - value = popRPN(patch); - value = popRPN(patch) < value; + value = popRPN(expr); + value = popRPN(expr) < value; break; case RPN_LOGGE: - value = popRPN(patch); - value = popRPN(patch) >= value; + value = popRPN(expr); + value = popRPN(expr) >= value; break; case RPN_LOGLE: - value = popRPN(patch); - value = popRPN(patch) <= value; + value = popRPN(expr); + value = popRPN(expr) <= value; break; case RPN_SHL: - value = popRPN(patch); + value = popRPN(expr); if (value < 0) { diagnosticAt( - patch, WARNING_SHIFT_AMOUNT, "Shifting left by negative amount %" PRId32, value + expr, WARNING_SHIFT_AMOUNT, "Shifting left by negative amount %" PRId32, value ); } if (value >= 32) { diagnosticAt( - patch, WARNING_SHIFT_AMOUNT, "Shifting left by large amount %" PRId32, value + expr, WARNING_SHIFT_AMOUNT, "Shifting left by large amount %" PRId32, value ); } - value = op_shift_left(popRPN(patch), value); + value = op_shift_left(popRPN(expr), value); break; case RPN_SHR: { - value = popRPN(patch); - int32_t lval = popRPN(patch); + value = popRPN(expr); + int32_t lval = popRPN(expr); if (lval < 0) { - diagnosticAt(patch, WARNING_SHIFT, "Shifting right negative value %" PRId32, lval); + diagnosticAt(expr, WARNING_SHIFT, "Shifting right negative value %" PRId32, lval); } if (value < 0) { diagnosticAt( - patch, WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %" PRId32, value + expr, WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %" PRId32, value ); } if (value >= 32) { diagnosticAt( - patch, WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32, value + expr, WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32, value ); } value = op_shift_right(lval, value); break; } case RPN_USHR: - value = popRPN(patch); + value = popRPN(expr); if (value < 0) { diagnosticAt( - patch, WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %" PRId32, value + expr, WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %" PRId32, value ); } if (value >= 32) { diagnosticAt( - patch, WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32, value + expr, WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32, value ); } - value = op_shift_right_unsigned(popRPN(patch), value); + value = op_shift_right_unsigned(popRPN(expr), value); break; case RPN_BANK_SYM: { uint32_t symID = 0; for (uint8_t shift = 0; shift < 32; shift += 8) { - symID |= getRPNByte(expression, size, patch) << shift; + symID |= getRPNByte(rpnBuffer, size, expr) << shift; } if (symID >= fileSymbols.size()) { - fatalAt(patch, "Requested `BANK()` of invalid symbol ID #%" PRIu32, symID); + fatalAt(expr, "Requested `BANK()` of invalid symbol ID #%" PRIu32, symID); } else if (Symbol const *symbol = getSymbol(fileSymbols, symID); !symbol) { rpnErrorAt( - patch, + expr, "Requested `BANK()` of undefined symbol `%s`", fileSymbols[symID].name.c_str() ); @@ -297,7 +297,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector const &fil } else if (std::holds_alternative