Télécharger la présentation
La présentation est en train de télécharger. S'il vous plaît, attendez
Publié parJean-Jacques Soucy Modifié depuis plus de 6 années
1
IFT313 Introduction aux langages formels
Froduald Kabanza Département d’informatique Université de Sherbrooke planiart.usherbrooke.ca/kabanza/cours/ift313 Automates à pile LL
2
Sujet Automate à pile LL. IFT313 © Froduald Kabanza
3
Objectif Pouvoir décrire et simuler un automate à pile LL pour une grammaire donnée. IFT313 © Froduald Kabanza
4
Références [2] Appel, A. and Palsberg. J. Modern Compiler Implementation in Java. Second Edition. Cambridge, 2004. Section 3.2 [4] Aho, A., Lam, M., Sethi R., Ullman J. Compilers: Principles, Techniques, and Tools, 2nd Edition. Addison Wesley, 2007. Sections 4.4.4 IFT313 © Froduald Kabanza
5
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 Kabanza
6
Rappel : Transitions u b g
Une transition de la forme (p, u, b) (q, g) signifie que l’automate peut passer de l’état p à l’état q, pourvu que la chaîne d’entrée commence par le préfixe u et la chaîne b est au sommet de la pile. Après la transition, u est lu et consommé du mot d’entrée, b est enlevé de la pile et remplacé par g, et le nouvel état devient q. La chaîne b est lue de gauche à droite : son premier caractère doit donc être au sommet de la pile. La chaîne g est écrite de telle façon que son premier caractère soit au sommet de la pile. entrée pile p q $ u b g IFT313 © Froduald Kabanza
7
Configurations, trace, acceptation
La configuration d’un automate est un triplet (s, V*, A*), indiquant, respectivement, son état courant, le contenu de la pile, et la partie de l’entrée qui reste à lire. Une trace (ou exécution) d’un automate sur une entrée est la séquence de configurations qu’il produit en lisant son entrée et en suivant ses transitions. Une exécution accepte une chaîne d’entrée si la dernière configuration est de la forme (p, $, $), avec p un état accepteur. En d’autre mot, dans la dernière configuration, la pile est vide, on est à la fin de l’entrée et l’état est accepteur. IFT313 © Froduald Kabanza
8
Rappel : Exemple s p a, ε/A b, A/ε 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) = {an bn | n >= 0}, c-à-d., chaîne commençant par des a suivi d’autant 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} s p a, ε/A b, A/ε IFT313 © Froduald Kabanza
9
Parseurs LL (Top-down)
Les parseurs LL (appelés aussi top-down parsers) valident la syntaxe d’une chaîne de tokens (le code d’un 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 (d’où le « top »), en allant vers la chaîne à dériver, c-à-d., vers le bas (d’où le « down »). Nous allons voir une procédure permettant de construire systématiquement un automate à pile LL à partir de n’importe quelle grammaire hors-contexte. Cette procédure va ensuite servir de source d’inspiration pour construire des parseurs LL efficaces. IFT313 © Froduald Kabanza
10
Procédure pour construire un automate à pile LL à partir d’une 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, a) pour chaque A 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] q ε, A/a p ε, ε/S q q a, a/ε Pour la transition (q, ε, A) (q, alpha), se rappeler que la chaîne alpha est écrite de façon que son premier caractère soit au sommet de la pile. IFT313 © Froduald Kabanza
11
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 d’une chaîne d’entré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, a) pour chaque A a dans P Le matching du prochain caractère de l’entrée, valide lorsque le sommet de la pile est un terminal. (q, a, a) (q, ε) pour chaque terminal a p ε, ε/S q q ε, A/a q a, a/ε IFT313 © Froduald Kabanza
12
Exemple 1 Simulation G = (V,A,P,S) : V = {S} A = {a,b}
P = {S ® ε, S ® aSb} Entrée : aabb Configuration Transition (p, $, aabb$) (q, S$, aabb$) (q, aSb$, aabb$) (q, Sb$, abb$) (q, aSbb$, abb$) (q, Sbb$, bb$) (q, bb$, bb$) (q, b$, b$) (q, $, $) 1. 3. 4. 2. 5. M = ({p,q}, {S, a, b}, {a, b}, R, p,{q},$) : R = { (p, ε, ε) ® (q, S) (q, ε, S) ® (q, ε) (q, ε, S) ® (q, aSb) (q, a, a ) ® (q, ε) (q, b, b ) ® (q, ε) } Bien observer que pour (q, ε, S) -> (q, aSb), aSb es écrit de façon que le premier caractère (a) est au sommet de la pile. Accepte IFT313 © Froduald Kabanza
13
Exemple 1 (suite) S Þ aSb Þ aaSbb Þ aabb
En affichant les règles de production correspondants aux transitions de l’automate, on obtient la dérivation la plus à gauche du mot d’entrée. G = (V,A,P,S) : V = {S} A = {a,b} P = {S ® ε, S ® aSb} Configuration Transition Règle Dérivation (p, $, aabb$) (q, S$, aabb$) (q, aSb$, aabb$) (q, Sb$, abb$) (q, aSbb$, abb$) (q, Sbb$, bb$) (q, bb$, bb$) (q, b$, b$) (q, $, $) S Þ 1. 3. 4. 2. 5. M = ({p,q}, {S, a, b}, {a, b}, R, p,{q},$) : R = { (p, ε, ε) ® (q, S) (q, ε, S) ® (q, ε) (q, ε, S) ® (q, aSb) (q, a, a ) ® (q, ε) (q, b, b ) ® (q, ε) } S ® aSb aSb Þ aaSbb Þ S ® aSb S ® ε aabb Accepte IFT313 © Froduald Kabanza
14
Exemple 2 M = ({p,q}, V U A, A, R, p, {q},$) : G = (V, A, R, Exp) :
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, ε) } G = (V, A, R, Exp) : V = {Exp} A = {(, ), +, *, num} R = { Exp ® num Exp ® ( Exp) Exp ® Exp + Exp Exp ® Exp * Exp } IFT313 © Froduald Kabanza
15
Exemple 2 (suite) Entrée : num+num*num
Configuration Transition 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, ε) } (p, $, num+num*num$) (q, Exp$, num+num*num$) (q, Exp+ Exp$, num+ num*num$) (q, num+Exp$, num+num*num$) (q, +Exp$, +num*num$) (q, Exp$, num*num$) (q, Exp*Exp$, num*num$) (q, num*Exp$, num*num$) (q, *Exp$, *num$) (q, Exp$, num$) (q, num$, num$) (q, $, $) 1 4 2 10 8 5 9 Accepte IFT313 © Froduald Kabanza
16
Exemple 2 (suite) Entrée : num+num*num Accepte Configuration
Transition Règle (p, $, num+num*num$) (q, Exp$, num+num*num$) (q, Exp+ Exp$, num+ num*num$) (q, num+Exp$, num+num*num$) (q, +Exp$, +num*num$) (q, Exp$, num*num$) (q, Exp*Exp$, num*num$) (q, num*Exp$, num*num$) (q, *Exp$, *num$) (q, Exp$, num$) (q, num$, num$) (q, $, $) 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, ε) } 1 4 2 10 8 5 9 Exp ® Exp+Exp Exp ® num Exp ® Exp*Exp Exp ® num Exp ® num Accepte IFT313 © Froduald Kabanza
17
Retour à l’intuition 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 d’entré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, a) pour chaque A a dans P Une transition match (match transition) reconnaît un symbole (token) qui commence le reste de la chaîne d’entrée, en utilisant le contenu de la pile. Si le symbole au sommet de la pile correspond au prochain symbole sur l’entrée, le symbole est enlevé de la chaîne d’entrée (il est lu) et de la pile (il est reconnu). (q, a, a) (q, ε) pour chaque terminal a Retour à l ’intuition derrière la procédure de construction d’un automate à pile LL à partir d’une grammaire IFT313 © Froduald Kabanza
18
Vers un driver pours parseurs LL
En réalité, les transitions de l’automate 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 l’automate à 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 à l’esprit que ce driver n’est rien d’autre qu’une simulation à la volée d’un automate à pile dérivé directement d’une grammaire hors-contexte par la procédure qu’on vient de voir. IFT313 © Froduald Kabanza
19
Pilote LL Algorithm LLDriver
variables : stack (pile), x (symbole au sommet de la pile), a (symbole d’entrée courant), in (entrée) initialement la pile contient $S (le symbole départ S) et l’entrée contient w$ (chaîne de tokens w). while (true) { if (x = = $) && (a= = $) return true ; // on accepte la chaîne d’entrée comme étant correcte if (x = = 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 y1 … yk; // trouver une production dont la partie gauche est x // les essayer tous jusqu’à en trouver menant à l’acceptation (backtracking) exit with error if no such production exists; pop x from the stack; push yk on the stack; …; push y1 on the stack; continue; } exit with error;} Avant on avait: if (x = = a) && (a != $) Mais la partie (a != $) est en fait inutile vue la condition précédente. IFT313 © Froduald Kabanza
20
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 d’autres mots, v est dérivable de la grammaire. Si v est une forme sententielle constitué uniquement de terminaux, on dit aussi que c’est 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 IFT313 © Froduald Kabanza
21
Deux observations importantes
L’exécution du driver LL, sur une chaîne d’entrée donne la dérivation la plus à gauche de l’entrée dans la mesure où, si on concatène le préfixe de la chaîne déjà scannée avec le contenu de la pile, on obtient une forme sententielle gauche de la grammaire. Ceci veut dire que, à tout instant durant l’exécution du driver LL, la chaîne restant à scanner doit être dérivable de la chaîne de symbole sur la pile pour que la chaîne de départ soit acceptée. Formellement: Soit a le contenu de la pile à une étape quelconque, v le reste de la chaîne à lire et w la chaîne d’entrée originale (donc w = uv avec u la chaîne déjà lue; forcément dans A*). Alors, on doit avoir a => v pour que la chaîne d’entrée soit acceptée, c’est-à-dire, pour que S => w (avec S le symbole de départ de la grammaire). * * IFT313 © Froduald Kabanza
22
Exemple S Þ aSb Þ aaSbb Þ aabb G = ({S},{a,b},P,S) :
P = {S ® ε, S ® aSb} Nous avons déjà vu qu’en affichant les règles de production correspondant aux transitions de l’automate, on obtient la dérivation la plus à gauche de la chaîne. Algorithm LLDriver 0. stack = ($S); a = in.read(); x=stack.top(); while (true) { if (x = = $) && (a= = $) return true ; if (x = = a) { pop a from stack; a = in.read(); continue;} if x is a nonterminal { find x y; pop x from stack; push y on stack; continue; } exit with error;} Étape Règle Pile Entrée Dérivation 0. 3. 2. 1. S$ aSb$ Sb$ aSbb$ Sbb$ bb$ b$ $ aabb$ abb$ bb$ b$ $ S Þ S ® aSb aSb Þ aaSbb Þ S ® aSb aabb S ® ε return true IFT313 © Froduald Kabanza
23
Exemple G = ({S},{a,b},P,S) : P = {S ® ε, S ® aSb}
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. Algorithm LLDriver 0. stack = ($S); a = in.read(); x=stack.top(); while (true) { if (x = = $) && (a= = $) return true ; if (x = = a) { pop a from stack; a = in.read(); continue;} if x is a nonterminal { find x y; pop x from stack; push y on stack; continue; } exit with error;} S Þ déjà lu + pile * Étape Règle Pile Entrée * 0. 3. 2. 1. S$ aSb$ Sb$ aSbb$ Sbb$ bb$ b$ $ aabb$ abb$ bb$ b$ $ S Þ aSb aaSbb aabb S ® aSb S ® aSb S ® ε return true IFT313 © Froduald Kabanza
24
Exemple G = ({S},{a,b},P,S) : P = {S ® ε, S ® aSb}
Observation 2 : la chaîne restant à lire est dérivable du contenu de la pile pour toute exécution qui accepte. Algorithm LLDriver 0. stack = ($S); a = in.read(); x=stack.top(); while (true) { if (x = = $) && (a= = $) return true ; if (x = = a) { pop a from stack; a = in.read(); continue;} if x is a nonterminal { find x y; pop x from stack; push y on stack; continue; } exit with error;} chaîne restante Þ pile * Étape Règle Pile Entrée * 0. 3. 2. 1. S$ aSb$ Sb$ aSbb$ Sbb$ bb$ b$ $ aabb$ abb$ bb$ b$ $ S Þ aabb aSb Þ aabb Sb Þ abb aSbb Þ abb Sbb Þ bb bb Þ bb b Þ b ε Þ ε * S ® aSb * * S ® aSb * * S ® ε * * return true IFT313 © Froduald Kabanza
25
Résumé Les algorithmes d’analyse syntaxique descendante sont aussi dit « prédictives » parce qu’ils prédisent la production à appliquer à chaque étape de la dérivation. L’algorithme 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 s’avè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 d’analyse syntaxique LL, descendant, non-récursif. IFT313 © Froduald Kabanza
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.