Introduction

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

Dans ce didacticiel, vous allez écrire les principales structures de contrôle dans le langage de la machine virtuelle.

Le temps de lecture de ce didacticiel est estimé à 15 minutes si les adresses mémoire, les pointeurs et les tableaux ont déjà été abordés.

Mise en place

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

#!/usr/bin/env svm
DESCRIPTION
Flow control example
END
LOG
DEBUG "Control" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmint.so"
PLUGIN "svmstr.so"
OPTION -t FLAG test
OPTION -s INT size
PROCESS "application"
	CODE "main" INLINE
	END
	MEMORY test size
END

Qu'est-ce-qu'une structure de contrôle ?

Une structure de contrôle est un ensemble d'instructions travaillant en collaboration pour orchestrer l'exécution d'autres instructions.

Il existe quelques schémas de structures de contrôle très classiques, et nous allons les présenter ici.

Alternatives

Les alternatives sont des structures de contrôle sans répétition de code, qui permettent d'apporter un traitement différent aux valeurs de l'application en fonction d'une ou plusieurs conditions.

Alternatives simples

Modifiez le code, pour ajouter :

#!/usr/bin/env svm
DESCRIPTION
Flow control example
END
LOG
DEBUG "Control" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmint.so"
PLUGIN "svmstr.so"
OPTION -t FLAG test
OPTION -s INT size
PROCESS "application"
	CODE "main" INLINE
		:com.message 1
		:goto end_of_alternative :unless @&test TRUE
		:com.message 2
	:label end_of_alternative
		:com.message 3
	END
	MEMORY test size
END

Maintenant, exécutez l'application sans option :

./controle.svm 
1
3

Puis avec l'option -t :

./controle.svm -t
1
2
3

L'instruction qui affiche 2 dans le terminal n'est exécutée que lorsque l'option -t est précisée sur la ligne de commande : elle fait partie d'une alternative simple.

Une alternative simple s'écrit :

	:goto etiquette_de_fin :unless condition
	instructions de l'alternative simple,
	exécutées que si la condition est vraie
:label etiquette_de_fin

Ce canevas peut être adapté à des besoins plus spécifiques si cela est nécessaire.

Alternatives doubles

Parfois, il est utile d'exécuter aussi une suite d'instructions uniquement dans le cas où la condition est fausse.

Transformez le code pour obtenir :

#!/usr/bin/env svm
DESCRIPTION
Flow control example
END
LOG
DEBUG "Control" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmint.so"
PLUGIN "svmstr.so"
OPTION -t FLAG test
OPTION -s INT size
PROCESS "application"
	CODE "main" INLINE
		:com.message 1
		:goto false_part_of_alternative :unless @&test TRUE
		:com.message 2
		:goto end_of_alternative
	:label false_part_of_alternative
		:com.message 3
	:label end_of_alternative
		:com.message 4
	END
	MEMORY test size
END

Cette fois encore, exécutez l'application sans option :

./controle.svm 
1
3
4

Puis avec l'option -t :

./controle.svm -t
1
2
4

On a bien les instructions qui affichent 2 et 3 jouées alternativement, en fonction de la présence de l'option -t.

Une alternative double s'écrit :

	:goto etiquette_de_condition_fausse :unless condition
	instructions de l'alternative simple,
	exécutées que si la condition est vraie
	:goto etiquette_de_fin
:label etiquette_de_condition_fausse
	instructions de l'alternative simple,
	exécutées que si la condition est fausse
:label etiquette_de_fin

Ce canevas peut être adapté à des besoins plus spécifiques si cela est nécessaire.

Alternatives multiples

Le procédé employé pour l'alternative double peut être aisément étendu pour un plus grand nombre d'alternatives : toutes les alternatives sauf la dernière devront comporter une instruction de saut avec une condition différente, et comporter un saut vers la fin de la structure de contrôle après les instructions de l'alternative.

Boucles

Les boucles sont des structures de contrôle avec répétition, qui permettent d'exécuter un certain nombre de fois des instructions du code.

