• Aucun résultat trouvé

Chapitre 5 Génération du code Uppaal d’un ordonnanceur

5.1.1 Le langage B0 classique

Le langage B comporte un sous-ensemble appelé B0 permettant de décrire des implantations directement traduisibles en langage exécutable. B0 peut être considéré comme un langage de programmation manip- ulant des données concrètes, contrairement à B qui est un langage de spécification et de programmation.

A partir du langage B0, l’utilisateur peut générer un code C exécutable.

Modules d’implantation

Rappelons que la méthode B est une méthode de développement basée sur le mécanisme du raffinement. Ce dernier est composé de plusieurs étapes, les étapes intermédiaires sont appelées les raffinements et la dernière étape est l’implantation. Après la phase d’implantation, nous pouvons générer le code exécutable du système logiciel.

L’implantation “importe” des spécifications de machines abstraites existantes, qui sont soit implé- mentées dans le projet, soit prédéfinies et présentes dans l’environnement, comme par exemple dans les librairies de l’outil Atelier B. Cette nouvelle clause d’importation impose des restrictions d’usage sur les variables des machines importées rendant celle-ci plus forte que la clause d’inclusion, interdite dans une implantation.

Tout comme un raffinement, une implantation possède une en-tête particulière IMPLEMENTATION. Elle doit posséder une clause REFINES, ainsi qu’une relation d’implantation dans l’invariant. Cette dernière donne la correspondance entre les niveaux abstrait et concret pour les variables à implémenter en terme de variables de machines importées et de variables concrètes. Une nouvelle clause VALUES vient s’ajouter pour définir la valeur des constantes et des ensembles. La figure 5.2 présente la structure d’une implantation.

Dans la machine d’implantation, nous devons respecter certaines règles afin de se rapprocher du code exécutable:

 Une implantation utilise les opérations des machines qu’elle importe, et dont elle ne peut accéder à leurs variables que pour exprimer les invariants.

 Certaines restrictions sont appliquées aux substitutions apparaissant dans une implantation afin d’assurer qu’elle pourra être traduite en un programme exécutable:

– pas de choix non déterministe ou de composition parallèle,

– les conditions dans les substitutions IF THEN ELSE sont limitées à des expressions booléennes simples,

– les opérations ne s’appliquent qu’à des variables locales ou des paramètres, – les affectations mettent en jeu des expressions simples.

 Une implantation peut introduire des substitutions correspondant à des boucles WHILE, mais il faudra indiquer pour chaque boucle, un invariant et un variant. Ce dernier représente une quantité qui décroît à chaque passage dans la boucle.

 Au moment de l’implantation, toutes les constantes déclarées et les ensembles non énumérés doivent être instanciés.

Substitutions autorisées

Dans une implantation, on autorise certaines substitutions et on interdit d’autres. Seules les substitutions suivantes sont autorisées:

 La substitution VAR IN END permettant d’introduire des variables locales. Ces variables doivent être typées dans la substitution en apparaissant dans une substitution d’initialisation (affectation ou variable résultat d’une opération).

IMPLEMENTATION nom de l’implantation REFINES

nom de la machine raffinée SEES

noms des machines vues IMPORTS

noms des machines importées PROMOTES

opérations utilisées des machines importées EXTENDS

noms des machines etendues SETS

déclaration des ensembles CONCRETE_CONSTANTS

déclaration des constantes concrètes PROPERTIES

propriétés des constantes VALUES

valuation des constantes et des ensembles CONCRETE_VARIABLES

déclaration des variables concrètes INVARIANT

propriétés invariantes des variables déclarées et relation d’implantation avec la machine à implémenter et les machines importées

ASSERTION

nouvelles assertions de l’implantation INITIALISATION

initialisation des variables de l’implantation OPERATIONS

définition des opérations de l’implantation END

Figure 5.2: Structure d’une implantation de la méthode B

 La substitution BEGIN END permettant de grouper une séquence de substitutions.

 La substitution IF THEN ELSE END où la condition doit correspondre à une expression booléenne calculable.

 La substitution CASE qui est une forme de SELECT mais dont les prédicats comparent des ex- pressions avec des constantes.

 Une boucle WHILE précisant un variant et un invariant.

 L’affectation d’une expression simple à une variable (“:=”) qui peut être une variable locale ou une variable résultat d’une opération.

 La substitution appel d’opération (“< ”). Les variables résultat peuvent être soit des variables locales, soit des variables résultat de l’opération dans laquelle apparaît la substitution.

 La substitution identité (“skip”) qui correspond à ne rien faire.

