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.

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.