From cee99a8b76e4467227989119aef9720cad3c9d03 Mon Sep 17 00:00:00 2001 From: Rangi42 Date: Thu, 28 Nov 2024 14:06:52 -0500 Subject: [PATCH] Implement `-Wunmatched-directive` --- contrib/bash_compl/_rgbasm.bash | 1 + contrib/zsh_compl/_rgbasm | 1 + include/asm/charmap.hpp | 1 + include/asm/opt.hpp | 1 + include/asm/section.hpp | 1 + include/asm/warning.hpp | 1 + man/rgbasm.1 | 11 +++++++++++ src/asm/charmap.cpp | 6 ++++++ src/asm/main.cpp | 4 ++++ src/asm/opt.cpp | 6 ++++++ src/asm/section.cpp | 6 ++++++ src/asm/warning.cpp | 1 + test/asm/pushs.asm | 1 + test/asm/unmatched-directive.asm | 4 ++++ test/asm/unmatched-directive.err | 6 ++++++ 15 files changed, 51 insertions(+) create mode 100644 test/asm/unmatched-directive.asm create mode 100644 test/asm/unmatched-directive.err diff --git a/contrib/bash_compl/_rgbasm.bash b/contrib/bash_compl/_rgbasm.bash index 1bf1e6275..505a81815 100755 --- a/contrib/bash_compl/_rgbasm.bash +++ b/contrib/bash_compl/_rgbasm.bash @@ -192,6 +192,7 @@ _rgbasm_completions() { shift-amount truncation unmapped-char + unmatched-directive unterminated-load user all diff --git a/contrib/zsh_compl/_rgbasm b/contrib/zsh_compl/_rgbasm index 8930d33a5..1b2a6bb36 100644 --- a/contrib/zsh_compl/_rgbasm +++ b/contrib/zsh_compl/_rgbasm @@ -26,6 +26,7 @@ _rgbasm_warnings() { 'shift-amount:Warn when a shift'\''s operand it negative or \> 32' 'truncation:Warn when implicit truncation loses bits' 'unmapped-char:Warn on unmapped character' + 'unmatched-directive:Warn on unmatched directive pair' 'unterminated-load:Warn on LOAD without ENDL' 'user:Warn when executing the WARN built-in' ) diff --git a/include/asm/charmap.hpp b/include/asm/charmap.hpp index d76a0e407..975ee8265 100644 --- a/include/asm/charmap.hpp +++ b/include/asm/charmap.hpp @@ -18,6 +18,7 @@ void charmap_New(std::string const &name, std::string const *baseName); void charmap_Set(std::string const &name); void charmap_Push(); void charmap_Pop(); +void charmap_CheckStack(); void charmap_Add(std::string const &mapping, std::vector &&value); bool charmap_HasChar(std::string const &input); std::vector charmap_Convert(std::string const &input); diff --git a/include/asm/opt.hpp b/include/asm/opt.hpp index 78471acdb..1f81a63f7 100644 --- a/include/asm/opt.hpp +++ b/include/asm/opt.hpp @@ -14,5 +14,6 @@ void opt_Parse(char const *option); void opt_Push(); void opt_Pop(); +void opt_CheckStack(); #endif // RGBDS_ASM_OPT_HPP diff --git a/include/asm/section.hpp b/include/asm/section.hpp index e3e731d75..a89a4b0cf 100644 --- a/include/asm/section.hpp +++ b/include/asm/section.hpp @@ -102,5 +102,6 @@ void sect_BinaryFileSlice(std::string const &name, int32_t startPos, int32_t len void sect_EndSection(); void sect_PushSection(); void sect_PopSection(); +void sect_CheckStack(); #endif // RGBDS_ASM_SECTION_HPP diff --git a/include/asm/warning.hpp b/include/asm/warning.hpp index 4b235021b..e2ca7d344 100644 --- a/include/asm/warning.hpp +++ b/include/asm/warning.hpp @@ -20,6 +20,7 @@ enum WarningID { WARNING_OBSOLETE, // Obsolete/deprecated things WARNING_SHIFT, // Undefined `SHIFT` behavior WARNING_SHIFT_AMOUNT, // Strange `SHIFT` amount + WARNING_UNMATCHED_DIRECTIVE, // `PUSH[C|O|S]` without `POP[C|O|S]` WARNING_UNTERMINATED_LOAD, // `LOAD` without `ENDL` WARNING_USER, // User-defined `WARN`ings diff --git a/man/rgbasm.1 b/man/rgbasm.1 index 325323eff..5b485ce0e 100644 --- a/man/rgbasm.1 +++ b/man/rgbasm.1 @@ -370,6 +370,17 @@ only warns if the active charmap is not empty. .Fl Wunmapped-char=2 warns if the active charmap is empty, and/or is not the default charmap .Sq main . +.It Fl Wunmatched-directive +Warn when a +.Ic PUSHC , PUSHO , +or +.Ic PUSHS +directive does not have a corresponding +.Ic POPC , POPO , +or +.Ic POPS . +This warning is enabled by +.Fl Wextra . .It Fl Wunterminated-load Warn when a .Ic LOAD diff --git a/src/asm/charmap.cpp b/src/asm/charmap.cpp index 488f9ec85..81ce492ca 100644 --- a/src/asm/charmap.cpp +++ b/src/asm/charmap.cpp @@ -113,6 +113,12 @@ void charmap_Pop() { charmapStack.pop(); } +void charmap_CheckStack() { + if (!charmapStack.empty()) { + warning(WARNING_UNMATCHED_DIRECTIVE, "`PUSHC` without corresponding `POPC`\n"); + } +} + void charmap_Add(std::string const &mapping, std::vector &&value) { if (mapping.empty()) { error("Cannot map an empty string\n"); diff --git a/src/asm/main.cpp b/src/asm/main.cpp index 31e529faa..d12cc47ca 100644 --- a/src/asm/main.cpp +++ b/src/asm/main.cpp @@ -384,6 +384,10 @@ int main(int argc, char *argv[]) { sect_CheckLoadClosed(); sect_CheckSizes(); + charmap_CheckStack(); + opt_CheckStack(); + sect_CheckStack(); + if (nbErrors != 0) errx("Assembly aborted (%u error%s)!", nbErrors, nbErrors == 1 ? "" : "s"); diff --git a/src/asm/opt.cpp b/src/asm/opt.cpp index b6e58280a..ac5442ccc 100644 --- a/src/asm/opt.cpp +++ b/src/asm/opt.cpp @@ -184,3 +184,9 @@ void opt_Pop() { warningsAreErrors = entry.warningsAreErrors; warningStates = entry.warningStates; } + +void opt_CheckStack() { + if (!stack.empty()) { + warning(WARNING_UNMATCHED_DIRECTIVE, "`PUSHO` without corresponding `POPO`\n"); + } +} diff --git a/src/asm/section.cpp b/src/asm/section.cpp index 3df440659..94c3746ad 100644 --- a/src/asm/section.cpp +++ b/src/asm/section.cpp @@ -973,6 +973,12 @@ void sect_PopSection() { std::swap(currentUnionStack, entry.unionStack); } +void sect_CheckStack() { + if (!sectionStack.empty()) { + warning(WARNING_UNMATCHED_DIRECTIVE, "`PUSHS` without corresponding `POPS`\n"); + } +} + void sect_EndSection() { if (!currentSection) fatalerror("Cannot end the section outside of a SECTION\n"); diff --git a/src/asm/warning.cpp b/src/asm/warning.cpp index 87e07a92d..b96b4a081 100644 --- a/src/asm/warning.cpp +++ b/src/asm/warning.cpp @@ -56,6 +56,7 @@ static const WarningFlag warningFlags[NB_WARNINGS] = { {"obsolete", LEVEL_DEFAULT }, {"shift", LEVEL_EVERYTHING}, {"shift-amount", LEVEL_EVERYTHING}, + {"unmatched-directive", LEVEL_EXTRA }, {"unterminated-load", LEVEL_EXTRA }, {"user", LEVEL_DEFAULT }, // Parametric warnings diff --git a/test/asm/pushs.asm b/test/asm/pushs.asm index 7ac2237cd..9d3fed87e 100644 --- a/test/asm/pushs.asm +++ b/test/asm/pushs.asm @@ -3,3 +3,4 @@ SECTION "This is invalid", ROM0 PUSHS ; We should be outside of section scope now db 69 + POPS diff --git a/test/asm/unmatched-directive.asm b/test/asm/unmatched-directive.asm new file mode 100644 index 000000000..ed342ee89 --- /dev/null +++ b/test/asm/unmatched-directive.asm @@ -0,0 +1,4 @@ +SECTION "test", ROM0 +PUSHC +PUSHO +PUSHS diff --git a/test/asm/unmatched-directive.err b/test/asm/unmatched-directive.err new file mode 100644 index 000000000..4828cbed8 --- /dev/null +++ b/test/asm/unmatched-directive.err @@ -0,0 +1,6 @@ +warning: unmatched-directive.asm(5): [-Wunmatched-directive] + `PUSHC` without corresponding `POPC` +warning: unmatched-directive.asm(5): [-Wunmatched-directive] + `PUSHO` without corresponding `POPO` +warning: unmatched-directive.asm(5): [-Wunmatched-directive] + `PUSHS` without corresponding `POPS`