• Aucun résultat trouvé

— OK dans le cas où l’accès ou la modification ont été acceptés par le facilitateur de l’agent. Il est à noter que le facilitateur peut décider de renvoyer une valeur approximative de la propriété même s’il renvoie OK (Dans le cas d’une coopération truquée par exemple) ;

— NOT_ALLOWED dans le cas où l’accès ou la modification ont été refusés par le facili- tateur de l’agent ;

— NOT_EXIST dans le cas où l’agent ne possède pas la propriété indiquée en argu- ment. Le facilitateur peut, dans le cas où la propriété n’existe pas, décider de re- tourner la valeur NOT_ALLOWED plutôt que NOT_EXIST.

Tous ces paramétrages doivent, à l’heure actuelle être fait directement dans le code. Mais pour faciliter l’utilisation par des utilisateurs novices, nous allons développer une interface permettant de paramétrer les facilitateurs des agents. Dans notre exemple, un agent mouton possède ces deux méthodes pour accéder et modifier les propriétés de type entier (int) comme présenté dans le code suivant :

ESetGetReturn GetProperty_Int(CShIdentifier PropertyIdentifier,

CShAgentInstance * pAsker,

int & value) {

if (pAsker.type() == " sheep ") {

if (PropertyIdentifier == " starvation ") {

value = self.starvation;

return(OK); }

else if (PropertyIdentifier == " resistance ") {

value = self.resistance;

return(OK); } else { return(NOT_EXIST); } } else { return(NOT_ALLOWED); }

88 CHAPITRE 6. GÉNÉRATION ET EXÉCUTION

}

ESetGetReturn SetProperty_Int(CShIdentifier PropertyIdentifier,

CShAgentInstance * pAsker,

int value) {

if (pAsker.type() == " sheep ") {

if (PropertyIdentifier == " starvation ") {

self.starvation = value;

return(OK); }

else if (PropertyIdentifier == " resistance ") {

self.resistance = value;

return(OK); } else { return(NOT_EXIST); } } else { return(NOT_ALLOWED); } }

Dans ces méthodes, on constate trois possibilités :

1. Si l’agent requérant (pAsker ) est un agent de type Mouton, il peut accéder ou mo- difier les valeurs de l’agent possédant les valeurs :

— Si la valeur existe, elle est modifiée ou assignée au paramètre value et la méthode retourne la valeur OK ;

— Si la valeur n’existe pas, la méthode retourne NOT_EXIST.

2. Si l’agent n’est pas un agent de type mouton, la méthode retourne la valeur NOT_ALLOWED.

Les conditions de l’exemple sont basiques. Mais il est possible de faire des tests plus complexes en vérifiant, par exemple, si l’agent requérant possède une compétence par- ticulière ou si un objet dans son inventaire est présent.

6.3.2/ LES CLASSES CShModel

Nous avons vu comment étaient générées les classes permettant le fonctionnement des compétences et des interactions des agents. Nous allons maintenant expliquer comment sont générées les classes permettant l’exécution des comportements.

Pour rappel, les comportements des agents sont modélisés dans des graphes de nœuds dans lesquels chaque nœud permet de définir une partie du comportement. Il existe 4 types de vues : les vues comportement, les vues état, les vues événement et les vues altération.

Les vues événement et état peuvent être utilisées dans d’autres vues. C’est pourquoi nous avons décidé de générer une classe C++ pour chaque vue. Lors des exécutions, il

6.3. GÉNÉRATION DU CODE 89

suffira d’instancier la classe correspondant à la vue désirée afin de pouvoir exécuter le comportement qu’elle définit.

Chaque vue possède un ou plusieurs points d’entrée modélisés par des nœuds entry point. C’est à partir de chacun de ces nœuds que nous démarrons la génération de code de chaque vue. Nous parcourons le flux d’activation partant de chaque nœud entry point jusqu’à ce qu’un nœud exit point soit atteint ou que le flux d’activation soit stoppé. Le fait d’exécuter la génération de cette manière permet de ne pas avoir à gérer les nœuds qui ne sont pas reliés à un flux d’activation. De plus, nous le verrons dans la suite de cette section, cela permet aussi la gestion de la portée des variables et la gestion de la fermeture des blocs.

Avant de faire ce parcours des flux d’activations, nous faisons une recherche des nœuds importants existants dans la vue. Il s’agit des nœuds entry points afin de connaître les points d’entrées de la génération ainsi que les nœuds states et events afin de pouvoir générer la déclaration, l’instanciation et l’initialisation des instances des classes de ces nœuds. Lorsqu’une instance est générée à partir d’un nœud state ou event, le nom de cette instance sera celui de l’identifier du nœud correspondant. En effet, dansSAMP-E, chaque nœud de chaque vue possède un identifier unique généré pour être compatible avec la syntaxe C++ de nommage des variables.

En plus des variables contenant les instances décrites précédemment, chaque classe héritant de CShModel possède une variable membre pointant sur l’instance de l’agent exécutant le comportement de la classe. Cette variable est appelée AgentPerformer. Une fois la définition de la classe terminée, nous pouvons générer la déclaration de la classe ainsi que les définitions du constructeur, du destructeur et de la méthode d’initia- lisation de la classe. Une fois cela réalisé, nous pouvons passer générer les définitions des méthodes OnEnter, OnLeave, OnPreUpdate et OnPostUpdate.

Chaque nœud génère un code particulier pour chacune de ces méthodes. Cette spécifi- cité permet une génération unitaire du code ce qui facilite le développement, la mainte- nance et la correction de la génération.

Dans la suite de cette section, nous décrivons le Code Manager permettant de gérer les transmissions des valeurs entre les nœuds au moment de la génération du code ainsi que la gestion de la portée des variables pour permettre la gestion des blocs de code.

6.3.3/ Code Manager : UN GESTIONNAIRE DE GÉNÉRATION DE CODE

Afin de nous aider dans le développement de notre générateur de code, nous avons mis au point un gestionnaire permettant de gérer divers aspects de la génération de code. Lorsqu’un nœud possède une valeur de sortie de type retour (cf 4.6.2), il créé le code correspondant lors de sa génération. Pour ce faire, il demande au Code Manager de générer une variable du type de la valeur (avec un nom de variable inutilisé) et de lui assigner sa valeur de retour. Dans le même temps, il va ajouter des informations sur cette variable dans un tableau du Code Manager qui fonctionne un peu comme un dictionnaire de données. Ces informations sont :

— Le nom de la variable ; — Le type de la variable ;

90 CHAPITRE 6. GÉNÉRATION ET EXÉCUTION