"Incomplete expression." in ASM6 macro

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

tepples
Posts: 21971
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

"Incomplete expression." in ASM6 macro

Post by tepples » Sat Mar 30, 2019 6:35 pm

I'm building an audio driver in ASM6, and I'm up to where I build a table of sound effect addresses and lengths. But when I try to express lookup tables using macros, I get "Incomplete expression" errors.

When I assemble this source file and provide -L to expand macros in the listing file:

Code: Select all

macro sfxdef name, baseaddr, length, period, channel
name = <((* - sfx_table) / 4)
dw baseaddr
db (channel<<2)|((period - 1)<<4)
db length
endm

base $C000
sfx_table:
sfxdef SFX_foo, foo_data, 1, 1, 0
sfxdef SFX_bar, bar_data, 1, 1, 0

foo_data: db $89,$10
bar_data: db $84,$20
This listing is produced:

Code: Select all

                                macro sfxdef name, baseaddr, length, period, channel
                                name = <((* - sfx_table) / 4)
                                dw baseaddr
                                db (channel<<2)|((period - 1)<<4)
                                db length
                                endm
                                
                                base $C000
0C000                           sfx_table:
0C000                           sfxdef SFX_foo, foo_data, 1, 1, 0
0C000                           SFX_foo = <((* - sfx_table) / 4)
*** Incomplete expression.
0C000 08 C0                     dw foo_data
0C002 00                        db (0<<2)|((1 - 1)<<4)
0C003 01                        db 1
0C004                           sfxdef SFX_bar, bar_data, 1, 1, 0
0C004                           SFX_bar = <((* - sfx_table) / 4)
*** Incomplete expression.
0C004 0A C0                     dw bar_data
0C006 00                        db (0<<2)|((1 - 1)<<4)
0C007 01                        db 1
0C008                           
0C008 89 10                     foo_data: db $89,$10
0C00A 84 20                     bar_data: db $84,$20
What is causing these errors, and what should I understand in order to figure out how to fix them?

User avatar
tokumaru
Posts: 11691
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: "Incomplete expression." in ASM6 macro

Post by tokumaru » Sat Mar 30, 2019 6:42 pm

Isn't this because the * is being interpreted as the multiplication operator, since ASM6 uses $ for the PC?

tepples
Posts: 21971
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: "Incomplete expression." in ASM6 macro

Post by tepples » Sat Mar 30, 2019 6:48 pm

Thanks for help. Now I have to figure out how to programmatically distinguish the two in the ca65 code I'm converting without having to hand-edit both copies every time I change something.

User avatar
tokumaru
Posts: 11691
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: "Incomplete expression." in ASM6 macro

Post by tokumaru » Sat Mar 30, 2019 6:53 pm

Well, you could use ca65's dollar_is_pc feature and start using $ all around...

tepples
Posts: 21971
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: "Incomplete expression." in ASM6 macro

Post by tepples » Sat Mar 30, 2019 7:09 pm

A new question

Translating * to $ at the start or end of an expression or parenthesized subexpression fixes one layer of the above MCVE but changes the error message I get when I assemble the whole project. If I try to translate the ca65 idiom for an include guard to ASM6, it ends up not recognizing the macro at all, instead producing "Illegal instruction" but only for the first use of each such macro.

Source:

Code: Select all

ifndef INCLUDE_GUARD
INCLUDE_GUARD = 1

macro sfxdef name, baseaddr, length, period, channel
name = <(($ - sfx_table) / 4)
dw baseaddr
db (channel<<2)|((period - 1)<<4)
db length
endm

endif

base $C000
sfx_table:
sfxdef SFX_foo, foo_data, 1, 1, 0
sfxdef SFX_bar, bar_data, 1, 1, 0

foo_data: db $89,$10
bar_data: db $84,$20
Listing:

Code: Select all

                                ifndef INCLUDE_GUARD
                                INCLUDE_GUARD = 1
                                macro sfxdef name, baseaddr, length, period, channel
                                name = <(($ - sfx_table) / 4)
                                dw baseaddr
                                db (channel<<2)|((period - 1)<<4)
                                db length
                                endm
                                endif
                                
                                base $C000
0C000                           sfx_table:
0C000                           sfxdef SFX_foo, foo_data, 1, 1, 0
*** Illegal instruction.
0C000                           sfxdef SFX_bar, bar_data, 1, 1, 0
0C000                           SFX_bar = <(($ - sfx_table) / 4)
0C000 0A C0                     dw bar_data
0C002 00                        db (0<<2)|((1 - 1)<<4)
0C003 01                        db 1
0C004                           
0C004 89 10                     foo_data: db $89,$10
0C006 84 20                     bar_data: db $84,$20

tepples
Posts: 21971
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: "Incomplete expression." in ASM6 macro

Post by tepples » Mon Apr 01, 2019 1:50 pm

