La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

Présentations similaires


Présentation au sujet: "IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs."— Transcription de la présentation:

1 IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs

2 IFT313© Froduald Kabanza2 Sujets Table danalyse LL (1) Générateurs danalyseurs LL(1) non récursifs Transformer les grammaires ambigües Éliminer la récursivité à gauche (left recursion) Factorisation à gauche (left factoring)

3 IFT313© Froduald Kabanza3 Objectifs Pouvoir générer une table danalyse LL(1) pour une grammaire donnée. Comprendre et pouvoir décrire et simuler lalgorithme danalyse LL (1) non récursif. Pouvoir transformer une grammaire non LL(1) en une grammaire LL (1) –Pouvoir transformer une grammaire ambigüe en une grammaire non ambigüe. –Pouvoir éliminer la récursivité à gauche (left recursion). –Pouvoir utiliser la factorisation à gauche (left factoring)

4 IFT313© Froduald Kabanza4 Références [1] Sudkamp, T. A.. Languages and Machines. Third Edition Edition. Addison-Wesley, – Sections 4.3 et 19.6 à 19.7 [2] Appel, A. and Palsberg. J. Modern Compiler Implementation in Java. Second Edition. Cambridge, – Section 3.2 [4] Aho, A., Lam, M., Sethi R., Ullman J. Compilers: Principles, Techniques, and Tools, 2 nd Edition. Addison Wesley, – Section 4.3 et à 4.4.5

