From e8422c1c88a8e87781af0f786ff09300f694678f Mon Sep 17 00:00:00 2001 From: Rangi <35663410+Rangi42@users.noreply.github.com> Date: Sat, 26 Sep 2026 13:10:39 -0400 Subject: [PATCH] Implement compound assignment operators `**=` and `>>>=` (#2158) --- man/rgbasm.5 | 3 ++- src/asm/lexer.cpp | 31 +++++++++++++++++++++---------- src/asm/parser.y | 9 ++++++++- test/asm/compound-assignment.asm | 8 ++++++-- test/asm/compound-assignment.err | 2 +- test/asm/compound-assignment.out | 8 ++++++-- 6 files changed, 44 insertions(+), 17 deletions(-) diff --git a/man/rgbasm.5 b/man/rgbasm.5 index bbbe2c6b..c601953b 100644 --- a/man/rgbasm.5 +++ b/man/rgbasm.5 @@ -1485,7 +1485,8 @@ Variables can be conveniently redefined by compound assignment operators like in .It Sy Operator Ta Sy Meaning .It Li += -= Ta Compound plus/minus .It Li *= /= %= Ta Compound multiply/divide/modulo -.It Li <<= >>= Ta Compound shift left/right +.It Li **= Ta Compound exponent +.It Li <<= >>= >>>= Ta Compound shift left/sign-extended right/zero-extended right .It Li &= \&|= ^= Ta Compound and/or/xor .El .Pp diff --git a/src/asm/lexer.cpp b/src/asm/lexer.cpp index 8d6dc4b8..2f560217 100644 --- a/src/asm/lexer.cpp +++ b/src/asm/lexer.cpp @@ -1683,9 +1683,6 @@ static Token yylex_NORMAL() { case '-': // Either -= or SUB return oneOrTwo('=', T_(POP_SUBEQ), T_(OP_SUB)); - case '*': // Either *=, MUL, or EXP - return oneOrTwo('=', T_(POP_MULEQ), '*', T_(OP_EXP), T_(OP_MUL)); - case '/': // Either /=, DIV, or a block comment if (peek() == '*') { shiftChar(); @@ -1716,6 +1713,14 @@ static Token yylex_NORMAL() { } return Token(T_(OP_LOGICNOT)); + case '*': // Either *=, **=, MUL, or EXP + c = peek(); + if (c == '*') { + shiftChar(); + return oneOrTwo('=', T_(POP_EXPEQ), T_(OP_EXP)); + } + return oneOrTwo('=', T_(POP_MULEQ), T_(OP_MUL)); + case '<': // Either <<=, LT, LTE, or left shift if (peek() == '<') { shiftChar(); @@ -1723,13 +1728,6 @@ static Token yylex_NORMAL() { } return oneOrTwo('=', T_(OP_LOGICLE), T_(OP_LOGICLT)); - case '>': // Either >>=, GT, GTE, or either kind of right shift - if (peek() == '>') { - shiftChar(); - return oneOrTwo('=', T_(POP_SHREQ), '>', T_(OP_USHR), T_(OP_SHR)); - } - return oneOrTwo('=', T_(OP_LOGICGE), T_(OP_LOGICGT)); - case ':': // Either :, ::, or an anonymous label ref c = peek(); if (c == '+' || c == '-') { @@ -1737,6 +1735,19 @@ static Token yylex_NORMAL() { } return oneOrTwo(':', T_(DOUBLE_COLON), T_(COLON)); + // Handle ambiguous 1-, 2-, 3-, or 4-char tokens + + case '>': // Either >>=, >>>=, GT, GTE, or either kind of right shift + if (peek() == '>') { + shiftChar(); + if (peek() == '>') { + shiftChar(); + return oneOrTwo('=', T_(POP_USHREQ), T_(OP_USHR)); + } + return oneOrTwo('=', T_(POP_SHREQ), T_(OP_SHR)); + } + return oneOrTwo('=', T_(OP_LOGICGE), T_(OP_LOGICGT)); + // Handle numbers case '0': // Decimal, fixed-point, or base-prefix number diff --git a/src/asm/parser.y b/src/asm/parser.y index 27613a86..44a55d80 100644 --- a/src/asm/parser.y +++ b/src/asm/parser.y @@ -143,8 +143,9 @@ %token POP_EQUAL "=" %token POP_ADDEQ "+=" POP_SUBEQ "-=" %token POP_MULEQ "*=" POP_DIVEQ "/=" POP_MODEQ "%=" +%token POP_EXPEQ "**=" %token POP_ANDEQ "&=" POP_OREQ "|=" POP_XOREQ "^=" -%token POP_SHLEQ "<<=" POP_SHREQ ">>=" +%token POP_SHLEQ "<<=" POP_SHREQ ">>=" POP_USHREQ ">>>=" // SM83 registers %token TOKEN_A "a" @@ -640,6 +641,9 @@ compound_eq: | POP_MODEQ { $$ = RPN_MOD; } + | POP_EXPEQ { + $$ = RPN_EXP; + } | POP_XOREQ { $$ = RPN_XOR; } @@ -655,6 +659,9 @@ compound_eq: | POP_SHREQ { $$ = RPN_SHR; } + | POP_USHREQ { + $$ = RPN_USHR; + } ; align: diff --git a/test/asm/compound-assignment.asm b/test/asm/compound-assignment.asm index 5255ef55..03ac5d6a 100644 --- a/test/asm/compound-assignment.asm +++ b/test/asm/compound-assignment.asm @@ -11,8 +11,10 @@ println \2 ; 14 println \2 ; 28 {prefix}\2 /= 4 println \2 ; 7 -{prefix}\2 %= 3 -println \2 ; 1 +{prefix}\2 %= 4 +println \2 ; 3 +{prefix}\2 **= 2 +println \2 ; 9 {prefix}\2 |= 11 println \2 ; 11 {prefix}\2 ^= 12 @@ -23,6 +25,8 @@ println \2 ; 5 println \2 ; 20 {prefix}\2 >>= 1 println \2 ; 10 +{prefix}\2 >>>= 1 +println \2 ; 5 purge prefix endm diff --git a/test/asm/compound-assignment.err b/test/asm/compound-assignment.err index 19dfb866..f817228b 100644 --- a/test/asm/compound-assignment.err +++ b/test/asm/compound-assignment.err @@ -1,3 +1,3 @@ error: Expected constant expression: undefined symbol `UnDeFiNeD` - at compound-assignment.asm(35) + at compound-assignment.asm(39) Assembly aborted with 1 error diff --git a/test/asm/compound-assignment.out b/test/asm/compound-assignment.out index c9d3f97c..6cc5cff8 100644 --- a/test/asm/compound-assignment.out +++ b/test/asm/compound-assignment.out @@ -4,23 +4,27 @@ $F $E $1C $7 -$1 +$3 +$9 $B $7 $5 $14 $A +$5 redef r: $A $F $E $1C $7 -$1 +$3 +$9 $B $7 $5 $14 $A +$5 $64 $0