diff options
| author | Miquel Sabaté Solà <mssola@mssola.com> | 2026-04-23 22:17:23 +0200 |
|---|---|---|
| committer | Miquel Sabaté Solà <mssola@mssola.com> | 2026-04-23 22:17:23 +0200 |
| commit | 7c01c29cec6f5fcc94abcd154c47d2c78f765a78 (patch) | |
| tree | d2ecd86e92047e071cfbbe97845ab3353915ec9f /lib/xixanta/src | |
| parent | b0def33f13f1fc2403b1a0bc6666ec874314d4ad (diff) | |
| download | tools.nes-7c01c29cec6f5fcc94abcd154c47d2c78f765a78.tar.gz tools.nes-7c01c29cec6f5fcc94abcd154c47d2c78f765a78.zip | |
Ensure expressions in arguments are fully parsed
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à <mssola@mssola.com>
Diffstat (limited to 'lib/xixanta/src')
| -rw-r--r-- | lib/xixanta/src/assembler.rs | 13 | ||||
| -rw-r--r-- | lib/xixanta/src/parser.rs | 20 |
2 files changed, 33 insertions, 0 deletions
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 @@ -4630,6 +4630,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( r#".proc Proc 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) } |
