Ce didacticiel est destiné aux utilisateurs maîtrisant la programmation en C ou C++, ainsi que l'architecture de la Simple Virtual Machine.
Dans ce didacticiel, vous allez commencer à écrire une extension de la machine virtuelle.
Le temps de lecture de ce didacticiel est estimé à 20 minutes.
Pour commencer, créez le canevas de l'extension dans le fichier ecriture.svm_plugin en utilisant ce code :
PLUGIN ecriture
DEFINE
INSTRUCTION ecriture.test
%{
%}
Le canevas de fichier d'extension présente une syntaxe particulière. Nous allons ici survoler cette syntaxe.
Le fichier est organisé en trois sections.
Cette première section définit en premier lieu le nom de l'extension, directement placé après le mot-clef PLUGIN
.
Ensuite, des directives peuvent être ajoutées pour décrire l'extension dans sa globalité.
Cette section contient des objets de la machine virtuelle utilisés comme dépendances. Cela signifie que le démarrage de la machine échouera si au moins un des objets de cette section n'est pas présent dans l'instance de la machine (en particulier, s'il manque une autre extension dans le fichier d'application).
Il est recommandé d'indiquer comme dépendances des objets tels qu'ils sont utilisés ou attendus par l'extension.
Modifiez le fichier pour ajouter deux dépendances :
PLUGIN ecriture
USE
TYPE com.device
WAITING INSTRUCTION com.write com.device INT INT
DEFINE
INSTRUCTION ecriture.test
%{
%}
Cela indique que lorsque cette extension est incluse, il faut également inclure une extension nommée com fournissant un type com.device et une instruction com.write qui accepte au minimum un com.device et deux entiers.
Cette dernière section contient les objets fournis par l'extension. La description de ces objets sera faite en détail dans des didacticiels ultérieurs.
Une directive est un des éléments de base de la syntaxe du fichier.
Une directive commence toujours par un prologue formé d'un identifiant indiquant quelle directive commence, d'une ou plusieurs options également représentées sous forme d'identifiants et se termine par un caractère deux-points (:).
Après le prologue, les directives peuvent demander des valeurs.
Certaines valeurs doivent être spécifiées par une chaine de caractères, commançant et terminant par une double-quote (") et sans retour à la ligne.
D'autres valeurs doivent être spécifiées par un bloc de texte :
%{}
,%{
en fin de ligne, puis en écrivant le texte du bloc, puis le marqueur de fin %}
en début de ligne,${
et $}
, ou par :{
et :}
si cela s'avère nécessaire.PLUGIN
, USE
et DEFINE
.Avant de pouvoir définir les premiers objets de l'extension, quelques directives présentes dans la section PLUGIN
peuvent être utiles.
Modifiez le fichier pour ajouter le langage utilisé par l'extension :
PLUGIN ecriture
lang: "C++"
USE
TYPE com.device
WAITING INSTRUCTION com.write com.device INT INT
DEFINE
INSTRUCTION ecriture.test
%{
%}
Cette directive s'appelle lang
, n'a pas d'option et accepte une valeur chaine qui précise :
Le code de l'extension peut nécessiter l'inclusion de fichiers d'en-tête C ou C++.
Modifiez le fichier pour ajouter des en-têtes :
PLUGIN ecriture
lang: "C++"
includes:
%{
#include <iostream>
#include <map>
%}
USE
TYPE com.device
WAITING INSTRUCTION com.write com.device INT INT
DEFINE
INSTRUCTION ecriture.test
%{
%}
Cette directive s'appelle includes
et accepte uniquement un bloc contenant le code en C/C++ d'inclusion des en-têtes.
Lorsque l'extension a besoin de définir des structures ou des fonctions en C/C++ qui pourront être utilisés dans le code des objets de la machine virtuelle.
Modifiez le code pour ajouter la définition d'une structure en C++ :
PLUGIN ecriture
lang: "C++"
includes:
%{
#include <iostream>
#include <map>
%}
code:
%{
struct O
{
O()
:_i(0) {}
long int _i;
};
static O _o;
%}
USE
TYPE com.device
WAITING INSTRUCTION com.write com.device INT INT
DEFINE
INSTRUCTION ecriture.test
%{
%}
Cette directive s'appelle code
et accepte également uniquement un bloc de texte. Le code en C++ présent dans le bloc peut contenir des structures, des classes, des fonctions et des définitions template.
Modifiez le code de l'extension :
PLUGIN ecriture
lang: "C++"
compile: "-g -O3"
link: "-lm"
includes:
%{
#include <iostream>
#include <map>
%}
code:
%{
struct O
{
O()
:_i(0) {}
long int _i;
};
static O _o;
%}
USE
TYPE com.device
WAITING INSTRUCTION com.write com.device INT INT
DEFINE
INSTRUCTION ecriture.test
%{
%}
La directive compile
permet d'ajouter des options sur la ligne du compilateur C/C++. Ces options sont également placées sur la ligne d'appel au lieur C/C++.
La directive link
ajoute en plus des options uniquement sur la ligne du lieur C/C++.
Une extension peut avoir besoin d'initialiser des valeurs lors du démarrage de la machine, et de les libérer lors de l'arrêt de la machine.
Modifiez le code :
PLUGIN ecriture
lang: "C++"
compile: "-g -O3"
link: "-lm"
includes:
%{
#include <iostream>
#include <map>
%}
code:
%{
struct O
{
O()
:_i(0) {}
long int _i;
};
static O _o;
%}
initialisation:
%{
_o._i = 1;
std::cout << "Start" << std::endl;
%}
finalisation:
%{
_o._i = 0;
std::cout << "End" << std::endl;
%}
USE
TYPE com.device
WAITING INSTRUCTION com.write com.device INT INT
DEFINE
INSTRUCTION ecriture.test
%{
%}
La directive initialisation
permet de préciser quel code appeller lorsque la machine démarre, et la directive finalisation
permet de préciser quel code appeller lorsque la machine s'arrête.
Ici, la valeur statique est modifiée, et un message est émis sur la sortie standard.
Vous pouvez générer l'extension, la compiler, regarder le code C++ généré, et l'utiliser dans une application de test pour vérifier que la machine virtuelle respecte bien les différentes directives de l'extension.
Il existe une autre fonction d'extension pouvant parfois être très pratique : startup
. Cette directive permet de préciser quel code sera joué entre le démarrage des ordonnanceurs et celui des processus de l'application. En particulier, il est possible dans cette fonction de créer des processus (de préférence en terminaison automatique) et de les attacher à un ordonnanceur directement depuis le code d'une extension.
Sa déclaration et son utilisation étant assez proche de la directive initialisation
, l'ajout d'une directive de démarrage est laissée en exercice au lecteur.
lang
permet de spécifier le langage de génération de l'extension.includes
permet d'inclure des en-têtes C ou C++ dans le fichier généré.code
permet d'ajouter des définitions en C ou C++ dans le fichier généré. Notez qu'il est également possible d'insérer une directive de code entre des définitions d'objets dans la section DEFINE
de l'extension.compile
permet d'ajouter des options de compilation et liage C/C++.link
permet d'ajouter des options de liage C/C++.initialisation
permet de lancer du code lorsque la machine démarre.startup
permet de lancer du code juste avant le démarrage de l'application.finalisation
permet de lancer du code lorsque la machine s'arrête.Vous venez de voir comment débuter l'écriture d'une extension pour la machine virtuelle.
La syntaxe du fichier a été conçue pour être très simple et répétitive pour une prise en main rapide de l'écriture des extensions.
Même si pour le moment il n'a pas été expliqué comment définir des objets pour la machine virtuelle, les directives présentées dans ce didacticiel seront parfois indispensables pour pouvoir définir correctement l'extension et les objets qui la composent.