Télécharger la présentation
La présentation est en train de télécharger. S'il vous plaît, attendez
1
IFT313 Introduction aux langages formels
Froduald Kabanza Département d’informatique Université de Sherbrooke planiart.usherbrooke.ca/kabanza/cours/ift313 Ensembles first et follow
2
Sujets C’est quoi un symbole nullable pour une grammaire?
C’est quoi un ensemble first pour une grammaire ? C’est quoi un ensemble follow pour une grammaire ? Quel l’algorithme pour calculer ces symboles et ces ensembles ? Quel est le rôle de ces concepts dans l’analyse syntaxique descendante (prédictive) ? C’est quoi une table d’analyse LL ? Comment la calculer. IFT313 © Froduald Kabanza
3
Exemple Entrée : n+n*n Algorithm LLDriver En d’autres mots:
1. E ® TE’ 2. E’ ® + TE’ | 3. ε 4. T ® FT’ 5. T’ ® *FT’ | 6. ε 7. F ® ( E ) | n Entrée : n+n*n S Þ déjà lu + pile * Étape Règle Pile Entrée * 0. 3. 2. 1. E ® TE’ T ® FT’ F ® n T’ ® ε E’ ® +TE’ T’ ® *FT’ T’® ε E’® ε E$ TE’$ FT’E’$ nT’E’$ T’E’$ E’$ +TE’$ FT’É’$ *FT’E’$ $ n+n*n$ +n*n$ n*n$ *n$ n$ $ E Þ TE’ FT’E’ nT’E’ nE’ n +TE’ n+TE’ n+FT’E’ n+nT’E’ n+n*FT’E’ n+n*nT’E’ n+n*nE’ n+n*n Algorithm LLDriver 0. stack = ($S); a = in.read(); x=stack.top(); while (true) { if (x = = $) && (a= = $) return true ; if (x = = a) { pop a from stack; a = in.read(); continue;} if x is a nonterminal { find x y; pop x from stack; push y on stack; continue; } exit with error;} Grammaire pour les expressions arithmétiques et pilote d’analyse LL Deux observations importantes 1. L’exécution du driver LL, sur une chaîne d’entrée donne la dérivation la plus à gauche de l’entrée dans la mesure où si on concatène le préfixe de la chaîne déjà scannée avec le contenu de la pile, on obtient une forme sententielle gauche de la grammaire. 2. (Corollaire) Ceci veut dire à tout instant durant l’exécution du driver LL, la chaîne restant à scanner doit être dérivable de la chaîne de symbole sur la pile pour que la chaîne de départ soit acceptée. En d’autres mots: Soit alpha le contenu de la pile à une étape quelconque, v le reste de la chaîne à lire et w la chaîne d’entrée originale (donc w = uv avec u la chaîne déjà lue; forcément dans A*). Alors, on doit avoir alpha => v pour que la chaîne d’entrée soit acceptée, c’est-à-dire, pour que S => w (avec S le symbole de départ de la grammaire). return true IFT313 © Froduald Kabanza
4
Définition de l’ensemble First
Étant donné a une chaîne de terminaux et de non-terminaux, alors First(a) est l’ensemble de terminaux commençant une chaîne dérivée de a. Exemple : First(TE’) = {(, n, +} First(+TE’) = { + } First(FT’) = { (, n} First(*FT’) = { * } First((E)) = { ( } First(n) = { n} G = (V, A, R, E) : V = {E, E’, T, T’} A = {(, ), +, *, n} R = { E ® TE’ E’ ® + TE’ | ε T ® FT’ | ε T’ ® *FT’ | ε F ® ( E ) | n} IFT313 © Froduald Kabanza
5
Utiliser l’ensemble First dans le driver LL
Si le sommet de la pile contient un terminal X, le driver LL doit prédire la règle X ® a tel que le prochain token est dans First(a). Exemple : First((E)) = {( } First(n) = {n} Si le sommet de la pile est F : - si le prochain token est ( , le driver LL prédit F ® ( E ) - sinon, si le prochain token est n le driver LL prédit F ® n - sinon le driver sort avec une erreur. G = (V, A, R, E) : V = {E, E’, T, T’} A = {(, ), +, *, n} R = { E ® TE’ E’ ® + TE’ | ε T ® FT’ | ε T’ ® *FT’ | ε F ® ( E ) | n} IFT313 © Froduald Kabanza
6
Utiliser l’ensemble First dans le driver LL
Si la grammaire ne contient pas deux productions X ® a et X ® b telles que First(a) et First(b) ont une intersection, alors le driver LL exécute de manière déterministe : Il y a zéro ou une production à prédire à chaque étape. Par contre si la grammaire contient deux productions X ® a and X ® b telles que First(a) et First(b) ont une intersection, le driver LL ne peut pas prédire la production à appliquer en lisant juste un token : le driver LL exécuterait de manière non-déterministe. On va justement éviter des grammaires qui donneraient lieu à un tel non-déterminisme. IFT313 © Froduald Kabanza
7
Exemple First(n) = {n} G = (V, A, R, E) : First((E)) = {(} V = {E}
A = {(, ), +, *, n} R = { 1. E ® n 2. E ® (E) 3. E ® E+E 4. E® E*E} First(n) = {n} First((E)) = {(} First(E+E) = {n,(} First(E*E) = {n,(} Si le sommet de la pile est E : - Si le prochain token est n, le driver ne peut pas prédire laquelle des productions 1, 3 ou 4 est appropriée. - Si le prochain token est (, le driver ne peut pas prédire non plus laquelle des productions 2, 3 ou 4 est appropriée. IFT313 © Froduald Kabanza
8
Motivation pour l’ensemble Follow
Nous venons de voir que la bonne production à prédire est une règle X ® a telle le prochain token est dans First(a ). Toute fois, cette ligne directrice doit être généralisée pour tenir compte des productions commençant par la chaîne vide. Pour ce faire, nous allons introduire les notions de symbolles nullables et d’ensemble Follow. IFT313 © Froduald Kabanza
9
Motivation pour les symboles nullables
À première vue le calcul de l’ensemble First parait très simple. Si a= XY, on a l’impression que Y peut être ignoré et que First(a)= First(XY) = First(X). En fait, cela est vrai uniquement si X ne peut pas dériver la chaîne vide. Autrement, First(a) doit aussi inclure First(Y). Exemple : G = (V, A, R, S) : V = {X, Y, S} A = {a, b, c} R = { 1. S ® a | 2. S ® X Y S 3. X ® b | 4. X ® Y 5. Y ® ε | 6. Y ® c} First(S) = { a, b, c } First(X) = { b, c } First(Y) = { c } First(a) = { a } First(b) = { b } First(c) = { c} Puisque X peut dériver Y (production 4), une chaîne dérivée de XYS peut tout aussi bien être dérivée de YYS. Vu que Y peut dériver la chaîne vide (production 5), la chaîne peut tout aussi bien être dérivée de YS, ou de S. First(S) = { a, b, c } First(X) = { b, c } First(Y) = { c } First(a) = { a } First(b) = { b } First(c) = { c} Puisque X peut dériver Y (production 4), une chaîne dérivée de XYS peut tout aussi bien être dérivée de YYS. Vu que Y peut dériver la chaîne vide (production 5), la chaîne peut tout aussi bien être dérivée de YS, ou de S. IFT313 © Froduald Kabanza
10
Définition de symboles nullables
On vient de voir qu’en calculant First(S) ou First(XYS) on doit tenir compte des non-terminaux qui pourraient dériver la chaîne vide et de ceux qui pourraient les suivre dans une dérivation. Les non-terminaux qui peuvent dériver la chaîne vides sont appelés des symboles nullables. Ainsi, X et Y sont nullables dans la grammaire ci après. Exemple : G = (V, A, R, S) : V = {X, Y, S} A = {a, b, c} R = { 1. S ® a | 2. S ® X Y S 3. X ® b | 4. X ® Y 5. Y ® ε | 6. Y ® c} First(S) = { a, b, c } First(X) = { b, c } First(Y) = { c } First(a) = { a } First(b) = { b } First(c) = { b } Puisque X peut dériver Y (production 4), une chaîne dérivée de XYS peut tout aussi bien être dérivée de YYS. Vu que Y peut dériver la chaîne vide (production 5), la chaîne peut tout aussi bien être dérivée de YS, ou de S. IFT313 © Froduald Kabanza
11
Définitions formelles
nullable(X) est vrai si et seulement si X peut dériver la chaîne vide en zéro ou plusieurs étapes. First(a) est l’ensemble de terminaux qui pourraient commencer une chaîne dérivée de a. Follow(X) est l’ensemble de terminaux qui pourraient suivre X immédiatement, dans une forme sententielle. En d’autres mots, l’ensemble de terminaux a tels que S => g Xab pour g et b quelconques. En plus, si X peut être le dernier symbole dans une forme sententielle, on ajoute $ à Follow(X). Ceci arriverait aussi si une dérivation contient XY tel que Y peut dériver la chaîne vide. Récursivement, ceci arriverait aussi si une dérivation contient XYZ tel que Y et Z peuvent chacun dériver la chaîne vide. Ainsi de suite … * IFT313 © Froduald Kabanza
12
Définitions formelles
Une définition plus formelle de nullable, First and Follow est que ce sont les plus petits ensembles pour lesquels les propriétés suivantes sont valides : If S is the start symbol, then Follow[S] contains $; For each terminal symbol a, First(a) = { a }; For each production X ® Y1 … Yk If Y1 … Yk are all nullable or (if k = 0) nullable[X] = true; for each i from 1 to k, if Y1… Yi-1 are all nullable (or if i=1) First[X] = Union(First[X], First[Yi]); if Yi+1… Yk are all nullable (or if i=k) Follow[Yi] = Union(Follow[Yi], Follow[X]); for each j from i + 1 to k if Yi+1… Yj-1 are all nullable (or if i+1=j) Follow[Yi] = Union(Follow[Yi], First[Yj]); Pour obtenir les ensembles nullable, First et Follow, on calcule le point fixe (ou la fermeture) de ces équations (c-à-d., on refait des itérations tant qu’on n’obtient pas une solution stable). Note: cet algorithme est tiré du livre [2] dans le plan de cours: Appel, A. W. Modern Compiler Implementation in Java. Second Edition. Cambridge University Press, 2004, page 49. Par contre, j’ai réorganisé les instructions un peu différemment. Dans la version originale, il y a une seule boucle itérant sur deux variables (i et j) à la fois, au lieu de deux boucles imbriquées. Cela parait plus simple et plus intuitif. Par contre, pour ceux qui veulent un pseudocode le plus proche du code, il y a deux incongruités. Premièrement, vu que l’instruction « if Y1… Yi-1 are all nullable (or if i=1) First[X] = Union(First[X], First[Yi]);” est mise dans la boucle pour j, on a que, pour i=1, on ne passe pas dans la boucle; ainsi pour une règle de production X->a, on ne calculerait pas First(X)={a}. Deuxièmement, l'instruction " if Yi+1…Yk are all nullable (or if i=k) Follow[Yi] = Union(Follow[Yi], Follow[X]);" ne porte pas sur "j“ et donc n’a pas de raison d’être dans la boucle sur “j”. IFT313 © Froduald Kabanza
13
Algorithme pour calculer nullable, First et Follow
Algorithme nullableFirstFollow Entrée : une grammaire. Sortie : Trois vecteur (nullable, First et Follow) tel que pour chaque symbole de grammaire X (terminal ou non): nullable(X) est true si X est nullable First(X) est l’ensemble de terminaux qui peuvent commencer une chaîne dérivable de X Follow(X) est l’ensemble de terminaux qui peuvent suivre X dans une dérivation. IFT313 © Froduald Kabanza
14
Algorithme pour calculer nullable, First et Follow
Algorithme nullableFirstFollow initialize all entries of First and Follow to the empty set and those of nullable to false; set Follow[S] = {$}, where S is the start symbol and $ the end marker; for each terminal symbol a, First(a) = {a}; do { for each production X ® Y1…Yk { if Y1…Yk are all nullable or (if k = 0) nullable[X] = true; for (i = 1; i <= k; i++) { if Y1…Yi-1 are all nullable (or if i=1) First[X] = Union(First[X], First[Yi]); if Yi+1…Yk are all nullable (or if i=k) Follow[Yi] = Union(Follow[Yi], Follow[X]); for (j = i+1; j <= k; j++) if Yi+1…Yj-1 are all nullable (or if i+1=j) Follow[Yi] = Union(Follow[Yi], First[Yj]); } } while First, Follow or nullable is modified in the current iteration La note dans la Slide 20 s’applique ici aussi. IFT313 © Froduald Kabanza
15
Exemple 1 S X Y G = (V, A, R, S) : V = {X, Y, S} A = {a, b, c}
Iter 0. nullable false false false G = (V, A, R, S) : V = {X, Y, S} A = {a, b, c} R = { S ® a 2. S ® X Y S 3. X ® b 4. X ® Y 5. Y ® ε 6. Y ® c} First {} {} {} Follow {$} {} {} Iter 1. nullable false false true First {a} {b} {c} Follow {$} {a, c} {a} Iter 2. nullable false true true First {a, b, c} {b, c} {c} Follow {$} {a, b, c} {a,b, c} IFT313 © Froduald Kabanza
16
Exemple 2 E E’ T T’ F G = (V, A, R, E) : V = {E, E’, T, T’, F, (, )}
A = {(, ), +, *, n} R = { E ® TE’ E’ ® + TE’ | ε T ® FT’ T’ ® *FT’ | ε F ® ( E ) | n } nullable false true false true false First {(,n} {+} {(,n} {*} {(,n} Follow {), $} {), $} {+, ), $} {+, ), $} {+,*,), $} E E’ T T’ F Nullable false true false true false First (, n (, n * (, n Follow ), $ ), $ , ), $ , ), $ , *, ), $ IFT313 © Froduald Kabanza
17
Généralisation aux chaînes de symboles
Il est utile de généraliser nullable et First à de chaînes de symboles d’une grammaire : Étant donne une chaîne a, nullable(a) si et seulement si chaque symbole de a est nullable. Étant donne un symbole X et une chaîne g : First(Xg)=First[X] if not nullable[X] First(Xg)=Union(First[X], First(g)) if nullable[X] IFT313 © Froduald Kabanza
18
Comment prédire une production ?
Nous utilisons les ensembles First et Follow pour prédire une production en fonction du non-terminal au dessus de la pile et du prochain token (terminal) à l’entrée. L’idée de base est que si le sommet de la pile est A, et le prochain token est a, alors on prédit la production A ® a telle que a est dans First(a). Ainsi le driver LL va appliquer A ® a , en remplaçant A par a au sommet de la pile. La seule complication est lorsque a peut dériver la chaîne vide. Dans ce cas, nous allons prédire A ® a si a est dans Follow(A) (ceci inclus le cas où le prochain token est $ (EOF) et $ est dans Follow(A)). IFT313 © Froduald Kabanza
19
Exemple E E’ T T’ F G = (V, A, R, E) : V = {E, E’, T, T’, F, (, )}
nullable First Follow true false {(,n} {+} {*} {), $} {+, ), $} T’ F {+,*,), $} G = (V, A, R, E) : V = {E, E’, T, T’, F, (, )} A = {(, ), +, *, n} R = { E ® TE’ E’ ® + TE’ | ε T ® FT’ T’ ® *FT’ | ε F ® ( E ) | n } IFT313 © Froduald Kabanza
20
Exemple E E’ T T’ F Entrée : n+n*n Algorithm LLDriver nullable First
Follow true false {(,n} {+} {*} {), $} {+, ), $} T’ F {+,*), $} Exemple 1. E ® TE’ 2. E’ ® + TE’ | 3. ε 4. T ® FT’ 5. T’ ® *FT’ | 6. ε 7. F ® ( E ) | n Entrée : n+n*n Étape Règle Pile Entrée Algorithm LLDriver 0. stack = ($S); a = in.read(); x=stack.top(); while (true) { if (x = = $) && (a= = $) return true ; if (x = = a) { pop a from stack; a = in.read(); continue;} if x is a nonterminal { find x y; pop x from stack; push y on stack; continue; } exit with error;} 0. 3. 2. 1. E ® TE’ T ® FT’ F ® n T’ ® ε E’ ® +TE’ T’ ® *FT’ T’® ε E’® ε E$ TE’$ FT’E’$ nT’E’$ T’E’$ E’$ +TE’$ FT’É’$ *FT’E’$ $ n+n*n$ +n*n$ n*n$ *n$ n$ $ return true IFT313 © Froduald Kabanza
21
Résumé Une fois de plus, voici les règles pour prédire une production:
L’idée de base est que si le sommet de la pile est A, et le prochain token est a, alors on prédit la production A ® a telle que a est dans First(a). Ainsi le driver LL va appliquer A ® a , en remplaçant A par a au sommet de la pile. La seule complication est lorsque a peut dériver la chaîne vide. Dans ce cas, nous allons prédire A ® a si a est dans Follow(A) (ceci inclut le cas où le prochain token est $ (EOF) et $ est dans Follow(A)). Avec ces règles, on peut générer une table d’analyse M, telle que M[A,a] contient la règle de production à appliquer lorsque A est au sommet de la pile et a est le prochain token. Nous verrons comment à la prochaine leçon. IFT313 © Froduald Kabanza
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.