Boucles à sortie terminale

Supprimez du code toutes les instructions précédentes, puis ajoutez ces instructions :

#!/usr/bin/env svm
DESCRIPTION
Flow control example
END
LOG
DEBUG "Control" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmint.so"
PLUGIN "svmstr.so"
OPTION -t FLAG test
OPTION -s INT size
PROCESS "application"
	CODE "main" INLINE
		:com.message "Start"
		:memory INT/index
		0 -> &index
	:label loop
		:com.message @&index
		:shift &index
		:goto loop :when @&index IN &0*@&size
		:com.message "End"
	END
	MEMORY test size
END

Lancez cette fois l'application avec l'option -s :

./controle.svm -s 5
Start
0
1
2
3
4
End

Entre les deux mots produits par l'application, on trouve bien 5 nombres entiers (de 0 à 4) : ce sont les valeurs que prend l'indice à chaque itération de la boucle.

Une boucle à sortie terminale s'écrit :

	0 -> adresse_indice
:label etiquette_de_boucle
	instructions de la boucle
	:shift valeur_increment adresse_indice
	:goto etiquette_de_boucle :when @adresse_indice IN &0*valeur_de_fin

Ce canevas peut être adapté à des besoins plus spécifiques si cela est nécessaire.

En particulier, si la valeur de départ n'est pas 0, il faut adapter la condition qui devient (&0+@adresse_indice) IN (&0+valeur_de_depart)*difference_entre_valeur_de_fin_et_valeur_de_depart

Avant de continuer, il nous semble important d'attirer votre attention sur un point important ici : la condition employée ici est celle qui sert à déterminer si un indice est valide pour un pointeur, alors qu'aucune zone mémoire n'est parcourue !

En vérité, l'exécution de la condition ne nécessite pas d'avoir la mémoire associée au pointeur définie. On peut donc construire de toutes pièces un pointeur, et vérifier si un nombre se trouve entre zéro et sa taille moins un, ce qui est souvent utile dans les boucles.

Boucles à sortie prématurée

Maintenant, tentez de lancer l'application avec la valeur 0 : la boucle est quand même exécutée une fois, ce qui n'est pas toujours souhaitable car cela peut générer des erreurs dans certains cas :

./controle.svm -s 0
Start
0
End

Modifiez le code :

#!/usr/bin/env svm
DESCRIPTION
Flow control example
END
LOG
DEBUG "Control" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmint.so"
PLUGIN "svmstr.so"
OPTION -t FLAG test
OPTION -s INT size
PROCESS "application"
	CODE "main" INLINE
		:com.message "Start"
		:memory INT/index
		0 -> &index
	:label loop
		:goto loop_end :unless @&index IN &0*@&size
		:com.message @&index
		:shift &index
		:goto loop
	:label loop_end
		:com.message "End"
	END
	MEMORY test size
END

Et maintenant, tentez de lancer l'application avec plusieurs valeurs, dont 0 :

./controle.svm -s 0
Start
End

Maintenant, la boucle n'est même plus exécutée si la condition est fausse dès la première tentative d'exécution.

Une boucle à sortie prématurée s'écrit :

	0 -> adresse_indice
:label etiquette_de_boucle
	:goto etiquette_de_fin_de_boucle :unless @adresse_indice IN &0*valeur_de_fin
	instructions de la boucle
	:shift valeur_increment adresse_indice
	:goto etiquette_de_boucle
:label etiquette_de_fin_de_boucle

Ce canevas peut être adapté à des besoins plus spécifiques si cela est nécessaire, de la même manière que pour la boucle terminale.

Conclusion

Vous venez de voir comment écrire les structures de contrôle simples pour commencer à faire de l'algorithmie.

Même si vous ne pouvez toujours pas écrire d'applications en totale autonomie, vous venez de franchir un pas important dans l'apprentissage du langage de la machine virtuelle. En effet, pour la première fois se dessinent des patrons de code génériques et réutilisables. Cela vous sera d'un précieux secours plus tard, lorsque vous commencerez à écrire vos propres applications.