Telechargé par Fatiha Ait BOURHOU

4-analyseurs-LR (1)

publicité
Analyse Syntaxique ascendante
LR Parsing Techniques
11
Sujets
• Préfixes viables.
• Éléments LR(0).
• AFD LR(0) pour reconnaître les préfixes viables.
• Analyseur LR(0).
17/05/2016
2
Objectifs
• Pouvoir calculer l’AFD qui reconnait les préfixes viables.
• Pouvoir générer une table d’analyse LR(0).
• Pouvoir décrire le driver LR(0) et le simuler.
17/05/2016
3
Introduction(1)
!
Analyseurs descendants
!
!
!
4
commence la construction de l'arbre d'analyse à partir du
la racine de l'arbre et se déplacer vers le bas (vers les
feuilles).
Facile à mettre en œuvre à la main, mais travailler avec les
grammaires restreintes.
exemple: analyseur prédictifs LL(1)
Introduction(2)
!
Analyseurs ascendants (Bottom-up)
!
!
On cherche à construire un arbre de dérivation à partir des feuilles
selon un parcours inverse d’un parcours en profondeur d’abord de
gauche a droite.
Les étapes de réduction tracent une dérivation à droite à l'envers.
Suitable pour un générateur d'analyseur syntaxique automatique
Peut gérer une grande classe de grammaires.
!
exemples: shift-reduce parser (or LR (k) parsers)
!
!
Grammaire
S → aABe
A → Abc | b
B →d
5
input string : abbcde.
10/5/20
Introduction(3)
Bottom-Up Parser Example
Shift a
INPUT:
Production
S → aABe
A → Abc
A→b
B→d
6
a
b
b
c
d
e
$
Bottom-Up Parsing
Program
OUTPUT:
Introduction(4)
Bottom-Up Parser Example
Shift b
Reduce from b to A
INPUT:
Production
S → aABe
A → Abc
A→b
B→d
7
a
b
b
c
d
e
$
Bottom-Up Parsing
Program
OUTPUT:
A
b
Introduction(5)
Bottom-Up Parser Example
Shift A
INPUT:
Production
S → aABe
A → Abc
A→b
B→d
8
a
A
b
c
d
e
$
Bottom-Up Parsing
Program
OUTPUT:
A
b
Introduction(6)
Bottom-Up Parser Example
Shift b
INPUT:
Production
S → aABe
A → Abc
A→b
B→d
9
a
A
b
c
d
e
$
Bottom-Up Parsing
Program
OUTPUT:
A
b
Introduction(7)
Bottom-Up Parser Example
Shift c
Reduce from Abc to A
INPUT:
Production
S → aABe
A → Abc
A→b
B→d
10
a
A
b
c
d
e
$
Bottom-Up Parsing
Program
OUTPUT:
A
A
b
b
c
Introduction(8)
Bottom-Up Parser Example
Shift A
INPUT:
Production
S → aABe
A → Abc
A→b
B→d
11
a
A
d
e
$
Bottom-Up Parsing
Program
OUTPUT:
A
A
b
b
c
Introduction(9)
Bottom-Up Parser Example
Shift d
Reduce from d to B
INPUT:
Production
S → aABe
A → Abc
A→b
B→d
12
a
A
d
e
$
Bottom-Up Parsing
Program
OUTPUT:
A
b
A
B
b
c d
Introduction(10)
Bottom-Up Parser Example
Shift B
INPUT:
Production
S → aABe
A → Abc
A→b
B→d
13
a
A
B
e
$
Bottom-Up Parsing
Program
OUTPUT:
A
b
A
B
b
c d
Introduction(11)
Bottom-Up Parser Example
Shift e
Reduce from aABe to S
INPUT:
a
A
B
e
$
OUTPUT:
S
Production
S → aABe
A → Abc
A→b
B→d
14
Bottom-Up Parsing
Program
a
A
B
A
b
c d
b
e
Introduction(12)
Bottom-Up Parser Example
Shift S
Hit the target $
INPUT:
S
$
OUTPUT:
S
Production
S → aABe
A → Abc
A→b
B→d
Bottom-Up Parsing
Program
a
A
B
A
b
c d
e
b
Cet analyseur est connu comme un analyseur LR parce
il balaye l'entrée de gauche à droite, et il construit
une dérivation plus à droite dans l'ordre inverse.
15
Introduction(13)
!
Conclusion
!
Le balayage des productions pour faire correspondre avec
des poignées dans la chaîne d'entrée
!
Le Backtracking rend la procédure utilisé dans
l'exemple précédent très inefficace.
Pouvons-nous faire mieux? Discuter plus tard !!!
Architecture précedente
16
Renouveler l'Architecture
Shift-Reduce Parsers(1)
!
Shift-Reduce (bottom-up) parser is known as an LR Parser
! Il scanne l'entrée de gauche à droite
! Dérivation droite dans l'ordre inverse
! Types d'analyseurs LR
! LR(k) : Le plus puissant analyseur ascendants déterministes en
utilisant k symboles d'anticipations
! SLR(k)
! LALR(k)
- Dérivation droite dans l'ordre inverse
- Le mécanisme pour effectuer l'analyse
ascendant est la machine à états finis en
manipulant des "poignées"
!
Composants
!
Parse stack
!
Shift-reduce driver
!
Action table
!
Goto table
17
Shift-Reduce Parsers(2)
!
Parse stack
!
!
!
18
Iinitialement vide, contient des symboles déjà analysés
Les éléments de la pile sont des symboles terminaux ou
non terminaux
La pile d'analyse enchaîné avec l'entrée restante
représente toujours une bonne forme sententielles
Shift-Reduce Parsers(3)
!
Shift-Reduce driver
! Shift -- Quand le sommet de la pile ne contient pas une poignée de la
forme sententielles
!
!
Push le jeton d'entrée (avec informations contextuelles) dans la
pile
Reduce -- Quand le sommet de la pile contient une poignée pop la
poignée
!
19
push le non-terminal réduite (avec des informations
contextuelles)
Rappel : Algorithme LRDriver
Algorithm LRDriver
variables : stack, handle (sous-chaîne au sommet de la pile), a (token), in (entrée)
initialement la pile est vide ($) et l’entrée est w$ (une chaîne w).
while (true) {
if (symbol on top of stack is S’ ) return (a = = $); //accepte
handle = stack.findHandle();
//trouver une poignée. Étape cruciale !
if handle != void {
// void si la poignée n’est pas trouvée
soit ‘A → handle’ la règle correspondante // reduce (nondeterminisme si plusieurs règles)
pop handle from the stack;
push A on the stack;
print out the production ‘A → handle’; // pour imprimer la séquence de dérivation
}
else {
a = in.nextToken();
// shift
if a = $ exit with error(); // erreur si ni reduce ni shift ne sont possibles
push a on the stack;
continue;
}
}
17/05/2016
20
Exemple
Grammaire augmentée
Grammaire
G = (V, A, R, E), avec
V= {E, F, T}
A = {(, ), +, *, num}
R= {
E
E
T
T
F
F
17/05/2016
→ E+T
→ T
→ T*F
→ F
→ ( E)
→ num}
G = (V, A, R, E) :
V= {E’, E, F, T}
A = {(, ), +, *, num}
R= {
E’ → Ε
E
E
T
T
F
F
→ E+T
→ T
→ T*F
→ F
→ ( E)
→ num}
21
Exemple, suite
Productions
1. E’ → Ε
2. E → E + T
3. E → T
4. T → T * F
5. T → F
6. F → ( E)
7. F → num
Simulation du driver LR
concaténé avec les tokens
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
restant à lire (w) est une
Dérivation correspondante :
Observation
Le contenu de la pile (γ )
forme sententielle pour une
dérivation la plus à droite :
($,
($(,
($(num,
($(F,
($(T,
($(E,
($(E),
($F,
($T,
($E,
($E’,
(num)$)
num)$)
)$)
)$)
)$)
)$)
$)
$)
$)
$)
$)
Shift
Shift
Reduce
Reduce
Reduce
Shift
Reduce
Reduce
Reduce
Reduce
Accepte
7
5
3
6
5
3
1
(num) <= (num) <= (num) <= (F) <= (T) <= (E) <=
(E) <= F <= T <= E <= E’
S =>
* γω
R
17/05/2016
22
Le problème de trouver la poignée
− Pour une version déterministe, le défi est de trouver la poignée (méthode
‘stack.findHandle()’).
− Pour certaines classes de GHC, on peut trouver la poignée sans examiner tout le
contenu la pile. Cela découle de la propriété suivante sur les automates à pile LR :
➢ S’il est possible de reconnaître une poignée seulement à partir du contenu de la
pile, alors il existe un AFD, qui en lisant les symboles de la grammaire à partir
du sommet de la pile, détermine quel poignée, s’il y en a, est au sommet.
− On va démontrer cette propriété en montrant comment construire l’AFD.
− Ensuite on va voir comment utiliser l’AFD pour implémenter stack.findHandle().
− Ceci nous conduira à deux techniques d’analyse LR (SLR(1) et LALR(1)), résultant
d’une combinaison ingénieuse de l’automate à pile LR et de l’AFD pour reconnaître
les poignées.
17/05/2016
23
Que doit être l’alphabet de l’AFD
pour reconnaître les poignées ?
− Pour répondre à cette question, il faut garder à l’esprit que l’objectif est
d’avoir un AFD qui lit le contenu de la pile (à partir du sommet) pour
indiquer s’il y a une poignée au sommet de la pile.
− Étant donné que la pile contient des symboles de la grammaire (terminaux et
non-terminaux), l’alphabet de l’AFD doit être les symboles de la grammaire.
− En d’autre mots, les transitions de l’AFD seront étiquetées par les symboles
de la grammaires (terminaux et non terminaux).
− La question qui reste est de savoir quels devraient être les états de l’AFD et
quelles devraient être les transitions entre ces états.
17/05/2016
24
Préfixes viables
− Pour répondre à la question précédente, rappelons d’abord que le contenu de
la pile (γ) concaténé avec le reste des tokens (α) est une forme sententielle
pour la dérivation la plus à droite.
− Par conséquent, le contenu de la pile est toujours un préfixe d’une forme
sententielle pour la dérivation la plus à droite.
− De tels préfixes de formes sententielles de dérivation à droite, pouvant
apparaître sur la pile, sont appelées des préfixes viables.
− On va voir comment construire un AFD pour reconnaître des préfixes viables.
− Ensuite on va expliquer comment l’utiliser pour reconnaître des poignées.
17/05/2016
25
AFN pour reconnaître les préfixes viables
− Les transitions de l’AFN vont être étiquetées par des symboles dont la séquence
forme un préfixe viable.
− En d’autres mots, on aura les transitions
préfixe viable.
X
Y
Z
si XYZ est un
− Un état de l’AFN sera une production de la grammaire avec un point (« . ») à
une position particulière dans la partie droite.
− Ainsi, à partir de la production A → XYZ, on va générer 4 états de l’AFN :
A → . XYZ
•
A → X . YZ
•
A → XY . Z
•
A → XYZ .
•
− Pour la production A → ε, on va générer un seul état : A → .
17/05/2016
26
Que signifient les états de l’AFN?
− Intuitivement, un état de l’AFN indique la portion de la partie droite d’une
production, reconnue au sommet de la pile, à un moment donnée durant l’analyse
syntaxique LR.
▪ Par exemple l’état A → . XYZ indique qu’aucune portion n’est encore reconnue
sur la pile, et on espère que le reste des tokens à lire commence par un préfixe
dérivable de XYZ.
▪ L’état A → X.YZ indique qu’on vient juste de lire une sous-chaîne de tokens
dérivable de X (c.-à-d., le préfixe viable X est au sommet de la pile) et on s’attend
à lire ensuite une suite de tokens formant un sous-chaîne dérivable de YZ.
− Un état de l’AFN est appelé un élement LR(0) (item LR(0) en anglais; ou élément tout
court) de la grammaire.
▪ On peut implémenter un élément LR(0) par une paire d’entiers, le premier
indiquant le numéro de la production, le deuxième indiquant la position du point.
− On peut maintenant expliquer la technique pour obtenir l’AFN de la grammaire.
17/05/2016
27
AFN pour reconnaître les préfixes viables
1.
L’état initial est S’ → . S
2.
Pour chaque paire d’états A → α . X β et A → αX . β, ajouter une transition du
premier état vers le deuxième, étiquetée par X.
Il faut garder à l’esprit que A → α . Xβ signifie : à un moment donné durant l’analyse
syntaxique, on vient juste de scanner un sous-chaîne dérivable de α et on s’attend à
scanner une sous-chaîne dérivable de X, ensuite une sous-chaîne dérivable de
β.
Ainsi, la transition de A → α . X β à A → αX . β, étiquetée X, signifie qu’on vient
juste de lire une sous-chaîne dérivable de X et on s’attend maintenant à en lire une
dérivable de β.
3.
Pour chaque paire d’états A → α . X β et X → . γ, ajouter une transition du
premier vers le deuxième, étiquetée ε.
Intuitivement, si on s’attend à scanner une sous-chaîne dérivable de X et si X peut
dériver γ, on peut s’attendre aussi bien à scanner une chaîne dérivable de γ.
17/05/2016
28
Éléments canoniques (de base) et
l’opération de fermeture (closure)
1.
2.
L’état initial est S’ → . S
Pour chaque paire d’états A → α . X β et A → αX . β, ajouter une transition du premier
état vers le deuxième, étiquetée par X.
Pour chaque paire d’états A → α . X β et X → .γ, ajouter une transition du premier vers
le deuxième, étiquetée ε.
3.
Les éléments impliqués dans les deux premières opérations sont appelés des
éléments canoniques (c-à-d., des éléments du noyau, ou des éléments de base ou
kernels en anglais).
−
▪
Il s’agit de l’élément S’ → . S et des éléments dont le point ne commence pas la partie
droite de la production.
−
Les éléments dont le point apparaît au début de la partie droite de la production
sont dits non canoniques.
−
La troisième opération est une fermeture ε.
17/05/2016
29
Exemple 1/3
Grammaire
Grammaire augmentée
G = (V, A, R, E) :
V= {E, F, T}
A = {(, ), +, *, num}
R= {
G = (V, A, R, E) :
V= {E’, E, F, T}
A = {(, ), +, *, num}
R= {
}
E
E
T
T
F
F
→ E+T
→ T
→ T*F
→ F
→ ( E)
→ num
E’ → Ε
}
17/05/2016
E
E
T
T
F
F
→ E+T
→ T
→ T*F
→ F
→ ( E)
→ num
30
Exemple 2/3
AFN pour les préfixes viables
ε
Grammaire
E’→ Ε
E→ E+T
E→ Τ
E’→.Ε
ε
E→.E+T
Ε
E
E’→Ε.
E→E.+T
E→.Τ
+
T→F.
E→Τ.
F
ε
E→E+.T
T→T*F
ε
T→.F
ε
T→ F
F→ (E)
T
E→E+T.
T→.T*F
F→(E.)
T→T*.F
T→T.*F
F→num
T→T*F.
ε
F→ .num
F→.(E)
F→num.
F→(.E)
F→(E).
Seulement quelques transitions sont présentes !
Compléter les autres comme exercice.
17/05/2016
31
Exemple 3/3
E’
Grammaire
E’→ Ε
E→ E+T
E→ Τ
T→T*F
T→ F
F→ (E)
F→num
1. E’→ .Ε
2. E’→ Ε.
3. E→ .E+T
4. E→ E.+T
5. E→ E+.T
6. E→ E+T.
7. E→ .Τ
8. E→ Τ.
9. T→.T*F
10. T→T.*F
11. T→T*.F
E
2
T
F
(
)
+
*
num
ε
3,7
Même AFN, avec
table de transition.
Seulement deux
entrées complétées.
Les autres sont
laissées comme
exercice.
12. T→T*F.
13. T→ .F
14. T→ F.
15. F→ .(E)
16. F→ (E)
17. F→ (E)
18. F→num
19. F→num
17/05/2016
32
AFD pour reconnaître les préfixes viables
− On obtient l’AFD pour les préfixes viables en déterminisant l’AFN (par la méthode
subset construction).
I0
E’→ .Ε
E→ .E+T
E→ .Τ
T→.T*F
T→ .F
F→ .(E)
F→.num
I1
E’→ Ε.
E→ E.+T
I2
E→ Τ.
T→T.*F
I3
T→ F.
I4
F→ (.E)
E→ .E+T
E→ .Τ
T→.T*F
T→ .F
F→ .(E)
F→ .num
I7
T→T*.F
F→ .(E)
F→.num
I5
F→ num.
I9
E→ E+T.
T→T.*F
I6
E→ E+.T
T→ .T*F
T→ .F
F→ .(E)
F→.num
E
I0
+
I1
T
I6
I9
F
(
I8
F→ (E.)
E→ E.+T
F
*
I2
to I4
to I5
F
I7
I10
(
I3
(
I0
T→T*F.
I11
F→ (E).
num
E
)
I8
T
num
I5
to I4
to I5
(
I4
num
to I7
to I3
num
T
*
F
I11
+
to I6
to I2
to I3
17/05/2016
33
AFD pour reconnaître les préfixes viables
− L’AFD avec une table de transition.
I0
E’→ .Ε
E→ .E+T
E→ .Τ
T→.T*F
T→ .F
F→ .(E)
F→.num
I1
E’→ Ε.
E→ E.+T
I2
E→ Τ.
T→T.*F
I3
T→ F.
I4
F→ (.E)
E→ .E+T
E→ .Τ
T→.T*F
T→ .F
F→ .(E)
F→ .num
I7
T→T*.F
F→ .(E)
F→.num
I5
F→ num.
I9
E→ E+T.
T→T.*F
I6
E→ E+.T
T→ .T*F
T→ .F
F→ .(E)
F→.num
I8
F→ (E.)
E→ E.+T
E’
I0
I1
E
T
F
(
I1
I2
I3
I4
)
+
*
num
I5
I6
I2
I7
I3
I4
I5
I0
T→T*F.
I6
I11
F→ (E).
I8
I7
I9
I8
I2
I9
I3
I4
I5
I3
I4
I5
I10
I4
I5
I11
I6
I7
I10
I1
17/05/2016
34
AFD LR(0) pour reconnaître les préfixes viables
− Les états de l’AFD sont donc des ensembles d’états de l’AFN, c’est-à-dire,
des ensembles d’éléments LR(0).
− La fonction de transition de l’AFD est appelée la fonction goto de
l’analyseur syntaxique:
Étant donné un état I de l’AFD et un symbole de grammaire X, goto(I,X)
est le successeur de I pour la transition étiqueté par X.
17/05/2016
35
Méthode efficace de construction
de l’AFD pour les préfixes viables
− Une méthode efficace de construction de l’AFD pour les préfixes viables est
d’appliquer la méthode de déterminisation (subset construction method), à la
volée, sans construire l’AFN au préalable.
− Pour ce faire, nous avons d’abord besoin de définir deux fonctions
auxiliaires: closer(I) et goto(I,X).
− closure(I) implémente la fermeture ε, sous-jacente à méthode
déterminisation, en éliminant notamment les transitions ε.
−
goto(I,X) implémente les transitions entre les éléments canoniques.
17/05/2016
36
Définition informelle de closure
− Soit I un ensemble d’éléments LR(0) d’une grammaire.
− closure(I) est l’ensemble obtenu de I en appliquant les opérations suivantes :
• Initialement, chaque élément de I est mis dans closure(I).
• Ensuite on applique l’opération suivante, jusqu’à ce qu’aucun nouvel
élément ne peut plus être ajouté :
Si A → α . Xβ est dans closure(I) et X → γ est une production,
ajouter l’élément X → .γ à closure(I).
17/05/2016
37
Définition formelle de closure(I)
Algorithm closure(I)
variables : I (ensemble d’éléments LR(0) : donnée d’entrée)
G (grammaire : donnée comme variable globale)
J (ensemble d’éléments LR(0): contient le résultat)
J = I; // initialisation
do {
for (each item A → α . Xβ in J and each production X → γ of G such that
X → .γ is not in J)
add X → .γ to J
} while (J is modified)
return J;
17/05/2016
38
Fonction goto
− Soit
− I un état de l’AFD (c.-à-d., un ensemble d’items LR(0)) et
− X un symbole de la grammaire.
− Notons I’ l’ensemble formé de tous les éléments A → αX . β pour lesquels il existe un
élément A → α . Xβ dans I.
− goto(I,X) = closure(I’).
− En d’autre mots, goto(I,X) est défini comme étant la fermeture (closure) de l’ensemble
formé de tous les éléments A → αX . β pour lesquels il existe un élément A → α . Xβ
dans I.
− Rappelons que les états de l’AFD sont aussi appelés des éléments (items) canoniques
LR(0).
− Comme on connaît la fonction goto, pour définir l’AFD il suffit d’itérer avec la fonction
goto à partir de l’état initial closure({S’→ . S}).
17/05/2016
39
Algorithme pour les états de l’AFD LR(0)
Algorithm Items(G)
variables : G (entrée : grammaire augmentée avec symbole de départ S) et
C (résultat : ensembles des états de l’AFD.)
Output : C et la fonction goto.
C = { closure({S’→ . S}) }; // état initial
do {
for (each state I in C and each grammar symbol X such that
goto(I,X) is not empty and not in C)
add goto(I,X) to C
} while (C is modified)
return C;
17/05/2016
40
Éléments valides
− Un élément A → β1 . β2 est dit valide pour un préfixe viable α β1 s’il existe une
dérivation la plus à droite telle que : S’ =>* αΑw =>*α β1 β2 w .
R
R
− On peut démontrer que l’ensemble des éléments valides pour un préfixe viable γ est
précisément l’ensemble des éléments atteignables à partir de l’état initial de l’AFD des
préfixes viables, en suivant un chemin étiqueté par γ.
− La validité de A → β1 . β2 pour un préfixe α β1 nous indique s’il faut faire shift ou alors
reduce dès que α β1 est au sommet de la pile.
−
En d’autre mots, ça nous indique si αβ1 est une poignée ou non.
17/05/2016
41
Quand faire shift, quand faire reduce ?
− Supposons que α β1 est au sommet de la pile et que l’élément A → β1 . β2 est valide
pour α β1. Alors :
• Si β2 = ε , cela veut dire qu’au sommet de la pile nous avons la partie droite de la
production A → β1. C.-à-d., β1 est une poignée, on peut donc réduire.
• Sinon, si β2 ≠ε , cela veut dire qu’on doit faire shift des tokens de la sous-chaîne β2
avant d’obtenir β1 β2 . C-à-d., on n’a pas encore une poignée sur la pile, on doit
continuer de faire shift.
−
De ces observations, on déduit que si on simule l’AFD pour les préfixes viables en
parallèle avec le driver LR (automate à pile LR), on sera capable de déterminer quand
faire shift et quand faire reduce.
17/05/2016
42
Idée de base
− L’idée de base pour simuler en parallèle l’automate à pile LR et l’AFD pour les préfixes
viables est la suivante.
− Initialement, l’automate à pile est vide et l’AFD est dans son état initial.
− Chaque fois qu’on shift un token sur la pile, l’AFD change son état en suivant la transition
étiquetée par le token.
− Ainsi, lorsque le sommet de la pile va contenir β1 l’AFD sera dans un état contenant l’élément
A → β1 . , ce qui indique que nous devons faire une réduction avec la production A → β1.
− En même temps que nous appliquons la réduction (en remplaçant β1 par A sur la pile), on doit
revenir en arrière dans l’AFD (backtracking) le long du chemin étiqueté β1 jusqu’à l’état I qui
est la racine du chemin étiqueté β1 .
− Puisque A est le nouveau symbole au sommet de la pile, on doit faire une transition
correspondante dans l’AFD; c-à-d., l’état courant de l’AFD doit devenir l’état retourné par
goto(I,A) (c.-à-d., le successeur de I sous la transition A dans l’AFD).
17/05/2016
43
De l’idée à l’implémentation
− Pour implémenter cette idée, on met les états de l’AFD sur la pile de sorte à garder
une trace de l’exécution de l’AFD.
− Plus précisément, sur la pile on va alterner un état de l’AFD avec un symbole de la
grammaire (terminal ou non-terminal), en commençant avec l’état initial de l’AFD.
− Donc une configuration du driver LR est dorénavant de la forme
(I0X1I1 … XmIm , ti … tn$),
tel que Ij sont des états de l’AFD, Xj des symboles de la grammaire, et ti … tn le
reste des tokens à lire.
− Nous n’avons plus besoin de mettre le $ pour reconnaître le fond de la pile.
− L’état initial de l’AFD va remplir ce rôle.
17/05/2016
44
De l’idée à l’implémentation
− Une configuration (I0X1I1 … XmIm, ti … tn$) signifie que:
− l’AFD est actuellement dans l’état Im ,
− le long d’un chemin (trace) étiqueté X1 … Xm à partir de l’état initial I0,
− et le reste de l’entrée à scanner est ti… tn.
− Ainsi, si Xj … Xm, est une poignée, pour un j quelconque :
− Il doit y avoir un élément « A→ Xj … Xm . » dans l’état Im.
− Dans ce cas, on fait une réduction en remplaçant Xj … Xm par A sur la pile.
− Plus précisément, on enlève Xj Ij … XmIm de la pile, et on ajoute AI’ tel que I’ est l’état
retourné par goto(Ij-1, A).
− La suppression de XjIj … XmIm
le long du chemin Xj … Xm.
17/05/2016
de la pile revient à un retour arrière (backtracking) dans l’AFD,
45
Analyseur LR(0) (1/2)
− Un analyseur (syntaxique) LR(0) n’a pas besoin d’anticiper le prochain token
(lookahead) pour prendre une décision shift ou reduce.
− Il décide de l’action appropriée (shift ou reduce) seulement en fonction de l’état
courant de l’AFD pour les préfixes viables.
− Ce comportement est reflété par la version suivante de l’analyseur LR(0).
Algorithm LR0Parser
Input: stream of tokens
Output: a derivation sequence
Variables: stack (pile), a (prochain token), in (entrée : flux de tokens)
AFD pour préfixes viables, avec état initial I0 et fonction de transition goto
Initialement la pile contient I0
17/05/2016
46
Analyseur LR(0) (2/2)
while (true) {
if (la pile contient I0S’ et l’entrée est $ (vide)) return true;
if (l’état au sommet de la pile contient un élément A → α . ) {
reduce with the production A → α; // α est une poignée et A → α la production correspondante
c.-à-d. : Supprimer 2⋅|α| symboles de la pile (|α| états et |α| symboles de grammaires).
Soit I le nouvel état au sommet de la pile.
Ajouter A au sommet de la pile.
Ajouter l’état retourné par goto(I,A) au sommet de la pile.
print out the production A → α;
continue;
}
if (l’état au sommet de la pile contient un élément A → α . aβ tel que a est un token) {
shift;
c.-à-d. : Soit I l’état au sommet de la pile.
Lire le prochain token a.
Ajouter a au sommet de la pile.
Ajouter l’état retourné par goto(I,a) au sommet de la pile.
continue;
}
error();
}
17/05/2016
47
Exemple
I0
E’→ .Ε
E→ .E+T
E→ .Τ
T→.T*F
T→ .F
F→ .(E)
F→.num
I1
E’→ Ε.
E→ E.+T
I2
E→ Τ.
T→ T.*F
I3
T→ F.
I4
F→ (.E)
E→ .E+T
E→ .Τ
T→.T*F
T→ .F
F→ .(E)
F→ .num
I7
T→T*.F
F→ .(E)
F→.num
I5
F→ num.
I9
E→ E+T.
T→T.*F
I6
E→ E+.T
T→ .T*F
T→ .F
F→ .(E)
F→.num
E
I0
T
I6
I9
F
(
F
*
I2
I10
(
I3
(
I0
T→T*F.
num
E
)
I8
T
num
I5
to I4
to I5
(
I4
num
to I7
to I4
to I5
F
I7
*
to I3
num
T
I8
F→ (E.)
E→ E.+T
I11
F→ (E).
+
I1
F
I11
+
to I6
to I2
to I3
17/05/2016
48
Exemple 1
E
I0
+
I1
T
I6
I9
F
(
F
*
I2
to I4
to I5
F
I7
I10
(
I3
(
num
num
E
T
num
I5
)
I8
F
Trace
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
(I0,
(I0(I4,
(I0(I4numI5,
(I0(I4FI3,
(I0(I4TI2,
(I0(I4EI8,
(I0(I4EI8)I11,
(I0FI3,
(I0TI2,
(I0EI1,
(I0E’,
(num)$)
num)$)
)$)
)$)
)$)
)$)
$)
$)
$)
$)
$)
Shift T→ .(E)
Shift T→ .num
Reduce F→ num.
Reduce T→ F.
Reduce E→ T.
Shift F→ (E.)
Reduce F→ (E).
Reduce T→ F.
Reduce E→ T.
Reduce E’→ E.
Accept
I11
+
to I2
to I3
17/05/2016
to I4
to I5
(
I4
to I7
to I3
num
T
*
to I6
Dérivation correspondante :
(num) <= (num) <= (num) <= (F) <= (T) <=
(E) <= (E) <= F <= T <= E <= E’
49
Exemple 2
Même entrée, mais à l’étape 9, on résoud le conflit en faveur de Shift
E
I0
+
I1
T
I6
I9
F
(
F
*
I2
to I4
to I5
F
I7
I10
(
I3
(
num
E
)
I8
T
num
I5
to I4
Trace
1.
2.
3.
4.
5.
6.
(I0,
(I0(I4,
(I0(I4numI5,
(I0(I4FI3,
(I0(I4TI2,
(I0(I4TI2),
(num)$)
num)$)
)$)
)$)
)$)
$)
Shift T→ .(E)
Shift T→ .num
Reduce F→ num.
Reduce T→ F.
Shift T→ T.*F
Error goto(I2, ‘)’)
non défini.
to I5
(
I4
num
to I7
to I3
num
T
*
F
I11
+
to I6
to I2
to I3
17/05/2016
50
Exemple 3
Une entrée différente
E
I0
+
I1
T
I6
I9
F
(
F
*
I2
to I4
to I5
F
I7
I10
(
I3
(
num
num
(
I4
E
T
num
I5
)
I8
F
to I7
to I3
num
T
*
Trace :
1.
2.
3.
4.
5.
(I0,
(I0(I4,
(I0(I4numI5,
(I0(I4FI3,
(I0(I4TI2,
(num*num)$)
num*num)$)
*num)$)
*num)$)
*num)$)
Shift T→ .(E)
Shift T→ .num
Reduce F→num.
Reduce T→ F.
…
to I4
Poursuivre comme exercice …
to I5
Remarquer le conflit Shift/Reduce à l’étape 5. L’état
I2 contient élément Shift (T → T.*F) et un élément
Reduce (E → T.).
I11
+
to I2
to I6
Contrairement à l’exemple précédent, cette fois-ci le
conflit devrait être réglé en faveur de Shift. Pourquoi?
to I3
17/05/2016
51
Analyseurs SRL(1)
17/05/2016
52
Sujets
• Algorithme générique pour l’analyse LR (Driver LR)
• Table d’analyse SLR(1).
17/05/2016
53
Objectifs
• Pouvoir définir et simuler l’algorithme d’analyse LR (Driver LR)
• Pouvoir générer une table d’analyse SLR(1) pour une grammaire
donnée.
• Pouvoir reconnaître les grammaires SLR(1).
17/05/2016
54
Rappel : AFD LR(0)
I0
E’→ .Ε
E→ .E+T
E→ .Τ
T→.T*F
T→ .F
F→ .(E)
F→.num
I1
E’→ Ε.
E→ E.+T
I2
E→ Τ.
T→T.*F
I3
T→ F.
I4
F→ (.E)
E→ .E+T
E→ .Τ
T→.T*F
T→ .F
F→ .(E)
F→ .num
I5
F→ num.
I6
E→ E+.T
T→ .T*F
T→ .F
F→ .(E)
F→.num
I7
T→T*.F
F→ .(E)
F→.num
E
I0
T
I6
I9
F
(
F
*
I2
I10
(
I9
E→ E+T.
T→T.*F
I3
(
I0
T→T*F.
num
E
)
I8
T
num
I5
to I4
to I5
(
I4
num
to I7
to I4
to I5
F
I7
*
to I3
num
T
I8
F→ (E.)
E→ E.+T
I11
F→ (E).
+
I1
F
I11
+
to I6
to I2
to I3
17/05/2016
55
Rappel : Analyseur LR(0)
− Un analyseur (syntaxique) LR(0) n’a pas besoin d’anticiper le prochain token
(lookahead) pour prendre une décision shift ou reduce.
− Il décide de l’action appropriée (shift ou reduce) seulement en fonction de l’état
courant de l’AFD pour les préfixes viables.
− Ce comportement est reflété par la version suivante de l’analyseur LR(0).
Algorithm LR0Parser.
Entrée : flux de tokens
Sortie : dérivation de l’entrée ou erreur.
Variables: stack (pile), a (prochain token), in (entrée : flux de tokens)
AFD pour préfixes viables, avec état initial I0 et fonction de transition goto
Initialement la pile contient I0
17/05/2016
56
Rappel : Analyseur LR(0)
while (true) {
if (la pile contient I0S’ et l’entrée est $ (vide)) return true;
if (l’état au sommet de la pile contient un élément A → α . ) {
reduce with the production A → α; // α est une poignée et A → α la production correspondante
c.-à-d. : Supprimer 2⋅|α| symboles de la pile (|α| états et |α| symboles de grammaires).
Soit I le nouvel état au sommet de la pile.
Ajouter A au sommet de la pile.
Ajouter l’état retourné par goto(I,A) au sommet de la pile.
print out the production A → α;
continue;
}
if (l’état au sommet de la pile contient un élément A → α . aβ tel que a est un token) {
shift;
c.-à-d. : Soit I l’état au sommet de la pile.
Lire le prochain token a.
Ajouter a au sommet de la pile.
Ajouter l’état retourné par goto(I,a) au sommet de la pile.
continue;
}
error();
}
17/05/2016
57
Rappel : Grammaires LR(0)
− Un élément shift (shift item) est un élément de la forme « A → α . aβ »€ tel que a
est un terminal.
− Un élément reduce (reduce item) est un élément de la forme « A → α . »
− Si l’AFD LR(0) a un état contenant à la fois un élément shift et un élément reduce,
ou plus d’un élément reduce, alors la grammaire correspondante n’est pas LR(0).
Par exemple, la grammaire précédente n’est pas LR(0) parce que les états I1, I2
et I9 contiennent des conflits Shift/Reduce.
− Un analyseur LR(0) fonctionne correctement uniquement pour des grammaires
LR(0).
17/05/2016
58
Exemple de grammaire LR(0)
S’→ S
1. S → E;
2. E → E + T
3. E → T
4. T → (E)
5. T → num
Terminaux : num, ‘+’ et‘;’
(habituellement non numérotée; production interne)
− La terminaison de l’entrée ‘;’ fait partie des terminaux. Sans elle, la grammaire n’est
plus LR(0).
− Pour montrer que la grammaire est LR(0), on construit l’AFD pour les préfixes viables
et on vérifie qu’aucun état ne contient à la fois d’éléments shift et d’élément reduce, ou
plus d’un élément reduce.
− Ci-après on donne aussi une simulation de l’analyseur LR(0) pour l’entrée ‘3 + 6;’, ce
qui correspond au flot de tokens ‘num + num;’
17/05/2016
59
AFD LR(0)
I0
S’→ .S
S→ .Ε;
E→ .E+T
E→ .Τ
T→ .(E)
T→ .num
I1
S→ Ε .;
E→ E .+T
I2
S→ E;.
17/05/2016
I3
E→ E+.T
T→ .(E)
T→ .num
I4
E→ E+T.
I7
T→ (E .)
E→ E .+T
I9
num
E
I5
S
I10 num
I8
F→ (E).
I5
T→ num.
I6
T→ (.E)
E→ .E+T
E→ .Τ
T→ .(E)
T→ .num
T
I0
I1
;
I3
T
I2
I9
E→T.
+
(
num
(
+
T
(
I6
E
I7
)
I4
I8
I10
S’→ S.
60
AFD + simulation de l’analyseur LR(0) avec une entrée
correcte
I0
S’→ . S
S→ .Ε;
E→ .E+T
E→ .Τ
T→ .(E)
T→ .num
I1
S→ Ε .;
E→ E .+T
I6
T→ (.E)
E→ .E+T
E→ .Τ
T→ .(E)
T→ .num
I2
S→ E;.
I7
T→ (E .)
E→ E .+T
I3
E→ E+.T
T→ .(E)
T→ .num
I4
E→ E+T.
17/05/2016
T
I5
T→ num.
I8
F→ (E).
I9
E→T.
I9
I0
num
E
I5
S
I10 num
I1
;
+
I3
T
I2
(
num
(
+
T
(
I6
E
1. (I0,
num+num;$)
2. (I0numI5,
+num;$)
3. (I0TI9,
+num;$)
4. (I0EI1,
+num;$)
5. (I0EI1+I3,
num;$)
6. (I0EI1+I3numI5,
;$)
7. (I0EI1+I3TI4,
;$)
8. (I0EI1,
;$)
9. (I0EI1;I2,
$)
10. (I0SI10,
$)
Shift
Reduce
Reduce
Shift
Shift
Reduce
Reduce
Shift
Reduce
Accept.
I7
)
I4
I8
Dérivation correspondante :
num + num; <= num+ num; <=
T + num; <= E + num <= E + num; <=
E + num; <= E + T; <= E; <= E; <= E’
I10
S’→ S.
61
AFD + simulation de l’analyseur LR(0) avec une entrée
erronée
I0
S’→ . S
S→ .Ε;
E→ .E+T
E→ .Τ
T→ .(E)
T→ .num
I5
T→ num.
I1
S→ Ε .;
E→ E .+T
I2
S→ E;.
I7
T→ (E .)
E→ E .+T
I4
E→ E+T.
17/05/2016
I9
I0
num
I6
T→ (.E)
E→ .E+T
E→ .Τ
T→ .(E)
T→ .num
I3
E→ E+.T
T→ .(E)
T→ .num
T
I8
F→ (E).
E
I5
S
I10 num
I1
;
+
I3
T
I2
(
num
(
+
T
(
I6
E
1.
2.
3.
4.
5.
6.
(I0,
num++num;$) Shift
(I0numI5,
++num;$) Reduce
(I0TI9,
++num;$) Reduce
(I0EI1,
++num;$) Shift
(I0EI1+I3,
+num;$) Shift
(I0EI1+I3+,
;$)
Error during
reduction : goto(I3,+) is not
defined.
I7
)
I4
I8
I9
E→T.
I10
S’→ S.
62
Vers un pilote pour Analyseur LR (1)
−
L’exemple précédent montre que lorsqu’on a une entrée erronée :
− L’analyseur LR(0) peut empiler (shift) le prochain token même s’il est erroné.
− Mais il va se rendre compte que le token est erroné plus tard, durant la réduction.
− En fait, en général, l’erreur peut être détectée après avoir empilé quelques tokens de plus
au-delà du token fautif.
−
Nous allons voir une variante de l’analyseur LR(0) qui fait shift uniquement si le prochain
token a un élément shift correspondant dans l’état courant de l’AFD.
− Techniquement parlant, ceci n’est pas un analyseur LR(0), puisqu’il consulte le prochain
token avant de décider de faire shift. C’est un anaylseur LR(1).
− Néanmoins, cette version est équivalente à l’analyseur LR(0), mis à part le fait qu’elle
permet de détecter des erreurs plus tôt. Avec l’exemple précédent, l’erreur serait détectée à
l’étape 5 lorsqu’on essaie d’empiler (shift) le ‘+’.
−
Nous décrivons cette variante parce qu’elle permet une bonne transition vers l’analyseur LR(1)
général qui nous intéresse le plus.
17/05/2016
63
Analyseur LR(1) équivalent à l’analyseur LR(0)
while (true) { // Version 2
if (la pile contient I0S’ et l’entrée est $ (vide)) return true;
if (l’état au sommet de la pile contient un élément A → α . ) {
reduce with the production A → α; // α est une poignée et A → α la production correspondante
c.-à-d. : Supprimer 2⋅|α| symboles de la pile (|α| états et |α| symboles de grammaires).
Soit I le nouvel état au sommet de la pile.
Ajouter A au sommet de la pile.
Ajouter l’état retourné par goto(I,A) au sommet de la pile.
print out the production A → α;
continue;
}
if (l’état au sommet de la pile contient un élément A → α . aβ tel que a est le prochain token) {
shift;
c.-à-d. : Soit I l’état au sommet de la pile.
Lire le prochain token a.
Ajouter a au sommet de la pile.
Ajouter l’état retourné par goto(I,a) au sommet de la pile.
continue;
}
error();
}
17/05/2016
64
Exemple revisité avec le nouvel algorithme
I0
S’→ . S
S→ .Ε;
E→ .E+T
E→ .Τ
T→ .(E)
T→ .num
I5
T→ num.
I1
S→ Ε .;
E→ E .+T
I2
S→ E;.
I7
T→ (E .)
E→ E .+T
I4
E→ E+T.
17/05/2016
I8
F→ (E).
E
I5
S
I10 num
I1
;
+
I3
T
I2
1.
2.
3.
4.
5.
I9
I0
num
I6
T→ (.E)
E→ .E+T
E→ .Τ
T→ .(E)
T→ .num
I3
E→ E+.T
T→ .(E)
T→ .num
T
(
num
(
+
T
(
I6
(I0,
num++num;$) Shift
(I0numI5,
++num;$) Reduce
(I0TI9,
++num;$) Reduce
(I0EI1,
++num;$) Shift
(I0EI1+I3,
+num;$) Error
during reduction : cannot shift ‘+’
in state I3.
E
I7
)
I4
I8
I9
E→T.
I10
S’→ S.
65
Tables d’analyse LR(0) 1/2
– On peut améliorer les deux ébauches d’analyseurs LR(0) précédents, en
utilisant une table pour implémenter l’AFD pour les préfixes viables.
– L’idée est que l’action shift aussi bien que l’action reduce dépend
seulement de l’état de l’AFD au sommet de la pile. Tout ce dont on a
besoin de savoir pour cet état c’est s’il contient :
• (a) un élément de la forme A → α . , et dans ce cas on fait reduce;
• (b) ou un élément de la forme A → α . aβ , et dans ce cas on fait shift;
– On peut mettre ces information dans une table annexée avec la fonction de
transition de l’AFD, goto.
– De cette façon, on peut utiliser un algorithme d’analyse LR universel,
piloté par la table d’analyse.
17/05/2016
66
Tables d’analyse LR(0) avec lookahead
– Avec lookhead, la table est indexée par l’état de l’AFD et le prochain token.
– L’entrée dans la table est un symbole désignant l’action (shift ou reduce)
et/ou l’état successeur pour la fonction goto.
– Nous utilisons les conventions suivantes pour la spécification des tables :
• si signifie ‘Fait shift ensuite empile l’état i’ (c.-à-d., action shif et goto état i);
• ri signifie ‘Fait reduce avec la production numéro i’;
• acc signifie accepte l’entrée;
• une entrée vide signifie que l’analyseur doit signaler une erreur.
17/05/2016
67
Construire la table d’analyse LR(0) avec lookahead 1/2
Algorithm construire la table d’analyse LR(0) avec lookahead
Entrée : Une grammaire augmentée G, avec le symbole de départ S’;
Sortie : Table d’analyse LR(0) avec lookahead;
Méthode :
1. Construire l’AFD pour les préfixes viables de G;
2. Nous notons i, l’état Ii. Les actions d’analyse pour l’état i sont déterminées comme suit :
a. Si un élément A → α . aβ, tel que a est un terminal, est dans Ii, avec goto(Ii , a) = j,
ajoute shift j dans action[i, a];
b. Si un élément A → α . est dans Ii , avec A différent de S’,
ajoute reduce A → α dans action[i, a], pour chaque terminal a;
c. Si l’élément S’ → S . est dans Ii ,
ajoute ‘accept’ dans action[i, $].
17/05/2016
68
Construire la table d’analyse LR(0) avec lookahead 2/2
3. Si goto(Ii, A) = Ij pour un non terminal A
goto[i, A] devient j ;
4. Toutes les entrées vides sont considérées comme ayant la valeur “erreur”.
5. L’état initial, 0, est celui construit à partir de l’état de l’AFD contenant l’élément S’ → . S
Si la table générée par cette algorithme contient des conflits, c.-à-d., des entrées avec
actions multiples, la grammaire correspondante n’est pas LR(0). Sinon, elle est LR(0).
17/05/2016
69
Exemple 1/2
1
2
3
4
5
I0
S’→ . S
S→ .Ε;
E→ .E+T
E→ .Τ
T→ .(E)
T→ .num
I5
T→ num.
I1
S→ Ε .;
E→ E .+T
I6
T→ (.E)
E→ .E+T
E→ .Τ
T→ .(E)
T→ .num
I2
S→ E;.
I7
T→ (E .)
E→ E .+T
I3
E→ E+.T
T→ .(E)
T→ .num
I4
E→ E+T.
17/05/2016
T
I9
I0
I8
T→ (E).
num
E
I5
S
I10 num
I1
;
+
I3
T
I2
(
num
(
+
T
(
I6
E
I7
)
I4
I8
I9
E→T.
I10
S’→ S.
70
Exemple 2/2
action/goto
T
I9
I0
num
E
I5
S
I10 num
I1
+
;
I3
T
I2
(
num
(
+
num
0
T
(
I6
E
I7
)
I4
I8
r1
3
s5
4
5
r2
r5
6
s5
)
r4
r3
;
$
s6
r1
S
10
E
T
1
9
s2
r1
r1
r1
r1
s6
r2
r5
r2
r5
4
r2
r5
r2
r5
r2
r5
s6
s3
7
10
(
s3
State 2
9
17/05/2016
s5
1
8
+
goto
r4
r3
7
9
s8
r4
r3
r4
r3
r4
r3
r4
r3
acc
71
Algorithme d’analyse LR (1) 1/2
Algorithm LR1Parser
Entrée : flux de tokens
Sortie : dérivation de l’entrée si elle est dans L(G), sinon erreur.
Variables : stack (pile), a (prochain token), in (entrée : flux de tokens)
i (sommet de la pile)
Table d’analyse LR(0) avec lookahead, ou SLR(1), ou LALR(1).
Méthode : Initialement la pile contient l’état 0.
Ensuite il exécute le code suivant.
17/05/2016
72
Algorithme d’analyse LR (1) 2/ 2
a = in.getNextToken();
while (true) {
i = state on top of stack;
if action[i,a] = shift j {
push a on top of the stack;
push j on top of the stack;
a = get.NextToken();
continue;
}
if action[i,a] = reduce A→α {
pop 2x|α| symbols off the stack;
i = the state now on top of the stack;
push A on top of stack;
push goto[i,A] on top of the stack;
printout the production A→α ;
continue;
}
if action[i,a] = accept
return true;
error();
}
17/05/2016
73
Exemple (Simulation de l’analyseur LR(1))
action/goto
num
0
s5
State 2
r1
3
s5
4
5
r2
r5
6
s5
S’→ S
1. S → Ε;
2. E → E+T
3. E → Τ
4. T → (E)
5. T → num
9
10
17/05/2016
)
r4
r3
;
$
s6
r1
S
10
E
T
1
9
s2
r1
r1
r1
r1
s6
r2
r5
r2
r5
4
r2
r5
r2
r5
r2
r5
s6
s3
7
8
(
s3
1
Grammar
+
goto
r4
r3
7
r4
r3
Shift
Reduce 5
Reduce 3
Shift
Shift
Reduce 5
Reduce 2
Shift
Reduce 1
Accept.
9
Corresponding derivation sequence:
s8
r4
r3
1. (0,
num+num;$)
2. (0 num 5,
+num;$)
3. (0 T 9,
+num;$)
4. (0 E 1,
+num;$)
5. (0 E 1 + 3,
num;$)
6. (0 E 1 + 3 num 5,
;$)
7. (0 E 1 + 3 T 4,
;$)
8. (0 E 1,
;$)
9. (0 E 1 ; 2,
$)
10. (0 S 10,
$)
r4
r3
r4
r3
acc
num + num; <= num+ num; <=
T + num; <= E + num <= E + num; <=
E + num; <= E + T; <= E; <= E; <= S
74
Forces et limites de l’analyse LR(0)
– On peut montrer que si un langage hors-contexte a un symbole spécifique
qui termine tous les mots du langage (comme le point virgule dans
l’exemple précédent), alors il existe une grammaire LR(0) équivalente.
– Remarquez que les langages de programmation sont en pratique des
langages hors-contexte et terminent par une fin de fichier. Donc,
théoriquement, on pourrait les analyser par un analyseur LR(0).
– Cependant, la grammaire LR(0) en question pourrait être très large, difficile
à lire et peu efficace. Mais il en existe une.
– En pratique on préfère des parsers LR qui utilise un lookahead, parce
qu’ils exigent des grammaires plus simples.
17/05/2016
75
Exemple de grammaire non LR(0)
− Un grand nombre de grammaires intéressantes ne sont pas LR(0) même si elles ne
sont pas ambiguës.
− Par exemple, la grammaire suivante pour les expressions arithmétiques n’est pas
LR(0):
E’ → E
1. E → E+T
2. E → T
3. T → T*F
4. T →F
5. F → (E)
6. F→ num
(non numéroté parce que c’est une production interne)
− Pour montrer que la grammaire n’est pas LR(0), on montre que l’AFD correspondant
pour les préfixes viables a au moins un état contenant à la fois un élément shift et un
élément reduce ou plus d’un élément reduce. Conséquemment la table d’analyse
correspondante aurait des entrées multiples.
17/05/2016
76
AFD pour préfixes viables
I0
E’→ .Ε
1 E→ .E+T
2 E→ .Τ
3 T→.T*F
4 T→ .F
5 F→ .(E)
6 F→.num
I4
F→ (.E)
E→ .E+T
E→ .Τ
T→.T*F
T→ .F
F→ .(E)
F→ .num
I7
T→T*.F
F→ .(E)
F→.num
I1
E’→ Ε.
E→ E.+T
I5
F→ num.
I9
E→ E+T.
T→T.*F
I2
E→ Τ.
T→T.*F
I3
T→ F.
I6
E→ E+.T
T→ .T*F
T→ .F
F→ .(E)
F→.num
E
I0
+
I1
T
I6
I9
F
(
I8
F→ (E.)
E→ E.+T
F
*
I2
to I4
to I5
F
I7
I10
(
I3
(
I0
T→T*F.
I11
F→ (E).
num
E
)
I8
T
num
I5
to I4
to I5
(
I4
num
to I7
to I3
num
T
*
F
I11
+
to I6
to I2
to I3
17/05/2016
77
Table d’analyse LR(0)
E
I0
+
I1
T
I6
I9
F
(
F
*
I2
(
I10
num
num
to I4
4
5
6
E
)
I8
T
num
I5
0
1
3
to I5
(
I4
num
State
2
(
I3
to I7
to I4
to I5
F
I7
actions / goto
to I3
num
T
*
F
+
to I2
to I6
9
11
*
s5
r2
r4
s5
r6
s5
s5
8
10
to I3
17/05/2016
7
I11
+
r1
r3
r5
(
goto
)
$
T
F
1
2
3
s4
E
s6
r2
r4
r6
s6
r1
r3
r5
s7
r2
r4
r6
s7
r1
r3
r5
r2
r4
s4
r6
s4
s4
r1
r3
r5
r2
r4
acc
r2
r4
8
r6
2
3
9
3
r6
10
s11
r1 r1
r3 r3
r5 r5
78
Analyse LR(1)
–
Puisque les analyseurs LR(0) n’utilisent pas de lookahead, ils ne peuvent pas
analyser efficacement les langages pratiques en programmation.
–
Les analyseurs LR(1) généralisent les analyseurs LR(0) en introduisant un
lookahead dans les tables d’analyse, un peu comme dans la version de l’analyseur
LR(0) avec lookahead.
–
La différence est que dans le cas d’un analyseur LR(1), le lookahead est non
seulement impliqué dans la décision de faire l’action shift, mais aussi dans la
décision de faire l’action reduce.
17/05/2016
79
Analyse LR(1)
–
Les analyseurs LR(1) les plus populaires sont SLR(1) et LALR(1).
–
SLR(1) signifie “simple” LR(1). Techniquement, c’est une simple modification de l’analyseur
LR(0) avec lookahead.
➢ La modification est très simple mais significative : on obtient un analyseur presque aussi
puissant qu’un analyseur LR(1) complet.
–
LALR(1) signifie “Look Ahead LR(1)”.
– Il est légèrement plus puissant que SLR(1).
– L’appellation “LALR” peut paraître inappropriée vu que SLR(1), aussi bien que tout
autre analyseur LR(1), utilise aussi un lookahead.
– En fait, en disant “Look Ahead LR(1),” le “Look Ahead” réfère à l’AFD pour les préfixes
viables : dans un analyseur LALR(1), l’AFD est composé des éléments qui sont associés
avec un lookahead, alors que ce n’est pas le cas ni dans l’analyse SLR(1) ni dans
l’analyse LR(0) avec lookahead.
17/05/2016
80
Construire la table d’analyse SLR(1) 1/2
Algorithm construire la table d’analyse SLR(1)
Entrée : Une grammaire augmentée G, avec le symbole de départ S’;
Sortie : Table d’analyse SLR(1);
Méthode :
1. Construire l’AFD pour les préfixes viables de G;
2. Nous notons i, l’état Ii. Les actions d’analyse pour l’état i sont déterminées comme suit :
a. Si un élément A → α . aβ, tel que a est un terminal, est dans Ii et goto(Ii , a) est défini,
ajoute shift dans action[i, a];
b. Si un élément A → α . est dans Ii , avec A différent de S’,
ajoute reduce A → α dans action[i, a], pour chaque terminal a dans Follow(A);
c. Si l’élément S’ → S . est dans Ii ,
ajoute ‘accept’ dans action[i, $].
17/05/2016
81
Construire la table d’analyse SLR(1) 2/2
3. Si goto(Ii, A) = Ij pour un non terminal A
goto[i, A] devient j ;
4. Toutes les entrées vides sont considérées comme ayant la valeur “erreur”.
5. L’état initial, 0, est celui construit à partir de l’état de l’AFD contenant l’élément S’ → . S
−
Si la table générée par cette algorithme contient des conflits, c.-à-d., des entrées avec des actions
multiples, la grammaire correspondante n’est pas SLR(1).
−
L’algorithme d’analyse demeure le même que le précédent (seule la table change).
−
Un analyseur SLR(1) est un analyseur qui utilise une table SLR(1). Dans ce cas on omet en
général le suffixe (1) puisqu’on ne s’intéresse pratiquement pas à des analyseurs SLR(k) avec
k>1.
17/05/2016
82
Exemple
I0
E’→ .Ε
1 E→ .E+T
2 E→ .Τ
3 T→.T*F
4 T→ .F
5 F→ .(E)
6 F→.num
I4
F→ (.E)
E→ .E+T
E→ .Τ
T→.T*F
T→ .F
F→ .(E)
F→ .num
I7
T→T*.F
F→ .(E)
F→.num
I1
E’→ Ε.
E→ E.+T
I5
F→ num.
I9
E→ E+T.
T→T.*F
I2
E→ Τ.
T→T.*F
I3
T→ F.
I6
E→ E+.T
T→ .T*F
T→ .F
F→ .(E)
F→.num
E
I0
+
I1
T
I6
I9
F
(
I8
F→ (E.)
E→ E.+T
F
*
I2
to I4
to I5
F
I7
I10
(
I3
(
I0
T→T*F.
I11
F→ (E).
num
E
)
I8
T
num
I5
to I4
to I5
(
I4
num
to I7
to I3
num
T
*
F
I11
+
to I6
to I2
to I3
17/05/2016
83
Table d’analyse SLR(1)
E
I0
+
I1
T
I6
I9
F
(
F
*
I2
to I4
to I5
F
I7
I3
(
to I4
4
5
6
E
)
I8
T
num
I5
0
1
F
7
I11
+
to I2
to I3
to I6
8
9
10
11
17/05/2016
+
*
s5
(
goto
)
$
E
T
F
1
2
3
s4
s6
r2
r4
3
to I5
(
I4
num
num
num
State
2
I10
(
actions / goto
to I7
to I3
num
T
*
s7
r4
s5
r2
r4
acc
r2
r4
s4
r6
r6
s5
s5
8
r6
s7
r3
r5
3
9
3
r6
s4
s4
s6
r1
r3
r5
2
10
s11
r1 r1
r3 r3
r5 r5
84
Simulation
actions / goto
num
0
1
7
8
9
10
11
(
)
$
s7
r4
s5
r2
r4
T
F
1
2
3
acc
r2
r4
s4
r6
r6
s5
s5
8
r6
s7
r3
r5
17/05/2016
2
3
r6
s4
s4
s6
r1
r3
r5
Exemple d’exécution :
E
s4
s6
r2
r4
3
6
*
s5
2
4
5
+
goto
9
(0,
(0 ( 4,
(0 ( 4 num 5,
(0 ( 4 F 3,
(0 ( 4 T 2,
(0 ( 4 E 8,
(0 ( 4 E 8 ) 11,
(0 F 3,
(0 T 2,
(0 E 1,
(num)$)
num)$)
)$)
)$)
)$)
)$)
$)
$)
$)
$)
s4
s5
r6: F→ num.
r4: T→ F.
r2: E→ T.
s11
r5: F→ (E).
r4: T→ F.
r2: E→ T.
accept
3
10
s11
r1 r1
r3 r3
r5 r5
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
Dérivation correspondante
(num) <= (num) <= (num) <= (F) <= (T)
<= (E) <= (E) <= F <= T <= E
85
Optionnel
ALGORITHME D’ANALYSE LR(0)
SANS LOOKAHEAD
17/05/2016
86
Tables d’analyse LR(0) sans Lookahead
–
En principle, pour l’analyse LR(0), on a pas besoin de lookahead. On aurait pu
donc formule l’analyse LR(0) sans lookahead.
–
Sans lookahead, la table d’analyse est indexée seulement par l’état de l’AFD.
–
Nous utilisons les conventions suivantes pour la spécification des tables :
• s signifie ‘Fait shift’ (utilisé seulement dans les tables sans lookahead); On n’a plus
besoin de si c.à`d. ‘Fait shift ensuite empile l’état i’ (c.-à-d., action shif et goto état
i);
• ri signifie encore ‘Fait reduce avec la production numéro i’;
• acc signifie accepte l’entrée;
• une entrée vide signifie que l’analyseur doit signaler une erreur.
17/05/2016
87
Construire la table d’analyse LR(0) sans lookahead 1/2
Algorithm construire la table d’analyse LR(0) sans lookahead
Entrée : Une grammaire augmentée G, avec le symbole de départ S’;
Sortie : Table d’analyse LR(0) sans lookahead;
Méthode :
1. Construire l’AFD pour les préfixes viables de G;
2. Nous notons i, l’état Ii. Les actions d’analyse pour l’état i sont déterminées comme suit :
a. Si un élément A → α . aβ, tel que a est un terminal, est dans Ii et goto(Ii , a) est défini,
ajoute shift dans action[i];
b. Si un élément A → α . est dans Ii , avec A différent de S’,
ajoute reduce A → α dans action[i];
c. Si l’élément S’ → S . est dans Ii ,
ajoute ‘accept’ dans action[i].
17/05/2016
88
Construire la table d’analyse LR(0) sans lookahead) 2/2
3. Si goto(Ii, A) = Ij pour un non terminal A
goto[i, A] devient j ;
4. Toutes les entrées vides sont considérées comme ayant la valeur “erreur”.
5. L’état initial, 0, est celui construit à partir de l’état de l’AFD contenant l’élément S’ → . S
Si la table générée par cette algorithme contient des conflits, c.-à-d., des entrées avec
des actions multiples, la grammaire correspondante n’est pas LR(0). Sinon, elle est
LR(0).
17/05/2016
89
Exemple 1/2
1
2
3
4
5
I0
S’→ . S
S→ .Ε;
E→ .E+T
E→ .Τ
T→ .(E)
T→ .num
I5
T→ num.
I1
S→ Ε .;
E→ E .+T
I2
S→ E;.
I7
T→ (E .)
E→ E .+T
I4
E→ E+T.
17/05/2016
I9
I0
num
I6
T→ (.E)
E→ .E+T
E→ .Τ
T→ .(E)
T→ .num
I3
E→ E+.T
T→ .(E)
T→ .num
T
I8
T→ (E).
E
I5
S
I10 num
I1
;
+
I3
T
I2
(
num
(
+
T
(
I6
E
I7
)
I4
I8
I9
E→T.
I10
S’→ S.
90
Exemple 2/2
T
I9
I0
num
E
I5
S
I10 num
I1
+
;
I3
T
I2
(
num
(
+
num
T
0
(
I6
E
1
State 2
3
I7
4
)
I4
I8
5
6
7
8
9
10
17/05/2016
goto
action
s
s
r1
s
r2
r5
s
s
r4
r3
acc
+
5
(
)
;
6
10
3
E
T
1
9
2
5
6
5
6
3
S
4
7
9
8
91
Algorithme d’analyse LR(0) avec table d’analyse sans
lookahead (1/2)
Algorithm LR0ParserWithTable
Entrée : flux de tokens
Sortie : dérivation de l’entrée si elle est dans L(G), sinon erreur.
Variables : stack (pile), a (prochain token), in (entrée : flux de tokens)
i (sommet de la pile)
Table d’analyse LR(0) sans lookahead.
Méthode : Initialement la pile contient 0 (c-.à-d., état 0).
Ensuite il exécute le code suivant.
17/05/2016
92
Algorithme d’analyse LR(0) avec table d’analyse sans
lookahead (2/2)
while (true) {
i = state on top of stack;
if action[i] = shift {
a = in.getNextToken();
// Ceci avance la tête de lecture.
push a on top of the stack;
push goto[i,a] on top of the stack;
continue;
}
if action[I] = reduce A→α {
pop 2x|α | symbols off the stack;
i = the state now on top of the stack;
push A on top of stack;
push goto[i,A] on top of the stack;
printout the production A→α ;
continue;
}
if action[i] = accept and the input is empty
return true;
error();
}
17/05/2016
93
Exemple (simulation de l’analyseur LR(0))
action
num
0
1
State 2
3
4
Grammar
S’→ S
1. S → Ε;
2. E → E+T
3. E → Τ
4. T → (E)
5. T → num
5
6
7
8
9
10
s
s
r1
s
r2
r5
s
s
r4
r3
acc
+
5
(
)
;
6
10
3
E
T
1
9
2
5
6
5
6
3
S
4
8
8
9
1. (0,
num+num;$)
2. (0 num 5,
+num;$)
3. (0 T 9,
+num;$)
4. (0 E 1,
+num;$)
5. (0 E 1 + 3,
num;$)
6. (0 E 1 + 3 num 5,
;$)
7. (0 E 1 + 3 T 4,
;$)
8. (0 E 1,
;$)
9. (0 E 1 ; 2,
$)
10. (0 S 10,
$)
Shift
Reduce 5
Reduce 3
Shift
Shift
Reduce 5
Reduce 2
Shift
Reduce 1
Accept.
Dérivation correspondante :
num + num; <= num+ num; <=
T + num; <= E + num <= E + num; <=
E + num; <= E + T; <= E; <= E; <= S
17/05/2016
94
Rappel : Algorithme d’analyse LR (1) 1/2
Algorithm LR1Parser
Entrée : flux de tokens
Sortie : dérivation de l’entrée si elle est dans L(G), sinon erreur.
Variables : stack (pile), a (prochain token), in (entrée : flux de tokens)
i (sommet de la pile)
Table d’analyse LR(0) avec lookahead, ou SLR(1), ou LALR(1).
Méthode : Initialement la pile contient l’état 0.
Ensuite il exécute le code suivant.
95
Rappel : Algorithme d’analyse LR (1) 2/ 2
a = in.getNextToken();
while (true) {
i = state on top of stack;
if action[i,a] = shift j {
push a on top of the stack;
push j on top of the stack;
a = get.NextToken();
continue;
}
if action[i,a] = reduce A→α {
pop 2x|α| symbols off the stack;
i = the state now on top of the stack;
push A on top of stack;
push goto[i,A] on top of the stack;
printout the production A→α ;
continue;
}
if action[i,a] = accept
return true;
error();
}
96
Rappel : Table d’analyse SLR(1)
Algorithm construire la table d’analyse SLR(1)
Entrée : Une grammaire augmentée G, avec le symbole de départ S’;
Sortie : Table d’analyse SLR(1);
Méthode :
1. Construire l’AFD LR(0) de G;
2. Nous notons i, l’état Ii. Les actions d’analyse pour l’état i sont déterminées comme suit :
a. Si un élément A → α . aβ, tel que a est un terminal, est dans Ii et goto(Ii , a) = Ij,
ajoute ‘shift j’ dans action[i, a];
b. Si un élément A → α . est dans Ii , avec A différent de S’,
ajoute reduce A → α dans action[i, a], pour chaque terminal a dans Follow(A);
c. Si l’élément S’ → S . est dans Ii ,
ajoute ‘accept’ dans action[i, $].
97
Rappel : Table d’analyse SLR(1)
3. Si goto(Ii, A) = Ij pour un non terminal A
goto[i, A] devient j ;
4. Toutes les entrées vides sont considérées comme ayant la valeur “erreur”.
5. L’état initial, 0, est celui construit à partir de l’état de l’AFD contenant l’élément
S’ → . S
− Si la table générée par cette algorithme contient des conflits, c.-à-d., des entrées avec
actions multiples, la grammaire correspondante n’est pas SLR(1).
− Un analyseur SLR(1) est un analyseur qui utilise une table SLR(1).
98
Exemple
–
Grammaire illustrant l’accès au contenu d’une adresse donnée par un pointeur dans
le langage C :
0.
1.
2.
3.
4.
5.
S’→ S
S→L=R
S→R
L→*R
L → id
R→L
Les terminaux sont : id, = et *.
– On peut interpréter les symboles L et R, respectivement comme étant la « L-value »
et la « R-value »; et * l’opérateur “contenu de”. Exemple: *x = y.
99
Table SLR(1)
AFD LR(0)
actions / goto
conflit shift/reduce
9
S→ L=R.
R
L
R
S
I1
S’→ S.
I7
L→*R.
0
S’→ .S
S→ .L=R
S→ . R
L→.*R
L→ .id
R→ .L
=
2
S→ L.=R
R→ L.
3
S→ R.
id
id
5
L→ id.
L
id
*
R
*
I6
S→ L=.R
R→ .L
L→.*R
L→ .id
4
L→*.R
R→ .L
L→.*R
L→ .id
*
L
id
*
0
1
2
3
s5 s4
4
5
6
7
8
9
s5 s4
=
$
goto
S
R L
1
3
2
acc
s6 r5 r5
r2
r4
8
R→ L.
1.
2.
3.
4.
5.
8
9
8
r4
s5 s4
r3
r5
7
r3
r5
r1
S→L=R
S→R
L→*R
L → id
R→L
100
Simulation
actions / goto
id
*
0
1
2
3
s5 s4
4
5
6
7
8
9
s5 s4
=
$
goto
S
R L
1
3
(0,
*id = id $)
(0 * 4,
id = id $)
(0 * 4 id 5,
= id $)
(0 * 4 L 8,
= id $)
(0 * 4 R 7,
= id $)
(0 L 2,
= id $)
2
acc
s6 r5 r5
r2
7
r4
r4
s5 s4
Conflit
r3
r5
r1
2
S→ L.=R
R→ L.
S→L=R
S→R
L→*R
L → id
R→L
conflit shift/reduce
shift
reduce
9
r3
r5
8
1.
2.
3.
4.
5.
8
(0 R 3,
= id $)
Error: no entry [3, =]
in table
(0 L 2 = 6,
id $)
(0 L 2 = 6 id 5,
$)
(0 L 2 = 6 L 8,
$)
(0 L 2 = 6 R 9,
$)
(0 S 1,
$)
Accepte
101
De SLR(1) à LR(1)
–
Dans SLR(1) lorsque l’état au sommet de la pile contient l’élément A → α . et que
le prochain token est dans Follow(A), on fait une réduction de α sur la pile.
–
Cette décision est trop approximative pour deux raisons :
– Follow(A) est l’union de tous les tokens qui peuvent suivre A, en tenant compte
de toutes les productions qui commencent par A, pas juste la production A → α
pour laquelle on a l’élément A → α .
– On ne devrait pas regarder juste A, mais le préfixe viable sur la pile (δΑ) pour
s’assurer que δΑ dérive effectivement une chaîne pouvant être suivi du
prochain token.
–
Cette approximation cause des conflits. Les éléments LR(1) font une meilleure
approximation, donnant lieu à moins de conflits.
102
Éléments LR(1)
–
Tout comme les éléments LR(0), un élément LR(1) consiste d’une production et
d’un point. En plus, un élément LR(1) a un symbole lookahead (le prochain token
attendu).
–
Plus précisément, un élément LR(1) est de la forme [A → α . β , a ].
– Comme pour les éléments LR(0), cela signifie que nous avons α au sommet de
la pile, et on s’attend à lire un préfixe du reste de l’entrée dérivé de β.
– En plus, le “a” signifie que le token “a” peut suivre A dans une forme
sentientielle droite, obtenue en utilisant la production A → α β :
*
*
S => xAy => xα β y et a est dans First(y).
103
AFD LR(1)
– En d’autres mots, un élément [A → α . β , a ] signifie que :
• Le reste de l’entrée débute par un préfixe dérivable de βa
• Après la réduction de αβ par A, on va faire shift de a. Ainsi, A sera
suivi de a sur la pile.
– Un état LR(1) est un ensemble d’éléments LR(1), obtenues en utilisant la
fonction etats(G) suivante.
– Cette version utilise des fonctions closure et goto qui sont des mises à jour
des fonctions similaires pour l’AFD LR(0).
104
Algorithme Closure
Algorithm Closure(I)
do {
pour chaque élément [A → α . Xβ , a ] dans I
chaque production X →γ dans la grammaire
et chaque terminal b dans First(βa)
tel que [X → . γ , b ] n’est pas dans I
ajouter [X → . γ , b ] à I
// b pourrait suivre X dans une dérivation droite
} while (des éléments nouveaux sont ajoutés dans I)
return I
105
Algorithmes goto et etats
Algorithm goto(I,X)
soit J l’ensemble d’éléments [A → αX . β , a ] tel que [A → α X . β , a ] est dans I;
return closure(I)
Algorithm etats(Augmented grammar G)
C = { closure({[S’ → . S , $]}) };
// C est l’ensemble des états
do
pour chaque état I dans C et chaque non terminal X
tel que goto(I,X) est non vide et n’est pas encore dans C
ajouter goto(I,X) dans C
while (un nouvel état est ajouté dans C)
return C
106
Générer la table d’analyse LR(1)
Algorithm Constructing LR(1) Parsing Table
Input: An augmented grammar G, with start symbol S’;
Output: LR(1) parsing table;
Method:
1. Construct the LR(1) DFA for G;
2. State i corresponds to Ii . The parsing actions for state i are determined as follows:
a. If an item [A → α . aβ, b] for a terminal a, is in Ii and goto(I , a) =i Ij ,
set action[i, a] to ‘shift j’
b. If an item [A → α . , a] is in Ii , where A is different from S’,
set action[i, a] to ‘reduce A → α ’
c. If item [S’ → S . , $] is in Ii ,
set action[i, $] to ‘accept ’.
107
Générer la table d’analyse LR(1), suite
3. If goto(Ii, a) = Ij
set goto[i, A] = j;
for a nonterminal A
4. All entries not defined by the rules 2 and 3 are made “error”
.
5. The initial state ‘0’ is the one constructed from the set of items containing [S’ → S , $]
− Si la table d’analyse contient des entrées multiples, la grammaire n’est pas LR(1).
− L’algorithme d’analyse demeure le même que pour l’analyse SLR(1) (LR1Driver).
− Un analyseur utilisant une table LR(1) est un analyseur LR(1).
108
Table SLR(1)
Rappel : AFD LR(0)
actions / goto
conflit shift/reduce
9
S→ L=R.
R
L
R
S
I1
S’→ S.
I7
L→*R.
0
S’→ .S
S→ .L=R
S→ . R
L→.*R
L→ .id
R→ .L
=
2
S→ L.=R
R→ L.
3
S→ R.
id
id
5
L→ id.
L
id
*
R
*
I6
S→ L=.R
R→ .L
L→.*R
L→ .id
4
L→*.R
R→ .L
L→.*R
L→ .id
*
L
id
*
0
1
2
3
s5 s4
4
5
6
7
8
9
s5 s4
=
$
goto
S
R L
1
3
2
acc
s6 r5 r5
r2
r4
8
R→ L.
1.
2.
3.
4.
5.
8
9
8
r4
s5 s4
r3
r5
7
r3
r5
r1
S→L=R
S→R
L→*R
L → id
R→L
109
Exemple 1 : AFD LR(1)
1
S’→ S. , $
S
2
S→ L.=R, $
R→ L.,
$
L
0
S’→ .S,
$
S→ .L=R, $
S→ . R,
L→.*R,
L→ .id,
R→ .L ,
*
*
$
$/=
$/=
$
R
id
id
5
L→*.R, $/=
R→ .L,
$/=
L→.*R, $/=
L→ .id,
$/=
4
S→ R.,
$
R
3
S→ L=.R,
R→ .L,
L→.*R,
L→ .id,
L
6
R→ L.,
$
7
L→ id., $/=
10
$
11
R→ L., $/=
9
L→*R., $/=
id
L
id
1.
2.
3.
4.
5.
$
$
$
$
S→L=R
S→R
L→*R
L → id
R→L
R
*
L→ id.,
L
=
8
S→ L=R., $
12
L→*.R,
R→ .L,
L→.*R,
L→ .id,
R
$
$
$
$
*
Le conflit dans l’état 2
a disparu
13
L→*R.,
$
110
Table LR(1)
1
S’→ S. , $
S
2
S→ L.=R, $
R→ L.,
$
L
0
S’→ .S,
$
1
2 S→ .L=R, $
$
3 S→ . R,
4 L→.*R,
$/=
5 L→ .id,
$/=
R→ .L ,
$
*
*
R
id
id
5
L→*.R, $/=
R→ .L,
$/=
L→.*R, $/=
L→ .id,
$/=
4
S→ R.,
$
R
3
S→ L=.R,
R→ .L,
L→.*R,
L→ .id,
L
6
R→ L.,
$
7
L→ id., $/=
10
$
11
R→ L., $/=
9
L→*R., $/=
id
L
id
actions / goto
$
$
$
$
R
*
L→ id.,
L
=
8
S→ L=R., $
12
L→*.R,
R→ .L,
L→.*R,
L→ .id,
R
$
$
$
$
13
L→*R.,
$
id
0
1
2
3
4
5
6
7
8
9
*
=
$
s7 s5
goto
S
R L
1
4
2
acc
s3 r5
s10 s12
8
6
9
11
r2
s7 s5
10
11
12 s10 s12
13
r5
r4 r4
r1
r3 r3
r4
r5 r5
13 6
r3
111
Exemple 1/ 2
Soit la grammaire
1. S→ CC
2. C→ cC
3. C→ d
Le symbole de départ est S. Les terminaux sont: c, d
Construire la table LR(1)
112
Exemple 2/2
0
S’→ .S, $
S→ .CC, $
C→ . cC, c/d
C→.d, c/d
S
1
S’→ S., $
2
S→ C.C, $
C→ . cC, $
C→.d, $
C
c
d
d
4
C→ d., c/d
c
c
6
d
c
3
C→ c.C, c/d
C→ . cC, c/d
C→.d, c/d
c
5
S→ CC., $
C
d
C→ c.C, $
C→ . cC, $
7
C→.d, $
C→ d., $
C
actions
C
0
1
2
3
4
5
6
7
8
9
d
goto
$
s3 s4
S
C
1
2
acc
s6 s7
s3 s4
r3 r3
5
8
r1
s6 s7
9
r3
r2 r2
r2
9
8
C→ cC., c/d
C→ cC., $
1. S→ CC
2. C→ cC
3. C→ d
113
ANALYSE LALR (1)
114
AFD LALR(1) et Table d’analyse LALR(1)
–
Les tables d’analyse LR(1) peuvent devenir très larges. On ne les utilisent pas en
pratique.
–
La décomposition de l’ensemble Follow en lookahead associé à chaque élément
LR(0) est la source de la puissance de l’analyse LR(1).
–
Mais on n’a pas besoin de cette décomposition dans chaque état. Cette observation
mène à une approximation de l’AFD LR(1) beaucoup plus efficace (moins d’états),
mais légèrement moins expressive: l’AFD LALR(1).
–
Un AFD LALR(1) est obtenu de l’AFD LR(1) en fusionnant les états identiques
pour les éléments LR(0) (seuls les composantes lookahead diffèrent).
–
Une table d’analyse LALR(1) est obtenue de l’AFD LALR(1) de la même façon
que la table d’analyse LR(1) est obtenue de l’AFD LR(1).
–
Il peu arriver que la table d’analyse LALR(1) contient des conflits alors que la table
d’analyse LR(1) correspondant n’en a pas. Mais c’est rare.
115
Exemple 1 : AFD LR(1)
1
S’→ S. , $
S
2
S→ L.=R, $
R→ L.,
$
L
0
S’→ .S,
$
S→ .L=R, $
S→ . R,
L→.*R,
L→ .id,
R→ .L ,
*
*
$
$/=
$/=
$
R
id
id
5
L→*.R, $/=
R→ .L,
$/=
L→.*R, $/=
L→ .id,
$/=
4
S→ R.,
$
R
3
S→ L=.R,
R→ .L,
L→.*R,
L→ .id,
L
6
R→ L.,
$
7
L→ id., $/=
10
$
11
R→ L., $/=
9
L→*R., $/=
id
L
id
1.
2.
3.
4.
5.
$
$
$
$
S→L=R
S→R
L→*R
L → id
R→L
R
*
L→ id.,
L
=
8
S→ L=R., $
12
L→*.R,
R→ .L,
L→.*R,
L→ .id,
R
$
$
$
$
*
13
L→*R.,
$
116
AFD LALR(1) et Table d’analyse
1
S’→ S. , $
S
2
S→ L.=R, $
R→ L.,
$
L
0
1
2
3
4
5
S’→ .S,
$
S→ .L=R, $
S→ . R,
L→.*R,
L→ .id,
R→ .L ,
*
*
$
$/=
$/=
$
L
R
id
id
4
S→ R.,
$
6
R→ L.,
$/=
$/=
$
$
$
$
R
7
L→ id., $/=
L→*.R, $/=
R→ .L,
L
3
S→ L=.R,
R→ .L,
L→.*R,
L→ .id,
id
*
5
=
8
S→ L=R., $
actions / goto
id
0
1
2
3
4
5
6
7
8
9
*
=
$
s7 s5
goto
S
R L
1
9
acc
s3 r5
s7 s5
8
6
9
6
r2
s7 s5
r5
r4
r3
r5
r4
r1
r3
R
L→.*R, $/=
L→ .id,
$/=
6
9
L→*R., $/=
117
Exemple 2
0
S’→ .S, $
S→ .CC, $
C→ . cC, c/d
C→.d, c/d
S
1
S’→ S., $
2
S→ C.C, $
C→ . cC, $
C→.d, $
C
c
c
d
d
4
C→ d., c/d
c
6
d
c
3
C→ c.C, c/d
C→ . cC, c/d
C→.d, c/d
c
5
S→ CC., $
C
d
C→ c.C, $
C→ . cC, $
7
C→.d, $
C→ d., $
actions
C
0
1
2
3
4
5
6
7
8
9
d
goto
$
s3 s4
S
C
1
2
acc
s6 s7
s3 s4
r3 r3
5
8
r1
s6 s7
9
r3
r2 r2
r2
C
9
8
C→ cC., c/d
C→ cC., $
1. S→ CC
2. C→ cC
3. C→ d
118
Exemple 2
0
S’→ .S, $
S→ .CC, $
C→ . cC, c/d
C→.d, c/d
S
1
S’→ S., $
5
S→ CC., $
C
C
c
c
2
S→ C.C, $
C→ . cC, $
C→.d, $
c
d
actions
c
0
1
2
3
d
goto
$
s3 s4
S
C
1
2
acc
s3 s4
s3 s4
r3 r3
r3
r3
r1
r2
4
5
6 r2
5
6
3
C→ c.C, c/d/$
C→ . cC, c/d/$
C→.d, c/d/$
d
d
4
C→ d., c/d/$
C
6
C→ cC., c/d/$
1. S→ CC
2. C→ cC
3. C→ d
119
Génération efficace des tables d’analyse LALR(1)
– Il existe une méthode efficace pour générer l’AFD LALR(1) et la table
d’analyse LALR(1) sans passer directement par l’AFD LR(1).
– Cette méthode calcule les états de l’AFD LALR(1) à la volée en utilisant
.
une technique de propagation des lookahead. Voir Aho-Sethi-Ullman.
Compilers: Principles, Techniques and Tools, 1988 :Pages 240 – 244.
– Dans le même livre : représentation compacte des tables LALR(1): Pages
244-245.
120
Commentaires sur l’analyse LALR(1)
–
Les états de l’AFD LR(1) sont toujours des versions dupliquées des états de l’AFD
LR(0), mis à part les lookahead qui diffèrent.
–
Donc l’AFD LALR(1) a le même nombre d’états que l’AFD LR(0) et les mêmes
transitions.
–
.
Une des raisons pour lesquelles l’analyse LALR(1) fonctionne si bien et que la
fusion des états de l’AFD LR(1) ne peut pas introduire des conflits shift-reduce. S’il
y en a dans l’AFD LALR(1) c’est qu’elles étaient dans l’AFD LR(1) d’origine.
Seuls des conflits reduce-reduce peuvent être introduites par la fusion des états.
121
Hiérarchie des grammaires hors-contexte
Grammaires non ambigües
LR(k)
LL(k)
LL(1)
Grammaires
ambigües
LR(1)
LALR (1)
SLR (1)
LL(0) LR(0)
122
Téléchargement