From 7c01c29cec6f5fcc94abcd154c47d2c78f765a78 Mon Sep 17 00:00:00 2001 From: Miquel Sabaté Solà Date: Thu, 23 Apr 2026 22:17:23 +0200 Subject: Ensure expressions in arguments are fully parsed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Imagine the following scenario: lda #.lobyte(@address + 1) Here we have an immediate which comes from the .lobyte call. That being said, since this is using the '#' symbol, we look ahead after noticing it just in case we need to disambiguate some scenarios. When a parenthesis is found, in extract_paren_expression() we temporarily discard the looking ahead status as expressions inside of parenthesis are no longer affected by any hypothetical external ambiguity. This, though, was not being done in parse_arguments(), which is the function that would be called in the above scenario. Hence, ensure that we temporarily decrease the look ahead status for the inner arguments, and then increase it back when we are done. This way, when the parser finds '@address', it will no longer go the "we have found a 'value', refrain from ambiguities and return early" route, and it will check for any binary expression. Note that all this dance actually applied here, as binary operations are a source of ambiguities, and the look ahead mechanism was brought about because of these kinds of expressions. Hence, it's not like the look ahead mechanism is troublesome in on itself, we just missed the special handling on this specific scenario. Signed-off-by: Miquel Sabaté Solà --- lib/xixanta/src/assembler.rs | 13 +++++++++++++ lib/xixanta/src/parser.rs | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+) (limited to 'lib') diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs index 2f0292e..54ba4c3 100644 --- a/lib/xixanta/src/assembler.rs +++ b/lib/xixanta/src/assembler.rs @@ -4629,6 +4629,19 @@ JAL procedure } } + #[test] + fn lobyte_with_arithmetic() { + let res = just_bundles( + r#"lda #.lobyte(@address - 1) +@address: +nop + "#, + ); + + assert_eq!(res[0].bytes[0], 0xA9); + assert_eq!(res[0].bytes[1], 0x01); + } + #[test] fn warnings_on_empty_proc_scope_macro() { let res = just_assemble( diff --git a/lib/xixanta/src/parser.rs b/lib/xixanta/src/parser.rs index 9f8ffc7..10340c4 100644 --- a/lib/xixanta/src/parser.rs +++ b/lib/xixanta/src/parser.rs @@ -1194,6 +1194,12 @@ impl Parser { // Skip any possible whitespace before the optional opening paren. self.skip_whitespace(line); + // If arguments are wrapped in a parenthesis, and the look ahead index + // is larger than zero, then the following code will temporarily + // subtract it. This is in a similar fashion as what we do in + // extract_paren_expression(). + let mut la_subtracted = false; + // Scope the end of the argument list. If the arguments are enclosed on // parenthesis, take that into account, otherwise we will parse until // the end of the cleaned line. @@ -1203,6 +1209,14 @@ impl Parser { self.next(); self.skip_whitespace(line); + // Arguments are in a parenthesis and we were looking + // ahead. Temporarily decrease the index and change 'la_subtracted' + // so we increase it back at the end. + if self.look_ahead_index > 0 { + self.look_ahead_index -= 1; + la_subtracted = true; + } + // If there is a parenthesis it might be either that the command // enclosed its arguments into parenthesis, or that the first // argument is using parenthesis to disambiguate with an @@ -1282,6 +1296,12 @@ impl Parser { } } + // Was the look ahead index subtracted temporarily? If so now it's time + // to increase it again. + if la_subtracted { + self.look_ahead_index += 1; + } + Ok(args) } -- cgit v1.2.3