# Introduction

Ce didacticiel est destiné aux nouveaux utilisateurs de la Simple Virtual Machine.

Dans ce didacticiel, vous allez marquer la pile de retour du processeur et agir en conséquence.

Le temps de lecture de ce didacticiel est estimé à 15 minutes si les fonctions ont été abordées.

# Mise en place

Pour commencer, créez le canevas de l'application dans le fichier exécutable drapeaux.svm en utilisant ce code :

    #!/usr/bin/env svm
    DESCRIPTION
    Flags example
    END
    LOG
    DEBUG "Flags" STYLE "default"
    PLUGIN "svmcom.so"
    PLUGIN "svmint.so"
    OPTION -i INT nb
    PROCESS "application"
    	CODE "main" INLINE
    		:interruption CASCADE NUMERIC recover
    		:memory (PTR, INT)/parameters
    		@&nb -> (parameters/1)
    		:call compute parameters
    		:com.message @&nb ": " @(parameters/1)
    		:shutdown
    	# function compute PTR (internal), INT (input/output) nb
    	:label compute
    		:memory BLN -> &P
    		:int.div 1000 @(P/1) -> (P/1)
    		:int.cmp @(P/1) < 100 -> &@&P
    		:call sub_compute P :when @&@&P TRUE
    		:return
    	:label sub_compute
    		:int.div 100 @(P/1) -> (P/1)
    		:return
    	:label recover
    		1 -> (P/1)
    		:return
    	END
    	MEMORY nb
    END

# Lever un drapeau

## Drapeau simple

Commencez par jouer avec l'application en l'exécutant avec diverses valeurs pour l'option -i :

    ./drapeaux.svm -i 0
    0: 100
    ./drapeaux.svm -i 1
    1: 1000
    ./drapeaux.svm -i 2
    2: 500
    ./drapeaux.svm -i 3
    3: 333
    ./drapeaux.svm -i 100
    100: 10
    ./drapeaux.svm -i 500
    500: 50
    ./drapeaux.svm -i 1000
    1000: 100
    ./drapeaux.svm -i 10000
    10000: 1

Ajoutez un point d'arrêt dans le gestionnaire d'interruption :

    #!/usr/bin/env svm
    DESCRIPTION
    Flags example
    END
    LOG
    DEBUG "Flags" STYLE "default"
    PLUGIN "svmcom.so"
    PLUGIN "svmint.so"
    OPTION -i INT nb
    PROCESS "application"
    	CODE "main" INLINE
    		:interruption CASCADE NUMERIC recover
    		:memory (PTR, INT)/parameters
    		@&nb -> (parameters/1)
    		:call compute parameters
    		:com.message @&nb ": " @(parameters/1)
    		:shutdown
    	# function compute PTR (internal), INT (input/output) nb
    	:label compute
    		:memory BLN -> &P
    		:int.div 1000 @(P/1) -> (P/1)
    		:int.cmp @(P/1) < 100 -> &@&P
    		:call sub_compute P :when @&@&P TRUE
    		:return
    	:label sub_compute
    		:int.div 100 @(P/1) -> (P/1)
    		:return
    	:label recover
    		:debug BREAK "recover"
    		1 -> (P/1)
    		:return
    	END
    	MEMORY nb
    END

Puis relancez l'application en mode débugueur avec les mêmes valeurs. L'application atteint le point d'arrêt pour les valeurs 0 depuis la fonction "compute" et 10000 depuis la fonction "sub_compute".

Modifiez le code pour obtenir :

    #!/usr/bin/env svm
    DESCRIPTION
    Flags example
    END
    LOG
    DEBUG "Flags" STYLE "default"
    PLUGIN "svmcom.so"
    PLUGIN "svmint.so"
    OPTION -i INT nb
    PROCESS "application"
    	CODE "main" INLINE
    		:interruption CASCADE NUMERIC recover
    		:memory (PTR, INT)/parameters
    		@&nb -> (parameters/1)
    		:call compute parameters
    		:com.message @&nb ": " @(parameters/1)
    		:shutdown
    	# function compute PTR (internal), INT (input/output) nb
    	:label compute
    		:flag "compute"
    		:memory BLN -> &P
    		:int.div 1000 @(P/1) -> (P/1)
    		:int.cmp @(P/1) < 100 -> &@&P
    		:call sub_compute P :when @&@&P TRUE
    		:return
    	:label sub_compute
    		:int.div 100 @(P/1) -> (P/1)
    		:return
    	:label recover
    		:debug BREAK "recover"
    		1 -> (P/1)
    		:return
    	END
    	MEMORY nb
    END

Puis relancez en mode débugueur avec la valeur 0. Lorsque le point d'arrêt est atteint, la fenêtre du processeur doit ressembler à :

Flags
Processor - K main - P application
State:
Next instruction: <main:1/15>
Current instruction: <main:1/14>
Code
Current memory: &1*2
Allocated memory:
Defined aliases:
Local interruptions:
Cascaded local interruptions: NUMERIC => <main:1/14>
Code
Flags:
Cascaded flags:
Return stack:
State:
Next instruction: <main:1/9>
Current instruction: <main:1/8>
Code
Current memory: &1*2
Allocated memory: &3*1
Defined aliases:
Local interruptions:
Cascaded local interruptions: NUMERIC => <main:1/14>
Code
Flags: compute
Cascaded flags:
State:
Next instruction: <main:1/4>
Current instruction: <main:1/3>
Code
Current memory: &0*0
Allocated memory: &1*2
Defined aliases: parameters
Local interruptions:
Cascaded local interruptions: NUMERIC => <main:1/14>
Code
Flags:
Cascaded flags:
Global interruptions:
Waiting interruptions:

