Académique Documents
Professionnel Documents
Culture Documents
Samir MBARKI
1 Introduction à la compilation
2 Analyse lexicale
3 Analyse syntaxique
4 Analyse sémantique
5 Séries d’exercies
1 Introduction à la compilation
Pourquoi étudier la compilation ?
Définition de Compilateur/Interpréteur
Traitement effectué par un compilateur
Phases d’un compilateur
2 Analyse lexicale
3 Analyse syntaxique
4 Analyse sémantique
5 Séries d’exercies
Définition
Le compilateur est un programme (fonction) qui prend en entrée un
programme écrit dans un langage L1 et produit en sortie un programme
équivalent écrit dans un langage L2.
Définition
L’ interpéteur est un programme (fonction) qui prend en entrée un programme
écrit dans un langage source L1 et produit en sortie le résultat d’exécution de
ce programme.
Exemple
Exercice
Ecrire un programme qui affiche les statistiques d’un fichier texte en comptant
le nombre de mots, d’entiers, de réels et le nombre de caractères de
ponctuation.
S. MBARKI Compilation 2014-2015 9 / 184
Introduction à la compilation
Analyse lexicale
Exemple
Soit l’instruction : Surf := base * hauteur / 2
Exemple
<Identificateur> <Affectation> <Identificateur> <Mult> <Identificateur>
<Divis><Nombre>
Exemple
conversion implicite de type :
2 → 2.0
1 Introduction à la compilation
2 Analyse lexicale
Introduction et spécification
Concepts et outils
L’outil Flex
3 Analyse syntaxique
4 Analyse sémantique
5 Séries d’exercies
L’analyseur lexical (Scanner) fusionne les caractères lus dans le code source
en groupes de mots qui forment logiquement des unités lexicales (tokens) du
langage.
Exemple
Exemple
Symboles (Unités lexicales) :
I Identificateur, Chaine, Constante numérique.
I Mot-clé (IF, WHILE, DO, ...)
I Opérateur (symbole spéciale) : <, >=,<=, ==, =, ...
Analyser les phrases suivantes :
I A+15+B => A, +, 15, B
I test+3148 => test, +, 3148
Question
Comment définir formellement les symboles d’un langage ?
Réponse
Les meilleurs modèles définissant les unités lexicales auxquelles
appartiennent les lexèmes sont les langages réguliers.
Il existe deux façons de décrire les langages réguliers :
I Les expressions régulières
I Les automates finis
Alphabet :
On appelle alphabet Σ un ensemble fini non vide.
Les elements de l’alphabet s’appellent symboles.
Exemple
Σ = {a, b, ..., z}
Σ = {α, β, ..., ϕ, +, ∗, −, /}
Mot :
Un mot est une suite de symboles appartenant à un alphabet Σ.
Exemple
Sur l’alphabet Σ = {0, 1}, on peut construire les mots : 101001, 11, 100.
ε est le mot vide.
La concaténation de deux mots est un mot.
S. MBARKI Compilation 2014-2015 22 / 184
Analyse lexicale
Langage formel
Exemple (suite)
Soit Σ = {0, 1}, si α = 100 et β = 1010 alors αβ = 1001010.
α2 = αα = 100100
α3 = ααα = 100100100
Langage formel :
Un langage sur un alphabet Σ est un ensemble de mots construits sur Σ.
Exemple
Σ∗ est l’ensemble de tous les mots construits sur Σ.
Remarque
Un langage construit sur un alphabet Σ est une partie de Σ∗ .
On distingue deux langages particuliers : ∅, Σ.
Exemple de langages
soit Σ={a, .., z}
L0 = {a}.
L1 = {aa, ab}.
L2 = {αaα/α ∈ Σ∗ } = {a, bab, cdacd, ...}.
L3 = {α ∈ Σ∗ /|α|a <= 10} : l’ensemble de tous les mots dont le nombre
d’occurences de a <= 10.
|.|x ∈Σ : Σ∗ →IN , |.|x calcule le nombre d’occurences de x dans un mot.
L’union.
L2 = {x / x ∈ L1 ou x ∈ L2}
S
I L1
L’intersection.
L2 = {x / x ∈ L1 et x ∈ L2}
T
I L1
La différence.
I L1 - L2 = {x / x ∈ L1 et x ∈
/ L2}
I ¯ =Σ∗ − L1
L1
La concaténation.
I L1L2 = {xy / x ∈ L1 et y ∈ L2}
I Ln = LL.....L
| {z }
n fois
I L1={a, b, c} ; L2={1, 2}
I L1L2={a1, a2, b1, b2, c1, c2}
I L2L1={1a, 1b, 1c, 2a, 2b, 2c}
S. MBARKI Compilation 2014-2015 25 / 184
Analyse lexicale
Fermeture de Kleene
Soit L un langage :
L∗ = K >=0 Lk
S
Exemple
L1={a, b}
L∗1 =L01 L11 L12 L13 ...
S S S S
Définition
Un langage régulier L sur un alphabet Σ est défini récursivement comme suit :
{ε} est un langage régulier sur Σ.
Soit a ∈ Σ alors {a} est un langage régulier sur Σ .
Si R est un langage régulier, alors R k et R ∗ sont des langages réguliers
sur Σ .
S
Si R1 et R2 sont deux langages réguliers alors R1 R2 et R1 R2 sont des
langages réguliers.
Exemple d’ER
Numérique : (0|1|2|...9)
Alphabétique : (a|b|c|...|z|A|...Z)
Opérateur : (<|>|<>|=|<=|>=)
Naturel : Numérique+ ou NumériqueNumérique∗
Entier : (+|-|ε)Naturel
Identificateur : Alphabétique ( Alphabétique|Numérique)∗
Exercice 1
Donner les expressions régulières qui décrivent :
1 Le langage de mots sur Σ={a, b} qui commencent par a est se terminent
par b.
2 Le langage de tous les mots sur {a, b} concaténés avec les mots sur {c, d}.
ab, aab, abb, aaab, abab, abababbab, ε, a, b, c,d,ac,abc, abcd,
ababcdcdc.
Réponse :
a(a|b)∗ b
(a|b)∗ (c |d )∗
Exercice 2
1 Est ce que le mot w appartient au langage décrit par l’ER r dans les cas
suivants :
- w= 10100010 r =(0 + 10)∗
- w= 01110110 r =(0 + (11)∗ )∗
- w= 000111100 r =((011 + 11)∗ (00)∗ )∗
2 Simplifier les ER suivantes :
- ε + ab + ab + abab(ab)∗
- aa(b∗ + a) + a(ab∗ + aa)
-a(a + b)∗ + aa(a + b)∗ + aaa(a + b)∗
Réponses
ε + ab + abab(ab)∗
= ε + ab + ab(ab)∗
= ε + ab(ε + (ab)∗ )
= ε + ab(ab)∗
= ε + (ab)∗
= (ab)∗
aa(b∗ + a)+ a(ab∗ + aa)
= aa(b∗ + a)+ aa(b∗ + a)
= aa(b∗ + a)
a(a + b)∗ + aa(a + b)∗ + aaa(a + b)∗
= (a + aa + aaa)(a + b)∗
Exercice 3
1 Montrer les égalités suivantes :
- b + ab∗ + aa∗ b+ aa∗ ab∗ = a∗ (b + ab∗ )
- a∗ (b + ab∗ ) = b + aa∗ b∗
2 Donner une expression r du langage formé sur {a,b} ayant au plus 3a.
Réponses
1 Vérification
- b + ab∗ + aa∗ b+ aa∗ ab∗ = a∗ (b + ab∗ )
=> (b + ab∗ ) + a+ (b + ab∗ )
=(ε + a+ )(b + ab∗ )= a∗ (b + ab∗ )
- a∗ (b + ab∗ )
= a∗ b + a∗ ab∗
= (ε + a + ) + a + b ∗
= b + a+ b + a+ b ∗
= b + a+ (b+b∗ )
= b + a+ b ∗
= b + aa∗ b
2 b∗ (a + ε)b∗ (a + ε)b∗ (a + ε)b∗
Automate :
Etat initiale e0 : bouton bloqué
Etat e1 : quand on insère 1DH
Etat e2 : quand on insère 2DH
Etat e3 : bouton C se libère
→ : état initial
: état final
Un automate lit un mot écrit sur son ruban d’entrée. Il part d’un état initial et à
chaque lettre lue, il change d’état. Si à la fin du mot, il est dans un état final, on
dit qu’il accepte le mot.
Définition
Un AFD A est définit comme un 5-uplet A=<Q, Σ, δ, q0 , F> : Q est l’ensemble
des états, Σ est un alphabet, δ : Q×Σ →Q est la fonction de transition, q0 est
l’état initial (q0 ∈ Q), F est l’ensemble des états finaux (F ⊆ Q) .
Les automates peuvent être représentés par des graphes où les états sont les
noeuds et les arcs représentent la fonction de transition.
S. MBARKI Compilation 2014-2015 37 / 184
Analyse lexicale
Automate fini déterministe
Si δ (q0 , a)=q1 ⇒
Exercice
Représenter graphiquement l’automate suivant :
A=<Q, Σ, δ, q0 , F> avec Σ={0, 1} et Q={q0 , q1 } q0 est l’état initial et F={q1 }
Définition
Un AFN A=<Q, Σ, δ, q0 , F>, se caractérise par :
δ : QX (Σ {ε})− > P (Q )
S
Exemple
Représenter graphiquement l’AFN suivant :
A=<Q, Σ, δ, q0 , F> avec Σ={0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, +, -, .} et
Q={q0 , q1 , q2 , q3 , q4 , q5 } q0 est l’état initial et F={q5 }
Exemple
Transformer en AFD l’automate suivant :
ΣD = { 0,1} ; qD0 = {q0 }
S
δD ({q0 ,q2 }, 1) =δN (q0 , 1) δN (q2 , 1)
S
={q0 } ∅
Remarque
Si Q’ ⊂ Q : ε-fermeture(Q’) =
S
q ∈Q 0 ε-fermeture(q)
ε-fermeture d’un état q est l’ensemble de tous les états accessibles à
partir de q par des ε- transitions.
Exemple de ε-fermeture
Algorithme de transformation
Soit AE = <QE , ΣE , δE ,qE0 , FE > un ε-AFN, il existe un AFD AD = <QD , ΣD ,
δD ,qD0 , FD > tel que L(AE )= L(AD ) avec :
QD ⊆ ε-fermeture(P(QE ))
Σ D =Σ E
qD0 = ε-fermeture( qE0 )
FD = {qD ∈ QD tq : qD FE 6= ∅}
T
Soit qD ∈ QD et a∈ ΣD alors :
S
δD (qD , a)= ε-fermeture( qE ∈qD δE (qE , a))
Exemple de transformation
Donnée :
un automate déterministe
Résultat :
L’automate minimal reconnaissant le même langage que l’automate initial
Principe général :
l’algorithme calcule les classes d’équivalences.
Après examen de tous les symboles, un bilan est fait : il consiste à
attribuer un numéro (en chiffre romain) à chaque classe d’équivalence.
Algorithme
Construire un tableau dont les colonnes sont les différents états de
l’automate de départ.
La première ligne de bilan s’obtient en séparant (par ε) les états finaux et
les autres en deux classes.
I Numéroter I l’état de la première colonne ;
I Numéroter I ou II les états des autres colonnes de manière à séparer les
états finaux des autres états.
Les lignes suivantes du tableau sont construites une par une en
regardant, pour chaque état, dans quel état mène la transition par un
symbole de l’alphabet et en notant la classe à laquelle appartient cet état
dans la ligne bilan précédente.
Exemple
Exemple
Théorème
Un langage est régulier si et seulement s’il est généré par un automate fini.
Exemple
Soit l’expression régulière (a + b)∗ ab, l’automate associé est :
Méthode de Kleene :
Soit A= <Σ, Q , q0 , F , δ> un automate fini non déterministe ne contenant pas
d’ε-transitions.
Pour tout état q , notons Xq l’ensemble des mots menant de l’état q à un
état final.
Chaque langage Xq satisfait l’équation linéaire
Xq = Σoù q 0 =δ(q ,a) aXq 0 [+ε si q ∈ F ]
Pour obtenir une expression régulière du langage, il suffit de résoudre le
système des équations linéaires ci-dessus par élimination de variables
Toutes les équations qu’on manipule peuvent être mises sous la forme
Xq = KXq + L où K et L sont des expressions linéaires des variables Xq 0 ,
q’ 6= q ;
Lemme d’Arden
Soient X, K et L des langages sur un alphabet Σ. On suppose que ε∈
/ K. Alors
S
X=KX L si et seulement si X=K L ∗
Exemple
Soit L le langage reconnu par l’automate suivant :
Le
système d’équations linéaires associé à cet automate est :
X1 = bX1 + (a + b)X2 (1)
X2 = aX3 + ε (2)
X3 = (a + b)X2 + ε (3)
Les méta-symboles :
I Les symboles suivants ont une signification précise pour Flex :
• " \ [ ] ∧ -? . * + | ( ) $ / { } % < >
I Pour introduire un de ces symboles dans un motif comme caractère du
texte, il faut soit le précéder par un caractère \, soit l’encadrer de ".
I On utilise la notation du C : "\n" pour le retour à la ligne et "\t" pour le
caractère tabulation.
Définitions des méta-symboles :
I [xyz] : correspond à un seul caractère parmi ceux indiqués.
Les opérateurs :
I ∧ : placé en début du motif, indique que le motif doit se trouver en début de
ligne.
• Exemple : [∧a] signifie que la ligne doit commencer par a.
I $ : placé en fin du motif, indique que le motif doit se trouver en fin de ligne.
• Exemple : [a$] signifie que la ligne doit se terminer par a.
L’action par défaut de tout programme Flex est de recopier tous les
caractères qui ne correspondent à aucun motif dans le fichier de
description.
D’autres actions prédéfinies peuvent être utilisés dans les actions :
I ; : sert à ne pas recopier les caractères non reconnus.
I ECHO ; : sert à recopier les caractères reconnus.
I | : sert à reporter l’action sur la règle suivante. Elle signifie la même chose
que l’action pour la règle suivante.
exemple
Un programme Flex qui élimine tous les caractères blancs (sauf \n) et
imprime les chiffres et les lettres majuscules.
%%
[0-9] | [A-Z] |
\n ECHO ; . ;
S. MBARKI Compilation 2014-2015 73 / 184
Analyse lexicale
Variables globales et sous-programmes
Deux règles sont ambiguës si elles peuvent être déclenchées avec une
même entrée.
Flex utilise une résolution d’ambiguïté qui est la suivante :
I La règle qui correspond à la plus longue entrée est appliquée en priorité.
I Si deux règles ambiguës correspondent à la même entrée, la première
définie est appliquée en priorité.
exemple
%%
algo printf("mot clé") ;
[a-z]+ printf("identificateur") ;
La chaîne algorithme est reconnue comme identificateur.
1 Introduction à la compilation
2 Analyse lexicale
3 Analyse syntaxique
Introduction
Définition de grammaire formelle
Vocabulaire et notation
Analyse descendante
Analyse ascendante
L’outil Bison
4 Analyse sémantique
5 Séries d’exercies
Exemple
Définir une ER qui décrit le langage suivant :
L={an bn /n > 0}
Propositions :
(ab)∗ => contient ε
aa∗ bb∗ <=> a+ b+ => le nombre de a n’est pas nécesserement égale au
nombre de b.
(ab)+ => contient abab
a∗ b∗ => contient ε
=> Le langage L n’est pas régulier. Il n’y a pas d’ER qui décrit le langage L.
ST : a,b SN : S Axiome : S
Règle de production : S -> ab ; S->aSb
Vérification pour aaaabbbb appartient au langage.
S. MBARKI Compilation 2014-2015 78 / 184
Analyse syntaxique
Phase d’analyse d’un compilateur
Exemple
Soit la grammaire suivante :
ST : a,b,c,d,+,-,*,/,(,),ˆ
SN : E,T,F
Axiome : E
Règles de production :
E → T |T + E |T − E expression
T → F |F ∗ T |F /T terme
F → a|b|c |d |(E )|F ˆF facteur
Vérifier si le mot a+d*cˆa appartient au langage ?
=> R1 : E → T R2 : E → T + E R3 : E → T − E
R4 : T → F R5 : T → F ∗ T R6 : T → F /T
R7 : F → a R8 : F → b R9 : F → c
R10 : F → d R11 : F → (E ) R12 : F → F ˆF
Définition
Une grammaire G est définie par : G=(Vt , Vn , P , S) avec :
Vt : Ensemble des symboles terminaux (Unités lexicales)
Vn : Ensemble des symboles non terminaux
P : Ensemble des règles de production
S : Axiome
Remarque :
T
Vn Vt = ∅
S ∈ Vn
Exemple de grammaire
Soit la grammaire G=(Vt , Vn , P , S) avec :
Vt ={a,b}
Vn ={A,B}
P={A→a , A→aB , B→b , B→bB}
Exemple
Définir la règle gramaticale dont la partie gauche est aAb.
α = aAb
Trouver β ∈ (Vt Vn )∗ tel que :
S
α⇒β
aAb ⇒ aaBbAb
Donc : β = aaBbAb
Dérivation-Réduction :
Soit λ ∈ (Vt Vn )∗ contenant plusieurs occurences de α.
S
λ = ..α...α...α...α...
Dérivation immédiate :
Consiste à fabriquer la chaine λ’ à partir de λ , en utilisant α ⇒ β , en
remplaçant une occurence de α par β dans λ
Réduction immédiate :
0
Est l’opération réciproque. Elle consiste à fabriquer la chaine λ à partir de λ en
0
utilisant la règle α ⇒ β , en remplaçant une occurence de β par α dans λ .
Dérivation multiple :
0
Consiste à fabriquer la chaine λ à partir de λ en utilisant α ⇒ β , en
remplaçant successivement plusieurs occurences de α par β dans λ .
S. MBARKI Compilation 2014-2015 86 / 184
Analyse syntaxique
Dérivation-Réduction
Réduction multiple :
0
Est l’opération réciproque. Elle consiste à fabriquer la chaine λ à partir λ , en
utilisant α ⇒ β , en remplaçant successivement plusieurs occurences de β par
α
Exemple
Soit la règle A → bAb , et λ = aAa
1 abAba est une dérivation immédiate de aAa.
2 abbbbAbbbba est une dérivation multiple de aAa
aAa ⇒ abAba ⇒ abbAbba ⇒ abbbAbbba ⇒ abbbbAbbbba
note L(α) le langage engendré par α . L(α) est l’ensemble de toutes les
chaines terminales β qui sont des dérivations de α.
L(α) = {β ∈ Vt∗ /∃α ⇒∗ β}
L(G) = est le langage engendré par la grammaire G.
L(G) est l’ensemble de toutes les chaînes terminales β qui sont des
dérivations de S.
L(G) = L(S) = {β ∈ Vt∗ /∃S ⇒∗ β}
Arbre de dérivation :
Soit G=(Vt , Vn , P , S).
Soit α ∈ Vt∗ (chaine terminale). On appelle l’arbre dérivation de α une
representation graphique de S ⇒∗ α tel que :
S est le sommet de l’arbre.
Vn ) ∗ .
S
Chaque noeud de l’arbre est un element de (Vt
Les feuilles de l’arbre forment α en les parcourant de la gauche vers la
doite et du haut vers le bas.
Le passage d’un noeud de niveau i vers un noeud de niveau j se fait par
application d’une règle grammaticale.
Grammaire ambigüe :
Définition
Une grammaire est ambigüe si et seulement s’il existe une chaîne qui admet
plusieurs arbres de dérivation.
Exemple
Expressions
arithmétique
Exp → (Exp)
Exp → Exp + Exp
Exp → Exp − Exp
Exp → Exp ∗ Exp
Exp → num
Exp → idf
Arbres de dérivation
Élimination d’ambigüité
1 Choix
des proirotés : L’opérateur * est prioritaire sur + et - .
Exp → Terme
Terme → Terme ∗ Terme|Facteur
Facteur → idf |num|(Exp)
2 Choix d’associativités : On décide que les opérateurs sont associatifs à
gauche.
Exp → Exp + Terme|Exp − Terme|Terme
Terme → Terme ∗ Facteur |Facteur
Facteur → idf |num|(Exp)
Principe
Exemple
S → aSbT | cT | d
T → aT | bS | c
On prend le mot w=accbbadbc
On commence par un arbre contenant juste le sommet S
On traite la première lettre a du mot w.
Avec S → aSbT
Exemple (suite)
Ensuite S → cT
Solution
I Avoir une table d’analyse qui indique pour chaque symbole non-terminal
A et terminal a la règle de production à appliquer.
Pour construire une table d’analyse, on a besoin des ensembles
PREMIER et SUIVANT.
Exemple
S→Ba
B→cP|bP|P|ε
P→dS
S⇒*a donc a∈PREMIER(S)
S⇒*cPa donc c∈PREMIER(S)
S⇒*bPa donc b∈PREMIER(S)
S⇒*dSa donc d∈PREMIER(S)
Pas de dérivation S⇒*ε
Donc PREMIER(S)={a,b,c,d}
Algorithme
1 Si X est un non-terminal et X→Y1 Y2 ...Yn est une production de la
grammaire (avec Yi symbole terminal ou non-terminal) alors
I ajouter les éléments de PREMIER(Y ) sauf ε dans PREMIER(X)
1
I s’il existe j (j∈ {2, ..., n}) tel que pour tout i=1, ..., j-1 on a ε ∈ ( Premier(Y ),
i
alors ajouter les éléments de PREMIER(Yj ) sauf ε dans PREMIER(X).
I si pour tout i=1, ..., n ; ε ∈ PREMIER(Y ), alors ajouter ε dans PREMIER(X)
i
2 Si X est un non terminal et X→ε est une production, ajouter ε dans
PREMIER(X)
3 Si X est un terminal, PREMIER(X) = {X}.
4 Recommencer jusqu’à ce qu’on n’ajoute rien de nouveau dans les
ensembles PREMIER.
Exemple 1
→ TE’
E
→
E’ +TE’|ε
T → FT’
T’ → *FT’|ε
→
F (E)|nb
PREMIER(E) = PREMIER(T) = {(,nb}
PREMIER(E’) = {+,ε}
PREMIER(T) = PREMIER(F) = {(,nb}
PREMIER(T’) = {*,ε}
PREMIER(F) = {(,nb}
Exemple 2
S → ABC
A → aA|ε
B → bB|cB|ε
→
C dc|da|dA
PREMIER(S) = {a,b,c,d}
PREMIER(A) = {a, ε}
PREMIER(B) = PREMIER(F) = {b,c,ε}
PREMIER(C) = {d}
Exemple
S→Sc|Ba
B→Pa|bPb|P|ε
P→dS
a, b, c ∈ SUIVANT(S) car il y a les dérivations S⇒*Sc, S⇒*dSa et
S⇒*bdSba..
Algorithme
1 Ajouter un marqueur de fin de chaîne (symbole $ par exemple) à
SUIVANT(S) (où S est le symbole de départ de la grammaire)
2 S’il y a une production A → α Bβ où B est un non terminal, alors ajouter
le contenu de PREMIER(β) à SUIVANT(B), sauf ε
3 S’il y a une production A→ α B, alors ajouter SUIVANT(A) à SUIVANT(B)
4 S’il y a une production A → α Bβ avec ε∈ PREMIER(β), alors ajouter
SUIVANT(A) à SUIVANT(B)
5 Recommencer à partir de l’étape 3 jusqu’à ce qu’on n’ajoute rien de
nouveau dans les ensembles SUIVANT.
Exemple 1
E→TE’
E’→+TE’|ε
T→FT’
T’→*FT’|ε
→
F (E)|nb
SUIVANT(E) = {$,)}
SUIVANT(E’) = {$,)}
SUIVANT(T) = {+,),$}
SUIVANT(T’) = {+,),$}
SUIVANT(F) = {+,),*,$}
Exemple 2
S→aSb|cd|SAe
A→aAdB|ε
→
B bb
PREMIER(S) ={a,c} SUIVANT(S) ={$,b,a,e}
PREMIER(A) ={ a,ε} SUIVANT(A) ={ e,d}
PREMIER(B) = {b} SUIVANT(B) = {e,d}
Une table d’analyse est un tableau M à deux dimensions qui indique pour
chaque symbole non terminal A et chaque symbole terminal a ou symbole
$ la règle de production à appliquer.
Algorithme
Pour chaque production A→α faire
1 pour tout a∈PREMIER(α) (et a6=α), rajouter la production A→α dans la case
M[A,a]
2 si ε∈PREMIER(α), alors pour chaque b∈SUIVANT(A) ajouter A→α dans M[A,b]
Exemple
Avec
la grammaire de l’exemple1 :
E→TE’
E’→+TE’|ε
T→FT’
T’→*FT’|ε
→
F (E)|nb
La table d’analyse produite est :
nb + * ( ) $
E E →TE’ E → TE’
E’ E’→+TE’ E’→ε E’→ε
T T →FT’ T →FT’
T’ T’→ ε T’→*FT’ T’→ ε T’→ ε
F F→nb F→(E)
On utilise la table d’analyse pour déterminer si un mot m donné est tel que
S⇒*m.
On utilise une pile et l’algorithme suivant :
Algorithme
Données : mot m, table d’analyse M.
Initialisation de la pile :
[$S ]
On ajoute un pointeur ps sur la 1ère lettre de m
repeter
Soit X le symbole en sommet de pile
Soit a la lettre pointée par ps
Sinon
Si X=a alors
enlever X de la pile
avancer ps
Sinon
ERREUR
finsi
finsi
finsi
jusqu’à ERREUR ou ACCEPTER
Exemple
Considérons la grammaire E,E’,T,T’,F et le mot m=3+4*5
Exemple (suite)
Pile Entrée Sortie
$E’T’ *5$ T 0 → ∗FT 0
$E’T’F* *5$
$E’T’F 5$ F → nb
$E’T’5 5$
$E’T’ $ T0 → ε
$E’ $ E0 → ε
$ $ Analyse réussie
Définition
On appelle grammaire LL(1) une grammaire pour laquelle la table d’ana-
lyse décrite précédemment n’a aucune case définie de façon multiple.
Le terme "LL(1)" a la signification suivante :
I le premier L indique qu’on parcourt l’entrée de gauche à droite (Left to right
scanning).
I le second L indique qu’on utilise les dérivations à gauche (Leftmost
derivation).
I le 1 indique qu’un seul symbole de prévision est nécessaire à chaque étape
nécessitant la prise d’une décision d’action d’analyse.
Exemple
S → aAb
A → cd|c
Nous avons PREMIER(S)={a}, PREMIER(A)={c }, SUIVANT(S)={$} et
SUIVANT(A)={b}
a c b d $
La table d’analyse associée : S S → aAb
A → cd
A
A→c
Exemple
S → ScA | B
A → Aa | ε
→
B Bb | d|e
=> beaucoup de récursivités à gauche immédiates
Exemple
S→BS’
→
S’ cAS’|ε
A→A’
A→aA’|ε
B→dB’|eB’
→
B’ bB’| ε
Cette grammaire reconnaît le même langage que la première.
Exemple
S → Aa | b
A → Ac | Sd | ε
S est récursif à gauche car S⇒Aa⇒Sda
Exemple 1
Dans l’exemple précédent :
Ordonner S,A
i=1 pas de récursivité immédiate dans S→Aa | b
i=2 et j=1 on obtient A→Ac | Aad | bd |ε
on élimine la recursivité immédiate :
A→bdA’ | A’
A’→cA’ | adA’ |ε
on
a obtenu la grammaire
S → Aa | b
A → bdA’ | A’
→
A’ cA’ | adA’ |ε
Exemple 2
Avec
la grammaire suivante :
S→Sa| TSc|d
T→TbT|ε
On
obtient la grammaire :
S→TScS’|dS’
→
S’ aS’|ε
T→T’
→
T’ bTT’|ε
Or on a S⇒TScS’ ⇒ T’ScS’ ⇒ ScS’
=> une récursivité à gauche
l’algorithme ne marche pas toujours lorsque la grammaire possède une
règle A→ε
S→bacdAbd ou S→bacdBcca,
=> il faut lire la 5ième lettre du mot (a ou c).
Impossible de savoir dès le départ quelle production prendre.
Algorithme
Factorisation à gauche :
Pour chaque non terminal A
trouver le plus long préfixe α commun à deux de ses alternatives ou plus
Si α 6= ε, remplacer A→αβ1 |..|αβn |γ1 |..|γp (où les γi ne commencent pas
par α ) par les deux règles
A→αA’|γ1 |..|γp et A’→β1 |..|βn
fin pour
Recommencer jusqu’à ne plus en trouver.
Exemple
S→aEbS| aEbSeB|a
E→bcB|bca
B→ba
Factorisée
à gauche, cette grammaire devient :
S →aEbSS’|a
S’→eB|ε
E→bcE’
E’→B|a
→
B ba
Exemple
On considère la grammaire :
E→E+E|E*E|(E)
Elle est ambiguë.
1 Lever l’ambiguïté (on considère les priorités classiques des opérateurs) :
E→E+T|T T→T*F|T F→(E)
2 Supprimer la récursivité à gauche :
E→TE’ E’→+TE’|ε T→FT’
T’→*FT’|ε F→(E)|nb
Principe
Exemple
S→aSbS|c avec le mot u=aaacbaacbcbcbcbacbc
aaacbaacbcbcbcbacbc on ne peut rien réduire, donc on décale
aaacbaacbcbcbcbacbc on ne peut rien réduire, donc on décale
aaacbaacbcbcbcbacbc on ne peut rien réduire, donc on décale
aaacbaacbcbcbcbacbc On peut réduire par S→c
aaaSbaacbcbcbcbacbc on ne peut rien réduire, donc on décale
aaaSbaacbcbcbcbacbc on ne peut rien réduire, donc on décale
................ ................
aaaSbaacbcbcbcbacbc On peut réduire par S→c
aaaSbaaSbcbcbcbacbc on ne peut rien réduire, donc on décale
aaaSbaaSbcbcbcbacbc on ne peut rien réduire, donc on décale
aaaSbaaSbcbcbcbacbc On peut réduire par S→c
aaaSbaaSbSbcbcbacbc On peut réduire par S→aSbS
Exemple (Suite)
aaaSbaSbcbcbacbc on ne peut rien réduire, donc on décale
aaaSbaSbcbcbacbc on ne peut rien réduire, donc on décale
aaaSbaSbcbcbacbc On peut réduire par S→c
aaaSbaSbSbcbacbc On peut réduire par S→aSbS
aaaSbSbcbacbc On peut réduire par S→aSbS
aaSbcbacbc on ne peut rien réduire, donc on décale
aaSbcbacbc on ne peut rien réduire, donc on décale
aaSbcbacbc On peut réduire par S→c
aaSbSbacbc On peut réduire par S→aSbS
aSbacbc on ne peut rien réduire, donc on décale
aSbacbc on ne peut rien réduire, donc on décale
aSbacbc on ne peut rien réduire, donc on décale
aSbacbc On peut réduire par S→c
Exemple (Suite)
aSbaSbc on ne peut rien réduire, donc on décale
aSbaSbc on ne peut rien réduire, donc on décale
aSbaSbc On peut réduire par S→c
aSbaSbS On peut réduire par S→aSbS
aSbS On peut réduire par S→aSbS
S C’est terminé ! ! !
Le mot aaacbaacbcbcbcbacbc est bien dans le langage
Solution
Si Etat=i et Symbole courant = a alors :
I dj : décaler (empiler a et passer à l’état j)
I rp : réduire par la règle p (remplacer la chaine en sommet de pile par la
partie gauche de la règle et passer à l’état qui dépend du non terminal)
I ACC : On accepte le mot
I : Erreur de syntaxe
Pour construire la table d’analyse, on utilise :
I Ensembles SUIVANT
I Fermeture de 0-items (items)
Exemples d’items :
I E→E•+T
I F→(E•)
Calcul de Fermeture(I) :
1 Ajouter les items de I dans Fermeture(I)
2 Si I contient A→α•Bβ alors pour chaque B→λi ajouter : B→•λi dans
Fermeture(I)
3 Recommencer 2) tant que Fermeture(I) n’est pas stable
Exemple
On considère la grammaire suivante :
(1)E → E+T (3)T → T*F (5)F → (E)
→
(2)E T (4)T → F (6)F → nb
Fermeture({ T→T*•F , E→E•+T} ) =
{
T→T*•F, E→E•+T,
F→•(E), F→•nb
}
S. MBARKI Compilation 2014-2015 132 / 184
Analyse syntaxique
Transition d’un ensemble d’items par un symbole
Exemple
On considère la grammaire suivante :
(1)E → E+T (3)T → T*F (5)F → (E)
(2)E → T (4)T → F (6)F → nb
I={T→T*•F, E→E•+T, F→•(E), F→•nb}
∆(I, F) = {T→T*F•}
∆(I, nb) = {F→nb•}
∆(I, +) = {E→E+•T, T→•T*F, T→•F, F→•(E), F→•nb}
∆(I, ( ) = {F→(•E), E→E+T, E→T, T→•T*F, T→•F, F→•(E), F→•nb}
Algorithme
1 Ajouter la règle S’→S. I0 = Fermeture({S’→•S})
2 Mettre I0 dans Collection
3 Pour chaque I dans Collection :
Pour chaque X / ∆(I, X)6= ∅ :
ajouter ∆(I, X) dans Collection
Fin pour
Fin pour
4 Recommencer 3. tant que la collection n’est pas stable
Exemple
On considère la grammaire suivante :
(1)E → E+T (3)T → T*F (5)F → (E)
(2)E → T (4)T → F (6)F → nb
I0 ={E’→•E, E→ •E+T, E→ •T, T→•T*F, T→•F, F→•(E), F→•nb}
I1 =∆(I0 , E) = {E’→E•, E→ E•+T}
→ M[1,$]=ACC
I2 =∆(I0 , T) ={E→ T•, T→T•*F}
→ M[2,$]=r2 , M[2,+]=r2 , M[2,)]=r2
I3 =∆(I0 , F) = {T→F•}
→ M[3,$]=r4 , M[3,+]=r4 M[3,*]=r4 , M[3,)]=r4
I4 =∆(I0 , ( ) ={F→(•E), E→ •E+T, E→ •T, T→•T*F, T→•F, F→•(E),
F→•nb}
Exemple (Suite)
I5 =∆(I0 , nb) = {F→nb•}
→ M[5,$]=r6 , M[5,+]=r6 , M[5,*]=r6 , M[5,)]=r6
I6 =∆(I1 , +) ={E→ E+•T, T→•T*F, T→•F, F→•(E), F→•nb}
I7 =∆(I1 , *) ={T→T*•F, F→•(E), F→•nb}
I8 =∆(I4 , E) ={F→(E•), E→ E•+T}
I2 =∆(I4 , T) = {E→ T•, T→T•*F}
I3 =∆(I4 , F) ={T→F•}
I4 =∆(I4 , ( ) = {F→(•E), E→ •E+T, E→ •T, T→•T*F, T→•F, F→•(E),
F→•nb}
I5 =∆(I4 , nb) = {F→nb•}
I9 =∆(I6 , T) ={E→ E+T•, T→T•*F}
→ M[9,$]=r1 , M[9,+]=r1 , M[9, ) ]=r1
S. MBARKI Compilation 2014-2015 137 / 184
Analyse syntaxique
Construction de la table d’analyse SLR
Exemple (Suite)
I3 =∆(I6 , F) ={T→F•}
I4 =∆(I6 , ( ) = {F→(•E), E→ •E+T, E→ •T, T→•T*F, T→•F, F→•(E),
F→•nb}
I5 =∆(I6 , nb) = {F→nb•}
I5 =∆(I4 , nb) = {F→nb•}
I9 =∆(I6 , T) ={E→ E+T•}
→ M[9,$]=r1 , M[9,+]=r1 , M[9,+]=r1
Exemple 1
L’analyse du mot m=3+*48 est donnée dans la figure suivante :
Exemple 1 (Suite)
Pile Entrée Action
$0 3+*48 d5
$035 +*48 r5 : F→nb
$0F +*48 Je suis en 0 avec F je vais en 3
$0F3 +*48 r4 : T→F
$0T +*48 Je suis en 0 avec T je vais en 2
$0T2 +*48 r2 : E→T
$0E +*48 Je suis en 0 avec E je vais en 1
$0E1 +*48 d6
$0E1+6 *48 ERREUR ! !ce mot n’est pas dans le langage
Exemple 2
La figure suivante donne la table d’analyse SLR.
Exemple 2 (Suite)
La figure suivante donne l’analyse du mot 3+4*2.
Pile Entrée Action
$0 3+4*2$ d5
$035 +4*2$ r6 :F→nb
$0F +4*2$ Je suis en 0 avec F je vais en 3
$0F3 +4*2$ r4 :T→F
$0T +4*2$ Je suis en 0 avec T je vais en 2
$0T2 +4*2$ r2 :E→T
$0E +4*2$ Je suis en 0 avec E je vais en 1
$0E1 +4*2$ d6
$0E1+6 4*2$ d5
$0E1+645 *2$ r6 :F→nb
$0E1+6F *2$ Je suis en 6 avec F je vais en 3
Exemple 2 (Suite)
La figure suivante donne l’analyse du mot 3+4*2.
Pile Entrée Action
$0E1+6F3 *2$ r4 :T→F
$0E1+6T *2$ Je suis en 6 avec T je vais en 9
$0E1+6T9 *2$ d7
$0E1+6T9*7 2$ d5
$0E1+6T9*725 $ r6 :F→nb
$0E1+6T9*7F $ Je suis en 7 avec F je vais en 10
$0E1+6T9*7F10 $ r3 :T→T*F
$0E1+6T $ Je suis en 6 avec T je vais en 9
$0E1+6T9 $ r1 :E→E+T
$0E $ Je suis en 0 avec E je vais en 1
$0E1 $ ACCEPTE ! ! !
Remarques
La méthode ascendante analyse plus de grammaires que la méthode
descendante.
plus de grammaires SLR que LL
Aucune importance que la grammaire soit récursive à gauche.
Les grammaires ambiguës provoquent des conflits
I conflit décalage/réduction :laquelle choisir ?
I conflit réduction/réduction :
lire le terminal a
réduire S→α ou T→β
Introduction à Bison :
Langage Bison :
Il permet de définir des grammaires hors contexte.
Il utilise des variables, des terminaux et des règles de production.
Il permet aussi de définir l’axiome, gérer les priorités des opérateurs, etc.
Le dossier d’installation de Gnu Bison ne doit pas contenir d’espaces. Il
est préférable que Flex et Bison soient installés dans le même dossier.
Après l’installation de Gnu Bison, Copier la bibliothèque "liby.a" dans le
dossier lib de DevCpp.
Programme Bison :
Constitué d’un ensemble de définitions écrites en utilisant le langage de
Bison.
Enregistré dans un fichier avec l’extension ".y".
Compilateur Bison :
Génère un analyseur syntaxique à partir de la grammaire Bison.
Appel du compilateur : par la commande " bison d xxx.y".
Le résultat de la compilation est un fichier C nommé " xxx.tab.c" contenant
le code C de l’analyseur syntaxique.
Compilation de l’analyseur :
Par la commande " gcc" et en utilisant l’option " -ly" qui inclut la librairie
relative à bison.
Collaboration Flex/Bison
Section de déclarations
Commence par " %{" et se termine par " %}" (en début de ligne). Elle
contient :
I Des déclarations et définitions en C.
I Des inclusions de fichiers ".h ".
Cette section est copiée tel quel au début du fichier " xxx.tab.c ".
Ces déclarations et ces définitions sont globales.
Les déclarations et les définitions peuvent être utilisées dans les sections
suivantes.
Une variable globale est fournie :
I yylval : l’analyseur lexical y stocke les attributs de l’unité lexicale reconnue,
alors que l’analyseur syntaxique y récupère ces attributs.
I yyval : l’analyseur syntaxique y stocke les attributs du symbole non
terminal courant (locale dans yyparse()).
I Sont de même type : YYSTYPE (int par défaut)
Exemple de déclarations
Soit la grammaire G définie par :
I V = {E, T, F} ;
I T = {nb, +, *} ;
I S = E ; (Axiome)
Les règles de production sont :
I E → E + T
I E → T
I T → T * F
I T → F
I F → nb
I F → (E)
Exemple (Suite)
Considérons que l’attribut d’un non terminal est un entier, alors on doit
déclarer :
%{
#include "lex.yy.c"
extern FILE *yyin ;
int res ;
%}
%union {
int * ptr_nbr ;
int nbr ;
}
Exemple (Suite)
Les terminaux peuvent être déclarés par :
%token <ptr_nbr> NBENT
%token OPADD
%token OPMUL
%token PAROUV
%token PARFER
Les non terminaux peuvent être déclarés par :
%type <nbr> E
%type <nbr> T
%type <nbr> F
La précédence des opérateurs est (+ est moins prioritaire que *) :
%left OPADD
%left OPMUL
L’axiome est défini par : %start E
S. MBARKI Compilation 2014-2015 154 / 184
Analyse syntaxique
Section des règles de production
La partie " action_i " permet, par exemple, de manipuler (lire, écrire, ...)
les attributs des terminaux et non terminaux, comme suit :
I Soit la règle A : U U ...U {actions} où :
1 2 n
• A : est un symbole non terminal.
• Ui : est un symbole terminal ou non terminal.
I Dans {actions}, on peut utiliser les variables suivantes :
Exemple
%{#include "pars.tab.h" %}
BLANC [ \t\n]
NBRE [0-9]+
%%
{BLANC} ;
"+" { return OPADD ; }
"*" { return OPMUL ; }
"(" { return PAROUV ; }
")" { return PARFER ; }
{NBRE} {yylval.ptr_nbre=(int*)
valeur(yytext) ;return NBENT ; }
%%
int* valeur(char * t)
{ // corps de la fonction }
S. MBARKI Compilation 2014-2015 160 / 184
Analyse syntaxique
Exemple de code auxiliaire
Exemple
%%
main( ) {
yyin = fopen("test.exp", "r") ;
if(yyparse() == 0)
printf("La syntaxe est correcte\n") ;
else
printf("Erreur de syntaxe\n") ;
}
1 Introduction à la compilation
2 Analyse lexicale
3 Analyse syntaxique
4 Analyse sémantique
Rôle de l’analyse sémantique
Cas de la portée des identificateurs
Traduction dirigée par la syntaxe
Attributs synthétisés et hérités
Grammaire S-attribuée et grammaire L-attribuée
Graphe de dépendance
5 Séries d’exercies
Exemple de propriétés :
I Ne pas utiliser une variable non déclarée.
I Ne pas déclarer deux fois une même variable dans le même bloc.
I Dans un appel de fonction, le nombre de paramètres formels doit
correspondre au nombre de paramètres effectifs, et leurs types doivent être
compatibles.
I Ne pas multiplier un réel avec une chaîne, etc.
Le rôle de l’analyseur sémantique est de vérifier ces contraintes (analyse
contextuelle).
S’effectue en même temps que l’analyse syntaxique en définissant des
action sémantiques dans les règles de production (Traduction dirigée
par la syntaxe).
Il n’y a pas de méthode universelle pour faire une analyse
sémantique, car les propriétés ne sont pas unifiées.
Définition
On appelle DDS, la donnée d’une grammaire et de son ensemble de
règles sémantiques.
On notera X.a l’attribut a du symbole X. S’il y a plusieurs symboles X dans
une production, on les notera X (1) , ...X (n) et X (0) s’il est dans la partie
gauche.
S. MBARKI Compilation 2014-2015 170 / 184
Analyse sémantique
Traduction dirigée par la syntaxe
Exemple 1
Soit la grammaire :
num → num chiffre|chiffre
chiffre → 0|1|2|3|4|5|6|7|8|9
Attributs : val
Attributs hérités :
I Un attribut est dit hérité lorsqu’il est calculé à partir des attributs du non
terminal de la partie gauche, et éventuellement des attributs d’autres non
terminaux de la partie droite.
I Sur l’arbre décoré : la valeur d’un attribut à un nœud se calcule en fonction
des attributs des frères et du père.
I Si les attributs d’un nœud donné ne dépendent pas des attributs de ses
frères droits, alors les attributs hérités peuvent être facilement évalués lors
d’une analyse descendante, mais pas lors d’une analyse ascendante.
Une grammaire attribuée est dite S-attribuée, si tous ses attributs sont
synthétisés (elle n’a aucun attribut hérité).
La grammaire de l’exemple 1 est S-attribuée.
Une grammaire L-attribuée est une grammaire attribuée n’ayant que des
attributs hérités qui ne dépendent pas des frères droits.
Les attributs d’une grammaire L-attribuée peuvent être évaluées lors
d’une analyse syntaxique descendante.
il existe des grammaires attribuées qui possèdent à la fois des attributs
hérités et des attributs synthétisés.
Exemple 2
Soit la grammaire :
decl → type vlist
type → int|float
vlist → id,vlist|id
Atributs : type (ENT, REEL)
float x, y
Une DDS peut utiliser à la fois des attributs synthétisés et des attributs
hérités. Dans ce cas, il faut établir un ordre d’évaluation des règles
sémantiques en construisant un graphe de dépendances.
On appelle graphe de dépendances le graphe orienté représentant les
interdépendances entre les divers attributs. Le graphe a pour sommet
chaque attribut. Il y a un arc de a à b si le calcul de b dépend de a.
On construit le graphe de dépendances pour chaque règle de production,
ou bien directement le graphe de dépendances d’un arbre syntaxique
donné. Ce dernier explicite l’ordre d’évaluation des attributs.
Le graphe de dépendances pour chaque règle de production simplifie
l’obtention du graphe de l’arbre syntaxique entier.
Création de noeud :
t_pAST creer_noeud(t_operateur op, t_pAST p1, t_pAST p2)
I Alloue mémoire pour un noeud
I Dépose la valeur de op, p1, p2 dans la zone allouée
I Retourne l’adresse de la zone allouée
S. MBARKI Compilation 2014-2015 180 / 184
Analyse sémantique
Analyse sémantique avec l’outil bison
Affichage d’AST
void afficher_AST(t_pAST p, int niv)
où p est un pointeur sur un noeud ou une feuille de l’AST et niv est le niveau
de l’élément correspondant
1 Introduction à la compilation
2 Analyse lexicale
3 Analyse syntaxique
4 Analyse sémantique
5 Séries d’exercies