Toutes les autres substitutions ANY, SELECT, LET, . . . ne sont pas autorisées dans les implantations.

Exemple: Génération du code B0 de la machine istacks

Reprenons la machine istacks présentée dans le chapitre précédent, et illustrée par la figure 5.3.

MACHINE istacks(ELEM) VARIABLES istack

INVARIANT istack2iseq(ELEM) /* iseq représente une séquence injective*/

INITIALISATION istack := [] OPERATIONS

push(ee) =

PRE ee2ELEM^ee62ran(istack) THEN

istack := istack ee

END ; pop =

PRE istack6=[] THEN

istack := front(istack)

END END

Figure 5.3: istacks en B

Afin d’aboutir au code B0, il faut éliminer par raffinements successifs les séquences et les opérateurs k, pour les remplacer respectivement par des tableaux et des séquencements “;”. Ces raffinements seront décrits dans les paragraphes suivants.

Machine istacks_fun Un premier raffinement illustré par la machine istacks_fun de la figure 5.4 in- troduit de nouvelles variables avec les traitements nécessaires. Il consiste donc à remplacer la séquence injective istack par une fonction totale next: ELEM -> ELEM et à définir une variable itop contenant la tête de pile. La fonction next associe à chaque processus empilé celui qui le précède dans la pile.

Espace d’état La machine istacks_fun comprend comme on l’a déjà cité les variables itop et next, en plus d’un booléen empty déterminant si la pile est vide. Elle contient également plusieurs invariants de collage avec les données de la machine istacks:

 L’invariant ista k 6= [℄ ) itop= last(ista k)indique que la variableitopcorrespond à la tête de la pileista k, lorsque cette dernière est non vide.

 La propriété invariante8ii:(ii22::size(ista k))next(ista k(ii))=ista k(ii 1))exprime que lorsque la pile contient plus d’un élément, la fonction nextappliquée à l’élément de rangii n’est autre que l’élément de rangii 1.

 L’invariant ista k 6= [℄ ) next(first(ista k)) = first(ista k)indique que la fonction next appliquée au premier élément de la pile correspond à cet élément.

VARIABLES

INVARIANT

itop 2 ELEM

^ next 2 ELEM --> ELEM

^ empty 2 BOOL

^ (empty = bool(istack = []))

^ (istack 6= [] ) itop = last(istack))

^ (8ii.(ii 2 2..size(istack) ) next(istack(ii)) = istack(ii-1))) ^ (istack 6= [] ) next(first(istack)) = first(istack))

Opérations L’opération push permet, si la pile est vide, de chaîner le nouvel élément ee à lui- même et de donner à itop la valeur de cet élément, tout en indiquant que la pile contient actuellement des éléments. Dans le cas contraire, next va pointer sur itop et ce dernier est actualisé à ee.

push(ee) = BEGIN

IF empty = TRUE THEN

next(ee) := ee k itop := ee k empty := FALSE

ELSE

next(ee) := itop k itop := ee

END END

Dans l’opération pop, si on a plus qu’un seul élément, c’est à dire siitop6=next(itop), la variable itop prend la valeur du next. Sinon la valeur de empty devient vraie.

pop = BEGIN

IF itop 6= next(itop) THEN

itop := next(itop) ELSE

empty := TRUE END

END

Machine istacks_seq Ce raffinement présenté par la figure 5.5 consiste à éliminer les opérateurs k en les remplaçant par des ;afin d’exprimer l’enchaînement des actions de chaque opération. Ceci va nous permettre de réduire le non déterminisme des actions et il n’affecte pas la structure générale de la machine. Le non déterminisme ne peut pas être complètement éliminé ici puisqu’aucune valeur par défaut de type ELEM n’est définie pour itop.

Machine istacks_implementation L’Atelier B contient dans sa librairie des machines de base comme par exemple celles définissant les tableaux génériques. La taille de ces tableaux dépend des paramètres de la machine. Une des machines de base est BASIC_ARRAY_VAR modélisant des tableaux à une dimension. Le code B de cette machine est présenté dans l’annexe E. Elle prend deux paramètres INDEX et VALUE correspondant respectivement à l’ensemble des valeurs permettant d’indexer le tableau et à l’ensemble des valeurs possibles pour les éléments du tableau. BASIC_ARRAY_VAR contient une variable arr_vrb et deux opérations prédéfinies:

 L’opération VAL_ARRAY permet la lecture d’un élément du tableau, sa syntaxe est la suivante: vv VAL_ARRAY(ii). Sa précondition est que ii doit être un INDEX. Cette opération retourne l’élément en position ii.

REFINEMENT istacks_fun(ELEM) REFINES istacks

