Vous êtes sur la page 1sur 38

Cours : Techniques de compilation

CH5. Analyse syntaxique descendante

Khaled Bsaïes
Khaled.Bsaies@gmail.com

2012-13

03/02/2013 Khaled Bsaïes 1


khaled.bsaies@gmail.com
Emplacement d’un analyseur syntaxique
dans un modèle de compilateur

fournit
programme analyseur l’U.L. analyseur construit Reste de représentation
un arbre la partie intermédiaire
source lexicale demande syntaxique d’analyse frontale
U.L suivante.

table des
symboles

gestion de erreurs

03/02/2013 Khaled Bsaïes 2


khaled.bsaies@fst.rnu.tn
Rôle de l’analyseur syntaxique
• Étant donnée une grammaire G, Le rôle principal d'un
analyseur syntaxique est de vérifier si un mot (ou phrase)
est généré(e) à partir de G.
• Dans le cas où le mot n'est pas dérivable de la grammaire,
l'analyse syntaxique va le plus loin possible dans l'analyse
du mot par l'utilisation de procédures de recouvrement
d'erreurs et fournit des messages d'erreurs permettant la
localisation des erreurs.
• Dans le contexte de la compilation de langage de
programmation : le mot analysé est le programme source et
la grammaire est celle du langage de programmation
considéré.

03/02/2013 Khaled Bsaïes 3


khaled.bsaies@fst.rnu.tn
Objectifs du chapitre

Fournir des :
• techniques d'analyse syntaxique qui
conviennent à une implantation manuelle
(descendante)
• algorithmes utilisés par des outils de
génération automatique d'analyseurs
syntaxiques ascendants

03/02/2013 Khaled Bsaïes 4


khaled.bsaies@fst.rnu.tn
Types d'analyseurs syntaxiques

• On distingue trois types d'analyseurs syntaxiques :


– Méthodes universelles : permettent d'analyser une
grammaire quelconque. Ces méthodes sont inefficaces
pour être utilisées dans les compilateurs industriels.
– Méthodes descendantes : construisent des arbres
d'analyse de haut (la racine) en bas (les feuilles).
– Méthodes ascendantes : construisent des arbres
d'analyse de bas en haut.
• Dans les deux derniers cas, l'entrée de l'analyseur
syntaxique est parcourue de la gauche vers la
droite, un symbole à la fois.

03/02/2013 Khaled Bsaïes 5


khaled.bsaies@fst.rnu.tn
Traitement d'erreurs
• Par les statistiques :
– 60% des programmes sont syntaxiquement et sémantiquement
corrects
– 80% des instructions erronées ont une seule erreur
– 13% en ont deux (erreurs)
– 90% des erreurs sont triviales.
• Exemple :
– , au lieu de ;
– oubli de ;
– = au lieu de :=

• Plusieurs stratégies de récupération d'erreurs sont


proposées :
03/02/2013 Khaled Bsaïes 6
khaled.bsaies@fst.rnu.tn
Stratégies de récupération d'erreurs
• Mode panique
– En cas d'erreurs, sauter toutes les unités lexicales
jusqu'à l'unité lexicale de synchronisation : en général
les délimiteurs.
– Exemple : , ; BEGIN END
– L'avantage de cette méthode est sa simplicité de mise
en oeuvre.
• Niveau du syntagme
– Corriger localement un préfixe du code source.
– Exemple : remplacer un , par un ;
– Insérer un ; manquant.
– Notons que ces remplacement présentent un risque.
03/02/2013 Khaled Bsaïes 7
khaled.bsaies@fst.rnu.tn
Stratégies de récupération d'erreurs
(suite)
• Productions d'erreurs
– Utilisation des grammaires augmentées à la main avec
des productions qui engendrent des constructions
erronées.
– Si une production d'erreur est utilisée par l'analyseur
syntaxique, celui-ci peut émettre les diagnostics
d'erreurs appropriés pour indiquer la construction
erronée qui a été reconnue et peut aussi effectuer une
action de recouvrement de l'erreur, par exemple, en
fournissant une unité lexicale de synchronisation.

