Code Z80
29 janvier 2024

Des énumérations avec SJASM+

Par Claire CheshireCat

Ceux qui suivent de près le microcosme du CPC savent que Frédéric Mantegazza, l’un des auteurs du jeu Fugitif s’est mis en tête de pimper son code d’origine de manière à publier une version améliorée de son jeu. Ça avance tranquillement et il nous tient régulièrement au courant de ses progrès sur le Discord Z80 Corner. Pour ses développements il a eu besoin de créer des labels dont le numéro s’incrémentait automatiquement. Il partage ici son source.

L’utilisation est très simple : Tout d’abord on définit un namespace avec la commande « M_ENUM_SET_NAMESPACE » (Mettre un simple point comme nom de namespace si vous n’utilisez pas cette fonctionnalité), ensuite on donne la valeur de début du décompte avec « M_ENUM_SET_VALUE », et pour finir « M_ENUM_GEN » suivi d’un nom d’étiquette donnera une valeur incrémentée à chacun des labels que vous lui fournirez.

Par exemple :

ASM
    M_ENUM_SET_NAMESPACE .
    M_ENUM_SET_VALUE #0003
    M_ENUM_GEN CLE
    M_ENUM_GEN PELLE
    M_ENUM_GEN PORTE

Produira :

ASM
CLE   EQU 3
PELLE EQU 4
PORTE EQU 5

Et voilà ! Bien pratique quand on gère des listes d’objets dans un jeu d’aventure.
Le listing complet :

ASM
/*
Les macros ci-dessous permettent de générer des labels avec des valeurs
numériques abritraires, automatiquement incrémentées, comme on le ferait
en C avec des énumérations.

Il est possible de les préfixer avec un namespace, ou non (dans ce cas,
utiliser . comme namespace).

Elles sont écrites pour l'assembleur SJASM+, et utilisent des scripts LUA.
 */

; -----------------------------------------
; Set namespace of the next enumerates
;
; Prepend namespace with module name if needed

    MACRO M_ENUM_SET_NAMESPACE namespace
    LUA ALLPASS
        enumNamespace = sj.get_define("namespace", true)
        enumValue = 0
    ENDLUA
    ENDM
; -----------------------------------------

; -----------------------------------------
; Set value to use for the next enumerate

    MACRO M_ENUM_SET_VALUE value
    LUA ALLPASS
        valueStr = sj.get_define("value", true)
        if string.sub(valueStr, 1, 1) == '#' then
            valueStr = "0x"..string.sub(valueStr, 2, -1)
        end
        if tonumber(valueStr) then
            enumValue = tonumber(valueStr)
        else
            sj.error("Macro M_ENUM_SET_VALUE expects a number (got '"..valueStr.."')")
        end
    ENDLUA
    ENDM
; -----------------------------------------

; -----------------------------------------
; Increment value to use for the next enumerate

    MACRO M_ENUM_INC_VALUE
    LUA ALLPASS
        enumValue = enumValue + 1
    ENDLUA
    ENDM
; -----------------------------------------

; -----------------------------------------
; Decrement value to use for the next enumerate

    MACRO M_ENUM_DEC_VALUE
    LUA ALLPASS
        enumValue = enumValue - 1
    ENDLUA
    ENDM
; -----------------------------------------

; -----------------------------------------
; Generate enumerate, and increment value to use for the next enumerate

    MACRO M_ENUM_GEN label
    LUA ALLPASS
        labelStr = sj.get_define("label", true)
        if enumNamespace == "." then
            sj.insert_label(labelStr, enumValue)
        else
            sj.insert_label(enumNamespace.."."..labelStr, enumValue)
        end
        enumValue = enumValue + 1
    ENDLUA
    ENDM
; -----------------------------------------


; -----------------------------------------
; Test

        M_ENUM_SET_NAMESPACE ns
        M_ENUM_GEN ENTRY0
        M_ENUM_DEC_VALUE            ; revert next value to 0
        M_ENUM_GEN ENTRY00
        M_ENUM_GEN ENTRY1
        M_ENUM_GEN ENTRY2

        M_ENUM_SET_NAMESPACE .      ; do not use namespace for the next enumerates
        M_ENUM_SET_VALUE #0003      ; SJASM+ hex values allowed
        M_ENUM_GEN ENTRY3
        M_ENUM_GEN ENTRY4
        M_ENUM_GEN ENTRY5

; The above code is equivalent to:
;
; ns.ENTRY0   EQU 0
; ns.ENTRY00  EQU 0
; ns.ENTRY1   EQU 1
; ns.ENTRY2   EQU 2
; ENTRY3      EQU 3
; ENTRY4      EQU 4
; ENTRY5      EQU 5

    DISPLAY /D, ns.ENTRY0
    DISPLAY /D, ns.ENTRY00
    DISPLAY /D, ns.ENTRY1
    DISPLAY /D, ns.ENTRY2
    DISPLAY ENTRY3
    DISPLAY ENTRY4
    DISPLAY ENTRY5

; Output:
; > 0
; > 0
; > 1
; > 2
; > #0003
; > #0004
; > #0005