Analyse (lexicale, syntaxique) L3 MIAGE Analyse descendante Avec tous mes remerciements à Mirabelle Nebut pour son excellent cours de COMPIL Université de Lille, France 2014-2015
1 Méthodes d analyse syntaxique 2 Principes de l analyse descendante 3 Analyseur récursif 4 Construction de la table d analyse Ensembles Premier Ensemble des ɛ-prod Ensembles Suivant Remplissage de la table d analyse 5 Caractérisation d une grammaire LL(1) 6 Quand une grammaire n est pas LL(1) Factorisation à gauche Suppression de la récursivité à gauche 7 Analyseurs LL(k), LL(*)
1 Méthodes d analyse syntaxique 2 Principes de l analyse descendante 3 Analyseur récursif 4 Construction de la table d analyse Ensembles Premier Ensemble des ɛ-prod Ensembles Suivant Remplissage de la table d analyse 5 Caractérisation d une grammaire LL(1) 6 Quand une grammaire n est pas LL(1) Factorisation à gauche Suppression de la récursivité à gauche 7 Analyseurs LL(k), LL(*)
Déterministe Méthodes déterministes : grammaire non ambiguë algorithme linéraire en nombre de lexèmes lus pas de retour en arrière/explorations de plusieurs dérivations potentielles unique exécution de l analyseur sur un mot certitude sur l acceptation ou le refus du mot applicable uniquement pour une sous classe restrainte de grammaires algébriques Il existe des méthodes non déterministes pour traiter des classes de grammaires plus générales hors cours.
Descendante et Ascendante Il y a deux méthodes classique d analyse déterministes : 1 descendante (LL) : construction de l arbre de la racine vers les feuilles parcours préfixé : racine en premier prédiction des productions à appliquer en fonction du lexème courant : construire les noeuds dont les fils ont pu être prédits dérivation gauche écriture manuelle ou génération automatique d analyseurs 2 ascendante (LR, LALR) : construction de l arbre des feuilles vers la racine parcours postfixé : racine en dernier association des lexèmes d entrée pour déterminer les productions appliquées : trouver et construire les noeuds dont les tous les fils sont déjà construits dérivation droite génération automatique d analyseur : + complexe à la main
Gestion des erreurs Souvent quand on trouve une erreur la partie qui pose problème est passée depuis longtemps (e.g. mauvais parenthésage) On s arrête dès la première erreur? une compilation pour résoudre chaque erreur... Deux modes de gestion : récupération d erreur : ignorer l erreur, essayer de continuer réparation d erreur : ajouter/retirer ce qui a l air de manquer, essayer de continuer risque de provoquer d autres erreurs plus loin Gérer les erreurs : pas toujours facile, utile dans un vrai compilateur, pas vraiment l objectif du cours
1 Méthodes d analyse syntaxique 2 Principes de l analyse descendante 3 Analyseur récursif 4 Construction de la table d analyse Ensembles Premier Ensemble des ɛ-prod Ensembles Suivant Remplissage de la table d analyse 5 Caractérisation d une grammaire LL(1) 6 Quand une grammaire n est pas LL(1) Factorisation à gauche Suppression de la récursivité à gauche 7 Analyseurs LL(k), LL(*)
Analyse descendante LL(k) construction de l arbre de l axiome (racine) vers les symboles terminaux (feuilles) prédiction de la production à appliquer en fonction des k prochains lexèmes dérivation gauche : traiter toujours le non terminal le plus à gauche traiter les lexèmes de gauche à droite prédictions grâce à la table d analyse de la grammaire LL(1) : prédiction grâce au seul lexème courant qui doit toujours être défini marqueur de fin de mot #
Principe de la table d analyse Soit la grammaire G = {T, N, S, R} avec : T = {a, b, d, e}; N = {S, A, B, D} ; R contient les productions : S AB Da A aab ɛ B bb ɛ D dd e Quelle dérivation gauche pour... a.. b.. d..
Principe de la table d analyse Soit la grammaire G = {T, N, S, R} avec : T = {a, b, d, e}; N = {S, A, B, D} ; R contient les productions : S AB Da A aab ɛ B bb ɛ D dd e Quelle dérivation gauche pour... a.. il faut S AB aabb b.. d..
Principe de la table d analyse Soit la grammaire G = {T, N, S, R} avec : T = {a, b, d, e}; N = {S, A, B, D} ; R contient les productions : S AB Da A aab ɛ B bb ɛ D dd e Quelle dérivation gauche pour... a.. il faut S AB aabb : pas le choix prédiction! b.. d..
Principe de la table d analyse Soit la grammaire G = {T, N, S, R} avec : T = {a, b, d, e}; N = {S, A, B, D} ; R contient les productions : S AB Da A aab ɛ B bb ɛ D dd e Quelle dérivation gauche pour... a.. il faut S AB aabb : pas le choix prédiction! b.. il faut S AB ɛb bb d..
Principe de la table d analyse Soit la grammaire G = {T, N, S, R} avec : T = {a, b, d, e}; N = {S, A, B, D} ; R contient les productions : S AB Da A aab ɛ B bb ɛ D dd e Quelle dérivation gauche pour... a.. il faut S AB aabb : pas le choix prédiction! b.. il faut S AB ɛb bb d.. il faut S Da dda
Principe de la table d analyse Soit la grammaire G = {T, N, S, R} avec : T = {a, b, d, e}; N = {S, A, B, D} ; R contient les productions : S AB Da B bb ɛ Quelle dérivation gauche pour... A aab ɛ D dd e a.. il faut S AB aabb : pas le choix prédiction! b.. il faut S AB ɛb bb d.. il faut S Da dda La table donne pour chaque non terminal quelle production doit nécessairement être appliquée pour obtenir le lexème courant.
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
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 N ; chaque ligne est indicée par un terminal T ou # ; chaque case contient une unique production R ou erreur. On verra plus tard comment remplir cette table. déterministe
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
Interprétation de Table[a, X] et si le lexème courant est le terminal a T si le non-terminal en cours de traitement est X N = X est la racine du sous arbre syntaxique en construction alors on consulte Table[a, X]. Si Table[X, a] contient X γ alors on choisit cette production pour construire les fils du noeud X dans l arbre syntaxique en construction erreur alors erreur de syntaxe : X et a ne s accordent pas.
1 Méthodes d analyse syntaxique 2 Principes de l analyse descendante 3 Analyseur récursif 4 Construction de la table d analyse Ensembles Premier Ensemble des ɛ-prod Ensembles Suivant Remplissage de la table d analyse 5 Caractérisation d une grammaire LL(1) 6 Quand une grammaire n est pas LL(1) Factorisation à gauche Suppression de la récursivité à gauche 7 Analyseurs LL(k), LL(*)
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 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 T #.
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.
Collaboration avec un analyseur lexical On utilises les notations : 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 lexcur ; retourne le symbole lu, de type Symbole. on remplace le marqueur # par TS.EOF.
Construction de l analyseur syntaxique... public class Parser { // analyseur lexical private Scanner anlex; // symbole courant reçu de l analyseur lexical private Symbole lexcur; public Parser (Scanner anlex) { this.anlex = anlex; }...
Lancement de l analyseur syntaxique Dans la classe Parser : public void analyser() throws ScannerException, ParserException { // positionnement tete de lecture this.lexcur = (Symbole) this.anlex.next_token(); this.s(); // je veux reconnaître l axiome // et uniquement l axiome if (this.lexcur.gettype()!= TS.EOF) throw new ParserException(); }
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.lexcur.gettype() == TS.a)... // S -> AB else if (this.lexcur.gettype() == TS.b)... // S -> AB else if (this.lexcur.gettype() == TS.d)... // S -> Da else if (this.lexcur.gettype() == TS.e)... // S -> Da else if (this.lexcur.gettype() == TS.EOF)... // S -> AB else throw new ParserException(); }
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.lexcur.gettype() == TS.a } this.lexcur.gettype() == TS.b this.lexcur.gettype() == TS.EOF)... // S -> AB else if (this.lexcur.gettype() == TS.d this.lexcur.gettype() == TS.e)... // S -> Da else throw new ParserException();
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.
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.lexcur.gettype() == type) this.lexcur = (Symbole) this.anlex.next_token(); else throw new ParserException(); Code pour S Da : D(); this.consommer(ts.a);.
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.lexcur.gettype() == TS.a this.lexcur.gettype() == TS.b this.lexcur.gettype() == TS.EOF) { // S -> AB A(); B(); } else if (this.lexcur.gettype() == TS.d this.lexcur.gettype() == TS.e) { // S -> Da D(); this.consommer(ts.a); } else throw new ParserException(); } Quand S() termine, pour un mot accepté, la tête de lecture est sur TS.EOF.
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.lexcur.gettype() == TS.a)... // A -> aab else if (this.lexcur.gettype() == TS.b this.lexcur.gettype() == TS.EOF)... // A -> else // erreur throw new ParserException(); }
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.
Code final de A() A a A aab b A ɛ d erreur e erreur # A ɛ private void A() throws... { if (this.lexcur.gettype() == TS.a) { // A -> aab this.consommer(ts.a); A(); this.consommer(ts.b); } else if (this.lexcur.gettype() == TS.b this.lexcur.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.
Code final de B() B a erreur b B bb d erreur e erreur # B ɛ private void B() throws... { if (this.lexcur.gettype() == TS.b) { // B -> bb this.consommer(ts.b); B(); } } else if (this.lexcur.gettype() == TS.EOF) { // rien, B -> } else // erreur throw new ParserException();
Code final de D() D a erreur b erreur d D dd e D e # erreur private void D() throws... { if (this.lexcur.gettype() == TS.d) { // D -> dd this.consommer(ts.d); D(); } } else if (this.lexcur.gettype() == TS.e) { // D -> e this.consommer(ts.e); } else // erreur throw new ParserException();
Exemple d exécution Reconnaître abb#?
1 Méthodes d analyse syntaxique 2 Principes de l analyse descendante 3 Analyseur récursif 4 Construction de la table d analyse Ensembles Premier Ensemble des ɛ-prod Ensembles Suivant Remplissage de la table d analyse 5 Caractérisation d une grammaire LL(1) 6 Quand une grammaire n est pas LL(1) Factorisation à gauche Suppression de la récursivité à gauche 7 Analyseurs LL(k), LL(*)
Ensembles Premier 1 Méthodes d analyse syntaxique 2 Principes de l analyse descendante 3 Analyseur récursif 4 Construction de la table d analyse Ensembles Premier Ensemble des ɛ-prod Ensembles Suivant Remplissage de la table d analyse 5 Caractérisation d une grammaire LL(1) 6 Quand une grammaire n est pas LL(1) Factorisation à gauche Suppression de la récursivité à gauche 7 Analyseurs LL(k), LL(*)
Ensembles Premier 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 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 T.
Ensembles Premier 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 #?
Ensembles Premier Ensemble Premier - définition On dit que Premier(AB) = {a, b} et Premier(Da) = {d, e}. Pour α (T N) +, Premier(α) contient l ensemble des terminaux de T susceptibles de commencer un mot de T + dérivé de α. Si α = ɛ, cet ensemble est vide. Definition Soit une grammaire algébrique. On définit : Premier : (T N) P(T ) α {a T α au, u T }
Ensembles Premier Les Premier sur les arbres syntaxiques S S S A B A B A B A B a b b α (T N) S S D D d D a e a Premier(α)
Ensembles Premier Calcul des Premier - 0 Soit α (N T ) : cas α = ɛ :? α = a, a T :? α = aβ, a T, β (N T ) :? α = X, X N :? α = Xβ, X N, β (N T ) :? fcas
Ensembles Premier Calcul des Premier - 1 Soit α (N T ) : cas α = ɛ : α = a, a T : {a} α = aβ, a T, β (N T ) : {a} α = X, X N :? α = Xβ, X N, β (N T ) :? fcas
Ensembles Premier Calcul de Premier(X), X N Si l ensemble des productions de membre gauche S est : S AB Da alors on a : Premier(S) = Premier(AB) Premier(Da) Cas général : Si la grammaire contient les productions de membre gauche X : X γ 1... γ n alors : Premier(X) = i=1...n{premier(γ i ) X γ i R}
Ensembles Premier Calcul des Premier - 2 Soit α (N T ) : cas α = ɛ : α = a, a T : {a} α = aβ, a T, β (N T ) : {a} α = X, X N : {Premier(γ i ) X γ i R} α = Xβ, X N, β (N T ) :? fcas
Ensembles Premier Calcul des Premier, α = Xβ, X N Deux cas selon que X peut "s effacer" ou non : X ɛ? Si X ɛ on dit que X est ɛ-productif : X ɛ-prod
Ensembles Premier 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)
Ensembles Premier Calcul des Premier, α = Xβ, X ɛ-prod - exemple Par exemple A ɛ-productif : A ɛ aab Premier(AB) = Premier(A) Premier(B) A S S B A B a A b b B Donc, si X ɛ alors Premier(X β) = Premier(X) Premier(β)
Ensembles Premier Calcul des Premier Soit α (N T ) : cas α = ɛ : α = a, a T : {a} α = aβ, a T, β (N T ) : {a} α = X, X N : {Premier(γ i ) X γ i R} α = Xβ, X N\ɛ-Prod, β (N T ) : Premier(X) α = Xβ, X N ɛ-prod, β (N T ) : Premier(X) Premier(β) fcas
Ensembles Premier 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.
Ensembles Premier Exemple S AB Da A aab ɛ B bb ɛ D dd e ɛ-prod = {A, B, S} Premier(S) =? Premier(A) =? Premier(B) =? Premier(D) =? α = ɛ : α = a, a T : {a} α = aβ, a T, β (N T ) : {a} α = X, X N : {Premier(γ i ) X γ i R} α = Xβ, X N\ɛ-Prod, β (N T ) : Premier(X) α = Xβ, X N ɛ-prod, β (N T ) : Premier(X) Premier(β)
Ensembles Premier Exemple 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(ɛ) =
Ensembles Premier 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
Ensembles Premier 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
Ensembles Premier 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.
Ensembles Premier 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
Ensemble des ɛ-prod 1 Méthodes d analyse syntaxique 2 Principes de l analyse descendante 3 Analyseur récursif 4 Construction de la table d analyse Ensembles Premier Ensemble des ɛ-prod Ensembles Suivant Remplissage de la table d analyse 5 Caractérisation d une grammaire LL(1) 6 Quand une grammaire n est pas LL(1) Factorisation à gauche Suppression de la récursivité à gauche 7 Analyseurs LL(k), LL(*)
Ensemble des ɛ-prod Définition des ɛ-prod Definition Un non terminal X 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 } N ne contient que des non-terminaux ɛ-productifs. Algorithme de calcul similaire à celui qui calcule les productifs.
Ensemble des ɛ-prod Exemple S AB Da A aab ɛ B bb ɛ D dd e ɛ-prod?
Ensembles Suivant 1 Méthodes d analyse syntaxique 2 Principes de l analyse descendante 3 Analyseur récursif 4 Construction de la table d analyse Ensembles Premier Ensemble des ɛ-prod Ensembles Suivant Remplissage de la table d analyse 5 Caractérisation d une grammaire LL(1) 6 Quand une grammaire n est pas LL(1) Factorisation à gauche Suppression de la récursivité à gauche 7 Analyseurs LL(k), LL(*)
Ensembles Suivant 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.
Ensembles Suivant Ensembles Suivant, 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)
Ensembles Suivant Ensembles Suivant, intuition On a donc b Suivant(A) A a A aab b A ɛ d? e? #?
Ensembles Suivant Ensembles Suivant, intuition Pour α (T N) +, Suivant(α) contient l ensemble des terminaux de T susceptibles de suivre α dans un mot de T + dérivé de l axiome S. Si α = ɛ, cet ensemble est vide. Par convention, Suivant(S) {#}.
Ensembles Suivant Ensembles Suivant, définitions équivalentes Definition Soit une grammaire algébrique d axiome S. On définit : Suivant : (T N) P(T ) α {a T S βαaγ, pour β, γ (N T ) } Definition Suivant : (T N) P(T ) α {a Premier(γ) S βαγ, pour β, γ (N T ) }
Ensembles Suivant 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 A S AB S A B a b
Ensembles Suivant Calcul des Suivant - 2 Soit R X R l ensemble des productions p dans lesquelles X apparaît en partie droite : Suivant(X) = p R X Suivant p (X) Ex : R A = {S AB, A aab} Suivant(A) = Suivant(A) S AB Suivant(A) A aab
Ensembles Suivant Calcul des Suivant, cas de l axiome Pour l axiome, on ajoute le marqueur de fin de mot : Suivant(S) = {#} p R S Suivant p (S) Ex : pour X axb ɛ R X = {X axb} Suivant(X) = {#} Suivant(X) X axb
Ensembles Suivant Calcul des Suivant - 3 - exemple Suivant(A) S AB? (exemple précédent) Cas déjà vu : S A B Suivant(A) Premier(B)
Ensembles Suivant Calcul des Suivant - 3 - exemple Suivant(A) S AB? (exemple précédent) mais B est ɛ-prod! S A B Suivant(A) Suivant(S)
Ensembles Suivant Calcul des Suivant - 3 - exemple Puisque B est ɛ-prod : Suivant(A) S AB = Premier(B) Suivant(S)
Ensembles Suivant Calcul des Suivant - 4 Quand une production est de la forme... Xα : pour calculer Suivant(X) ; Il faut pouvoir dire si α (N T ) est ɛ-productif ou pas. Definition α (N T ) est ɛ-productif si α ɛ. On définit la fonction : P ɛ : (N T ) {vrai, faux} α α est ɛ-productif On verra après comment calculer P ɛ.
Ensembles Suivant Calcul des Suivant - 5 Pour calculer Suivant p (X) avec : p = Y αxβ et P ɛ (β) = faux, α, β (N T ) Y X β Suivant p (X) = Premier(β) Ex : pour Y Xb, Suivant(X) Y Xb = {b}.
Ensembles Suivant Calcul des Suivant - 6 Pour calculer Suivant p (X) avec : p = Y αx Y α X Suivant p (X) = Suivant(Y )
Ensembles Suivant Calcul des Suivant - 7 Pour calculer Suivant p (X) avec : p = Y αxβ et P ɛ (β) = vrai, α, β (N T ) Y X β Suivant p (X) = Premier(β) Suivant(Y ) Ex : pour S AB, Suivant(A) S AB = Premier(B) Suivant(S).
Ensembles Suivant Remarque - 1 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 XaXaXc Suivant Y XaXaXc (X) = {a, c}
Ensembles Suivant Remarque - 2 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 )
Ensembles Suivant Calcul des Suivant, récapitulons! # Suivant(axiome) Soit R X R l ensemble des productions p dans lesquelles X apparaît en partie droite : Suivant(X) = p R X Suivant p (X) avec : Suivant p (X) = cas p = Y αx : Suivant(Y ) p = Y αxβ et P ɛ (β) = faux : Premier(β) p = Y αxβ et P ɛ (β) = vrai : Premier(β) Suivant(Y ) fincas
Ensembles Suivant 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) =.
Ensembles Suivant Exemple S AB Da A aab ɛ B bb ɛ D dd e P ɛ (B) = vrai Suivant? # Suivant(axiome) Suivant(X) = p R X Suivant p (X) avec : Suivant p (X) = cas p = Y αx : Suivant(Y ) p = Y αxβ et P ɛ (β) = faux : Premier(β) p = Y αxβ et P ɛ (β) = vrai : Premier(β) Suivant(Y ) fincas
Ensembles Suivant 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
Ensembles Suivant 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
Ensembles Suivant Calcul des ɛ-productifs On connaît déjà ɛ-prod, ens. des non-terminaux ɛ-productifs. Pour calculer P ɛ (α) : P ɛ (α) = cas α = ɛ : vrai α = X 1... X n, n 1 avec {X 1,..., X n } N et {X 1,..., X n } ɛ-prod : vrai autre : faux // α contient un terminal fincas
Ensembles Suivant Exemple Sachant que ɛ-prod = {A, B, S} : P ɛ (Da)? P ɛ (AB)? P ɛ (ɛ)? P ɛ (B)?
Remplissage de la table d analyse 1 Méthodes d analyse syntaxique 2 Principes de l analyse descendante 3 Analyseur récursif 4 Construction de la table d analyse Ensembles Premier Ensemble des ɛ-prod Ensembles Suivant Remplissage de la table d analyse 5 Caractérisation d une grammaire LL(1) 6 Quand une grammaire n est pas LL(1) Factorisation à gauche Suppression de la récursivité à gauche 7 Analyseurs LL(k), LL(*)
Remplissage de la table d analyse Table d analyse : au préalable On calcule : les ɛ-productifs ; les ensembles Premier ; les ensembles Suivant.
Remplissage de la table d analyse 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 γ R faire pour tout a Premier(γ) faire ajouter X γ à Table[X, a] fait si P ɛ (γ) = 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
Remplissage de la table d analyse Exemple S AB : Premier(AB) = {a, b} ; P ɛ (AB) = vrai ; Suivant(S) = {#}. S Da : Premier(Da) = {d, e} ; P ɛ (Da) = faux. Rien à compléter par erreur. S a S AB b S AB d S Da e S Da # S AB
Remplissage de la table d analyse Exemple A aab : Premier(aAb) = {a} ; P ɛ (aab) = faux. A ɛ : Premier(ɛ) = ; P ɛ (ɛ) = vrai ; Suivant(A) = {b, #}. On complète par erreur. A a A aab b A ɛ d erreur e erreur # A ɛ
1 Méthodes d analyse syntaxique 2 Principes de l analyse descendante 3 Analyseur récursif 4 Construction de la table d analyse Ensembles Premier Ensemble des ɛ-prod Ensembles Suivant Remplissage de la table d analyse 5 Caractérisation d une grammaire LL(1) 6 Quand une grammaire n est pas LL(1) Factorisation à gauche Suppression de la récursivité à gauche 7 Analyseurs LL(k), LL(*)
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).
Caractérisation d une grammaire LL(1) 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 P ɛ (α) = vrai et Premier(β) Suivant(X) ; Ex : S as Ab, A ɛ b 3 soit P ɛ (α) = vrai et P ɛ (β) = vrai (la grammaire est ambiguë) Ex : S A B, A ɛ, B ɛ
LL(1) et ambiguïté Une grammaire LL(1) n est pas ambiguë. Une grammaire ambiguë n est pas LL(1).
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!
1 Méthodes d analyse syntaxique 2 Principes de l analyse descendante 3 Analyseur récursif 4 Construction de la table d analyse Ensembles Premier Ensemble des ɛ-prod Ensembles Suivant Remplissage de la table d analyse 5 Caractérisation d une grammaire LL(1) 6 Quand une grammaire n est pas LL(1) Factorisation à gauche Suppression de la récursivité à gauche 7 Analyseurs LL(k), LL(*)
Factorisation à gauche 1 Méthodes d analyse syntaxique 2 Principes de l analyse descendante 3 Analyseur récursif 4 Construction de la table d analyse Ensembles Premier Ensemble des ɛ-prod Ensembles Suivant Remplissage de la table d analyse 5 Caractérisation d une grammaire LL(1) 6 Quand une grammaire n est pas LL(1) Factorisation à gauche Suppression de la récursivité à gauche 7 Analyseurs LL(k), LL(*)
Factorisation à gauche Factorisation à gauche : exemple - 1 Les listes d identificateur de INIT : listeident IDENT IDENT SEPVAR listeident On factorise IDENT et on obtient : listeident IDENT suitelisteident suitelisteident ɛ SEPVAR listeident
Factorisation à gauche Factorisation à gauche : exemple - 2 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.
Factorisation à gauche Factorisation à gauche - algorithme On remplace les règles de la forme : où X αβ 1... αβ n γ 1... γ m α (T N) + et β i, γ j (T 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.
Suppression de la récursivité à gauche 1 Méthodes d analyse syntaxique 2 Principes de l analyse descendante 3 Analyseur récursif 4 Construction de la table d analyse Ensembles Premier Ensemble des ɛ-prod Ensembles Suivant Remplissage de la table d analyse 5 Caractérisation d une grammaire LL(1) 6 Quand une grammaire n est pas LL(1) Factorisation à gauche Suppression de la récursivité à gauche 7 Analyseurs LL(k), LL(*)
Suppression de la récursivité à gauche Suppression de la récursivité à gauche Récursivité gauche : immédiate : production A Aα, α (T N) + ; générale : il existe une dérivation A Aα, α (T N) +. Il est possible de supprimer les deux cas. On ne verra que la récursivité immédiate.
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 (T N) + et β j (T 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.
Suppression de la récursivité à gauche Suppression de la récursivité gauche : exemple Après suppression de la rec Grammaire non ambiguë gauche : des expressions arithmétiques : E TE E E + T T E +TE ɛ T T F F T FT F i (E) T FT ɛ F i (E) X Xα 1... Xα n β 1... β m X β 1 X... β m X X α 1 X... α n X ɛ
Suppression de la récursivité à gauche Parfois ça ne suffit pas La grammaire ({a, b}, {S, A}, S, R) avec R = {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).
Suppression de la récursivité à gauche Au delà des grammaires LL(1) - 1 La grammaire ({a, b}, {A, B}, A, R) avec R = {A abb ɛ, B Aaa b} n est pas LL(1). En effet P ɛ (A) = vrai et a Premier(A) Suivant(A).
1 Méthodes d analyse syntaxique 2 Principes de l analyse descendante 3 Analyseur récursif 4 Construction de la table d analyse Ensembles Premier Ensemble des ɛ-prod Ensembles Suivant Remplissage de la table d analyse 5 Caractérisation d une grammaire LL(1) 6 Quand une grammaire n est pas LL(1) Factorisation à gauche Suppression de la récursivité à gauche 7 Analyseurs LL(k), LL(*)
Grammaires LL(k), exemple La grammaire: declaration DECLINT listeident FININSTR listeident IDENT IDENT SEPVAR listeident n est pas LL(1). 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
Grammaire LL(k), autre exemple R = {A abb ɛ, B Aaa b} Cette grammaire est LL(2) : Premier 2 (A) = {ab} Premier 2 (B) = {ab, aa, b} Suivant 2 (A) = {aa, #}
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
Analyseurs LL(k), principe Effectuent une prédiction basée sur k symboles. k borné. Ex: javacc