03/02/2013 Khaled Bsaïes 8


khaled.bsaies@fst.rnu.tn
Principe de fonctionnement de l’A.S.
• Le principe de fonctionnement d'un compilateur
est le suivant :
– l'analyseur syntaxique obtient une chaîne d'unités
lexicales de l'analyseur lexical,
– et vérifie que la chaîne peut être engendrée par la
grammaire du langage source.
• Nous supposons que l'analyseur syntaxique
signale chaque erreur de syntaxe de façon à
pouvoir continuer le traitement du texte restant.
03/02/2013 Khaled Bsaïes 9
khaled.bsaies@fst.rnu.tn
Grammaires formelles

• La notion de grammaire (quadruplet(VN,VT,P,S))


est un formalisme qui doit permettre :
– Une spécification syntaxique précise
– La possibilité de construire automatiquement un
analyseur syntaxique (l'outils YACC, BISON)
– La possibilité de traduction systématique en codes
objets corrects (traducteurs dirigés par la syntaxe)
– La déclaration des erreurs (production d’erreurs)

03/02/2013 Khaled Bsaïes 10


khaled.bsaies@fst.rnu.tn
Définition : analyse syntaxique
descendante
• En partant d’une grammaire G, ayant comme
axiome S, on construit un arbre syntaxique dont
les feuilles (lues de gauche à droite) constituent la
chaîne w d’entrée que l’on doit analyser.
• Une procédure par Non-Terminal
• Problème : récursivité à gauche (bouclage)

03/02/2013 Khaled Bsaïes 11


khaled.bsaies@fst.rnu.tn
Exemple
Soit G={S cAd (1) A ab (2) |a (3) }, S est l’axiome,
w=cad est la chaîne à analyser.
S S

c A d c A d

a a b

Cas de conflit

03/02/2013 Khaled Bsaïes 12


khaled.bsaies@fst.rnu.tn
Grammaire prédictive ou de type LL(1)
• LL(1) : L : Lecture de gauche à droite, L : construction d’une dérivation gauche et (1) :
un caractère de prévision.
• Une grammaire pour laquelle, on peut développer un analyseur syntaxique descendant,
et pour laquelle un seul symbole sur la tête de lecture permet de choisir au plus une règle
à appliquer.
• Une condition nécessaire et non suffisante pour rendre une grammaire non ambiguë
LL(1) et de factoriser puis de dérécursiver.
Exemple : la Grammaire G précédente n’est pas LL(1), car on ne sait pas décider si l’on doit
appliquer la dérivation : Aab ou Aa pour le symbole ‘a’. Par contre la grammaire
G’ : {ScAd (1) A aA’ (2) A’b (3) |ε (4) } est LL(1). En effet :

S est le seul arbre syntaxique permettant


de reconnaître w=cad
A d
c
a A’
03/02/2013 ε Khaled Bsaïes 13
khaled.bsaies@fst.rnu.tn
Algorithme de factorisation à gauche
Soit une grammaire G, l’algorithme produit une grammaire G’ équivalente
où tous les préfixes communs les plus longs entre les parties droites de
productions auront été factorisés.
1. tant que il existe des productions avec préfixe commun faire
2. pour chaque non-terminal A faire
3. trouver le plus long préfixe α commun à deux alternatives de
productions ou plus
4. si α ≠ε alors
5. remplacer toutes les A-productions A αβ1| αβ2|… |αβn|γ, où γ
représente toutes les alternatives qui ne commencent pas par α, par les
productions :
A αA’|γ
A’ β1| β2|… |βn
fin
fin

03/02/2013 Khaled Bsaïes 14


khaled.bsaies@fst.rnu.tn
Factorisation - exemple
• Factorisation à gauche
• "if then else" à la Pascal, C, et Java

INST → si EXP alors INST |


si EXP alors INST sinon INST |
A_INST

ambiguïté:
• si E1 alors ( si E2 alors I1 sinon I2 )
• si E1 alors ( si E2 alors I1 ) sinon I2

• "if then else" après factorisation

INST → si EXP alors INST INST_S | A_INST


INST_S → sinon INST | ε

la même ambiguïté à lever par la sémantique choisie

03/02/2013 Khaled Bsaïes 15


khaled.bsaies@fst.rnu.tn
Algorithme d’élimination des
récursivités à gauche
+
Soit une grammaire G sans cycle (dérivation de la forme AA) et sans production
vide (i.e. de la forme A ε), l’algorithme produit une grammaire G’ équivalente sans
récursivité à gauche.

1. On ordonne les non terminaux A1,A2,…,An.


2. pour i:=1 jusqu’à n faire
3. pour j:=1 jusqu’à i-1 faire
4. remplacer toutes les productions AiAjγ par les productions Ai δ1 γ | δ2 γ |… |δn γ, où
Aj  δ1 | δ2 |… |δn sont toutes les Aj productions courantes.
fin
5. éliminer les récursivités à gauche immédiates des Ai productions à l’aide de la transformation suivante :
Ai Aiα1| … | Aiαm |β1|…| βn
devient :
Ai β1Ai’|…| βnAi’
Ai’ α1Ai’| … | αmAi’|ε
fin

03/02/2013 Khaled Bsaïes 16


khaled.bsaies@fst.rnu.tn
Récursivité à gauche - Exemple
• Élimination de la récursivité gauche
- Les récursivités immédiates
E→E+T|T E → T E'
E' → + T E' | ε
T→T*F|F T → F T'
T' → * F T' | ε
F → ( E ) | id F → ( E ) | id

- Les récursivités immédiates ou non


S → Aa | Bb | c S → Aa | Bb | c
A → Aa | Bb |Sd | a A → Aa | Bb | a | Aad | Bbd | cd
B → Se | b B → b | Aae | Bbe | ce

S → Aa | Bb | c
A → BbA' | aA'| BbdA' | cdA'
A' → aA' | adA' | ε
B → b | Bbe | ce | Aae

B → b | Bbe | ce | BbA'ae | aA'ae| BbdA'ae | cdA'ae ….

03/02/2013 Khaled Bsaïes 17


khaled.bsaies@fst.rnu.tn
Méthode d’analyse descendante
• En règle générale, on peut associer une procédure à chaque
non-terminal de la grammaire. Ensuite on effectue une
analyse syntaxique descendante récursive de la catégorie
syntaxique associée (si G est non ambiguë).
• Exemple : Soit G la grammaire suivante :
EE+T|T TT*F|F F(E)|id
G est non ambiguë
• On commence par créer des diagrammes de transition pour
chaque non-terminal, après avoir au préalable vérifier que
la grammaire est non-ambiguë, non-récursive à gauche et
bien factorisée.
03/02/2013 Khaled Bsaïes 18
khaled.bsaies@fst.rnu.tn
Exemple : G est transformée en G’:
E TE’ E’ +TE’|ε TFT’ T’*FT’|ε F(E)|id

T E’
E: 0 1 2
+ T E’
3 4 5 6
E’ : ε
F T’
T: 7 8 9
* F T’
10 11 12 13
T’ : ε
( E )
F: 14 15 16 17
id
03/02/2013 Khaled Bsaïes 19
khaled.bsaies@fst.rnu.tn
Diagrammes de transitions simplifiés :
+
E:
T ε
0 3 6
*
F ε
T: 7 8 13

( E )
F: 14 15 16 17
id

Analyse syntaxique récursive directe :


E:={T ; E’} E’:={si symbole=‘+’ alors {accepter(‘+’) ; T ; E’}}
T:={F ; T’} T’ :={si symbole=‘*’ alors {accepter(‘*’) ; F ; T’}}
F:={si symbole=‘(‘ alors {accepter(‘(‘), E; si symbole =‘)’ alors accepter(‘)’ sinon erreur}
sinon { si symbole = id alors accepter(id) sinon erreur}

03/02/2013 Khaled Bsaïes 20


khaled.bsaies@fst.rnu.tn
Analyse descendante non récursive ou
itérative
a + b $ Tampon d’entrée

Pile
Programme d’analyse
X Flot de sortie
prédictive
Y

Table d’analyse M

03/02/2013 Khaled Bsaïes 21


khaled.bsaies@fst.rnu.tn
Analyseur descendant à pile
(non récursif ou itéatif)
• Positionner le pointeur source ps sur le premier symbole de w$ et l’axiome sur la pile
• répéter :
• Soit X le symbole en sommet de la 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
– Émettre en sortie XY1Y2…Yk
• fin
• Sinon erreur()
• Jusqu’à X=$ /* La pile est vide */

03/02/2013 Khaled Bsaïes 22


khaled.bsaies@fst.rnu.tn
Exemple
Table d’analyse M pour la grammaire G’
E TE’ E’ +TE’|ε TFT’ T’*FT’|ε F(E)|id

Symbole d'entrée
Non term ( ) + * id $
E E → TE' erreur erreur erreur E → TE' erreur
E' erreur E' → ε E' → +TE' erreur erreur E' → ε
T T → FT' erreur erreur erreur T → FT' erreur
T' erreur T' → ε T' → ε T' → * FT' erreur T' → ε
F F→(E) erreur erreur erreur F → id erreur

03/02/2013 Khaled Bsaïes 23


khaled.bsaies@fst.rnu.tn
Trace de l’analyse LL(1) d’une expression
Contenu de la pile Chaîne d'entrée Sortie
$E id+id*id$

03/02/2013 Khaled Bsaïes 24


khaled.bsaies@fst.rnu.tn
Construction de la Table d’analyse M
• Grammaires LL(1) sont celles définies par des tables d’analyse sans
conflit

– Aucune entrée ne peut avoir plus d’une règle de production à


appliquer

• Nous voulons générer des tables d’analyse à partir d’une GNC


• Méthode de construction de la table d’analyse en utilisant les
fonctions:
PREMIER et
SUIVANT

03/02/2013 Khaled Bsaïes 25


khaled.bsaies@fst.rnu.tn
Les fonctions PREMIER et SUIVANT

PREMIER(X) SUIVANT(X)

PREMIER(X)=ensemble des terminaux pouvant apparaître au début d’une


dérivation de X
SUIVANT(X)=ensemble des terminaux pouvant suivre X dans une dérivation quelconque
Annulable(X) est vrai ssi X*ε
PREMIER : (VT ∪ VN)*  P(VT) ∪ {ε}
SUIVANT : VN  P(VT) ∪ {$}
03/02/2013 Khaled Bsaïes 26
khaled.bsaies@fst.rnu.tn
Calcul de PREMIER
Définition :
PREMIER(X) =Ensemble de terminaux commençant
une chaîne dérivée à partir de X.
PREMIER(X) = { t terminal | X * tα} ∪ {ε | X * ε}
Algorithme :
1. PREMIER(t α) = {t}, si t est un symbole terminal
2. ε ∈ PREMIER(X) si X → ε est une production
3. ε ∈ PREMIER(X) si X → A1 … An
et ε ∈ PREMIER(Ai) pour 1 ≤ i ≤ n
4. PREMIER(α) ⊆ PREMIER(X) si X → A1 … An α
et ε ∈ PREMIER(Ai) pour 1 ≤ i ≤ n

03/02/2013 Khaled Bsaïes 27


khaled.bsaies@fst.rnu.tn
La fonction PREMIER - Exemples
• Soit la grammaire : E TE’ E’ +TE’|ε TFT’ T’*FT’|ε F(E)|id
PREMIER(E)=PREMIER(T)=PREMIER(F)={(,id}
PREMIER(E’)={+, ε }
PREMIER(T’) ={*, ε }
Exercice : Calculer PREMIER(E’T’) et PREMIER(E’T)
• Soit la grammaire
E→TX X→+E|ε
T → ( E ) | int Y Y→*T|ε
PREMIER( ( ) = { ( } PREMIER( T ) = {int, ( }
PREMIER( ) ) = { ) } PREMIER( E ) = {int, ( }
PREMIER( int) = { int } PREMIER( X ) = {+, ε }
PREMIER( + ) = { + } PREMIER( Y ) = {*, ε }
PREMIER( * ) = { * }

03/02/2013 Khaled Bsaïes 28


khaled.bsaies@fst.rnu.tn
Calcul de PREMIER (2ème façon)
• On construit un graphe entre tous les symboles grammaticaux.
• Flèche de x vers y ssi
x αyβ et α est vide (= ε) ou annulable

• Ici, α ne peut contenir que les non terminaux, β est quelconque


• PREMIER(x) ={a terminal | il existe un chemin de x à a}; si x est
annulable, il faut y ajouter ε.
• Exemple de la grammaire précédente E TE’ E’ +TE’|ε
TFT’ T’*FT’|ε F(E)|id : annulable (T’) et annulable(E’) vrai.
Graphe :
ETF( E’+ T’*

id
PREMIER(E)=PREMIER(T)=PREMIER(F)={(,id} et
PREMIER(E’)={ε , +} PREMIER(T’)={ε , *}

03/02/2013 Khaled Bsaïes 29


khaled.bsaies@fst.rnu.tn
Calcul des ensembles SUIVANT

Définition
SUIVANT(X) = {t terminal | S * β X t δ et X
non-terminal S n’est pas forcément l’axiome }
∪ {$} si X est l’axiome
Intuition Si X → A B alors
– (PREMIER(B)−{ε}) ⊆ SUIVANT(A)
– SUIVANT(X) ⊆ SUIVANT(B)
– si B * ε alors SUIVANT(X) ⊆ SUIVANT(A)
– Si S est l’axiome alors le symbole marqueur de fin de
fichier $ ∈ SUIVANT(S)

03/02/2013 Khaled Bsaïes 30


khaled.bsaies@fst.rnu.tn
Calcul des ensembles SUIVANT (Suite)

Algorithme :
1. $ ∈ SUIVANT(S), S l’axiome
2. PREMIER(β) - {ε} ⊆ SUIVANT(X)
– Pour chaque production A → α X β
3. SUIVANT(A) ⊆ SUIVANT(X)
– Pour chaque production A → α X β où
ε ∈ PREMIER(β)

03/02/2013 Khaled Bsaïes 31


khaled.bsaies@fst.rnu.tn
La fonction SUIVANT : Exemple

• E TE’ E’ +TE’|ε TFT’ T’*FT’|ε F(E)|id


• SUIVANT(E)=SUIVANT(E’)={),$}
• SUIVANT(T)=SUIVANT(T’)={+,),$}
• SUIVANT(F)={+,*,),$}
En effet :
– ) est dans SUIVANT(E) car F(E)
– $ est dans SUIVANT(E) car E est l’axiome
– SUIVANT(E) ⊆ SUIVANT(E’) car E  TE’donc SUIVANT(E’)={$,)}
– PREMIER(E’)- ε ⊆ SUIVANT(T) car E’+TE’ donc SUIVANT(T)={+,),$}car
SUIVANT(E’) ⊆ SUIVANT(E) (car E’+TE’| ε ) et
SUIVANT(T’)=SUIVANT(T),
– SUIVANT(F)=PREMIER(T’)- ε ∪ SUIVANT(T)

03/02/2013 Khaled Bsaïes 32


khaled.bsaies@fst.rnu.tn
La fonction SUIVANT : Exemple

• Rappelons la grammaire
E→TX X→+E|ε
T → ( E ) | int Y Y→*T|ε
• Les ensembles SUIVANT
SUIVANT ( E ) = {), $}
SUIVANT ( X ) = {$, ) }
SUIVANT ( T ) = {+, ) , $}
SUIVANT ( Y ) = {+, ) , $}

