• Aucun résultat trouvé

Comment définir des stratégies « utilisateur »

Dans le document Réécriture et compilation de confiance (Page 145-148)

6. Stratégies de réécriture réflexives en Java 113

6.4. Rendre les stratégies utilisables

6.4.1. Comment définir des stratégies « utilisateur »

Le langage de stratégies permet de spécifier la manière d’appliquer des

transforma-tions dans un arbre. Ces transformatransforma-tions sont décrites par des stratégies spécifiées par

l’utilisateur du système, à la manière des règles nommées du langageElan, décrites en

section 6.1.2.

Dans l’expression de stratégie présentée en figure 6.7, les nœuds grisés correspondent

aux stratégies utilisateur qui décrivent les différentes optimisations effectuées par le

compilateur, tandis que les autres nœuds sont les combinateurs qui décrivent la procédure

d’optimisation.

Note A. La stratégie présentée en figure 6.7 est représentée avec toutes les stratégies

composées affichées sous la forme de leur graphe de stratégies élémentaires. Cette

straté-gie dont le graphe est complexe est programmée en combinant des stratéstraté-gies prédéfinies.

Ainsi, la première branche de la séquence principale est décrite dans le programme par :

InnermostId(ChoiceId(RepeatId((NopElimAndFlatten())),NormExpr()))

Dans laquelle NopElimAndFlatten() et NormExpr() construisent les stratégies «

utili-sateur » qui respectivement éliminent les instructions inutiles, et normalisent les

expres-sions booléennes. On voit ici que la règle NopElimAndFlatten() est réutilisée à trois

reprises, dans des contextes différents. En effet, dans certains cas elle est utilisée sous

une stratégie TopDown pour normaliser, mais elle est aussi utilisée sous une stratégie

OnceTopDownlorsque l’on sait dans le processus d’optimisation que la règle ne doit être

appliquée qu’une seule fois, après fusion des blocks et des tests qui peuvent l’être.

La définition de telles transformations se fait dans le cadre de la librairie JJTraveler

par l’écriture d’une classe Javaqui étend une classe spécifique à la structure de données

Sequence Mu Mu Sequence Sequence All SequenceId x ChoiceId x Mu NormExpr SequenceId Identity NopElimAndFlatten x Identity All SequenceId x ChoiceId x Sequence SequenceId Mu Mu InterBlock Mu SequenceId SequenceId IfSwapping x Identity SequenceId x ChoiceId Mu

BlockFusion IfFusion ChoiceId Identity Identity NopElimAndFlatten OneId

Identity x Identity ChoiceId Mu OneId SequenceId x NopElimAndFlatten x Identity

6.4. Rendre les stratégies utilisables

traversée. Nous appellerons par la suite cette classe dépendant de la structure de données

Fwd. Celle-ci prend en argument une stratégie, généralementIdentity() ouFail(), et

définit des méthodes de visite préservant les types de la structure de données, dont le

comportement par défaut est de déléguer l’appel à la stratégie argument. L’utilisateur

peut alors redéfinir une de ces méthodes spécifiques à un type dans la structure de

données pour obtenir un comportement particulier. On peut voir en figure 6.7 que les

stratégies utilisées pour la définition de l’optimiseur du compilateur Tom étendent le

comportement de la stratégie identité. Ainsi, lorsque la règle ne peut pas être appliquée,

la stratégie effectue l’identité, et ne change pas le terme courant, ni n’échoue.

Une construction de déclaration de stratégies

Pour pouvoir programmer une telle stratégie utilisateur, il est nécessaire de connaître

les détails de fonctionnement interne de la bibliothèque, comme illustré en figure 6.8. La

structure de données utilisée avec les stratégies est généralement une structure générée

automatiquement pas un outil commeGom. Ainsi, il n’est pas nécessaire que l’utilisateur

définisse lui-même la classeFwdconstituant la base des stratégies utilisateur. Cependant,

il reste nécessaire de connaître les patrons de conception dirigeant la librairie de stratégie

pour développer les stratégies.

Pour rendre le développement de stratégies plus facile, nous définissons une extension

du langageTompar une construction%strategypermettant de définir une stratégie de

manière abstraite. Cette construction, illustrée en figure 6.8 par l’encodage d’une règle de

réécrituref(x, x)→g(x), pour laquelle on supposef etgde sorteT, permet une écriture

concise et abstraite de la règle. La définition qui suitvisit Texplicite le comportement

de la stratégie lorsqu’elle visite un nœud de sorteT, en utilisant le filtrage sur les termes

comme dans l’instruction%match. On peut définir une constructionvisitpour chaque

sorte de l’algèbre de termes. Cette stratégie étend l’échec, ce qui signifie qu’elle échoue

lorsque la règle définie ne peut pas s’appliquer, et donc n’échoue pas uniquement sur les

radicaux qui filtrent f(x, x).

Cette construction %strategy permet aussi de décrire des stratégies paramétrées,

les paramètres étant passés comme arguments lors de la construction de la règle. La

stratégie une fois déclarée peut être utilisée à la manière des combinateurs élémentaires

dans l’écriture d’une expression de stratégie.

La stratégie définie à l’aide de la construction %strategy a le même statut que

les combinateurs pour la librairie de stratégie. Elle est donc elle-même visitable et

il est possible d’utiliser une construction de filtrage sur cette stratégie. La procédure

de µ-expansion traite ainsi les sous-termes d’une stratégie utilisateur qui sont de type

Strategy, ce qui permet d’écrire des versions spécialisées des briques de base, ainsi que

des stratégies dont les arguments représentent la suite du calcul pouvant être récursives.

Cela est utile pour décrire une stratégie réutilisable effectuant un appel récursif

expli-cite non pas sur la brique de base elle-même, mais sur la stratégie de parcours elle-même.

Stratégie f(x, x)→g(x)utilisant JJTraveler et Tom pour le filtrage :

public static class Rule extends TFwd {

public Rule() {

super(new Fail());

}

public T visit_T(T arg) throws jjtraveler.VisitFailure {

%match(T arg) {

f(x,x) -> { return ‘g(x); }

}

}

}

Stratégief(x, x)→g(x) utilisant%strategy :

%strategy Rule() extends Fail() {

visit T {

f(x,x) -> { return ‘g(x); }

}

}

Fig. 6.8: Exemple de stratégie codant une règle de réécriture

Dans le document Réécriture et compilation de confiance (Page 145-148)