In ca65, square brackets mean indirect long, a 65816-exclusive addressing mode.
Putting the
0+ workaround in the macro could mess up operator precedence, as addition is fairly low in
ca65's precedence chart.
Code:
; With a macro like this
.define sprite(sprnum, sprattr) 0+($700+(sprnum*4)+sprattr)
; Something like this
.word 0x8000 | sprite(0, tile)
; would expand to this
.word 0x8000 | 0+($700+(0*4)+tile)
; But because bitwise OR operator | binds more tightly than the
; addition operator +, it automatically parenthesizes thus
.word (0x8000 | 0)+($700+(0*4)+tile)
Instead, you can wrap with a unary prefix operator, as these tend to have the tightest precedence. One might try using
+, the unary numeric no-op, but because
+ is also the numeric addition operator, it can hide syntax errors.
Code:
; With a macro like this
.define sprite(sprnum, sprattr) +($700+(sprnum*4)+sprattr)
; Something like this will unexpectedly assemble correctly
.word 0x8000 sprite(0, tile)
; because it expands to this
.word 0x8000 +($700+(0*4)+tile)
An invertible unary prefix operator that doesn't do double duty as an infix operator is
~, the ones' complement operator. Doubling it on an integer is a no-op unless there's something broken that I hadn't considered. So try this:
Code:
; With a macro like this
.define sprite(sprnum, sprattr) ~~($700+(sprnum*4)+sprattr)
; Your instruction
sta sprite(0, tile)
; expands to this
sta ~~($700+(0*4)+tile)