nesdev.com
http://forums.nesdev.com/

ca65 C-style macro problems
http://forums.nesdev.com/viewtopic.php?f=2&t=15766
Page 1 of 1

Author:  nicklausw [ Wed Apr 05, 2017 6:41 pm ]
Post subject:  ca65 C-style macro problems

Code:
.define sprite(sprnum, sprattr) ($700+(sprnum*4)+sprattr)

The above does its job, but it seems ca65 doesn't expect it to be a function when used like this:
Code:
sta sprite(0, tile)

(tile is defined as 1). Unexpected trailing garbage characters.

The best workaround I've found is to add a "0+", as such.
Code:
sta 0+sprite(0, tile)

This isn't preferable, since it's kinda ugly. Are there any better ways around this?

Author:  tepples [ Wed Apr 05, 2017 6:44 pm ]
Post subject:  Re: ca65 C-style macro problems

The macro appears to expand as follows:
Code:
sta ($700+(0*4)+tile)

But because the parentheses are outermost, ca65 thinks it's indirect addressing mode, which sta doesn't have.

Author:  rainwarrior [ Wed Apr 05, 2017 6:50 pm ]
Post subject:  Re: ca65 C-style macro problems

In my version of ca65 this gives "illegal addressing mode" which suggests to me that the problem is the parentheses () which suggest "STA (indirect)" which is an illegal addressing mode. Try your .define without the enclosing parentheses?

Edit: Hmm, didn't even get a ninja notification from tepples' post. ;)

Author:  rainwarrior [ Wed Apr 05, 2017 7:08 pm ]
Post subject:  Re: ca65 C-style macro problems

It's normal C macro practice to use the prophylactic () around your macro results, but it has this particular consequence in 6502 assembly where the meaning of () has this one contextual overload.

I've hit this particular problem myself a few times when using ca65 defines, making me wish there was some sort of "safe" expression enclosing operator that could wrap them up, like .expr() or something. Though, your 0+ solution is interesting; what if you put that directly in the .define instead of everywhere it's used?
Code:
.define sprite(sprnum, sprattr) 0+($700+(sprnum*4)+sprattr)


My actual practice is just to be very sparing with my use of .define in ca65, I think, preferring .macro in most cases (which has slightly fewer caveats). I find there's a lot of counter-intuitive things about its macro system if you're already used to C style macros, because it's not really a text substitution at all, but more like substituting a symbolic tokenized version.

Also, the command line -D define behaves differently from the .define control command, which is another thing to watch out for. (I forget exactly how at the moment. :S)

Author:  RT-55J [ Wed Apr 05, 2017 9:37 pm ]
Post subject:  Re: ca65 C-style macro problems

I know DASM allows you to use square brackets as an equivalent to parentheses (e.g. [[blah+blah]*blah] ). Perhaps ca65 is similarly permissive.

Author:  tepples [ Thu Apr 06, 2017 7:57 am ]
Post subject:  Re: ca65 C-style macro problems

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)

Author:  nicklausw [ Thu Apr 06, 2017 8:27 am ]
Post subject:  Re: ca65 C-style macro problems

Removing the parentheses fixed the problem, but I will consider ~~(using this) for other macros that may be mixed into formulas themselves.

Thanks all!

Author:  thefox [ Thu Apr 06, 2017 8:29 am ]
Post subject:  Re: ca65 C-style macro problems

As tepples suggested, I have been using ~~ to disambiguate these cases, although it's unfortunate that it's needed.

Author:  tepples [ Thu Apr 06, 2017 9:04 am ]
Post subject:  Re: ca65 C-style macro problems

Unfortunate but understandable. I guess MOS didn't anticipate that the equivalent of the C preprocessor would eventually be used on assembly language source code for its CPU. The first edition of The C Programming Language by K&R wouldn't even come out until 1978, three years after the 1975 introduction of the 6501 and 6502.

Author:  rainwarrior [ Thu Apr 06, 2017 5:55 pm ]
Post subject:  Re: ca65 C-style macro problems

Apparently there is a .feature extension that selects [] for indirection instead of (). Maybe not useful on an existing project, but if you're starting from scratch (or perhaps switching from NESASM) you could just use square brackets for indirection instead and not have the conflict.
Code:
.feature bracket_as_indirect
jmp [$FFFC]

Page 1 of 1 All times are UTC - 7 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/