03/02/2013 Khaled Bsaïes 33


khaled.bsaies@fst.rnu.tn
Calcul de SUIVANT
• On ajoute $ à SUIVANT(S) avec S l’axiome
• On construit un graphe entre tous les symboles grammaticaux (terminaux et
non terminaux)
• Flèche de x vers y ssi ou bien
– Il existe z αxβ y est terminal et y ∈ PREMIER(β);
– Il existe y αxβ et β est vide ou annulable.
• Ici, α et β sont quelconques, même vides, et y différent de ε
• SUIVANT(x)={a terminal | il existe un chemin de x à a}
• Exemple de la grammaire précédente :
SUIVANT(T)={+,),$} SUIVANT(T)=SUIVANT(E’) ∪ SUIVANT(E) ∪ {+}
T’ E $
SUIVANT(E)={$,)}
SUIVANT(T’)=SUIVANT(T)
T E’ ) SUIVANT(E’)=SUIVANT(E)
F
* + SUIVANT(F)=SUIVANT(T) ∪ {*}
03/02/2013 Khaled Bsaïes 34
khaled.bsaies@fst.rnu.tn
Construction de la Table d’analyse LL(1) (M)

Construire une Table d’analyse (M) pour G Grammaire


Non Contextuelle
• Pour chaque production A → α dans G faire :
– Pour chaque terminal a ∈ PREMIER(α) faire
M[A, a] = A  α
– Si ε ∈ PREMIER(α), pour chaque a ∈ SUIVANT (A) faire
M[A, a] = A  α
– Si ε ∈ PREMIER(α) et $ ∈ SUIVANT(A) faire
M[A, $] = A  α
• Faire de chaque entrée non définie de M une erreur
03/02/2013 Khaled Bsaïes 35
khaled.bsaies@fst.rnu.tn
Remarques sur les Tables d’analyse LL(1)