VARIABLES itop, next, empty INVARIANT

itop2ELEM ^ next2ELEM!ELEM ^ empty2BOOL

^ (empty = bool(istack = []))

^ (istack6=[] =) itop = last(istack))

^ (8ii.(ii22::size(istack) =) next(istack(ii)) = istack(ii-1)))

^ (istack6=[] =) next(first(istack)) = first(istack))

INITIALISATION

itop:2ELEMknext:2ELEM!ELEMkempty := TRUE

OPERATIONS push(ee) =

BEGIN

IF empty = TRUE THEN

next(ee) := eekitop := eekempty := FALSE

ELSE

next(ee) := itopkitop := ee

END END; pop =

BEGIN

IF itop6=next(itop) THEN

itop := next(itop) ELSE empty := TRUE END END END

Figure 5.4: Machine istacks_fun en B

 L’opération STR_ARRAY permet l’écriture d’un élément du tableau, sa syntaxe est: STR_ARRAY(ii, vv) avec comme préconditions queiidoit être un INDEX et vv doit être une VALUE. L’application de cette opération mène à l’introduction de la valeur vv dans le tableau à l’index ii.

Afin d’implémenter la machine istacks_seq, nous avons importé la machine prédéfinieBASIC_ARRAY_VAR

en la préfixant à l’aide de deux noms différents tab et init. Ceci va nous permettre d’introduire deux tableaux. Le premier sert à raffiner la fonction next de la machine istacks_seq, il possède ELEM comme dimension et prend aussi ses valeurs dans ELEM. Donc next n’est autre que la variable prédéfinie arr_vrb. Le second est introduit ici afin d’initialiser la variable itop. Il ne contient qu’un seul élément et prend ses valeurs dans ELEM.

IMPORTS

tab.BASIC_ARRAY_VAR(ELEM,ELEM) , init.BASIC_ARRAY_VAR(1..1,ELEM)

CONCRETE_VARIABLES itop, empty INVARIANT

REFINEMENT istacks_seq(ELEM) REFINES istacks_fun

VARIABLES itop, next, empty INITIALISATION

itop:2ELEM ; next:2ELEM!ELEM ; empty := TRUE

OPERATIONS push(ee) =

BEGIN

IF empty = TRUE THEN

next(ee) := ee ; itop := ee ; empty:= FALSE ELSE next(ee) := itop ; itop := ee END END ; pop = BEGIN

IF itop6=next(itop) THEN

itop := next(itop) ELSE empty := TRUE END END END

Figure 5.5: Machine istacks_seq en B

INITIALISATION empty := TRUE

; itop <-- init.VAL_ARRAY(1)

Ici, l’opération push possède la même structure que celle de istacks_seq. L’écriture des valeurs ee et itop à l’indice ee est effectuée respectivement à l’aide des opérations tab.STR_ARRAY(ee, ee) et tab.STR_ARRAY(ee, itop).

push(ee) = BEGIN

IF empty = TRUE THEN

tab.STR_ARRAY(ee, ee) ; itop := ee

; empty := FALSE

ELSE

tab.STR_ARRAY(ee,itop) ; itop := ee

END END

Dans l’opération pop, nous déclarons une variable locale nn correspondant à la valeur présente à l’indice itop du tableau. Le test et la mise à jour sont effectués en prenant en compte cette variable.

pop =

VAR nn IN

nn <-- tab.VAL_ARRAY(itop)

; IF itop 6= nn THEN itop := nn ELSE empty := TRUE END END

Le code détaillé de la machine istacks_implementation est illustré dans la figure 5.6.

IMPLEMENTATION istacks_implementation(ELEM) REFINES istacks_seq

IMPORTS tab.BASIC_ARRAY_VAR(ELEM, ELEM) , init.BASIC_ARRAY_VAR(1::1, ELEM)

CONCRETE_VARIABLES itop, empty INVARIANT tab.arr_vrb = next INITIALISATION

empty := TRUE ; itop init.VAL_ARRAY(1)

OPERATIONS push(ee) =

BEGIN

IF empty = TRUE THEN

tab.STR_ARRAY(ee, ee) ; itop := ee ; empty := FALSE ELSE tab.STR_ARRAY(ee, itop) ; itop := ee END END; pop = VAR nn IN nn tab.VAL_ARRAY(itop) ; IF itop6=nn THEN itop := nn ELSE empty := TRUE END END END

Figure 5.6: Machine istacks_implementation en B0

La section suivante présente le langage B0_Uppaal avec ses caractéristiques et les règles à respecter. Il définit un sous-ensemble de B traduisible en automates Uppaal.

Documents relatifs