IFT313 Introduction aux langages formels

Slides:



Advertisements
Présentations similaires
IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke planiart.usherbrooke.ca/kabanza/cours/ift313.
Advertisements

IFT451 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke planiart.usherbrooke.ca/kabanza/cours/ift313.
IFT313 Introduction aux langages formels
IFT313 Introduction aux langages formels
IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke planiart.usherbrooke.ca/kabanza/cours/ift313.
IFT313 Introduction aux langages formels
IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Automates à pile LR Notion de poignée.
Rappel Modèle analyse-synthèse de la compilation
Introduction à la notion de fonction 1. Organisation et gestion de données, fonctions 1.1. Notion de fonction ● Déterminer l'image d'un nombre par une.
Tutoriel : faire le montage des enregistrement audio des p’tit déj’ Contact Ce tutoriel est conçu pour le logiciel libre Audacity, téléchargeable gratuitement.
Nouveau programme de 3ème Probabilités Document de travail – Académie de Rouen
Volée 1316 S3 Cours No 2_3 : Le nombre en 1-2H. Les fonctions du nombre  Dénombrer, énumérer, décrire une collection. Aspect cardinal  Dater, classer,
Concepts pour le contrôle de flux
Calcul de probabilités
Le Mouvement Directionnel
Valeurs de toutes les différences observables sous H0
I- ANALYSE DU BESOIN / Plan
Coloration de graphe, backtracking, branch and bound
Première partie : La droite de budget
La représentation des atomes
IFT 702 – Planification en intelligence artificielle Langage PDDL
IFT313 Introduction aux langages formels
Algorithme et programmation
Lois fondamentales de l'algèbre de Boole
Premier objectif : définir un acide et une base :
Ce videoclip produit par l’Ecole Polytechnique Fédérale de Lausanne
Les opérations sur les nombres
L’Instruction de Test Alternatif
IFT 615 – Intelligence artificielle Recherche heuristique
Javadoc et débogueur Semaine 03 Version A16.
Bddictionnairique Phase 1
Principes de programmation (suite)
2°9 lycée Beauregard à Montbrison
VI. Tri par tas (Heap sort)
Semaine #4 INF130 par Frédérick Henri.
Le choix optimal.
Tableau de bord des risques
Techniques du Data Mining
Information, Communication, Calcul
1.2 dénombrement cours 2.
IFT313 IFT313 Introduction aux langages formels Froduald Kabanza Département d’informatique Université de Sherbrooke planiart.usherbrooke.ca/kabanza/cours/ift313.
Chapter 12: Structures de données
Introduction aux langages formels
Réseaux de neurones appliqués à la reconnaissance de caractères
Sylvie BRETON & Christiane CARIOU
Lois de Probabilité Discrètes
IFT313 Introduction aux langages formels
IFT313 Introduction aux langages formels
IFT313 Introduction aux langages formels
Difficultés d’apprentissage
Université de la méditerranée
IFT313 Introduction aux langages formels
IFT313 Introduction aux langages formels
IFT313 Introduction aux langages formels
Le code de Huffman: est une méthode de compression statistique de données qui permet de réduire la longueur du codage d'un alphabet. Le code de Huffman.
MATHÉMATIQUES FINANCIÈRES I
IFT313 Introduction aux langages formels
IFT313 Introduction aux langages formels
Reconnaissance de formes: lettres/chiffres
IFT313 Introduction aux langages formels
NUMÉRATION POSITIONNELLE / PRINCIPE DE GROUPEMENT
IFT313 Introduction aux langages formels
Projection, cosinus et trigonométrie.
PROGRAMMATION ET ENSEIGNEMENT
Chapitre 12 : Notion de fonction
Chapter 11: Récursivité Java Software Solutions Second Edition
STSWEB Rattacher Services et ARE Gestion des pondérations
Type Tableau Partie 1 : Vecteurs
La loi des signes.
Dérivation – Fonctions cosinus et sinus
Transcription de la présentation:

IFT313 Introduction aux langages formels Froduald Kabanza Département d’informatique Université de Sherbrooke Analyseurs LR(0)

Sujets Préfixes viables. Éléments LR(0). AFD LR(0) pour reconnaître les préfixes viables. Analyseur LR(0). IFT313 © Froduald Kabanza