(M)
L’algorithme précédent peut être appliqué à une grammaire G pour produire une table
d’analyse M. Cependant cette table peut avoir des entrées qui sont définies de façon
multiple.
• Si une entrée est multiple alors G n’est pas LL(1) et G peut être :
– ambiguë
– récursive à gauche
– factoriser à gauche
– Et d’autres cas …
• Exemple : SiEtSS’|a S’eS| ε Eb. Cette grammaire n’est pas LL(1) car sa table

d’analyse que vous pouvez faire a titre d’exercice est la suivante :


Non- Symbole d’entrée
terminal a b e i t $

S Sa SiEtSS’
S’ S’ ε S’ ε
S’eS
E Eb
03/02/2013 Khaled Bsaïes 36
khaled.bsaies@fst.rnu.tn
Conditions pour qu’une grammaire soit LL(1)
Une grammaire est LL(1) si à chaque fois qu’un non
terminal a plus d’une alternative c’est-à-dire ses règles
de production sont de la forme : A α | β les conditions
suivantes sont vérifiées:
1. Pour tout terminal a, α et β ne se dérivent pas en des
chaînes commençant par a
ou PREMIER(α) ∩PREMIER(β)=ensemble vide
1. Une des chaînes au plus α et β peut se dériver en la
chaîne vide.

2. Si β * ε, α ne se dérive pas en une chaîne


commençant par un terminal de SUIVANT(A).
03/02/2013 Khaled Bsaïes 37
khaled.bsaies@fst.rnu.tn
Récupération sur erreur en analyse prédictive
Une erreur est détectée si M[A,a] de la Table d’analyse est vide, ou bien si
le terminal au sommet de pile ne correspond pas au terminal en lecture.
Récupération en mode panique :
1. Mettre tous les symboles de SUIVANT(A) dans l’ensemble de
synchronisation du non-terminal A. Si nous sautons les unités
lexicales jusqu’à trouver un élément de SUIVANT(A) et si nous
dépilons A, il est possible que l’analyse puisse continuer
2. Ajouter des symboles commençant des constructions de haut niveau
dans les symboles de synchronisation
3. SYN SYN ∪ PREMIER(A)
4. Si un terminal au sommet de pile ne peut pas être reconnu, une idée
simple est de le supprimer et de poursuivre l’analyse.

03/02/2013 Khaled Bsaïes 38


khaled.bsaies@fst.rnu.tn

Vous aimerez peut-être aussi