• Aucun résultat trouvé

On d´ecrit maintenant une impl´ementation en ML sans GADT de l’automate. Cette impl´ementation est bien typ´ee mais elle effectue les tests superflus mentionn´es dans la section pr´ec´edente.

Pour commencer, on doit sp´ecifier les moyens d’interaction entre l’analyse lexicale et notre analy- seur syntaxique. On d´eclare le type des symboles terminaux :

type token =

KPlus | KStar | KLeft | KRight | KEnd | KInt of int

On suppose que l’analyseur lexicale fournit deux fonctions, l’une permettant de lire le symbole en cours d’analyse et l’autre de passer au terminal suivant :

val peek : unit → token val discard : unit → unit

9.4 Une impl´ementation en ML 103

On se plonge maintenant dans la conception de l’analyseur syntaxique. L’ensemble des ´etats est d´ecrit par une ´enum´eration, c’est `a dire un type alg´ebrique ordinaire dont tous les constructeurs ont une arit´e nulle :

type state = S0 | S1 | . . . | S11

Ensuite, on d´eclare un autre type alg´ebrique ordinaire pour impl´ementer la pile de l’automate. L’approche canonique consiste `a mimer la d´efinition des piles (σ ::= ² | σsv, voir la section9.3) :

(∗ D´efinition temporaire. ∗) type stack =

SEmpty | SCons of stack × state × semantic value and semantic value = ...

Cette d´eclaration affirme qu’une pile est une liste de paires form´ees d’un ´etat et d’une valeur s´emantique.

Il ne nous reste plus qu’`a d´efinir le type des valeurs s´emantiques. Ici, les symboles +, *, (, ) et $ ont des valeurs s´emantiques valant de type unit alors que int, E, T et F ont des valeurs s´emantiques de type int. Il est clair que cette h´et´erog´en´eit´e des types des valeurs s´emantiques force la d´efinition d’un type somme, c’est-`a-dire une nouvelle d´efinition de type alg´ebrique ordinaire.

Bien que naturelle et simple, cette solution introduit une certaine redondance puisqu’`a la fois les cellules et les valeurs s´emantiques contiennent des ´etiquettes. Pour ´eviter cette redondance, on utilise une m´ethode un peu moins directe qui fusionne les ´etiquettes des valeurs s´emantiques et des cellules en int´egrant les diff´erents types de valeurs s´emantiques directement `a l’int´erieur de la d´efinition des piles : type stack = | SEmpty | SP of stack × state | SS of stack × state | SL of stack × state | SR of stack × state | SI of stack × state × int | SE of stack × state × int | ST of stack × state × int | SF of stack × state × int

(Dans les noms choisis pour les constructeurs de donn´ees, P, S, L, R, et I sont des raccourcis pour

Plus, Star, Left, Right, et Int.)

En examinant l’´etiquette attach´ee `a une valeur de type stack, on peut r´epondre en mˆeme temps `a deux questions : est-ce que la pile est vide ? si elle n’est pas vide, quel type de valeurs s´emantiques contient-elle `a son sommet ?

Par ailleurs, `a des fins d’optimisation, on choisit de ne pas repr´esenter `a l’ex´ecution les valeurs de type unit. Par cons´equent, les cellules associ´ees aux symboles +, *, ( et ) contiennent seulement un ´etat et non une paire contenant un ´etat et la valeur unit.

Enfin, aucune cellule n’est construite avec le symbole $ parce que, par construction, l’automate n’effectue jamais une action shift  lorsqu’il rencontre ce symbole.

Pour r´esumer, chaque valeur du type stack contient une ´etiquette qui doit ˆetre examin´ee pour que le contenu r´eel soit accessible. Si, grˆace `a un raisonnement externe, l’´etiquette est connue par avance alors ce test dynamique est redondant.

C’est cette approche o`u les valeurs s´emantiques et/ou les cellules de la pile sont ´etiquet´es qui est adopt´ee par ML-Yacc et happy.

La fonction centrale de l’analyseur syntaxique, run impl´emente l’´evaluation de l’automate `a pile. Elle est param´etr´e par l’´etat courant et la pile courante. Il peut s’arrˆeter soit en lan¸cant l’exception

104 9. Application : Analyseur LR bien typ´e

1 exception SyntaxError 2

3 let rec run : state → stack → int = 4 fun s stack →

5 match s, peek() with 6 | . . .

7 | S9, KStar →

8 (∗ D´ecale vers l ’ ´etat 7. ∗)

9 discard ();

10 run S7 (SS (stack, S9))

11 | S9, KPlus →

12 (∗ R´eduit E{x} + T {y} → E{x + y}. ∗) 13 (∗ D´epile trois cellules . ∗)

14 let ST (SP (SE (stack, s, x), ), , y) =

15 stack in

16 (∗ Empile l’ ´etat courant et la nouvelle valeur s´emantique sur la pile . ∗) 17 let stack = SE (stack, s, x + y) in

18 (∗ Choisit un successeur sur la pile en utilisant la colonne E de la table goto. ∗)

19 gotoE s stack

20 | . . .

21 | ,

22 raise SyntaxError

23

24 and gotoE : state → stack → int = 25 fun s → 26 match s with 27 | S0 → 28 run S1 29 | S4 → 30 run S8

Fig. 9.3: Une impl´ementation bien typ´ee en ML.

SyntaxError ce qui signifie que l’entr´ee n’est pas conforme `a la grammaire, ou bien en retournant une

valeur s´emantique enti`ere correspondant `a la valeur de l’expression arithm´etique E qui a ´et´e analys´ee. `

A l’exception des fonctions peek et discard qui font des effets de bord pour manipuler le flux d’entr´ee, la totalit´e de ce programme est purement fonctionnel.

La d´efinition de run apparaˆıt dans la figure 9.3. La fonction examine l’´etat courant s ainsi que l’entr´ee courante obtenue par la fonction peek et d´etermine quelle action effectuer. Il y a plusieurs cas, on en d´etaille deux.

Quand l’´etat courant vaut 9 et le symbole `a analyser est * (ligne7), la table action de la figure9.2

indique que l’automate doit effectuer une action  shift 7 . On passe donc au symbole suivant, l’´etat courant 9 est plac´e au sommet de la pile et l’´etat courant est maintenant 7 (ligne 10). Dans ce cas particulier, aucune valeur s´emantique n’est pouss´ee sur la pile parce qu’aucune valeur s´emantique n’est associ´ee au symbole *. De mˆeme, le constructeur de donn´ees n’attend pas un troisi`eme argument. L’´etat courant et la pile sont chang´es en suivant l’idiome de programmation fonctionnelle pure qui consiste `a effectuer un appel r´ecursif `a run avec ces nouveaux param`etres.

Quand l’´etat courant est 9 et le symbole `a analyser est + (ligne 11), la table action indique que l’automate doit r´eduire la production 1, c’est-`a-dire E{x} + T {y} → E{x + y}. Comme on l’a expliqu´e dans la section pr´ec´edente, la structure des trois ´el´ements plac´es au sommet de la pile est connue en