IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke planiart.usherbrooke.ca/kabanza/cours/ift313 Automates à pile LL
IFT313© Froduald Kabanza2 Sujet Automate à pile LL.
IFT313© Froduald Kabanza3 Objectif Pouvoir décrire et simuler un automate à pile LL pour une grammaire donnée.
IFT313© Froduald Kabanza4 Références [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, – Sections 4.4.4
IFT313© Froduald Kabanza5 Rappel : Automate à pile Un automate à pile a : Une entrée et une tête de lecture. Un nombre fini détats dont un état initial et des états accepteurs. Une relation de transition. Une pile pouvant croître arbitrairement. Automate à pile entrée pile $ $
IFT313© Froduald Kabanza6 Rappel : Transitions Une transition de la forme (p, u, q, signifie que lautomate peut passer de létat p à létat q, pourvu que la chaîne dentrée commence par le préfixe u et la chaîne est au sommet de la pile. Après la transition, u est lu et consommé du mot dentrée, est enlevé de la pile et remplacé par et le nouvel état devient q. La chaîne est lue de gauche à droite : son premier caractère doit donc être au sommet de la pile. La chaîne est écrite de telle façon que son premier caractère soit au sommet de la pile. entrée pile pq $ $ entrée pile pq $ $ uu
IFT313© Froduald Kabanza7 Configurations, trace, acceptation La configuration dun automate est un triplet (s, V * A * ), indiquant, respectivement, son état courant, le contenu de la pile, et la partie de lentrée qui reste à lire. Une trace (ou exécution) dun automate sur une entrée est la séquence de configurations quil produit en lisant son entrée et en suivant ses transitions. Une exécution accepte une chaîne dentrée si la dernière configuration est de la forme (p, $, $), avec p un état accepteur. En dautre mot, dans la dernière configuration, la pile est vide, on est à la fin de lentrée et létat est accepteur.
IFT313© Froduald Kabanza8 Rappel : Exemple M = (S,V,T,R,s,S,$), tel que: S = {s,p} V = {A} T = {a,b} R = { (s, a, ε ) (s, A), (s, b, A) (p, ε ), (p, b, A) (p, ε )} L(M) = {a n b n | n >= 0}, c-à-d., chaîne commençant par des a suivi dautant de b. Cette automate non-déterministe correspond à la grammaire G = (V,A,R,S), tel que : V = {S} A = {a,b} R = {S ε, S aSb}
IFT313© Froduald Kabanza9 Parseurs LL (Top-down) Les parseurs LL (appelés aussi top-down parsers) valident la syntaxe dune chaîne de tokens (le code dun programme) en cherchant la dérivation la plus à gauche de la chaîne. La recherche de la dérivation se fait en partant du symbole de départ (doù le « top »), en allant vers la chaîne à dériver, c-à-d., vers le bas (doù le « down »). Nous allons voir une procédure permettant de construire systématiquement un automate à pile LL à partir de nimporte quelle grammaire hors-contexte. Cette procédure va ensuite servir de source dinspiration pour construire des parseurs LL efficaces.
IFT313© Froduald Kabanza10 Procédure pour construire un automate à pile LL à partir dune grammaire hors-contexte Pour chaque grammaire G = (V, T, P, S), on génère un automate à pile non- déterministe M = ({p, q}, V U T, T, R, p, {q},$), tel que R contient les transitions suivantes : (p, ε, ε) (q, S) (q, ε, A ) (q, ) pour chaque A dans P (q, a, a) (q, ε ) pour chaque terminal a dans T Une preuve de la validité de cette construction est donnée dans [Wolper, Pierre. Introduction à la calculabilité, 3è édition. Dunod, 2006]
IFT313© Froduald Kabanza11 Intuition derrière la construction Intuitivement, les transitions implémentent trois types de mouvements de symboles sur la pile, de manière à simuler la dérivation la plus à gauche dune chaîne dentrée par la grammaire. Le placement initiale qui place le symbole de départ de la grammaire sur la pile. (p, ε, ε) (q, S) pour le symbole de départ S La prédiction de la règle de production à appliquer pour une étape de dérivation, valide lorsque le sommet de la pile est un non-terminal. (q, ε, A) (q, ) pour chaque A dans P Le matching du prochain caractère de lentrée, valide lorsque le sommet de la pile est un terminal. (q, a, a) (q, ε ) pour chaque terminal a
IFT313© Froduald Kabanza12 Exemple 1 G = (V,A,P,S) : V = {S} A = {a,b} P = {S ε, S aSb} M = ({p,q}, {S, a, b}, {a, b}, R, p,{q},$) : R = { 1. (p, ε, ε) (q, S) 2. (q, ε, S) (q, ε) 3. (q, ε, S) (q, aSb) 4. (q, a, a ) (q, ε ) 5. (q, b, b ) (q, ε ) } Entrée : aabb (p, $, aabb $ ) (q, $ S, aabb $ ) (q, $ bSa, aabb $ ) (q, $ bS, abb $ ) (q, $ bbSa, abb $ ) (q, $ bbS, bb $ ) (q, $ bb, bb $ ) (q, $ b, b $ ) (q, $, $ ) Accepte Configuration Simulation Transition
IFT313© Froduald Kabanza13 Exemple 1 (suite) G = (V,A,P,S) : V = {S} A = {a,b} P = {S ε, S aSb} M = ({p,q}, {S, a, b}, {a, b}, R, p,{q},$) : R = { 1. (p, ε, ε) (q, S) 2. (q, ε, S) (q, ε) 3. (q, ε, S) (q, aSb) 4. (q, a, a ) (q, ε ) 5. (q, b, b ) (q, ε ) } (p, $, aabb $ ) (q, $ S, aabb $ ) (q, $ bSa, aabb $ ) (q, $ bS, abb $ ) (q, $ bbSa, abb $ ) (q, $ bbS, bb $ ) (q, $ bb, bb $ ) (q, $ b, b $ ) (q, $, $ ) Accepte Configuration Transition En affichant les règles de production correspondants aux transitions de lautomate, on obtient la dérivation la plus à gauche du mot dentrée. RègleDérivation S aSb S aSb S aSb aaSbb S ε aabb
IFT313© Froduald Kabanza14 Exemple 2 G = (V, A, R, Exp) : V = {Exp} A = {(, ), +, *, num} R = { Exp num Exp ( Exp) Exp Exp + Exp Exp Exp * Exp } M = ({p,q}, V U A, A, R, p, {q},$) : R = { (p, ε, ε) (q, Exp) (q, ε, Exp) (q, num) (q, ε, Exp) (q, (Exp) ) (q, ε, Exp) (q, Exp + Exp ) (q, ε, Exp) (q, Exp * Exp ) (q, (, () (q, ε ) (q, ), )) (q, ε ) (q, +, +) (q, ε ) (q, *, *) (q, ε ) (q, num, num ) (q, ε ) }
IFT313© Froduald Kabanza15 Exemple 2 (suite) Entrée : num+num*num (p, $, num+num*num$) (q, $Exp, num+num*num$) (q, $Exp+ Exp, num+ num*num$) (q, $Exp+num, num+num*num$) (q, $Exp+, +num*num$) (q, $Exp, num*num$) (q, $Exp*Exp, num*num$) (q, $Exp*num, num*num$) (q, $Exp*, *num$) (q, $Exp, num$) (q, $num, num$) (q, $, $) Accepte M = ({p,q}, V U A, A, R, p, {q},$) : R = { 1. (p, ε, ε) (q, Exp) 2. (q, ε, Exp) (q, num) 3. (q, ε, Exp) (q, (Exp) ) 4. (q, ε, Exp) (q, Exp + Exp ) 5. (q, ε, Exp) (q, Exp * Exp ) 6. (q, (, () (q, ε ) 7. (q, ), )) (q, ε ) 8. (q, +, +) (q, ε ) 9. (q, *, *) (q, ε ) 10. (q, num, num ) (q, ε ) } Configuration Transition
IFT313© Froduald Kabanza16 Exemple 2 (suite) Entrée : num+num*num (p, $, num+num*num$) (q, $Exp, num+num*num$) (q, $Exp+ Exp, num+ num*num$) (q, $Exp+num, num+num*num$) (q, $Exp+, +num*num$) (q, $Exp, num*num$) (q, $Exp*Exp, num*num$) (q, $Exp*num, num*num$) (q, $Exp*, *num$) (q, $Exp, num$) (q, $num, num$) (q, $, $) Accepte M = ({p,q}, V U A, A, R, p, {q},$) : R = { 1. (p, ε, ε) (q, Exp) 2. (q, ε, Exp) (q, num) 3. (q, ε, Exp) (q, (Exp) ) 4. (q, ε, Exp) (q, Exp + Exp ) 5. (q, ε, Exp) (q, Exp * Exp ) 6. (q, (, () (q, ε ) 7. (q, ), )) (q, ε ) 8. (q, +, +) (q, ε ) 9. (q, *, *) (q, ε ) 10. (q, num, num ) (q, ε ) } Configuration Transition Règle Exp Exp+Exp Exp num Exp Exp*Exp Exp num
IFT313© Froduald Kabanza17 Retour à lintuition derrière la construction Une transition prédictive (predictive transition) essaie de prédire la règle de production qui pourrait être appliquée à létape courante pour dériver le reste de la chaîne dentrée. Pour ce faire la partie gauche de la production (un non-terminal) est enlevée de la pile et remplacée par la partie droite de la production. (q, ε, A) (q, ) pour chaque A dans P Une transition match (match transition) reconnaît un symbole (token) qui commence le reste de la chaîne dentrée, en utilisant le contenu de la pile. Si le symbole au sommet de la pile correspond au prochain symbole sur lentrée, le symbole est enlevé de la chaîne dentrée (il est lu) et de la pile (il est reconnu). (q, a, a) (q, ε ) pour chaque terminal a
IFT313© Froduald Kabanza18 Vers un driver pours parseurs LL En réalité, les transitions de lautomate ainsi formulées peuvent être implémentées à la volée, en partant directement des règles de production de la grammaire, sans avoir à décrire lautomate à pile explicitement. Les déplacements des symboles sur la pile, et de la pile, se font directement, en partant des règles de production de la grammaire. A chaque étape on doit décider si on prédit une règle de production pour dériver le reste de la chaîne ou si on matche le prochain symbole du reste de la chaîne. Le driver LL suivant implémente un tel automate à pile piloté directement par la grammaire. Il est important de garder à lesprit que ce driver nest rien dautre quune simulation à la volée dun automate à pile dérivé directement dune grammaire hors-contexte par la procédure quon vient de voir.
IFT313© Froduald Kabanza19 Pilote LL 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 { 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;}
IFT313© Froduald Kabanza20 Rappel : Notion de forme sententielle Étant donné une grammaire G = (V, A, R, S), une chaine v dans (VUA) * est appelée une forme sentantielle (sentatial form) si et seulement si S v. En dautres mots, v est dérivable de la grammaire. Si v est une forme sententielle constitué uniquement de terminaux, on dit aussi que cest une phrase (sentence). Si v est dérivé par une dérivation la plus à gauche, on parle de forme sentielle gauche (left sentential form). De manière analogue, si v est dérivé par une dérivation la plus à droite, on parle de forme sententielle droite (right sentential form). *G*G
IFT313© Froduald Kabanza21 Deux observations importantes Lexécution du driver LL, sur une chaîne dentrée donne la dérivation la plus à gauche de lentré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. Ceci veut dire que, à tout instant durant lexé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. Formellement: Soit le contenu de la pile à une étape quelconque, v le reste de la chaîne à lire et w la chaîne dentrée originale (donc w = uv avec u la chaîne déjà lue; forcément dans A*). Alors, on doit avoir v pour que la chaîne dentrée soit acceptée, cest-à-dire, pour que S w (avec S le symbole de départ de la grammaire). * *
IFT313© Froduald Kabanza22 Exemple G = ( {S}, {a,b},P,S) : P = {S ε, S aSb} $S$S $ bSa $ bS $ bbSa $ bbS $ bb $b$b $ return true Pile Étape Nous avons déjà vu quen affichant les règles de production correspondant aux transitions de lautomate, on obtient la dérivation la plus à gauche de la chaîne. RègleDérivation S aSb S aSb aaSbb S ε aabb 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 { find x y; pop x from stack; push y on stack; continue; } 4. exit with error;} Entrée aabb$ abb$ bb$ b$ $ S aSb
IFT313© Froduald Kabanza23 Exemple G = ( {S}, {a,b},P,S) : P = {S ε, S aSb} $S$S $ bSa $ bS $ bbSa $ bbS $ bb $b$b $ return true Pile Étape Observation 1 : La chaîne obtenue en concaténant le préfixe de la chaîne déjà scannée (soulignée) et le contenu de la pile est une forme sententielle gauche. Règle S aSb aaSbb aabb S aSb S ε 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 { find x y; pop x from stack; push y on stack; continue; } 4. exit with error;} Entrée aabb$ abb$ bb$ b$ $ S aSb S déjà lu + pile * *
IFT313© Froduald Kabanza24 Exemple G = ( {S}, {a,b},P,S) : P = {S ε, S aSb} $S$S $ bSa $ bS $ bbSa $ bbS $ bb $b$b $ return true Pile Étape Observation 2 : la chaîne restant à lire est dérivable du contenu de la pile pour toute exécution qui accepte. Règle S aSb aabb Sb abb aSbb abb Sbb bb bb b ε S aSb S ε 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 { find x y; pop x from stack; push y on stack; continue; } 4. exit with error;} Entrée aabb$ abb$ bb$ b$ $ S aSb chaîne restante pile * * * * * * * * *
IFT313© Froduald Kabanza25 Résumé Les algorithmes danalyse syntaxique descendante sont aussi dit « prédictives » parce quils prédisent la production à appliquer à chaque étape de la dérivation. Lalgorithme LLDriver implémente un automate à pile non-déterministe pour une analyse syntaxique LL, descendante. Le non-déterminisme est implémenté en mémorisant les différents choix possibles de règles de production applicables à un moment donné, de manière à revenir en arrière (backtracking) si un choix savère un échec. La leçon suivante explique comment éliminer le non déterminisme en prédisant la bonne règle de production à utiliser, en fonction, non seulement du symbole au sommet de la pile comme dans la version précédente, mais aussi du prochain token. Cela mène à un algorithme efficace danalyse syntaxique LL, descendant, non- récursif.