Objectifs Pouvoir calculer l’AFD qui reconnait les préfixes viables. Pouvoir générer une table d’analyse LR(0). Pouvoir décrire le driver LR(0) et le simuler. IFT313 © Froduald Kabanza

Références [1] Sudkamp, T. A.. Languages and Machines. Third Edition Edition. Addison-Wesley, 2005. Sections 20.1 à 20.4 [2] Appel, A. and Palsberg. J. Modern Compiler Implementation in Java. Second Edition. Cambridge, 2004. Section 3.3 [4] Aho, A., Lam, M., Sethi R., Ullman J. Compilers: Principles, Techniques, and Tools, 2nd Edition. Addison Wesley, 2007. Section 4.6 IFT313 © Froduald Kabanza

Rappel : Algorithme LRDriver Algorithm LRDriver variables : stack, handle (sous-chaîne au sommet de la pile), a (token), in (entrée) initialement la pile est vide ($) et l’entrée est w$ (une chaîne w). while (true) { if (symbol on top of stack is S’ ) return (a = = $); //accepte handle = stack.findHandle(); //trouver une poignée. Étape cruciale ! if handle != void { // void si la poignée n’est pas trouvée soit ‘A → handle’ la règle correspondante // reduce (nondeterminisme si plusieurs règles) pop handle from the stack; push A on the stack; print out the production ‘A → handle’; // pour imprimer la séquence de dérivation } else { a = in.nextToken(); // shift if a = $ exit with error(); // erreur si ni reduce ni shift ne sont possibles push a on the stack; continue; Remarquer que cet algorithme suppose qu’on fait reduce d’abord avant de faire shift. Comme vu précédemment, dans le cas non-déterministe, à priori on peut avoir des situations pour lesquelles shift et reduce sont simultanément possibles. Toutefois, comme cet algorithme est une ébauche pour une version déterministe qu’on verra plus tard, les grammaires qu’on va utiliser n’auront pas de tel conflits. IFT313 © Froduald Kabanza

Exemple Grammaire augmentée Grammaire G = (V, A, R, E) : V= {E’, E, F, T} A = {(, ), +, *, num} R = { E’ ® E E ® E + T E ® T T ® T * F T ® F F ® ( E) F ® num} Grammaire G = (V, A, R, E), avec V= {E, F, T} A = {(, ), +, *, num} R = { E ® E + T E ® T T ® T * F T ® F F ® ( E) F ® num} IFT313 © Froduald Kabanza

Exemple, suite Productions Observation 1. E’ ® E 2. E ® E + T 3. E ® T 4. T ® T * F 5. T ® F 6. F ® ( E) 7. F ® num Simulation du driver LR 1. ($, (num)$) Shift 2. ($(, num)$) Shift 3. ($(num, )$) Reduce 7 4. ($(F, )$) Reduce 5 5. ($(T, )$) Reduce 3 6. ($(E, )$) Shift 7. ($(E), $) Reduce 6 8. ($F, $) Reduce 5 9. ($T, $) Reduce 3 10. ($E, $) Reduce 1 11. ($E’, $) Accepte Dérivation correspondante : (num) <= (num) <= (num) <= (F) <= (T) <= (E) <= (E) <= F <= T <= E <= E’ Observation Le contenu de la pile (g ) concaténé avec les tokens restant à lire (w) est une forme sententielle pour une dérivation la plus à droite : S => g w * R IFT313 © Froduald Kabanza

Rappel : Contexte LR(0) 1/2 On aurait pu formuler l’analyser LR(0) à l’aide du concept de «contexte LR(0)» plutôt que celui « poignée » (Sudkamp [1] , page 596). Nous avons introduit la « poignée » comme suit: Si S => aAw =>ab w, alors A ® b dans la position juste après a est une poignée pour ab w Étant donné une grammaire (V, Σ, P, S), la chaîne ab est un contexte LR(0) pour la règle de production A ® b s’il existe une dérivation S => aAw =>ab w, avec a et b ϵ (V U Σ)* et w ϵ Σ*. Autrement dit, ab est un contexte LR(0) pour la règle de production A ® b ssi A ® b est un poignée pour ab w, avec a et b ϵ (V U Σ)* et w ϵ Σ* . * R R * Dans le manuel du cours [1] (Sudkamp, T. A. Languages and Machines. Third Edition Edition. Addison-Wesley, 2005), on utilise le concept de “contexte LR(0)” plutôt que celui de “poignée”. Un contexte LR(0) est un préfixe d’une forme sentantielle droite (rappelons que le contenu de la pile est toujours un préfixe d’une forme sentielle droite) donnant lieu à une réduction; c-à-d., un préfixe d’une forme sententielle terminé par une poignée. Les deux concepts sont très proches et ont la même finalité : déterminer la bonne action à prendre (shift ou reduce). Les deux notions expriment relativement la même chose. Le poignée fait référence à un suffixe de la pile; le contexte LR(0) fait référence à tout le contenu de la pile. Cependant le concept de poigné est le plus fréquemment rencontré dans la littérature. R R IFT313 © Froduald Kabanza

Rappel : Contexte LR(0) 2/2 Tout comme pour un poignée, un contextes LR(0) détermine quand faire une réduction durant l’analyse LR, sinon quand faire « shift ». Si A ® b est une poignée (c.-à-d., si le contenu de la pile (ab) est un contexte LR(0) de la règle A ® b) , on réduit avec A ® b. S’il n’y a pas de poignée au sommet de la pile, mais le sommet de la pile contient un préfixe d’une poignée (c.-à-d., si le contenu de la pile (ab) est n’est pas un contexte LR(0) mais est un préfixe d’un contexte LR(0)), on met (shit) le prochain token sur la pile. Si le sommet de la pile n’est pas un préfixe pour une poignée quelconque (c.à-d., le contenu de la pile n’est pas un préfixe pour un contexte LR(0) quelconque), on rejette la chaîne d’entrée. Pour une grammaire non ambiguë, il y au plus une seule poignée à chaque étape d’une dérivation la plus à droite. De façon équivalente, il y a au plus un seul contexte LR(0). Donc, les deux premières étapes de l’algorithme donnent lieu à une seule action possible. Le contenu de la pile est un préfixe viable si et seulement si c’est un préfixe d’un contexte LR(0) (autrement dit, le contenu de la pile a un suffixe qui est une poignée). Si tel est le cas, une séquence de shift produit un contexte LR(0) (autrement dit, produit une poignée au sommet de la pile). Nous reviendrons sur le concept de préfixe viable plus tard. IFT313 © Froduald Kabanza

Le problème de trouver la poignée Pour une version déterministe, le défi est de trouver la poignée (méthode ‘stack.findHandle()’). Pour certaines classes de GHC, on peut trouver la poignée sans examiner tout le contenu la pile. Cela découle de la propriété suivante sur les automates à pile LR : S’il est possible de reconnaître une poignée seulement à partir du contenu de la pile, alors il existe un AFD, qui en lisant les symboles de la grammaire à partir du sommet de la pile, détermine quel poignée, s’il y en a, est au sommet. On va démontrer cette propriété en montrant comment construire l’AFD. Ensuite on va voir comment utiliser l’AFD pour implémenter stack.findHandle(). Ceci nous conduira à deux techniques d’analyse LR (SLR(1) et LALR(1)), résultant d’une combinaison ingénieuse de l’automate à pile LR et de l’AFD pour reconnaître les poignées. IFT313 © Froduald Kabanza

Que doit être l’alphabet de l’AFD pour reconnaître les poignées ? Pour répondre à cette question, il faut garder à l’esprit que l’objectif est d’avoir un AFD qui lit le contenu de la pile (à partir du sommet) pour indiquer s’il y a une poignée au sommet de la pile. Étant donné que la pile contient des symboles de la grammaire (terminaux et non-terminaux), l’alphabet de l’AFD doit être les symboles de la grammaire. En d’autre mots, les transitions de l’AFD seront étiquetées par les symboles de la grammaires (terminaux et non terminaux). La question qui reste est de savoir quels devraient être les états de l’AFD et quelles devraient être les transitions entre ces états. IFT313 © Froduald Kabanza

Préfixes viables Pour répondre à la question précédente, rappelons d’abord que le contenu de la pile (g) concaténé avec le reste des tokens (a) est une forme sententielle pour la dérivation la plus à droite. Par conséquent, le contenu de la pile est toujours un préfixe d’une forme sententielle pour la dérivation la plus à droite. De tels préfixes de formes sententielles de dérivation à droite, pouvant apparaître sur la pile, sont appelées des préfixes viables. De façon équivalente, un préfixe viable est défini comme étant un préfixe d’un contexte LR(0). On va voir comment construire un AFD pour reconnaître des préfixes viables. Ensuite on va expliquer comment l’utiliser pour reconnaître des poignées. Dans la leçon¸on précédente, nous avons vu qu’un contexte LR(0) est un contenu de la pile donnant lieu à une réduction, autremenent dit un contenu de la pile ayant un suffixe qui est une poignée. Voir aussi la note de la slide 24 dans la lécon précédente (automates à pile LR). IFT313 © Froduald Kabanza

AFN pour reconnaître les préfixes viables Les transitions de l’AFN vont être étiquetées par des symboles dont la séquence forme un préfixe viable. En d’autres mots, on aura les transitions si XYZ est un préfixe viable. Un état de l’AFN sera une production de la grammaire avec un point (« . ») à une position particulière dans la partie droite. Ainsi, à partir de la production A ® XYZ, on va générer 4 états de l’AFN : A ® . XYZ A ® X . YZ A ® XY . Z A ® XYZ . Pour la production A ® e, on va générer un seul état : A ® . X Y Z IFT313 © Froduald Kabanza

Que signifient les états de l’AFN? Intuitivement, un état de l’AFN indique la portion de la partie droite d’une production, reconnue au sommet de la pile, à un moment donnée durant l’analyse syntaxique LR. Par exemple l’état A ® . XYZ indique qu’aucune portion n’est encore reconnue sur la pile, et on espère que le reste des tokens à lire commence par un préfixe dérivable de XYZ. L’état A ® X.YZ indique qu’on vient juste de lire une sous-chaîne de tokens dérivable de X (c.-à-d., le préfixe viable X est au sommet de la pile) et on s’attend à lire ensuite une suite de tokens formant un sous-chaîne dérivable de YZ. Un état de l’AFN est appelé un élement LR(0) (item LR(0) en anglais; ou élément tout court) de la grammaire. On peut implémenter un élément LR(0) par une paire d’entiers, le premier indiquant le numéro de la production, le deuxième indiquant la position du point. On peut maintenant expliquer la technique pour obtenir l’AFN de la grammaire. IFT313 © Froduald Kabanza

AFN pour reconnaître les préfixes viables L’état initial est S’ ® . S Pour chaque paire d’états A ® a . X b et A ® aX . b, ajouter une transition du premier état vers le deuxième, étiquetée par X. Il faut garder à l’esprit que A ® a . Xb signifie : à un moment donné durant l’analyse syntaxique, on vient juste de scanner un sous-chaîne dérivable de a et on s’attend à scanner une sous-chaîne dérivable de X, ensuite une sous-chaîne dérivable de b. Ainsi, la transition de A ® a . X b à A ® aX . b, étiquetée X, signifie qu’on vient juste de lire une sous-chaîne dérivable de X et on s’attend maintenant à en lire une dérivable de b. Pour chaque paire d’états A ® a . X b et X ® . g, ajouter une transition du premier vers le deuxième, étiquetée e. Intuitivement, si on s’attend à scanner une sous-chaîne dérivable de X et si X peut dériver g, on peut s’attendre aussi bien à scanner une chaîne dérivable de g. IFT313 © Froduald Kabanza

Éléments canoniques (de base) et l’opération de fermeture (closure) L’état initial est S’ ® . S Pour chaque paire d’états A ® a . X b et A ® aX . b, ajouter une transition du premier état vers le deuxième, étiquetée par X. Pour chaque paire d’états A ® a . X b et X ® .g, ajouter une transition du premier vers le deuxième, étiquetée e. Les éléments impliqués dans les deux premières opérations sont appelés des éléments canoniques (c-à-d., des éléments du noyau, ou des éléments de base ou kernels en anglais). Il s’agit de l’élément S’ ® . S et des éléments dont le point ne commence pas la partie droite de la production. Les éléments dont le point apparaît au début de la partie droite de la production sont dits non canoniques. La troisième opération est une fermeture e. IFT313 © Froduald Kabanza

Exemple 1/3 Grammaire Grammaire augmentée G = (V, A, R, E) : V= {E, F, T} A = {(, ), +, *, num} R = { E ® E + T E ® T T ® T * F T ® F F ® ( E) F ® num } Grammaire augmentée G = (V, A, R, E) : V= {E’, E, F, T} A = {(, ), +, *, num} R = { E’ ® E E ® E + T E ® T T ® T * F T ® F F ® ( E) F ® num } IFT313 © Froduald Kabanza

AFN pour les préfixes viables Exemple 2/3 AFN pour les préfixes viables e Grammaire E’® E E® E+T E® T T®T*F T® F F® (E) F®num E T T®F. E’®.E E’®E. E®.T E®T. e e F E + E®.E+T E®E.+T E®E+.T e T®.F e e F® .num E®E+T. T®.T*F T®T.*F F®.(E) F®num. F®(.E) T®T*.F F®(E.) T®T*F. F®(E). Seulement quelques transitions sont présentes ! Compléter les autres comme exercice. IFT313 © Froduald Kabanza

Exemple 3/3 e E’ E T ( F ) + * num 1. E’® .E 2. E’® E. 3. E® .E+T 9. T®.T*F 10. T®T.*F 11. T®T*.F 12. T®T*F. 13. T® .F 14. T® F. 15. F® .(E) 16. F® (E) 17. F® (E) 18. F®num 19. F®num 2 7. E® .T 3,7 Même AFN, avec table de transition. Seulement deux entrées complétées. Les autres sont laissées comme exercice. Grammaire E’® E E® E+T E® T T®T*F T® F F® (E) F®num IFT313 © Froduald Kabanza

AFD pour reconnaître les préfixes viables On obtient l’AFD pour les préfixes viables en déterminisant l’AFN (par la méthode subset construction). I0 I1 I6 I9 I2 I7 I10 I8 I11 I5 E T + F ( num * ) to I7 to I2 to I6 to I3 to I4 to I5 I4 I3 I0 E’® .E E® .E+T E® .T T®.T*F T® .F F® .(E) F®.num I1 E’® E. E® E.+T I2 E® T. T®T.*F I3 T® F. I4 F® (.E) F® .num I5 F® num. I6 E® E+.T T® .T*F I7 T®T*.F I8 F® (E.) I9 E® E+T. T®T*F. I11 F® (E). IFT313 © Froduald Kabanza

AFD pour reconnaître les préfixes viables L’AFD avec une table de transition. I0 E’® .E E® .E+T E® .T T®.T*F T® .F F® .(E) F®.num I1 E’® E. E® E.+T I2 E® T. T®T.*F I3 T® F. I4 F® (.E) F® .num I5 F® num. I6 E® E+.T T® .T*F I7 T®T*.F I8 F® (E.) I9 E® E+T. T®T*F. I11 F® (E). E T ( F ) + * num I1 E’ I0 I2 I4 I3 I7 I5 I9 I8 I10 I6 I11 IFT313 © Froduald Kabanza

AFD LR(0) pour reconnaître les préfixes viables Les états de l’AFD sont donc des ensembles d’états de l’AFN, c’est-à-dire, des ensembles d’éléments LR(0). La fonction de transition de l’AFD est appelée la fonction goto de l’analyseur syntaxique: Étant donné un état I de l’AFD et un symbole de grammaire X, goto(I,X) est le successeur de I pour la transition étiqueté par X. Les états de l’AFD sont donc des ensembles d’états de l’AFN, c’est-à-dire, des ensembles d’éléments LR(0). En fait, on verra que les états de l’AFD sont les éléments canoniques LR(0) puisqu’on peut obtenir le reste d’un état par l’opération de fermeture. IFT313 © Froduald Kabanza

Méthode efficace de construction de l’AFD pour les préfixes viables Une méthode efficace de construction de l’AFD pour les préfixes viables est d’appliquer la méthode de déterminisation (subset construction method), à la volée, sans construire l’AFN au préalable. Pour ce faire, nous avons d’abord besoin de définir deux fonctions auxiliaires: closer(I) et goto(I,X). closure(I) implémente la fermeture e, sous-jacente à méthode déterminisation, en éliminant notamment les transitions e. goto(I,X) implémente les transitions entre les éléments canoniques. IFT313 © Froduald Kabanza

Définition informelle de closure Soit I un ensemble d’éléments LR(0) d’une grammaire. closure(I) est l’ensemble obtenu de I en appliquant les opérations suivantes : Initialement, chaque élément de I est mis dans closure(I). Ensuite on applique l’opération suivante, jusqu’à ce qu’aucun nouvel élément ne peut plus être ajouté : Si A ® a . Xb est dans closure(I) et X ® g est une production, ajouter l’élément X ® .g à closure(I). IFT313 © Froduald Kabanza

Définition formelle de closure(I) Algorithm closure(I) variables : I (ensemble d’éléments LR(0) : donnée d’entrée) G (grammaire : donnée comme variable globale) J (ensemble d’éléments LR(0): contient le résultat) J = I; // initialisation do { for (each item A ® a . Xb in J and each production X ® g of G such that X ® .g is not in J) add X ® .g to J } while (J is modified) return J; IFT313 © Froduald Kabanza

Fonction goto Soit I un état de l’AFD (c.-à-d., un ensemble d’items LR(0)) et X un symbole de la grammaire. Notons I’ l’ensemble formé de tous les éléments A ® aX . b pour lesquels il existe un élément A ® a . Xb dans I. goto(I,X) = closure(I’). En d’autre mots, goto(I,X) est défini comme étant la fermeture (closure) de l’ensemble formé de tous les éléments A ® aX . b pour lesquels il existe un élément A ® a . Xb dans I. Rappelons que les états de l’AFD sont aussi appelés des éléments (items) canoniques LR(0). Comme on connaît la fonction goto, pour définir l’AFD il suffit d’itérer avec la fonction goto à partir de l’état initial closure({S’® . S}). Ceci veut dire que si on veut représenter l’AFD de manière compacte, on peut juste stocker les éléments canoniques. Étant donné les éléments canoniques, il suffit alors de leur appliquer la fermeture pour retrouver l’état correspondant. IFT313 © Froduald Kabanza

Algorithme pour les états de l’AFD LR(0) Algorithm Items(G) variables : G (entrée : grammaire augmentée avec symbole de départ S) et C (résultat : ensembles des états de l’AFD.) Output : C et la fonction goto. C = { closure({S’® . S}) }; // état initial do { for (each state I in C and each grammar symbol X such that goto(I,X) is not empty and not in C) add goto(I,X) to C } while (C is modified) return C; IFT313 © Froduald Kabanza

Éléments valides Un élément A ® b1 . b2 est dit valide pour un préfixe viable a b1 s’il existe une dérivation la plus à droite telle que : S’ => aAw => a b1 b2 w . On peut démontrer que l’ensemble des éléments valides pour un préfixe viable g est précisément l’ensemble des éléments atteignables à partir de l’état initial de l’AFD des préfixes viables, en suivant un chemin étiqueté par g. La validité de A ® b1 . b2 pour un préfixe a b1 nous indique s’il faut faire shift ou alors reduce dès que a b1 est au sommet de la pile. En d’autre mots, ça nous indique si ab1 est une poignée ou non. * * R R IFT313 © Froduald Kabanza

Quand faire shift, quand faire reduce ? Supposons que a b1 est au sommet de la pile et que l’élément A ® b1 . b2 est valide pour a b1. Alors : Si b2 = e , cela veut dire qu’au sommet de la pile nous avons la partie droite de la production A ® b1. C.-à-d., b1 est une poignée, on peut donc réduire. Sinon, si b2 ≠e , cela veut dire qu’on doit faire shift des tokens de la sous-chaîne b2 avant d’obtenir b1 b2 . C-à-d., on n’a pas encore une poignée sur la pile, on doit continuer de faire shift. De ces observations, on déduit que si on simule l’AFD pour les préfixes viables en parallèle avec le driver LR (automate à pile LR), on sera capable de déterminer quand faire shift et quand faire reduce. betta2 = epsilon signifie que le point est à la fin d’une partie droite de la règle de production. betta2 différent de epsilon signifie que le point n’est pas à la fin d’une partie droite de la règle de production. IFT313 © Froduald Kabanza

Idée de base L’idée de base pour simuler en parallèle l’automate à pile LR et l’AFD pour les préfixes viables est la suivante. Initialement, l’automate à pile est vide et l’AFD est dans son état initial. Chaque fois qu’on shift un token sur la pile, l’AFD change son état en suivant la transition étiquetée par le token. Ainsi, lorsque le sommet de la pile va contenir b1 l’AFD sera dans un état contenant l’élément A ® b1 . , ce qui indique que nous devons faire une réduction avec la production A ® b1. En même temps que nous appliquons la réduction (en remplaçant b1 par A sur la pile), on doit revenir en arrière dans l’AFD (backtracking) le long du chemin étiqueté b1 jusqu’à l’état I qui est la racine du chemin étiqueté b1 . Puisque A est le nouveau symbole au sommet de la pile, on doit faire une transition correspondante dans l’AFD; c-à-d., l’état courant de l’AFD doit devenir l’état retourné par goto(I,A) (c.-à-d., le successeur de I sous la transition A dans l’AFD). IFT313 © Froduald Kabanza

De l’idée à l’implémentation Pour implémenter cette idée, on met les états de l’AFD sur la pile de sorte à garder une trace de l’exécution de l’AFD. Plus précisément, sur la pile on va alterner un état de l’AFD avec un symbole de la grammaire (terminal ou non-terminal), en commençant avec l’état initial de l’AFD. Donc une configuration du driver LR est dorénavant de la forme (I0X1I1 … XmIm , ti … tn$), tel que Ij sont des états de l’AFD, Xj des symboles de la grammaire, et ti … tn le reste des tokens à lire. Nous n’avons plus besoin de mettre le $ pour reconnaître le fond de la pile. L’état initial de l’AFD va remplir ce rôle. IFT313 © Froduald Kabanza

De l’idée à l’implémentation Une configuration (I0X1I1 … XmIm, ti … tn$) signifie que: l’AFD est actuellement dans l’état Im , le long d’un chemin (trace) étiqueté X1 … Xm à partir de l’état initial I0, et le reste de l’entrée à scanner est ti… tn. Ainsi, si Xj … Xm, est une poignée, pour un j quelconque : Il doit y avoir un élément « A® Xj … Xm . » dans l’état Im. Dans ce cas, on fait une réduction en remplaçant Xj … Xm par A sur la pile. Plus précisément, on enlève Xj Ij … XmIm de la pile, et on ajoute AI’ tel que I’ est l’état retourné par goto(Ij-1, A). La suppression de XjIj … XmIm de la pile revient à un retour arrière (backtracking) dans l’AFD, le long du chemin Xj … Xm. IFT313 © Froduald Kabanza

Analyseur LR(0) (1/2) Un analyseur (syntaxique) LR(0) n’a pas besoin d’anticiper le prochain token (lookahead) pour prendre une décision shift ou reduce. Il décide de l’action appropriée (shift ou reduce) seulement en fonction de l’état courant de l’AFD pour les préfixes viables. Ce comportement est reflété par la version suivante de l’analyseur LR(0). Algorithm LR0Parser Input: stream of tokens Output: a derivation sequence Variables: stack (pile), a (prochain token), in (entrée : flux de tokens) AFD pour préfixes viables, avec état initial I0 et fonction de transition goto Initialement la pile contient I0 IFT313 © Froduald Kabanza

Analyseur LR(0) (2/2) while (true) { if (la pile contient I0S’ et l’entrée est $ (vide)) return true; if (l’état au sommet de la pile contient un élément A ® a . ) { reduce with the production A ® a; // a est une poignée et A ® a la production correspondante c.-à-d. : Supprimer 2×|a| symboles de la pile (|a| états et |a| symboles de grammaires). Soit I le nouvel état au sommet de la pile. Ajouter A au sommet de la pile. Ajouter l’état retourné par goto(I,A) au sommet de la pile. print out the production A ® a; continue; } if (l’état au sommet de la pile contient un élément A ® a . ab tel que a est un token) { shift; c.-à-d. : Soit I l’état au sommet de la pile. Lire le prochain token a. Ajouter a au sommet de la pile. Ajouter l’état retourné par goto(I,a) au sommet de la pile. error(); IFT313 © Froduald Kabanza

Exemple to I7 to I2 to I6 to I3 to I4 to I5 IFT313 © Froduald Kabanza + F ( num * ) to I7 to I2 to I6 to I3 to I4 to I5 I4 I3 I0 E’® .E E® .E+T E® .T T®.T*F T® .F F® .(E) F®.num I1 E’® E. E® E.+T I2 E® T. T® T.*F I3 T® F. I4 F® (.E) F® .num I5 F® num. I6 E® E+.T T® .T*F I7 T®T*.F I8 F® (E.) I9 E® E+T. T®T.*F T®T*F. I11 F® (E). IFT313 © Froduald Kabanza

Exemple 1 Trace 1. (I0, (num)$) Shift T® .(E) + F ( num * ) to I7 to I2 to I6 to I3 to I4 to I5 I4 I3 Trace 1. (I0, (num)$) Shift T® .(E) 2. (I0(I4, num)$) Shift T® .num 3. (I0(I4numI5, )$) Reduce F® num. 4. (I0(I4FI3, )$) Reduce T® F. 5. (I0(I4TI2, )$) Reduce E® T. 6. (I0(I4EI8, )$) Shift F® (E.) 7. (I0(I4EI8)I11, $) Reduce F® (E). 8. (I0FI3, $) Reduce T® F. 9. (I0TI2, $) Reduce E® T. 10. (I0EI1, $) Reduce E’® E. 11. (I0E’, $) Accept Dérivation correspondante : (num) <= (num) <= (num) <= (F) <= (T) <= (E) <= (E) <= F <= T <= E <= E’ À l’étape 5, l’état I2 contient un conflit Shift (élément T -> T.*F) / Reduce (élément E -> T.). La grammaire n’est donc pas LR(0); l’analyseur LR(0) correspondant n’est pas déterministe. Le conflit devrait être résolu en fonction de reduce (intuitivement parce que, selon cette grammaire, « ) » ne peut suivre « T » dans une forme sententielle; c.-à-d., « ((T) » ne serait pas un préfixe viable.). On verra plus tard, comment résoudre ce conflit en utilisant un lookahead et l’ensemble Follow. Pour l’instant, résolvons donc le conflit en faveur de Reduce. À l’étape 10, l’état I1, contient un conflit Shift (élément E -> E.+T) / Reduce (élément E’ -> E.). De toute évidence, on est`rendu à la fin du fichier ($); il n’y a plus de token à lire (“shifter”). La seule option valide est donc Reduce. Là encore, on verra plus tard comment décider de cette option en se servant du lookahead et de l’ensemble Follow. IFT313 © Froduald Kabanza

Même entrée, mais à l’étape 9, on résoud le conflit en faveur de Shift Exemple 2 Même entrée, mais à l’étape 9, on résoud le conflit en faveur de Shift I0 I1 I6 I9 I2 I7 I10 I8 I11 I5 E T + F ( num * ) to I7 to I2 to I6 to I3 to I4 to I5 I4 I3 Trace 1. (I0, (num)$) Shift T® .(E) 2. (I0(I4, num)$) Shift T® .num 3. (I0(I4numI5, )$) Reduce F® num. 4. (I0(I4FI3, )$) Reduce T® F. 5. (I0(I4TI2, )$) Shift T® T.*F 6. (I0(I4TI2), $) Error goto(I2, ‘)’) non défini. IFT313 © Froduald Kabanza

Exemple 3 Une entrée différente Trace : + F ( num * ) to I7 to I2 to I6 to I3 to I4 to I5 I4 I3 Trace : 1. (I0, (num*num)$) Shift T® .(E) 2. (I0(I4, num*num)$) Shift T® .num 3. (I0(I4numI5, *num)$) Reduce F®num. 4. (I0(I4FI3, *num)$) Reduce T® F. 5. (I0(I4TI2, *num)$) … Poursuivre comme exercice … Remarquer le conflit Shift/Reduce à l’étape 5. L’état I2 contient élément Shift (T ® T.*F) et un élément Reduce (E ® T.). Contrairement à l’exemple précédent, cette fois-ci le conflit devrait être réglé en faveur de Shift. Pourquoi? Encore une fois, nous verrons plus tard comment résoudre ce conflit tenant compte du prochain token et de l’ensemble Follow. Cela nous mènera aux analyseurs SLR(1). IFT313 © Froduald Kabanza