Bureau 203 - M3 extension mirabelle.nebut at lifl.fr 2012-2013
Principes Factorisation à gauche Suppression de la récursivité à gauche 2/119
Objectif du cours Comprendre le fonctionnement des générateurs de parser descendants : LL(1), ex antlr V1 LL(k), ex javacc LL(*), ex antlr V3 3/119
Analyse descendante L automate à pile sous-jacent : effectue uniquement des lectures et des expansions ; construit un arbre en ordre préfixe (idem aut. items) ; part de l axiome (idem aut. items) ; construit une dérivation gauche (idem aut. items). 4/119
Différence avec l automate des items Deux différences fondamentales : analyse déterministe dite prédictive ; plus d items ni de réductions explicites. 5/119
Analyse déterministe À chaque expansion l analyseur sait choisir une production. Il ne revient jamais sur ce choix : en cas de succès le mot appartient au langage ; en cas d échec on est sûr que mot n appartient pas au langage. 6/119
Analyse prédictive L analyseur prédit quelle production utiliser...... en analysant les k prochains symboles sous la tête de lecture. Conséquences : ne fonctionne qu avec certaines grammaires, dites LL(k) ; tête de lecture toujours définie : marqueur de fin de mot #. NB : dans ce cours techniques pour k=1, on regarde uniquement la tête de lecture. 7/119
Se passer des items Rappel : item de la forme [X α β] : X est en cours de reconnaissance ; α a déjà été reconnu ; il reste à reconnaître β, le futur de l item Un analyseur LL : ne mémorise pas qu il est en train de reconnaître X ; ne mémorise pas qu il a reconnu α ; considère uniquement β. 8/119
Se passer des items : conséquences Plus besoin d axiome supplémentaire. Dans la pile : plus d items mais des mots étendus : mots de (V N V T ) ; l alphabet est V N V T ; le symbole de pile initiale est l axiome. S pile initiale A b B une pile pile vide (acceptation) 9/119
Exemple à suivre dans le cours Soit la grammaire G = {V T, V N, S, P} avec : V T = {a, b, d, e} ; V N = {S, A, B, D} ; P contient les productions : S AB Da A aab ɛ B bb ɛ D dd e 10/119
Exemple - les piles pour abb# S AB Da B bb ɛ A aab ɛ D dd e abb#? S abb# (1) A B abb# (2) a A b B abb# (3) A b B bb# (4) b B bb# (5) B b# (6) b B b# (7) B # (8) # (9) Comparer avec l automates des items! Dérivation gauche, arbre en ordre préfixe. 11/119
Généralisation La configuration initiale est (m#, S) ; La configuration finale est (#, ) : acceptation par pile vide. On traite systématiquement le sommet de pile. 12/119
Transition de lecture Si le sommet de pile est un terminal a V T : on contrôle que a est bien sous la tête de lecture (sinon échec) ; on le consomme ; on le dépile. Lecture de a : (am, z 1... z n a) (m, z 1... z n ) 13/119
Transition d expansion Si le sommet de pile est un non terminal X V N...... et que la tête de lecture est y V T {#}... si Table[X, y] contient X X 1... X n : on dépile X ; on empile à sa place X 1... X n, avec X 1 au sommet. (m, z 1... z n X ) (m, z 1... z n X n... X 1 ) sinon erreur. 14/119
Transition d expansion : remarque Expansion par X X 1... X n : (m, z 1... z n X ) (m, z 1... z n X n... X 1 ) X 1 sera traité en premier. on assure ainsi la construction d une dérivation gauche ; 15/119
Construction de l arbre syntaxique : ordre préfixe Transition d expansion par X X 1... X n : X est le prochain nœud à traiter dans l arbre (pour l ordre préfixe) ; on lui rajoute les fils X 1... X n de la gauche vers la droite ; le prochain nœud à traiter devient X 1. Transition de a-lecture : a est le prochain nœud à traiter dans l arbre (pour l ordre préfixe) ; on vérifie que a concorde bien avec la tête de lecture ; et on passe au nœud suivant. 16/119
Mise en œuvre Les outils n implantent pas un automate à pile. Ils utilisent une implémentation récursive. Dans tous les cas, le choix de l expansion est indiqué par une table d analyse. 17/119
Table d analyse - exemple S A B D a S AB A aab erreur erreur b S AB A ɛ B bb erreur d S Da erreur erreur D dd e S Da erreur erreur D e # S AB A ɛ B ɛ erreur 18/119
Table d analyse LL(1) Contient toute l intelligence de l analyseur syntaxique. Definition La table d analyse Table est un tableau à deux dimensions tel que : chaque colonne est indicée par un non-terminal V N ; chaque ligne est indicée par un terminal V T ou # ; chaque case contient une production P ou erreur. On verra plus tard comment remplir cette table. 19/119
Interprétation de Table[a, X ] si le terminal a V T est sous la tête de lecture ; et si le non-terminal en cours de traitement est X V N ; alors on consulte Table[a, X ]. Si Table[X, a] contient X γ alors on choisit une expansion par cette production ; erreur alors erreur de syntaxe : X et a ne s accordent pas. 20/119
Principes Factorisation à gauche Suppression de la récursivité à gauche 21/119
Analyseur descendant récursif Principe : analyseur LL codé par un ensemble de fonctions ; ces fonctions s appellent les unes les autres ; n utilise pas de pile explicite : pile implicite des appels. Codage des fonctions : une fonction X() par non-terminal X V N de la grammaire ; X() reconnaît un mot engendré par X ; la fonction X() code les productions Table[X, y] de la table d analyse, pour tout y V T #. 22/119
Exemple Écrire un analyseur syntaxique récursif LL(1) Parser pour G : S AB Da A aab ɛ B bb ɛ D dd e À voir : écriture de S(), A(), B(), D() ; collaboration avec un analyseur lexical. 23/119
Collaboration avec un analyseur lexical On reprend les conventions utilisées en TP : un an. lexical anlex de type Scanner (supposé donné) ; symboles de type Symbole ; codage entier du type des symboles dans TypeSymboles (noté TS dans les transparents) ; méthode int gettype() de Symbole pour obtenir ce type ; méthode Symbole next token() de Scanner : avance la tête de lecture tetelect ; retourne le symbole lu, de type Symbole. on remplace le marqueur # par TS.EOF. 24/119
Construction de l analyseur syntaxique... public class Parser { // analyseur lexical private Scanner anlex; // symbole courant reçu de l analyseur lexical private Symbole tetelect; public Parser (Scanner anlex) { this.anlex = anlex; }... 25/119
Lancement de l analyseur syntaxique Dans la classe Parser : public void analyser() throws ScannerException, ParserExcep // positionnement tete de lecture this.tetelect = (Symbole) this.anlex.next_token(); this.s(); // je veux reconna^ıtre l axiome } // et uniquement l axiome if (this.tetelect.gettype()!= TS.EOF) throw new ParserException(); 26/119
Code de S() La tête de lecture est déjà positionnée sur le symbole de prédiction. S a S AB b S AB d S Da e S Da # S AB private void S() throws... { if (this.tetelect.gettype() == TS.a)... // S -> AB else if (this.tetelect.gettype() == TS.b)... // S -> AB else if (this.tetelect.gettype() == TS.d)... // S -> Da else if (this.tetelect.gettype() == TS.e)... // S -> Da else if (this.tetelect.gettype() == TS.EOF)... // S -> AB else throw new ParserException(); } 27/119
Code de S() On factorise. S a S AB b S AB d S Da e S Da # S AB private void S() throws... { if (this.tetelect.gettype() == TS.a this.tetelect.gettype() == TS.b this.tetelect.gettype() == TS.EOF)... // S -> AB else if (this.tetelect.gettype() == TS.d this.tetelect.gettype() == TS.e)... // S -> Da else throw new ParserException(); } 28/119
Code des productions de S() Code pour S AB : je veux reconnaître A puis B ; A() ; B() ; Code pour S Da : je veux reconnaître D...... puis vérifier que a est bien sous la tête de lecture ; et consommer a. 29/119
Terminaux : vérification et consommation Méthode consommer dédiée à la gestion des terminaux : private void consommer(int type) throws ScannerException, ParserException { if (this.tetelect.gettype() == type) this.tetelect = (Symbole) this.anlex.next_token(); else throw new ParserException(); } Code pour S Da : D(); this.consommer(ts.a);. 30/119
Code final de S() S a S AB b S AB d S Da e S Da # S AB private void S() throws... { if (this.tetelect.gettype() == TS.a this.tetelect.gettype() == TS.b this.tetelect.gettype() == TS.EOF) { A(); B(); // S -> AB } else if (this.tetelect.gettype() == TS.d this.tetelect.gettype() == TS.e) { D(); this.consommer(ts.a); // S -> Da } else throw new ParserException(); } Quand S() termine, pour un mot accepté, la tête de lecture est sur TS.EOF. 31/119
Code de A() La tête de lecture est déjà positionnée sur le symbole de prédiction. A a A aab b A ɛ d erreur e erreur # A ɛ private void A() throws... { if (this.tetelect.gettype() == TS.a)... // A -> aab else if (this.tetelect.gettype() == TS.b this.tetelect.gettype() == TS.EOF)... // A -> else // erreur throw new ParserException(); } 32/119
Code des productions de A() Code pour A aab : this.consommer(ts.a); A(); this.consommer(ts.b); Code pour A ɛ : le mot vide est immédiatement reconnu ; sans toucher à la tête de lecture ; on ne fait rien. 33/119
Code final de A() A a A aab b A ɛ d erreur e erreur # A ɛ private void A() throws... { if (this.tetelect.gettype() == TS.a) { // A -> aab this.consommer(ts.a); A(); this.consommer(ts.b); } else if (this.tetelect.gettype() == TS.b this.tetelect.gettype() == TS.EOF) // rien, A -> } else // erreur throw new ParserException(); } Quand A() termine, pour un mot accepté, la tête de lecture est positionnée pour reconnaître un B ou lire un b. 34/119
Code final de B() B a erreur b B bb d erreur e erreur # B ɛ private void B() throws... { if (this.tetelect.gettype() == TS.b) { // B -> bb this.consommer(ts.b); B(); } else if (this.tetelect.gettype() == TS.EOF) // rien, B -> } else // erreur throw new ParserException(); } 35/119
Code final de D() D a erreur b erreur d D dd e D e # erreur private void D() throws... { if (this.tetelect.gettype() == TS.d) { // D -> dd this.consommer(ts.d); D(); } else if (this.tetelect.gettype() == TS.e) // D -> e this.consommer(ts.e); else // erreur throw new ParserException(); } 36/119
Exemple d exécution Reconnaître abb#? 37/119
Principes Factorisation à gauche Suppression de la récursivité à gauche 38/119
Principes Factorisation à gauche Suppression de la récursivité à gauche 39/119
Outils pour l analyse prédictive, intuition - 1 Comment choisir entre S AB et S Da? Supposons que je sache que : AB ne permet de dériver que des mots préfixés par a ou par b ; AB au et AB bu, pour u V T ; Da ne permet de dériver que des mots préfixés par d ou par e ; Da du et Da eu, pour u V T. 40/119
Outils pour l analyse prédictive, intuition - 1 Maintenant je sais (partiellement) choisir entre S AB et S Da : si tête lecture {a, b} : choisir S AB ; si tête lecture {d, e} : choisir S Da. S a S AB b S AB d S Da e S Da #? 41/119
Ensemble Premier - définition On dit que Premier(AB) = {a, b} et Premier(Da) = {d, e}. Pour α (V T V N ) +, Premier(α) contient l ensemble des terminaux de V T susceptibles de commencer un mot de V T + dérivé de α. Si α = ɛ, cet ensemble est vide. Definition Soit une grammaire algébrique. On définit : Premier : (V T V N ) P(V T ) α {a V T α au, u V T } 42/119
Les Premier sur les arbres syntaxiques S S S A B A B A B a A b b B α (V T V N ) S S D D d D a e a Premier(α) 43/119
Calcul des Premier - 0 Soit α (V N V T ) : cas α = ɛ :? α = a, a V T :? α = aβ, a V T, β (V N V T ) :? α = X, X V N :? α = X β, X V N, β (V N V T ) :? fcas 44/119
Calcul des Premier - 1 Soit α (V N V T ) : cas α = ɛ : α = a, a V T : {a} α = aβ, a V T, β (V N V T ) : {a} α = X, X V N :? α = X β, X V N, β (V N V T ) :? fcas 45/119
Calcul de Premier(X ), X V N Si l ensemble des productions de membre gauche S est : alors on a : S AB Da Premier(S) = Premier(AB) Premier(Da) Cas général : Si la grammaire contient les productions de membre gauche X : X γ 1... γ n alorspremier(x ) = {Premier(γ i ) X γ i P} 46/119
Calcul des Premier - 2 Soit α (V N V T ) : cas α = ɛ : α = a, a V T : {a} α = aβ, a V T, β (V N V T ) : {a} α = X, X V N : {Premier(γ i ) X γ i P} α = X β, X V N, β (V N V T ) :? fcas 47/119
Calcul des Premier, α = X β, X V N Deux cas selon que X peut s effacer ou non : X ɛ? Si X ɛ on dit que X est ɛ-productif : X ɛ-prod 48/119
Calcul des Premier, α = X β, X ɛ-prod - exemple Par exemple D ɛ-productif : S S D dd e D D alors Premier(Da) = Premier(D) d D a e a Donc, si X ɛ-prod, Premier(X β) = Premier(X ) 49/119
Calcul des Premier, α = X β, X ɛ-prod - exemple Par exemple A ɛ-productif : A ɛ aab Premier(AB) = Premier(A) Premier(B) Premier(ABS) = Premier(A) Premier(BS) a A A S b S B A B B b Donc, si X ɛ alors Premier(X β) = Premier(X ) Premier(β) 50/119
Calcul des Premier Principes Soit α (V N V T ) : cas fcas α = ɛ : α = a, a V T : {a} α = aβ, a V T, β (V N V T ) : {a} α = X, X V N : {Premier(γ i ) X γ i P} α = X β, X V N \ ɛ-prod, β (V N V T ) : Premier(X ) α = X β, X V N ɛ-prod, β (V N V T ) : Premier(X ) Premier(β) 51/119
Calcul effectif des ensembles Premier On procède en deux étapes : 1. on pose un système d équations pour Premier ; 2. on calcule par itération de point fixe les plus petits ensembles qui satisfont ces équations. Pour le moment on suppose donné ɛ-prod, l ensemble des ɛ-productifs. 52/119
Exemple Principes S AB Da A aab ɛ B bb ɛ D dd e ɛ-prod = {A, B, S} Premier(S) =? Premier(A) =? Premier(B) =? Premier(D) =? α = ɛ : α = a, a V T : {a} α = aβ, a V T, β (V N V T ) : {a} α = X, X V N : {Premier(γi ) X γ i P} α = X β, X V N \ɛ-prod, β (V N V T ) : Premier(X ) α = X β, X V N ɛ-prod, β (V N V T ) : Premier(X ) Premier(β) 53/119
Exemple Principes Premier(S) = Premier(A) Premier(B) Premier(D) Premier(A) = {a} Premier(B) = {b} Premier(D) = {d, e} D où Premier(S) = {a, b, d, e} Premier(A) = {a} Premier(B) = {b} Premier(D) = {d, e} Premier(AB) = {a, b} Premier(Da) = {d, e} Premier(aAb) = {a} Premier(bB) = {b} Premier(dD) = {d} Premier(e) = {e} Premier(ɛ) = 54/119
Exemple : remplissage de la table A aab et Premier(aAb) = {a} A ɛ et Premier(ɛ) = S A B D a S AB A aab erreur erreur b S AB A ɛ B bb erreur d S Da erreur erreur D dd e S Da erreur erreur D e # S AB A ɛ B ɛ erreur 55/119
Exemple : remplissage de la table S AB et Premier(AB) = {a, b} S Da et Premier(Da) = {d, e} S A B D a S AB A aab erreur erreur b S AB A ɛ B bb erreur d S Da erreur erreur D dd e S Da erreur erreur D e # S AB A ɛ B ɛ erreur 56/119
Remarque : résolution du système Premier(S) = Premier(A) Premier(B) Premier(D) Premier(A) = {a} Premier(B) = {b} Premier(D) = {d, e} Se résoud sans itération de point fixe : système d équations non récursif. Ce n est pas toujours le cas. 57/119
Résolution du système : autre exemple S S 1 S 2 a S 1 S b S 2 c Premier(S) = Premier(S 1 ) {a} Premier(S 1 ) = Premier(S) {b} Premier(S 2 ) = {c} iter Premier(S) Premier(S 1 ) Premier(S 2 ) 0 1 {a} {b} {c} 2 {a, b} {b, a} {c} 3 {a, b} {b, a} {c} stabilisation 58/119
Principes Factorisation à gauche Suppression de la récursivité à gauche 59/119
Définition des ɛ-prod Definition Un non terminal X V N est dit ɛ-productif si X ɛ. L ensemble des ɛ-productif est ɛ-prod. X est ɛ-productif si la grammaire contient la production : X ɛ ; ou X Y 1 Y 2... Y n telle que l ensemble des non-terminaux {Y 1, Y 2,..., Y n } V N ne contient que des non-terminaux ɛ-productifs. Algorithme de calcul similaire à celui qui calcule les productifs. 60/119
Exemple Principes S AB Da A aab ɛ B bb ɛ D dd e ɛ-prod? 61/119
Principes Factorisation à gauche Suppression de la récursivité à gauche 62/119
Outils pour l analyse prédictive, intuition - 2 Pour choisir entre S AB et S Da : si tête lecture {a, b} : choisir S AB ; si tête lecture {d, e} : choisir S Da. Et si la tête de lecture est #? # Premier(AB) Premier(Da). Comment choisir entre A aab et A ɛ? Premier(ɛ) = les ensembles Premier ne suffisent pas. 63/119
, intuition Quand appliquer A ɛ? Quand la tête de lect. correspond à un terminal qui peut suivre A. A S A A B a b b Suivant(A) Suivant(A) Premier(B) 64/119
, intuition On a donc b Suivant(A) A a A aab b A ɛ d? e? #? 65/119
, intuition Pour α (V T V N ) +, Suivant(α) contient l ensemble des terminaux de V T susceptibles de suivre α dans un mot de V T + dérivé de l axiome S. Si α = ɛ, cet ensemble est vide. Par convention, Suivant(S) {#}. 66/119
, définitions équivalentes Definition Soit une grammaire algébrique d axiome S. On définit : Suivant : (V T V N ) P(V T ) α {a V T S βαaγ, pour β, γ (V N V T ) } Definition Suivant : (V T V N ) P(V T ) α {a Premier(γ) S βαγ, pour β, γ (V N V T ) } 67/119
Calcul des Suivant - 1 Pour calculer Suivant(X ), on regarde les productions dans lesquelles X apparaît en partie droite (différent du calcul des Premier). Pour Suivant(A) : A aab A S AB S A A B a b 68/119
Calcul des Suivant - 2 Soit P X P l ensemble des productions p dans lesquelles X apparaît en partie droite : Suivant(X ) = p P X Suivant p (X ) Ex : P A = {S AB, A aab} Suivant(A) = Suivant(A) S AB Suivant(A) A aab 69/119
Calcul des Suivant, cas de l axiome Pour l axiome, on ajoute le marqueur de fin de mot : Ex : pour X axb ɛ Suivant(S) = {#} p P S Suivant p (S) P X = {X ax b} Suivant(X ) = {#} Suivant(X ) X ax b 70/119
Calcul des Suivant - 3 - exemple Suivant(A) S AB? (exemple précédent) Cas déjà vu : S A B Suivant(A) Premier(B) 71/119
Calcul des Suivant - 3 - exemple Suivant(A) S AB? (exemple précédent) mais B est ɛ-prod! S A B Suivant(A) Suivant(S) 72/119
Calcul des Suivant - 3 - exemple Puisque B est ɛ-prod : Suivant(A) S AB = Premier(B) Suivant(S) 73/119
Calcul des Suivant - 4 Quand une production est de la forme... X α : pour calculer Suivant(X ) ; Il faut pouvoir dire si α (V N V T ) est ɛ-productif ou pas. Definition α (V N V T ) est ɛ-productif si α ɛ. On définit la fonction : Eps : (V N V T ) {vrai, faux} α α est ɛ-productif On verra après comment calculer Eps. 74/119
Calcul des Suivant - 5 Pour calculer Suivant p (X ) avec : p = Y αx β et Eps(β) = faux, α, β (V N V T ) Y X β Suivant p (X ) = Premier(β) Ex : pour Y Xb, Suivant(X ) Y Xb = {b}. 75/119
Calcul des Suivant - 6 Pour calculer Suivant p (X ) avec : p = Y αx Y α X Suivant p (X ) = Suivant(Y ) 76/119
Calcul des Suivant - 7 Pour calculer Suivant p (X ) avec : p = Y αx β et Eps(β) = vrai, α, β (V N V T ) Y X β Suivant p (X ) = Premier(β) Suivant(Y ) Ex : pour S AB, Suivant(A) S AB = Premier(B) Suivant(S). 77/119
Remarque - 1 Principes Si X apparaît plusieurs fois en partie droite d une production, il faut prendre en compte toutes ses occurrences dans le calcul de Suivant(X ). Ex : Y X ax ax c Suivant Y X ax ax c (X ) = {a, c} 78/119
Remarque - 2 Principes Pourquoi pas Suivant(X ) Y X β = Premier(β) Suivant(β)? Parce que Suivant(Y ) Suivant(β). Ex : S Y Z Y X 1 X 2 X 1 a X 2 ɛ b Z X 2 c Suivant(S) = {#} Suivant(Y ) = Suivant(S) = {#} Suivant(Z) = Suivant(S) = {#} Suivant(X 2 ) = {c} Suivant(Y ) = {c, #} Suivant(X 1 ) = Premier(X 2 ) Suivant(Y ) 79/119
Calcul des Suivant, récapitulons! # Suivant(axiome) Soit P X P l ensemble des productions p dans lesquelles X apparaît en partie droite : Suivant(X ) = p P X Suivant p (X ) avec : Suivant p (X ) = cas p = Y αx : Suivant(Y ) p = Y αx β et Eps(β) = faux : Premier(β) p = Y αx β et Eps(β) = vrai : Premier(β) Suivant(Y ) fincas 80/119
Calcul effectif des ensembles Suivant On procède en deux étapes : on pose un système d équations pour Suivant ; on calcule par itération de point fixe les plus petits ensembles qui satisfont ces équations. avec initialement Suivant(S) = {#}, et pour les autres non-terminaux Suivant(X ) =. 81/119
Exemple Principes S AB Da A aab ɛ B bb ɛ D dd e Eps(B) = vrai Suivant? # Suivant(axiome) Suivant(X ) = p P X Suivant p (X ) avec : Suivant p (X ) = cas p = Y αx : Suivant(Y ) p = Y αx β et Eps(β) = faux : Premier(β) p = Y αx β et Eps(β) = vrai : Premier(β) Suivant(Y ) fincas 82/119
Exemple de remplissage de table A ɛ et Suivant(A) = {b, #} S A B D a S AB A aab erreur erreur b S AB A ɛ B bb erreur d S Da erreur erreur D dd e S Da erreur erreur D e # S AB A ɛ B ɛ erreur 83/119
Exemple de remplissage de table S AB et Suivant(S) = {#} S A B D a S AB A aab erreur erreur b S AB A ɛ B bb erreur d S Da erreur erreur D dd e S Da erreur erreur D e # S AB A ɛ B ɛ erreur 84/119
Calcul des ɛ-productifs On connaît déjà ɛ-prod, ens. des non-terminaux ɛ-productifs. Pour calculer Eps(α) : Eps(α) = cas α = ɛ : vrai α = X 1... X n, n 1 avec {X 1,..., X n } V N et {X 1,..., X n } ɛ-prod : vrai autre : faux // α contient un terminal fincas 85/119
Exemple Principes Sachant que ɛ-prod = {A, B, S} : Eps(Da)? Eps(AB)? Eps(ɛ)? Eps(B)? 86/119
Principes Factorisation à gauche Suppression de la récursivité à gauche 87/119
Table d analyse : au préalable On calcule : les ɛ-productifs ; les ensembles Premier ; les ensembles Suivant. 88/119
Remplissage de la table Entrée : une gram. alg. G, ses ensembles Premier et Suivant Sortie : la table d analyse Table pour toute production X γ P faire pour tout a Premier(γ) faire ajouter X γ à Table[X, a] fait si Eps(γ) = vrai alors pour tout b Suivant(X ) faire Table[X, b] = X γ fait finsi fait Ajouter erreur dans les entrées de Table restées vides 89/119
Exemple Principes S AB : Premier(AB) = {a, b} ; Eps(AB) = vrai ; Suivant(S) = {#}. S Da : Premier(Da) = {d, e} ; Eps(Da) = faux. Rien à compléter par erreur. S a S AB b S AB d S Da e S Da # S AB 90/119
Exemple Principes A aab : Premier(aAb) = {a} ; Eps(aAb) = faux. A ɛ : Premier(ɛ) = ; Eps(ɛ) = vrai ; Suivant(A) = {b, #}. On complète par erreur. A a A aab b A ɛ d erreur e erreur # A ɛ 91/119
Principes Factorisation à gauche Suppression de la récursivité à gauche 92/119
Analyseur LL(1) Un analyseur LL(1) est déterministe et piloté par le sommet de pile : si terminal a : lecture de a (ou erreur) ; si non terminal X avec a sous la tête de lecture : expansion selon Table[X, a]. Et si Table[X, a] contient plus d une production? Non-déterminisme : la grammaire n est pas LL(1) ; on ne peut pas appliquer une analyse LL(1). 93/119
Caractérisation par table d analyse : une grammaire est LL(1) si chaque case contient exactement une production ou erreur. Caractérisation par contre-exemple : une grammaire n est pas LL(1) s il existe 2 productions X α et X β telles que : 1. soit Premier(α) Premier(β) ; Ex : S as A, A a 2. soit Eps(α) = vrai et Premier(β) Suivant(X ) ; Ex : S as Ab, A ɛ b 3. soit Eps(α) = vrai et Eps(β) = vrai (la grammaire est ambiguë) Ex : S A B, A ɛ, B ɛ 94/119
LL(1) et ambiguïté Une grammaire LL(1) n est pas ambiguë. Une grammaire ambiguë n est pas LL(1). 95/119
Cas classiques non LL(1) Dans les cas suivants, la grammaire n est pas LL(1) : ambiguïté ; récursivité gauche : A Aa ɛ ; intuitivement récursivité infinie de A(). non factorisation gauche : S aa ab Solutions : : factorisation à gauche (parfois) ; suppression de la récursivité gauche (parfois) ; utiliser un générateur de parser plus puissant! 96/119
Factorisation à gauche Suppression de la récursivité à gauche Principes Factorisation à gauche Suppression de la récursivité à gauche 97/119
Factorisation à gauche Suppression de la récursivité à gauche Principes Factorisation à gauche Suppression de la récursivité à gauche 98/119
Factorisation à gauche : exemple - 1 Factorisation à gauche Suppression de la récursivité à gauche Les listes d identificateur de Init : listeident IDENT IDENT SEPVAR listeident On factorise IDENT et on obtient : listeident IDENT suitelisteident suitelisteident ɛ SEPVAR listeident 99/119
Factorisation à gauche : exemple - 2 Factorisation à gauche Suppression de la récursivité à gauche X ab abbx abbbx Factorisation de ab : on prend le plus grand préfixe commun. X aby Y ɛ bx bbx Puis à nouveau factorisation de b. 100/119
Factorisation à gauche Suppression de la récursivité à gauche Factorisation à gauche - algorithme On remplace les règles de la forme : où X αβ 1... αβ n γ 1... γ m α (V T V N ) + et β i, γ j (V T V N ) ; le préfixe commun α est choisi le plus grand possible ; α n est pas préfixe de γ j. par les règles : X αx γ 1... γ m X β 1... β n où X est un nouveau non-terminal. On réitère ce processus tant que nécessaire. 101/119
Factorisation à gauche Suppression de la récursivité à gauche Principes Factorisation à gauche Suppression de la récursivité à gauche 102/119
Factorisation à gauche Suppression de la récursivité à gauche Suppression de la récursivité à gauche Récursivité gauche : immédiate : production A Aα, α (V T V N ) + ; générale : il existe une dérivation A Aα, α (V T V N ) +. Il est possible de supprimer les deux cas. On ne verra que la récursivité immédiate. 103/119
Factorisation à gauche Suppression de la récursivité à gauche Suppression de la récursivité gauche immédiate On remplace les règles de la forme où X X α 1... X α n β 1... β m α i (V T V N ) + et β j (V T V N ) ; les β j ne commencent pas par X. par les règles : X β 1 X... β m X X α 1 X... α n X ɛ où X est un nouveau non-terminal. 104/119
Factorisation à gauche Suppression de la récursivité à gauche Suppression de la récursivité gauche : exemple Grammaire non ambiguë des expressions arithmétiques : E E + T T T T F F F i (E) X X α 1... X α n β 1... β m Après suppression de la rec gauche : E TE E +TE ɛ T FT T FT ɛ F i (E) X β 1 X... β m X X α 1 X... α n X ɛ 105/119
Factorisation à gauche Suppression de la récursivité à gauche Parfois ça ne suffit pas La grammaire ({a, b}, {S, A}, S, P) avec P = {S asb A, A aa ɛ} n est pas ambiguë ; n est pas récursive gauche ; est factorisée à gauche ; mais elle n est pas LL(1). 106/119
Au delà des grammaires LL(1) - 1 Factorisation à gauche Suppression de la récursivité à gauche La grammaire ({a, b}, {A, B}, A, P) avec P = {A abb ɛ, B Aaa b} n est pas LL(1). En effet Eps(A) = vrai et a Premier(A) Suivant(A). 107/119
Principes Factorisation à gauche Suppression de la récursivité à gauche 108/119
Grammaires LL(k), exemple La grammaire : n est pas LL(1). declaration DECLINT listeident FININSTR listeident IDENT IDENT SEPVAR listeident Elle est LL(2), et acceptée par un analyseur LL(k). En regardant 2 symboles sous la tête de lecture : si IDENT FININSTR : choisir listeident IDENT si IDENT SEPVAR : choisir listeident IDENT SEPVAR listeident 109/119
Grammaire LL(k), autre exemple P = {A abb ɛ, B Aaa b} Cette grammaire est LL(2) : Premier 2 (A) = {ab} Premier 2 (B) = {ab, aa, b} Suivant 2 (A) = {aa, #} 110/119
Table d analyse LL(2) A abb ɛ B Aaa b aa ab b # A A ɛ A abb erreur A ɛ B B Aaa B Aaa B b erreur 111/119
Analyseurs LL(k), principe Effectuent une prédiction basée sur k symboles. k borné. Ex : javacc 112/119
Insuffisance de l approche LL(k), [antlr] method type ID [ args ] ; type ID [ args ] { body } args unarg unarg, args unarg INT ID... Cette grammaire n est pas LL(k), mais est acceptée par antlr. 113/119
Analyseurs LL(*) Ne fixent pas une taille de look-ahead a priori. Représentent par un AFD le langage de look-ahead, pourvu qu il soit régulier. 114/119
Vers les formes ebnf Même un analyseur LL(*) refuse la récursivité gauche. Fâcheux pour les grammaires à opérateurs! Solution : grammaires dites en forme ebnf. E T ( + T ) * T F ( * T ) * F ( E ) id E E + T T T F * T F F ( E ) id 115/119
Grammaires sous forme ebnf Grammaires algébriques avec facilités d écriture. En partie droite de production : opérateurs à la expression régulière Refusé par Cup et tout générateur de parseur n acceptant pas les ebnf Accepté par la majorité des analyeurs LL(k). Semble plus simple, attention à l attribution. Ne pas utiliser en DS sauf si explicitement demandé. 116/119
Grammaires non LL(*) [antlr] s : label ID = expr label return expr ; label : ID : label ; n est pas LL(*) : [fatal] rule s has non-ll(*) decision due to recursive rule invocations from alts 1,2. [...] Version LL(*) : label : ( ID : )* 117/119
Génération de code à la ebnf E T ( + T ) * E() { T(); tant que tetelect est + { consommer(+); T(); } } Clôture de Kleene itération dans le code 118/119
Génération de code à la ebnf listea a* listea() { tant que tetelect est a { consommer(a); } } plus efficace que le code récursif généré par : listea a listea ɛ 119/119
AntLR Outil très riche. Décrit dans le même formalisme ebnf les entités lexicales et la syntaxe. Lit toute l entrée avant de lancer l analyse lexicale. 120/119