Labels

Labels are used to represent a position in the ROM and allow you to code without having to constantly update branches and jumps/calls. They can be used with any opcode, but were specifically designed to be used with branches, jumps, calls, pointer tables etc. When used with branches, they're automatically converted to offsets.

Main Labels

[#]{identifier}:

Main labels are the top-most level of labels supported by Asar. They're global and thus can be directly acessed from anywhere. Their identifier can contain any of the following characters: a-z A-Z 0-9 _

org $008000

Main:
    %do_frame()
    jmp Main    ; Equal to jmp $8000

An alternate form of defining main labels is by directly assigning a value to them. A common use-case for this is to make a label point to an existing address inside a ROM. Syntax:

{identifier} = {snes_address}

where snes_address can be a number or any math statement evaluating to an SNES address. Note that defining a main label this way does not start a new sub label group.

Main:
; ...

SomewhereInRom = $04CA40

.Sub:
; ...

Table:
    dl Main_Sub                 ; Okay!
    dl SomewhereInRom_Sub       ; Error, label not found

Prefixing a label definition (except label assignments) with a # will define the label without modifying existing label hierarchies. This can be useful for defining global routines inside call-anywhere macros without having them break existing label hierarchies.

macro my_new_routine()
    jsl MyNewRoutine
            
    !macro_routine_defined ?= 0
    
    if !macro_routine_defined == 0
        pushpc
        
        freecode cleaned
        
        #MyNewRoutine:
            incsrc routines/mynewroutine.asm
        
        pullpc
    
        !macro_routine_defined = 1
    endif
endmacro

Main:
    %my_new_routine()
.Sub

    ; Both of these are found
    dl MyNewRoutine
    dl Main_Sub

Asar includes a label optimizer which attempts to optimize performance by shortening opcodes accessing labels from 24-bit to 16-bit whenever possible. See section Program Counter for details.

Sub Labels

[#].{identifier}[:]

Sub labels are the second-most level of labels supported by Asar. They're local to the last main label declared and their identifiers can contain the same characters as main labels.

Proc1:
    nop
.Sub
    bra .Sub

Proc2:
    nop
.Sub:   ; Note that the colon is optional
    bra .Sub

Sub labels allow you to reuse redundantly named labels such as Loop, End, etc. without causing label redefinition errors. A new sub label group is automatically started after a main label is declared. Internally, sub labels are converted to MainLabel_SubLabel, which can be used to access them from anywhere.

Main1:
    ; ...
.Sub1:
    ; ...
.Sub2:
    ; ...
    
Main2:
    ; ...
.Sub1:
    ; ...
.Sub2:
    ; ...
    
Table:
    dl Main1_Sub1
    dl Main1_Sub2
    dl Main2_Sub1
    dl Main2_Sub2

Sub labels can themselves contain sub labels to an arbitrary depth by prepending additional dots.

Main1:
; ...
.Sub:
; ...
..Deeper:
; ...
...TheEnd:
; ...

Table:
    dl Main1_Sub_Deeper_TheEnd

Prefixing a sub label definition with a # will define the sub label without modifying existing label hierarchies, but there is probably no practical use for this and it's unintuitive, so it should be avoided.

+/- Labels

+[+...][:]

-[-...][:]

+/- labels are a special type of labels that are different from both main labels and sub labels in that they don't refer to a specific location in code, but rather to a location relative from where they are used. When used inside opcodes etc., + always refers to the next + label and - always refers to the previous - label. You can also chain an arbitrary number of + or an arbitrary number of - to create unique +/- labels that don't overwrite labels with a different number of +/-, for example +++ or -----.

    ldx.b #4
        
--              ; A
    lda $10,x
    beq +       ; Branches to "C"
        
    ldy.b #8
    
-               ; B
    %do_something()
    
    dey
    bne -       ; Branches to "B"
    
+:              ; C - note that +/- labels can also include an optional colon in their declaration
    dex
    bpl --      ; Branches to "A"

+/- labels are useful in a number of situations. For example: inside a long routine with multiple short loops, where even a sub label like .Loop would get repetitive. +/- labels aren't bound to any scope, which means they can technically be used across different scopes. Just like sub labels, +/- labels are converted to main labels internally. Unlike sub labels, they can not be referenced from code directly since their names depend on where in the code they're used, making it impractical to directly refer to them. This is by design. They can, however, be accessed via the Asar DLL API, and their full name may appear in error messages printed by Asar. The naming format used for them is :pos_x_y for + labels and :neg_x_y for - labels, where x = number of chained +/- and y = instance of this label within all +/- labels of the same name (starting from 0 for + labels and from 1 for - labels).

lorom
org $008000

---         ; :neg_3_1
-           ; :neg_1_1
    bra -
--          ; :neg_2_1
-           ; :neg_1_2
    bra ---
    bra --
    bra -
    
    bra ++
    bra +
    bra +++
    
++          ; :pos_2_0
+           ; :pos_1_0
    bra ++
++          ; :pos_2_1
+++         ; :pos_3_0

Macro Labels

[#]?{identifier}:

?{identifier} = {snes_address}

[#]?.{identifier}[:]

?+[+...]

?-[-...]

Macro labels are special variations of the labels mentioned in the previous sections. Functionally, they behave the same as the other labels with the exception of being local to the macro they're used in. This means they can't be referenced from outside the respective macro. Macro labels are created by prefixing any of the other label types with a ? .

macro do_something()
    ?MacroMainLabel:
    ?.MacroSubLabel
    ?-
        ; All of these are fine!
        dl ?MacroMainLabel
        dl ?.MacroSubLabel
        dl ?-
        dl ?+
        dl ?MacroMainLabel_MacroSubLabel
    ?+
endmacro

%do_something()

; ERROR! ?MacroMainLabel is undefined, because we're not inside %do_something() anymore.
dl ?MacroMainLabel

Prefixing a macro label definition (except for macro label assignments and macro +/- labels) with a # will define the macro label without modifying existing label hierarchies, but there is probably no practical use for this, so it should be avoided. Like all other labels, macro labels are converted to main labels internally and prefixed with an identifier of :macro_x_ where x = total macro call count. They can't be referenced in code directly, except inside their respective macro and using the respective macro label syntax seen above. They can, however, be accessed via the Asar DLL API, and their full name may appear in error messages printed by Asar.