5 IFT313© Froduald Kabanza5 Rappel : Algorithme Driver LL variables : stack (pile), x (symbole au sommet de la pile), a (symbole dentrée courant), in (entrée) initialement la pile contient $S (le symbole départ S) et lentrée contient w$ (chaîne de tokens w). while (true) { if (x = = $) && (a= = $) return true ; // on accepte la chaîne dentrée comme étant correcte if (x = = a) && (a != $) // match transition { pop a from the stack; // dépiler le symbole de la pile a = in.read(); // lire le token (symbole) courant et avancer la tête de lecture continue;} if x is a nonterminal // predictive transition { find a production x y 1 … y k ; // trouver une production dont la partie gauche est x // les essayer tous jusquà en trouver menant à lacceptation (backtracking) exit with error if no such production exists; pop x from the stack; push y k on the stack; …; push y 1 on the stack; continue; } exit with error; }

6 IFT313© Froduald Kabanza6 Rappel : Nullable, First et Follow Nullable(X) est vrai si et seulement si X peut dériver la chaîne vide en zéro ou plusieurs étapes. First( est lensemble de terminaux qui peuvent commencer une chaîne dérivée de Follow(X) est lensemble de terminaux qui peuvent suivre X immédiatement, dans une forme sententielle. En plus, si X peut être le dernier symbole dans une forme sententielle, on ajoute $ à Follow(X). Étant donne une chaîne nullable( ) si et seulement si chaque symbole de est annulable. Étant donne un symbole X et une chaîne First(X )=First[X] if not nullable[X] First(X )=Union(First[X], First( if nullable[X]

7 IFT313© Froduald Kabanza7 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 Y 1 … Y k If Y 1 … Y k are all nullable or (if k = 0) nullable[X] = true; for each i from 1 to k, if Y 1 … Y i-1 are all nullable (or if i=1) First[X] = Union(First[X], First[Y i ]); if Y i+1 … Y k are all nullable (or if i=k) Follow[Y i ] = Union(Follow[Y i ], Follow[X]); for each j from i + 1 to k if Y i+1 … Y j-1 are all nullable (or if i+1=j) Follow[Y i ] = Union(Follow[Y i ], First[Y j ]); Pour obtenir les ensembles Nullable, First et Follow, on calcule le point fixe (ou la fermeture) de ces équations.

8 IFT313© Froduald Kabanza8 Rappel: 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 Y 1 …Y k { if Y 1 …Y k are all nullable or (if k = 0) nullable[X] = true; for (i = 1; i <= k; i++) { if Y 1 …Y i-1 are all nullable (or if i=1) First[X] = Union(First[X], First[Y i ]); if Y i+1 …Y k are all nullable (or if i=k) Follow[Y 1 ] = Union(Follow[Y i ], Follow[X]); for (j = i+1; j <= k; j++) { if Y i+1 …Y j-1 are all nullable (or if i+1=j) Follow[Y 1 ] = Union(Follow[Y i ], First[Y j ]); } } while First, Follow or nullable is modified in the current iteration

9 IFT313© Froduald Kabanza9 Rappel : comment prédire une production ? Voici les règles pour prédire une production: Si le sommet de la pile est A, et le prochain token est a, alors on prédit la production A telle que a est dans First( ). Ainsi le driver LL va appliquer A en remplaçant A par au sommet de la pile Lorsque peut dériver la chaîne vide, on prédit la règle A si a est dans Follow( ) ou si le prochain token est $ (EOF) et $ est dans Follow(A). Avec ces règles, on peut générer une table danalyse 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.

10 IFT313© Froduald Kabanza10 Génération de la table danalyse LL (1) Algorithm generateLL1ParsingTable Entrée : grammaire G(V, T, P, S); Sortie : table danalyse M[symbole non terminal, symbole terminal]; Pour toutes les règles de production A dans P { Pour tous les terminaux a dans First( // a est un élément de T Ajouter A to M a // A est un élément de V Si nullable( // quand cest annulable, il faut aller voir ce qui peut suivre Pour tous les terminaux a dans Follow(A) Ajouter A to M a Mettre error dans chaque entrée de de M non définie (ne contenant pas de règle);

11 IFT313© Froduald Kabanza11 Exemple 1 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} SXY nullable First Follow true false {a, b, c}{b, c}{c} {$}{a, b, c} Table danalyse LL(1) abc S X Y S a S X Y S $ Y ε Y c X b X Y Pour chaque a dans First( Ajouter A to M a Si nullable( Pour chaque a dans Follow(A) Ajouter A to M a

12 IFT313© Froduald Kabanza12 Exemple 2 G = (V, A, R, E) : V = {E, E, T, T, F} A = {(, ), +, *, n} R = { E TE E + TE | ε T FT T *FT | ε F n } EET Nullable First Follow true false {(,n}{+}{*} {), $}{+, ), $} TF truefalse {(,n} {), $}{+, ), $}{+,*), $} Table danalyse n+ * E E TE $ E E +TE E ε T T FT T T ε T *FT T ε F F nF (E) () E TE Pour chaque a dans First( Ajouter A to M a Si nullable( Pour chaque a dans Follow(A) Ajouter A to M a

13 IFT313© Froduald Kabanza13 Algorithme danalyse LL(1) non récursif Nous pouvons maintenant mettre à jour lalgorithme LLDriver pour quil utilise une table danalyse LL(1) pour prédire une production. Si la table danalyse générée à partir dune grammaire contient des entrées avec des productions multiples, la grammaire est dite non LL(1). Pour certaines grammaires qui ne sont pas LL(1), on peut définir des grammaires LL(1) équivalentes par de simples transformations. On en verra certaines plus loin : Éliminer lambiguïté Éliminer la récursivité à gauche Factoriser les productions à gauche

14 IFT313© Froduald Kabanza14 Algorithme danalyse LL (1) non récursif Algorithm LL1Parser Entrée : - table danalyse de la grammaire; - chaîne dentrée terminée par $ (fin de fichier). Sortie : - une dérivation de la chaîne dentrée si elle syntaxiquement correcte; - sinon erreur.

15 IFT313© Froduald Kabanza15 Algorithme danalyse LL(1) non récursif Algorithm LLDriver variables : stack (pile), x (symbole au sommet de la pile), a (symbole dentrée courant), in (entrée, suite fini de symboles, lexèmes) initialement la pile contient $S (le symbole départ S) et lentrée contient w$ (chaîne de tokens w). while (true) { if (x = = $) && (a= = $) return true ; // on accepte la chaîne dentrée comme étant correcte if (x = = a) && (a != $) // match transition { pop a from the stack; // dépiler le symbole de la pile a = in.read(); // lire le token (symbole) courant et avancer la tête de lecture continue;} if x is a nonterminal // predictive transition { if M[x,a] is error exit with error; let x y 1 … y k the production in M[x,a] pop x from the stack; push y k on the stack; …; push y 1 on the stack; continue; } exit with error;}

16 IFT313© Froduald Kabanza16 Exemple G = (V, A, R, E) : V = {E, E, T, T, F} A = {(, ), +, *, n} R = { E TE E + TE | ε T FT *FT | ε F n } Table danalyse n+* E E TE $ E E +TE E ε T T FT T T ε T *FT T ε F F nF (E) () E TE

17 return true Pile Étape Règle Algorithm LLDriver 0. stack = ($S); a = in.read(); x=stack.top(); while (true) { 1. if (x = = $) && (a= = $) return true ; 2. if (x = = a) && (a != $) { pop a from stack; a = in.read(); continue;} 3. if x is a nonterminal { if M[x,a] is error exit with error; let x y1 … yk in M[x,a] pop x from stack; push y on stack; continue; } 4. exit with error;} Entrée Entrée : n+n*n $E $ET $ETF $ETn $ET $E $E T+ $E T $ETF $ETn $ET $ETF* $ETF $ETn $ET $E $ n+n*n$ +n*n$ n*n$ *n$ n$ $ $ $ E TE T FT F n T ε E +TE T FT F n T *FT F n T ε E ε n+* E E TE $ E E +TE E ε T T FT T T ε T *FT T ε F F nF (E) () E TE IFT31317© Froduald Kabanza

18 IFT313© Froduald Kabanza18 Quelques considérations pratiques Lalgorithme LL1Driver produit une dérivation de lentrée, plus précisément une séquence de règles de production qui dérivent la chaîne dentrée. Cet algorithme est essentiellement un automate à pile LL déterministe qui simule la dérivation la plus à gauche. Pour obtenir un processeur de langage (interpréteur ou compilateur), on peut associer les règles de production avec des actions qui seront exécutées chaque fois quune production est appliquée. Ces actions sappellent des routines sémantiques ou des actions sémantiques. Il faut ajouter aussi les gestions des erreurs.

19 IFT313© Froduald Kabanza19 Quelques considérations pratiques Un générateur danalyseur LL(1) non récursif prend comme entrée une grammaire avec des actions sémantiques et génère un parseur pour cette grammaire. Un tel générateur fonctionne comme suit. Il a comme coquille le code du driver LL(1), qui est indépendant de la grammaire. À partir de la grammaire, il génère une table danalyse. Il combine ensuite le code du driver LL(1) avec la table danalyse pour obtenir le parseur. Cela vous rappelle-t-il quelque chose ? Les générateurs danalyseurs lexicaux bien sûr. Un tel générateur emploie une approche similaire: un scanner est obtenu en combinant un DFA driver avec une table de transitions dun DFA obtenue dune spécification dexpressions régulières avec des actions associées.

20 IFT313© Froduald Kabanza20 Quelques considérations pratiques Il est possible de généraliser lanalyse LL(1) à lanalyse LL(k), pour un entier k fixé : un analyseur LL(k) prédit une production en se basant sur le symbole au sommet de la pile et les k prochains lexèmes (tokens). Plus k est grand, plus lanalyseur a une grande puissance dexpressivité, mais aussi plus il est compliqué à coder et souvent il est moins rapide. De plus, la table danalyse est beaucoup plus volumineuse. Une grammaire est dite LL(k) si et seulement si le langage généré par la grammaire est analysable par un analyseur LL(k). Pour beaucoup de langages de programmation, lanalyse LL(1) suffit moyennant quelques extensions, comme lajout de règles de priorité.

21 IFT313© Froduald Kabanza21 Transformer une grammaire ambigüe Nous avons vu que la grammaire suivante est ambigüe parce quelle produit deux arbres danalyse différentes pour la même entrée. Donc on pourrait avoir deux dérivations les plus à gauche différentes pour la même entrée. G = (V, A, R, Exp) : V= {Exp} A = {(, ), +, *, num} R = { Exp num Exp ( Exp ) Exp Exp + Exp Exp Exp * Exp } Exp * + num Exp num Exp + num * Exp num Exp num

22 IFT313© Froduald Kabanza22 Transformer une grammaire ambigüe La plupart des générateurs danalyseurs syntaxiques permettent la spécification de « règles de priorité » qui assure que la chaîne dentrée a une seule interprétation possible. Toutefois, dans dautres cas, on na pas dautres choix que de réécrire la grammaire en une grammaire équivalente acceptable pour une analyse LL(1) (ou, pour plus tard, LR(1)). Cependant, il nexiste pas de méthode systématique pour une telle opération de transformation de grammaire ambiguë en une grammaire non ambiguë. Il faut se servir de lintuition et de lexpérience.

23 IFT313© Froduald Kabanza23 Exemple 1 1/2 Pour obtenir une grammaire non ambigüe équivalente à la précédente, intuitivement on aimerait spécifier que lopérateur de multiplication (*) a une priorité sur celui daddition (+), de sorte que num + num * num soit interprété comme num + (num * num). Deuxièmement, on voudrait spécifier que chaque opération est évaluée par lassociativité à gauche, de sorte que la seule interprétation possible pour num - num - num soit (num – num) – num (plutôt que num – (num – num)). Nous pouvons faire cela en introduisant de nouveaux symboles non terminaux et de nouvelles règle de production. Traditionnellement, les facteurs (F) sont les nombres quon multiplie et les termes (T) les nombres quon additionne; on introduit donc les symboles F et T pour réécrire la grammaire.

24 IFT313© Froduald Kabanza24 Exemple 1 2/2 Grammaire ambigüe : G = (V, A, R, E) : V= {E} A = {(, ), +, *, n} R = { E E + E E E * E E ( E ) E n } Grammaire équivalente non ambigüe: G = (V, A, R, E) : V= {E, F, T} A = {(, ), +, *, n} R = { E E + T E T T T * F T F F ( E) F n }

25 IFT313© Froduald Kabanza25 Exemple 2 1/3 Considérons la grammaire S if E then S else S | if E then S | other E c Cette grammaire est ambiguë que linstruction if c1 then if c2 then s1 else S2 a deux arbres de dérivation. Linterprétation habituelle du « if then else » est que «chaque else est associé au plus récent if sans else correspondant». Cette interprétation correspond au premier arbre. S E then S if c1 E then s1 if c2 else s2 E then if c1 else s2 S S E then S1 if c2

26 IFT313© Froduald Kabanza26 Récursivité à gauche (left recursion) La nouvelle grammaire nest pas ambigüe. Il y a toujours un seul arbre danalyse possible pour une chaîne de lexèmes (tokens) du langage. Toutefois, la nouvelle grammaire nest pas pratique pour lanalyse LL(1). Les productions E E + T | T vont causer des entrées multiples dans la table danalyse LL(1), vu que tout token dans First(T) sera aussi dans First(E + T). Le problème est que E apparaît comme premier symbole de la partie droite dune production commençant par E. Ça sappelle la récursivité à gauche (left-recursion). Plus précisément, une grammaire est dite récursive à gauche (left- recursive) si elle a un non terminal A tel quil est possible davoir une dérivation A => A Lanalyse descendante ne peut pas gérer la récursivité à gauche. Par conséquent, il nous faut une transformation permettant de passer dune grammaire récursive à gauche à une grammaire non récursive à gauche.

27 IFT313© Froduald Kabanza27 Éliminer la récursivité à gauche Pour éliminer la récursivité à gauche pour les productions E E + T | T, on les réécrit avec une récursivité à droite. Plus précisément, on introduit un nouveau non- terminal E et on écrit : E TE E +TE E ε De manière plus systématique, chaque fois quon a deux productions X X et X cela veut dire quelle génèrent le langage décrit par lexpression régulière, cest à dire, un suivi par zéro ou plusieurs. On peut réécrire cette expression régulière par des productions récursives à droite comme suit : X X ε X X 1 X 1 X X 2 X 2 devient

28 IFT313© Froduald Kabanza28 Exemple -Grammaire récursive à gauche : G = (V, A, R, E) : V= {E, F, T} A = {(, ), +, *, n} R = { E E + T E T T T * F T F F ( E) F n } Grammaire équivalente non récursive à gauche: G = (V, A, R, E) : V = {E, E, T, T, F} A = {(, ), +, *, n} R = { E TE E + TE | ε T FT *FT | ε F n}

29 IFT313© Froduald Kabanza29 Factorisation à gauche Une situation un peu similaire à la récursivité à gauche est lorsque deux productions ayant la même partie gauche ont des parties droites ayant un préfixe commun. Cela conduit à des entrées multiples dans la table danalyse LL(1). Cs-à-d., si la grammaire contient deux production A 1 | 2, si lentrée contient une chaîne non vide dérivée de, on ne peut pas savoir sil faut dériver A vers 1 ou vers 2. Cependant on peut différer la décision, en dérivant A vers X, où X est un nouveau non-terminal. Une fois que nous avons scannée lentrée dérivée de, on peut alors dériver X vers 1 ou vers 2. Autrement dit, peut factoriser la grammaire à gauche, en introduisant un nouveau non terminal pour représenter le suffixe sur lequel les deux productions diffèrent, comme suit : A X X 1 | 2

30 IFT313© Froduald Kabanza30 Exemple de factorisation à gauche 1/3 Soit la grammaire S if E then S else S | if E then S | other E num Nous avons vu que cette grammaire est ambiguë. Nous avons vu aussi une grammaire non ambiguë équivalente. Au lieu de travailler avec la grammaire non ambiguë équivalente, on pourrait factoriser la grammaire à gauche, comme suit : S if E then S X | other X else S | ε E num Cette grammaire est équivalente. Elle est toujours ambiguë. Elle va donc générer un conflit dans la table danalyse LL(1). Par contre, cest un conflit plus facile à gérer comparé au conflit dans la grammaire dorigine.

31 IFT313© Froduald Kabanza31 Exemple de factorisation à gauche 2/3 En effet la table danalyse de la grammaire S if E then S X | other X else S | ε E c est Lentrée [X, else] a un conflit reflétant lambiguité dans le choix de la règle de pruction à utiliser pour X lorsque le prochain token est else. otherc elseifthen$ S S otherS if E then S X X X else S X ε E E num

32 IFT313© Froduald Kabanza32 Exemple de factorisation à gauche 3/3 Lentrée [X, else] a un conflit reflétant lambiguité dans le choix de la règle de pruction à utiliser pour X lorsque le prochain token est else. On peut résoudre cet ambiguïté, en retant juste la règle X else S dans lentrée [X, else]. Cela revient associer else avec le plus récent then. otherc elseifthen$ S S otherS if E then S X X X else S X ε E E c

33 IFT313© Froduald Kabanza33 Stratégies de recouvrement derreurs Une erreur apparaît lorsque la chaîne dentrée nest pas syntaxiquement correcte : Soit on a un token au sommet de la pile, mais il diffère de celui à lentrée Soit on a un non terminal x au sommet de la pile et M[x,a] est vide. En pratique, on ne veut pas arrêter lanalyse à la toute première erreur. Aimeriez-vous un compilateur qui vous donne uniquement une seule erreur à la fois ? On veut continuer lanalyse syntaxique jusquà un certain nombre derreurs ou jusquà un certain niveau de sévérité derreur. Les stratégies de recouvrement typiques consistent à réparer la chaîne dentrée pour que lanalyse continue. En particulier, on pourrait: Insérer des tokens supposément manquants. Supprimer des tokens supposément de trop. Remplacer des tokens supposément erronés.

34 IFT313© Froduald Kabanza34 Stratégies de recouvrement Algorithm LLDriver variables : stack (pile), x (symbole au sommet de la pile), a (symbole dentrée courant), in (entrée) initialement la pile contient $S (le symbole départ S) et lentrée contient w$ (chaîne de tokens w). while (true) { if (x = = $) && (a= = $) return true ; // on accepte la chaîne dentrée comme étant correcte if (x = = a) && (a != $) // match transition { pop a from the stack; // dépiler le symbole de la pile a = in.read(); // lire le token (symbole) courant et avancer la tête de lecture continue;} if x is a nonterminal // predictive transition { if M[x,a] is empty error(x,a); // recouvrement derreur let x y 1 … y k the production in M[x,a] pop x from the stack; push y k on the stack; …; push y 1 on the stack; continue; } error(x,a);} // recouvrement derreur

35 IFT313© Froduald Kabanza35 Insertion de tokens manquants Pour insérer un token manquant de linput, on na pas besoin de lajouter explicitement à la chaîne dentrée. Il suffirait de prétendre que le token est présent, imprimer un message approprié et continuer normalement. Pour ce cas, la fonction error(x,a) pourrait procéder comme suit : Si x, le symbole au sommet de la pile, est un token, afficher le message Expected x on the input. Si x est un non terminal, afficher le message Expected, a 1, …, a n on the input, tel que a i sont les tokens pour lesquels lentrée M[x, a i ] est définie (lentrée dans la table M est non vide). Dépiler et lire le prochain token : pop x from the stack; a = in.read();

36 Report the error Pile Étape Règle Algorithm LLDriver 0. stack = ($S); a = in.read(); x=stack.top(); while (true) { 1. if (x = = $) && (a= = $) return true ; 2. if (x = = a) && (a != $) { pop a from stack; a = in.read(); continue;} 3. if x is a nonterminal { if M[x,a] is error exit with error; let x y1 … yk in M[x,a] pop x from stack; push y on stack; continue; } 4. exit with error;} Entrée Entrée : n n*n $E $ET $ETF $ETn $ET $E $E T+ $E T $ETF $ETn $ET $ETF* $ETF $ETn $ET $E $ n n*n$ n*n$ Error : expected +, *, ), or $ +n*n$ On suppose le + +n*n$ n*n$ *n$ n$ $ $ $ E TE T FT F n T ε E +TE T FT F n T *FT F n T ε E ε n+* E E TE $ E E +TE E ε T T FT T T ε T *FT T ε F F nF (E) () E TE IFT31336© Froduald Kabanza Exemple 1

37 Report the error Pile Étape Règle Algorithm LLDriver 0. stack = ($S); a = in.read(); x=stack.top(); while (true) { 1. if (x = = $) && (a= = $) return true ; 2. if (x = = a) && (a != $) { pop a from stack; a = in.read(); continue;} 3. if x is a nonterminal { if M[x,a] is error exit with error; let x y1 … yk in M[x,a] pop x from stack; push y on stack; continue; } 4. exit with error;} Entrée Entrée : n+*n $E $ET $ETF $ETn $ET $E $E T+ $E T $ETF $ETn $ET $ETF* $ETF $ETn $ET $E $ n+*n$ +*n$ *n$ Error: expected n or (. n*n$ Si on suppose n. n*n$ *n$ n$ $ $ $ E TE T FT F n T ε E +TE T FT F n T *FT F n T ε E ε n+* E E TE $ E E +TE E ε T T FT T T ε T *FT T ε F F nF (E) () E TE IFT31337© Froduald Kabanza Exemple 2

38 Pile Étape Règle Algorithm LLDriver 0. stack = ($S); a = in.read(); x=stack.top(); while (true) { 1. if (x = = $) && (a= = $) return true ; 2. if (x = = a) && (a != $) { pop a from stack; a = in.read(); continue;} 3. if x is a nonterminal { if M[x,a] is error exit with error; let x y1 … yk in M[x,a] pop x from stack; push y on stack; continue; } 4. exit with error;} Entrée Entrée : n+*n $E $ET $ETF $ETn $ET $E $E T+ $E T $ETF $ET)E( $ET)E... n+*n$ +*n$ *n$ Error: expected n or (. (*n$ Si on suppose (. (*n$ *n$ Error: expected n or (. n*n$ Si on suppose n.... E TE T FT F n T ε E +TE T FT F n... n+* E E TE $ E E +TE E ε T T FT T T ε T *FT T ε F F nF (E) () E TE IFT31338© Froduald Kabanza Exemple 3

39 IFT313© Froduald Kabanza39 Recouvrement derreurs par insertion de tokens Le recouvrement derreur par insertion de tokens est à utiliser avec précaution parce que une cascade derreurs risque de mener à une situation où les tokens sont insérés (plus exactement, sont supposés présents) indéfiniment, de sorte que la chaine dentrée nest jamais vidée, c-à-d., menant à une boucle sans fin.

40 IFT313© Froduald Kabanza40 Recouvrement derreurs par suppression de tokens Le recouvrement derreur par suppression de tokens est plus sécuritaire parce quil garantie toujours que la chaîne dentrée va être vidée. Étant donné x, le symbole au sommet de la pile, la stratégie est, en cas derreur, de sauter (supprimer) les prochains tokens jusquau premier token x, si x est un token, ou jusquau premier token dans dans Follow(x) si x est un non terminal. Pour ce cas, la fonction error(x,a) va procéder comme suit : Si x, le symbole au sommet de la pile, est un token, afficher le message Expected x on the input. Si x est un non terminal, afficher le message Expected, a 1, …, a n on the input, tel que a i sont les tokens pour lesquels lentrée M[x, a i ] est définie (non vide). Dépiler x; Si x est un token, avancer la tête de lecture juste après le prochain token x (c-à- d., a devient ce token). Si x est un non terminal, avancer la tête de lecture jusquau prochain token dans Follow(x) (c-à-d., a devient ce token).

41 Pile Étape Règle Algorithm LLDriver 0. stack = ($S); a = in.read(); x=stack.top(); while (true) { 1. if (x = = $) && (a= = $) return true ; 2. if (x = = a) && (a != $) { pop a from stack; a = in.read(); continue;} 3. if x is a nonterminal { if M[x,a] is error exit with error; let x y1 … yk in M[x,a] pop x from stack; push y on stack; continue; } 4. exit with error;} Entrée Entrée : n+ *n $E $ET $ETF $ETn $ET $E $E T+ $E T $E $ n+*n$ +*n$ *n$ Error: expected n or (. *n$ Avancer jusquà au prochain terminal dans Follow de E $ $ E TE T FT F n T ε E +TE E ε n+* E E TE $ E E +TE E ε T T FT T T ε T *FT T ε F F nF (E) () E TE IFT31341© Froduald Kabanza Exemple 4 Report the error

42 IFT313© Froduald Kabanza42 Résumé Nous avons vu un nouvel algorithme pour lanalyse syntaxique non récursive, LL1Driver. Il utilise une table danalyse, générée à partir de la grammaire. Des transformations peuvent être nécessaires pour avoir grammaire LL(1). Au lieu du driver LL1 et de la pile, on peut écrire un analyseur syntaxique en considérant chaque règle de production comme un appel de fonction qui implémente une étape de dérivation et en « matchant » les tokens chaque fois quils apparaissent dans une dérivation. Ceci donne lieu à un analyseur descendant récursif. La table danalyse LL(1) demeure toujours nécessaire même dans ce cas. Cest lapproche utilisée par JavaCC. Nous la verrons à la leçon suivante.


Télécharger ppt "IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs."

Présentations similaires


Annonces Google