The macro does different things (both wrong) on different invocations. The first time it says "Illegal instruction" and the second time it generates incorrect code. This makes me think I'm hitting an ASM6 bug. I decided to work around it in the translator by detecting whether a particular .ifndef is an include guard and changing it to a .if 1 if so.

unregistered
Posts: 1071
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: "Incomplete expression." in ASM6 macro

Post by unregistered » Mon Apr 01, 2019 6:04 pm

Maybe that "*** Illegal Instruction" is attempting to say that your dw baseaddr and db length are confusing for asm6 bc you haven't defined the values of baseaddr and length? :)

unregistered
Posts: 1071
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: "Incomplete expression." in ASM6 macro

Post by unregistered » Mon Apr 01, 2019 6:18 pm

unregistered wrote:Maybe that "*** Illegal Instruction" is attempting to say that your dw baseaddr and db length are confusing for asm6 bc you haven't defined the values of baseaddr and length? :)
Sorry tepples, I just noticed that you do define the values in your macro calls... maybe this error is created bc you db length before you call the macro? I think tokumaru taught me that the macro has to be defined before it can be called... maybe the same logic applies to whatever baseaddr and length are. :)

User avatar
tokumaru
Posts: 11691
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: "Incomplete expression." in ASM6 macro

Post by tokumaru » Mon Apr 01, 2019 6:19 pm

Sounds like a bug indeed.

tepples
Posts: 21971
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: "Incomplete expression." in ASM6 macro

Post by tepples » Tue Apr 02, 2019 5:48 am

In any case, I've reduced another test case.

It seems like most actual bugs in ASM6 disappear once a forward reference is made no longer forward.
Attachments
macromystery.asm
(1.79 KiB) Downloaded 212 times

doppelganger
Posts: 184
Joined: Tue Apr 05, 2005 7:30 pm

Re: "Incomplete expression." in ASM6 macro

Post by doppelganger » Tue Apr 09, 2019 11:36 am

Are you trying to use include guards because multiple source files include the same stuff?
Be whatever the situation demands.

tepples
Posts: 21971
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: "Incomplete expression." in ASM6 macro

Post by tepples » Tue Apr 09, 2019 1:16 pm

doppelganger wrote:Are you trying to use include guards because multiple source files include the same stuff?
Yes. Both the driver and the instrument/sequence data include one of the header files, and I can't guarantee which gets included first because ASM6 requires them to be included in output file order.

doppelganger
Posts: 184
Joined: Tue Apr 05, 2005 7:30 pm

Re: "Incomplete expression." in ASM6 macro

Post by doppelganger » Tue Apr 09, 2019 2:37 pm

So both the driver and instrument/sequence data are assembled together in one unit?
Be whatever the situation demands.

tepples
Posts: 21971
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: "Incomplete expression." in ASM6 macro

Post by tepples » Tue Apr 09, 2019 2:42 pm

ASM6 normally assembles everything as one translation unit, so yes, driver and data are assembled together. It's possible though tricky to assemble something as multiple translation units with ASM6. If so, the separately assembled translation unit has to have entry points at fixed addresses, such as $8000, $8003, $8006, $8009, etc.

doppelganger
Posts: 184
Joined: Tue Apr 05, 2005 7:30 pm

Re: "Incomplete expression." in ASM6 macro

Post by doppelganger » Tue Apr 09, 2019 10:33 pm

The problem with the traditional .ifndef type include guard is that ASM6 is a multiple-pass assembler, and anything inside an .ifndef with a following .define inside it will get processed on the first pass, but not on the second. The ASM6 only states that .ifdef and .ifndef operate depending on whether the operand symbol is defined/not defined, without any mention as to whether the definition is supposed to occur prior to the directive or not, so it's implied then that forward references are included as part of .ifdef/.ifndef's operation.

The fallout, of course, is that when ASM6 gets to the second pass, the included file's contents end up not getting output at all.

What you obviously wanted was the first include, and ONLY the first include, to occur. After thinking it over, I may have an ASM6-specific workaround.

Let's say you have your driver in driver.asm and instruments/sequence data in song.asm, and they both include a file called foo.asm for whatever reason. Now, since ASM6 is assembling these as one translation unit, it follows that there must be a top-level source file for the driver and data to go into, assuming one of them isn't the top-level file (I don't know enough about your code to make too many assumptions here).

Now, you obviously don't want foo.asm included twice. My idea is this: define a symbol in the top-level file that precedes the driver and data files that matches whatever symbol you'd have used for foo.asm's include guard:

Code: Select all

FOO_ASM = 1
Then, at the beginning of foo.asm, put this in:

Code: Select all

.if FOO_ASM
FOO_ASM = 0
;insert contents of foo.asm here
.endif
And hopefully that should cause only the very first .include of foo.asm to have any effect on the unit's output, since FOO_ASM will be set to nonzero on the first include, but zero on any subsequent includes, until the next pass.
Be whatever the situation demands.

Post Reply