Dans la pile de retour, le premier niveau de retour contient bien le drapeau "compute".

## Drapeau cascadé

Modifiez maintenant le code :

    #!/usr/bin/env svm
    DESCRIPTION
    Flags example
    END
    LOG
    DEBUG "Flags" STYLE "default"
    PLUGIN "svmcom.so"
    PLUGIN "svmint.so"
    OPTION -i INT nb
    PROCESS "application"
    	CODE "main" INLINE
    		:interruption CASCADE NUMERIC recover
    		:memory (PTR, INT)/parameters
    		@&nb -> (parameters/1)
    		:call compute parameters
    		:com.message @&nb ": " @(parameters/1)
    		:shutdown
    	# function compute PTR (internal), INT (input/output) nb
    	:label compute
    		:flag CASCADE "compute"
    		:memory BLN -> &P
    		:int.div 1000 @(P/1) -> (P/1)
    		:int.cmp @(P/1) < 100 -> &@&P
    		:call sub_compute P :when @&@&P TRUE
    		:return
    	:label sub_compute
    		:int.div 100 @(P/1) -> (P/1)
    		:return
    	:label recover
    		:debug BREAK "recover"
    		1 -> (P/1)
    		:return
    	END
    	MEMORY nb
    END

Relancez une nouvelle fois en mode débugueur avec la valeur 0. Lorsque le point d'arrêt est atteint, la fenêtre du processeur doit ressembler à :

Flags
Processor - K main - P application
State:
Next instruction: <main:1/15>
Current instruction: <main:1/14>
Code
Current memory: &1*2
Allocated memory:
Defined aliases:
Local interruptions:
Cascaded local interruptions: NUMERIC => <main:1/14>
Code
Flags:
Cascaded flags: compute
Return stack:
State:
Next instruction: <main:1/9>
Current instruction: <main:1/8>
Code
Current memory: &1*2
Allocated memory: &3*1
Defined aliases:
Local interruptions:
Cascaded local interruptions: NUMERIC => <main:1/14>
Code
Flags:
Cascaded flags: compute
State:
Next instruction: <main:1/4>
Current instruction: <main:1/3>
Code
Current memory: &0*0
Allocated memory: &1*2
Defined aliases: parameters
Local interruptions:
Cascaded local interruptions: NUMERIC => <main:1/14>
Code
Flags:
Cascaded flags:
Global interruptions:
Waiting interruptions:

Cette fois, le drapeau est dans le registre "Cascaded flags", et il est présent également dans la fonction gestionnaire d'interruption.

Tout comme les gestionnaires d'interruption, lorsqu'un drapeau est cascadé, il est propagé à tous les appels de fonctions faits depuis la fonction où est levé le drapeau.

- Un drapeau est une chaine de texte qui peut être attachée à une fonction. Une fonction peut avoir plusieurs drapeaux levés.
- L'instruction `:flag chaine_drapeau` peut être utilisée pour lever un drapeau dans la fonction courante.
- L'instruction `:flag CASCADE chaine_drapeau` peut être utilisée pour lever un drapeau dans la fonction courante et toutes les fonctions appellées depuis la fonction courante.

# Tester un drapeau

Lever un drapeau n'est véritablement utile que si sa présence peut être testée. Modifiez le code :

    #!/usr/bin/env svm
    DESCRIPTION
    Flags example
    END
    LOG
    DEBUG "Flags" STYLE "default"
    PLUGIN "svmcom.so"
    PLUGIN "svmint.so"
    OPTION -i INT nb
    PROCESS "application"
    	CODE "main" INLINE
    		:interruption CASCADE NUMERIC recover
    		:memory (PTR, INT)/parameters
    		@&nb -> (parameters/1)
    		:call compute parameters
    		:com.message @&nb ": " @(parameters/1)
    		:shutdown
    	# function compute PTR (internal), INT (input/output) nb
    	:label compute
    		:flag CASCADE "compute"
    		:memory BLN -> &P
    		:int.div 1000 @(P/1) -> (P/1)
    		:int.cmp @(P/1) < 100 -> &@&P
    		:call sub_compute P :when @&@&P TRUE
    		:return
    	:label sub_compute
    		:flag CASCADE "sub_compute"
    		:int.div 100 @(P/1) -> (P/1)
    		:return
    	:label recover
    		:debug BREAK "recover"
    		:return :when "sub_compute" RAISED
    		1 -> (P/1)
    		:return
    	END
    	MEMORY nb
    END

Lancez l'application en mode débugueur avec les valeurs 0 puis 10000 :

    ./drapeaux.svm -i 0
    0: 100
    ./drapeaux.svm -i 10000
    10000: 0

Dans le cas où l'application lève une exception depuis la fonction "sub_compute", le traitement de l'erreur devient différent grâce au test de présence du drapeau "sub_compute". L'application ne répond plus 1 mais 0 dans ce cas.

La présence d'un drapeau peut être testé avec la condition `chaine_drapeau RAISED`

Les drapeaux peuvent ainsi servir de booléens situés dans le processeur, évitant la peine de les localiser dans la mémoire pour chaque fonction.

# Conclusion

Vous venez de voir comment manipuler les drapeaux du processeur.

Ces drapeaux sont rarement utiles dans le code, mais peuvent être salvateurs dans certaines circonstances précises.

Les extensions qui désirent manipuler la pile de retour du processeur peuvent également faire usage des drapeaux pour leur fonctionnement.