Des énumérations avec SJASM+
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 :
M_ENUM_SET_NAMESPACE .
M_ENUM_SET_VALUE #0003
M_ENUM_GEN CLE
M_ENUM_GEN PELLE
M_ENUM_GEN PORTE
Produira :
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 :
/*
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