Conditionals and Loops

Conditional compilation allows you to only compile specific sections of code when certain conditions are met. This can be used in a number of ways, but is most commonly used in conjunction with defines to make code easily customizable and/or provide some simple configuration options to end users.

if / elseif / else / endif

The most basic form of conditionals are if conditionals. They are given a math statement and only compile their enclosed code if that statement evaluates to a value greater than 0.

if {condition}
    {codeblock}
endif

The conditions can be any valid math expression. If the expression evaluates to zero, the condition is considered false, any other number is true (additionally, an empty string is false and any other string is true). The comparison operators and logical operators are especially useful in conditions.

Optionally, if conditionals can contain an arbitrary number of elseif branches as well as a single else branch. The assembler checks the if and all elseif branches in succession until a single condition evaluates to a truthy value - if none does, the code inside the else branch is compiled.

!mode = 0       ; Supported modes: 0, 1, 2, 3
!verbose = 0    ; Set to 1 to enable verbose mode

if !mode == 0
    ; ...
elseif !mode == 1
    ; ...
elseif !mode == 2
    ; ...
elseif !mode == 3
    if !verbose != 0
        print "Oh boy, so you're going with mode 3 today!"
    endif
    ; ...
else
    error "Unsupported mode! Please choose 0, 1, 2 or 3!"
endif

Alternatively, if statements can also be constructed on a single line via the following syntax:

if {condition} : {codeblock}[ : codeblock...] : endif
PressedY:
    if !fireballs_enabled : %PlaySoundEffect(!fireball_sfx) : jsr ShootFireball : endif
    rtl

If you plan to use labels in if conditions, note that there's certain restrictions that apply. More specifically, only static labels can be used. That is, only labels whose address can't change between Asar's passes, as demonstrated by the following example:

FirstLabel = $018000
        
freecode
    lda SecondLabel,x
    
SecondLabel:
    db $00,$01,$02,$03
    
; All good. FirstLabel was statically defined.
if FirstLabel == 0
endif

; Error Elabel_in_conditional. The label could move between passes.
if SecondLabel == 0
endif

while

while {condition}
    {code}
endwhile

A special variation of if conditionals are while loops. Instead of compiling their enclosed code only once, they compile it repeatedly until their condition evaluates to false. Typically, this would be used with a define that is modified inside the loop. This can be useful for generating data tables.

!counter = 0
        
while !counter < $10
    db (!counter<<8)|$00,(!counter<<8)|$01,(!counter<<8)|$02,(!counter<<8)|$03
    db (!counter<<8)|$04,(!counter<<8)|$05,(!counter<<8)|$06,(!counter<<8)|$07
    db (!counter<<8)|$08,(!counter<<8)|$09,(!counter<<8)|$0A,(!counter<<8)|$0B
    db (!counter<<8)|$0C,(!counter<<8)|$0D,(!counter<<8)|$0E,(!counter<<8)|$0F
            
    !counter #= !counter+1
endwhile

Be warned as improper use of while loops can lead to infinite loops and thus a dead-lock of the assembler, as Asar won't attempt to detect those.

for

for {variable} = {start}..{end}
    {code}
endfor

For loops repeat the contents a specified number of times. In the for loop body, you have access to a loop counter as a define. The range is specified as start-inclusive and end-exclusive. For example:

for i = 1..5
    db !i
    db 2*!i
endfor

This will write the bytes 01 02 02 04 03 06 04 08.

You can also put for loops on a single line, however in this case due to the order in which Asar parses defines, you will not be able to use the loop counter. For example:

for i = 0..10 : nop : endfor
; not allowed due to internal limitations:
for i = 0..10 : db !i : endfor