Télécharger la présentation
1
Chap 2. L'analyse descendante
Nous introduisons les idées de base sous-tendant l'analyse descendante efficace et montrons comment construire un analyseur syntaxique efficace, sans rebroussement, appelé analyseur prédictif. Nous définissons la classe des grammaires LL(1) à partir desquelles on peut construire automatiquement des analyseurs prédictifs. L'analyse descendante peut être considérée comme une tentative pour déterminer une dérivation gauche associée à une chaîne d'entrée.
2
L’analyse récursive La forme générale d'analyse descendante appelée descente récursive peut impliquer des retours arrière, c.à.d. nécessiter des passages répétés sur le texte source. Cependant, les analyseurs avec rebroussement ne sont pas très fréquents. Une des raisons est que le rebroussement est rarement nécessaire pour analyser les constructions des langages de programmation. Pour des situations comme analyse des langues naturelles, le rebroussement n'est pas très efficace et on lui préfère d'autres méthodes.
3
Exemple Grammaire : ScAd Aab|a la chaîne d'entrée w = cad. S S c A d c A d a b a
4
Suppression de la récursivité à gauche.
Une grammaire est récursive à gauche si elle contient un non-terminal A tel qu'il existe une dérivation A A, où est une chaîne quelconque. Les méthodes d'analyse descendante ne peuvent pas fonctionner avec les grammaires récursives à gauche ; on a donc besoin d'une transformation grammaticale qui élimine cette récursivité à gauche. On peut éliminer une production récursive à gauche en la réécrivant.
5
expr expr + terme | terme
Considérons le non-terminal A dans les deux productions : A A | où et sont des suites de terminaux et de non-terminaux qui ne commencent pas par A. Par exemple, dans : expr expr + terme | terme A = expr, = + terme et = terme. Le non-terminal A est récursif à gauche car la production A A contient A comme symbole le plus à gauche de sa partie droite. Une application répétée de cette production fabrique une suite de à droite de A : A A A A ……
6
Quand A is finalement remplacé par , nous avons suivi par une sequence de 0 ou plus . On peut obtenir le même effet, en réécrivant la production définissant A de la manière suivante : AR RR | Ici R est un nouveau non-terminal. A R R …………………… R R
7
Exemple Grammaire d’expressions arithmétiques: E E + T | T T T * F | F F (E) | id. Suppression de la récursivité à gauche. E TE' E' + TE' | T FT' T' * FT' |
8
Peu importe combien il y en a des A-productions, nous pouvons toujours éliminier la récursivité à gauche. A A 1 | A2 | …| Am | 1 | 2 | …| n ou aucun i ne commence avec A. Nous remplaçons les A-productions de la façon suivante. A 1A' | 2A' | … |nA' A'1A' | 2A' | … |mA' | Le non-terminal A génère exactement les mêmes chaînes.
9
Analyse prédictif non-récursif
Il est possible de construire un analyseur prédictif non récursif en tenant à jour une pile explicite, plutôt que la pile implicite résultant des appels récursifs. Le problème clé de l'analyse prédictive est la détermination de la production à appliquer pour développer un non-terminal. L'analyseur non récursif recherche la production à appliquer dans une table d'analyse.
10
Entrée a + b $ Analyseur prédictif X Y Table d’analyse M Z Pile Sortie
Entrée a + b $ Analyseur prédictif Pile X Sortie Y Table d’analyse M Z
11
Un analyseur syntaxique prédictif dirigé par table possède un tampon d’entrée, une pile, une table d’analyse et un flot de sortie. Le tampon d’entrée contient la chaîne à analyser, suivie de $, symbole utilisé comme marqueur de fin. La pile contient une séquence de symboles grammaticaux, avec $ marquant le fond de la pile. Initialement, la pile contient l’axiome de la grammaire au-dessus du $. La table d’analyse est un tableau à deux dimensions M[A,a] ou A est un non-terminal et a est un terminal ou un $.
12
L’analyse syntaxique est contrôlée par un programme qui a le comportement suivant. Ce programme considère X, le symbole en sommet de pile et a, le symbole d’entrée courant. Ces deux symboles déterminent l’action de l’analyseur. Il y a 3 possibilités : SI X = a = $, l’analyseur s’arrête et annonce la réussite finale de l’analyse. SI X = a <> $, l’analyseur enlève X de la pile et avance son pointeur d’entrée sur le symbole suivant. SI X est un non-terminal, le programme consulte l’entrée M[X,a] de la table d’analyse M. Cette entrée sera soit une X-production de la grammaire soit une erreur. Si, par exemple, M[X,a] = {X UVW}, l’analyseur remplace X en sommet de pile par WVU (avec U au sommet). L’analyseur se contente, pour tout résultat, d’imprimer la production utilisée : n’importe quelle autre action pourrait être exécutée à la place. Si M[X,a]=erreur, l’analyseur appelle une procédure de récupération sur erreur. Le comportement de l’analyseur peut se décrire en termes de ses configurations, qui décrivent le contenu de sa pile et le texte d’entrée restant.
13
Algorithme de l’analyse prédictive non récursive.
Donnée : Une chaîne w et une table d’analyse M pour une grammaire G. Résultat : Si w est dans L(G), une dérivation gauche pour w ; sinon, une indication d’erreur. Méthode : Initialement, l’analyseur est dans une configuration dans laquelle il a $S dans sa pile avec S, l’axiome de G au sommet et w$ dans son tampon d’entrée.
14
Programme d'analyse syntaxique prédictive Positionner le pointeur source ps sur le premier symbole de w$. Répéter Soit X le symbole en sommet de pile et a le symbole repéré par ps ; Si X est un terminal ou $ alors Si X=a alors Enlever X de la pile et avancer ps Sinon Erreur() Sinon /* X est un non-terminal */ Si M[X,a]=XY1Y2…Yk alors début Enlever X de la pile ; Mettre Yk, Yk-1,…, Y1 sur la pile, avec Y1 au sommet ; Emettre en sortie la production XY1Y2…Yk Fin Jusqu'à X=$ /* la pile est vide */
15
Exemple Considérons la grammaire : E E + T | T T T * F | F F (E) | id Eliminons la récursivité à gauche : E T E' E' + T E' | T F T' T' * F T' |
16
Non-terminal Symbole d'entrée id + * ( ) $ E E TE' E’ E’ ε T
E’ E’ +TE' E’ ε T T FT' T’ T’ ε T ‘ *FT' F F id F (E)
17
Sur la chaîne source id + id
Sur la chaîne source id + id * id l'analyseur prédictif effectue la séquence d'entrée suivante : Pile Entrée Sortie $E id+id*id$ $E'T E TE' $E'T'F T FT' $E'T'id F id $E'T' +id*id$ $E' T $E'T'+ E' +TE' id*id$ *id$ $E'T'F* T' *FT' id$ F id $ T' E'
18
PREMIER et SUIVANT La construction d’un analyseur Synt. Préd. est facilitée par 2 fonctions associées à une grammaire G. Ces fonctions PREMIER et SUIVANT, nous permettent, quand c’est possible, de remplir les entrées de la table d’analyse prédictive pour G. Si α est une chaîne de symboles grammaticaux, PREMIER(α) désigne l’ensemble des terminaux qui commencent les chaînes qui se dérivent de α. Si αε, alors ε est aussi dans PREMIER(α). Pour chaque non-terminal A, SUIVANT(A) définit l’ensemble des terminaux a qui peuvent apparaître immédiatement à droite de A dans une protophrase, c.a.d. l’ensemble des terminaux a tels qu’il existe une dérivation de la forme S αAaβ où α et β sont de chaînes de symboles grammaticaux. Si A peut être le symbole le plus à droite d’une proto-phrase, alors $ est dans SUIVANT(A).
19
Pour calculer PREMIER(X), pour tout symbole de la grammaire X, appliquer les règles suivantes jusqu’à ce qu’aucun terminal ni ε ne puisse être ajouté aux ensembles PREMIER. 1. Si X est un terminal, PREMIER(X) est {X} 2. Si X ε est une production, ajouter ε à PREMIER(X). 3. Si X est un non-terminal et XY1Y2…Yk une production, mettre a dans PREMIER(X) s’il existe i tel que a est dans PREMIER(Yi) et ε est dans tous les PREMIER(Y1), …, PREMIER(Yi-1), c.a.d. Y1…Yi-1 ε. Si ε est dans PREMIER(Yj) pour tous les j=1,…,k, ajouter ε à PREMIER(X), mais si Y1 ε, on ajoute PREMIER(Y2), etc.
20
On peut calculer PREMIER pour une chaîne X1X2…Xn de la façon suivante
On peut calculer PREMIER pour une chaîne X1X2…Xn de la façon suivante. Ajouter à PREMIER(X1X2…Xn) tous les symboles de PREMIER(X1). Si ε est dans PREMIER(X1), ajouter également les symboles de PREMIER(X2) différents de ε. Si ε est dans PREMIER(X1) et également dans PREMIER(X2) ajouter également les symboles de PREMIER(X3) différents de ε, etc. Finalement, si quel que soit i, PREMIER(Xi) contient ε, ajouter ε à PREMIER(X1X2…Xn).
21
Pour calculer SUIVANT(A) pour tous les non-terminaux A, appliquer les règles suivantes jusqu’à ce qu’aucun terminal ne puisse être ajouté aux ensembles SUIVANT. 1.Mettre $ dans SUIVANT(S), où S est l’axiome et $ est le marqueur de fin. 2. S’il y a une production AαBβ, le contenu de PREMIER(β) excepté ε, est ajouté à SUIVANT(B). 3. S’il existe une production AαB ou une production AαBβ telle que PREMIER(β) contient ε (c.a.d. β ε), les éléments de SUIVANT(A) sont ajoutés à SUIVANT(B).
22
Exemple ETE' E'+TE' | TFT' T'*FT' | F(E) | id Alors FIRST(E) = FIRST(T) = FIRST(F) = {(, id} FIRST(E') = {+, } FIRST(T') = {*, } FOLLOW(E) = FOLLOW(E') = {), $} FOLLOW(T) = FOLLOW(T’) ={$, ), +} FOLLOW(F) = {+,*, ), $}
23
Construction d’une table d’un analyseur prédictif
Algorithme. Donnée. Grammaire G Sortie. Table d’analyse M Méthode : 1. Pour chaque production A α de la grammaire, procéder aux étapes 2 et 3. 2. Pour chaque terminal a dans PREMIER(α), ajouter A α à M[A,a]. 3. Si ε est dans PREMIER(α), ajouter A α à M[A,b] pour chaque terminal b dans SUIVANT(A). Si ε est dans PREMIER(α) et $ est dans SUIVANT(A), ajouter A α à M[A,$]. 3. Faire de chaque entrée non définie de M une erreur.
24
Exemple Appliquons l'algorithme donné à la grammaire des expressions arithmétique : 1. Puisque PREMIER(TE') = PREMIER(T) = {(, id}, la production E TE' implique que les entrées M[E,(] et M[E,id] prennent toutes les deux la valeur E TE'. 2. La production E' +TE' implique que l'entrée M[E',+] prend la valeur E' +TE'. 3. La production E' implique que les entrées M[E',)] et M[E',$] prennent tous les deux la valeur E' car SUIVANT(E') = {),$}
25
Grammaires LL(1) L’algo décrit peut être appliqué à une grammaire G pour produire la table d’analyse M. Cependant, pour certaines grammaires, M peut avoir des entrées qui sont définies de façon multiple. Par exemple, si G est récursive à gauche ou ambiguë, M aura alors au moins une de ses entrées définie de façon multiple.
26
Exemple Considérons la grammaire : S iEtSS' | a S' eS | E b
PREMIER(S) = {i, a} PREMIER(S') = {e, } PREMIER(E) = {b} SUIVANT(S) = SUIVANT(S') ={$,e} SUIVANT(E) = {t}
27
Non-terminal Symbole d'entrée a b e i t $ S S a S' S' S' eS E
S iEtSS' S' S' S' eS E E b
28
L'entrée M[S',e] contient à la fois S' et S' eS, car SUIVANT(S') = {e,$}.
La grammaire est ambiguë et cette ambiguïté se manifeste par un choix sur la production à utiliser quand on voit un e (sinon). Nous pouvons résoudre cette ambiguïté en choisissant S' eS. Ce choix correspond à l'association du sinon avec le alors précédent le plus proche.
29
Une grammaire dont la table d’analyse n’a aucune entrée définie de façon multiple est appelée LL(1).
Parcours de l’entrée de la gauche vers la droite. (Left to right scanning) Leftmost derivation. Dérivation gauche (Leftmost derivation) Un seul symbole d’entrée de pré-vision
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.