Vous êtes sur la page 1sur 58

Compilation : Cours

Chapitre 1: Introduction à la compilation

Chapitre 2: Analyse lexicale


Unités lexicales, modèles et lexèmes
Chaînes et langages (définitions)
Opérations sur les langages
Expressions régulières
Diagramme de transition
Automates Finis
Automates finis déterministes
Automates avec sortie (Transducteurs)
Lex : langage de spécification d’analyseurs lexicaux

1
Chapitre 3: Analyse syntaxique descendante
Dérivation
Qualités des grammaires
Ambigüités
Récursivité à gauche
Factorisation à gauche
Analyseurs descendants
Principe
Analyse par descente récursive
Construction de la table d’analyse

2
Chapitre 4: Langages réguliers

Grammaires régulières

Graphe orienté d'une grammaire algébrique

Lemme de l‘étoile pour les grammaires régulières


Lemme de l‘étoile pour les langages réguliers : (critères de régularité)

 Automates et grammaires régulières

Transformation des grammaires algébriques


Forme normale de Chomsky
Forme normale de Greibach
Forme ≪ presque Greibach ≫

3
Chapitre 5: Analyse syntaxique ascendante
Grammaires LR(k)
Langages R0(A)
R0(i) et grammaires LR(0)
Construction de l’automate LR(0)
Fonctionnement de l’analyseur
Méthode des 0-items
Grammaires SLR(1)
Construction des tables d’analyse SLR(1)
Algorithme d’analyse SLR(1)
Grammaires LR(1)
Construction des ensembles d’items LR(1)
Construction des tables canoniques LR(1)
Construction des tables d’analyse LALR(1)
Bison et utilisation des grammaires ambigües

4
Chapitre 1: Introduction à la compilation

Les principes et techniques de compilation sont si généraux qu’ils utilisent


les idées de la plupart des domaines fondamentaux de l’informatique:

- Langages de programmation
- Algorithmique
- Architecture des machines
- Théorie des langages
- Génie logiciel

5
Les compilateurs

Définition simplifiée:

Programme source Programme cible


compilateur

Messages d’erreurs

6
Il existe des milliers de langages source

Un langage source peut être un langage de programmation traditionnel:


(Pascal, c, fortran) ou un langage spécialisé.

Il existe presque autant de langages cible que source

Un langage cible peut être un autre langage de programmation


ou bien un langage machine
Classes :
compilateurs en une passe
compilateurs multi-passes
compilateurs-exécuteurs
compilateurs optimisants

Malgré cette diversité, on utilise généralement les mêmes techniques


fondamentales pour construire un compilateur

7
Modèle de compilation par analyse et synthèse

Deux parties:

1- Analyse: Partitionnement du programme source en


constituants et création d’une représentation intermédiaire

2- Synthèse: Construction du programme cible à partir de


la représentation intermédiaire

De ces deux parties c’est la synthèse qui nécessite les techniques


les plus spécialisées

8
Environnement du compilateur

Squelette du programme source

Préprocesseur

programme source

Compilateur

Programme cible en langage assemblage

Assembleur

Code machine translatable

Relieur-chargeur Bibliothèque, fichiers


objets translatables

Code machine absolu


9
Analyse du programme source

En compilation l’analyse comprend trois phases:

L’analyse linéaire: le flots de caractères formant le programme source


est lu de gauche à droite et groupé en unités lexicales ;

L’analyse hiérarchique: les unités lexicales sont regroupées


hiérarchiquement dans des collections imbriquées;

l’analyse sémantique: contrôle pour s’assurer que l’assemblage des


constituants du programme a un sens.

10
Analyse lexicale
Dans un compilateur l’analyse linéaire est appelée analyse lexicale.

Exemple:
position := initiale + vitesse * 60

Les caractères formants cette instruction sont regroupés dans les unités
lexicales suivantes:

1 – l’identificateur position
2 – le symbole d’affectation :=
3 – l’identificateur initiale
4 – le symbole plus
5 – l’identificateur vitesse
6 – le symbole de multiplication
7 – le nombre 60
Les espaces sont éliminés lors de l’analyse lexicale.

11
Analyse syntaxique

Dans un compilateur l’analyse hiérarchique est appelée analyse syntaxique ou


grammaticale.

Les unités lexicales sont regroupées en structures grammaticales qui sont


généralement représentées par des arbres syntaxiques.

La structure hiérarchique d’un programme est généralement exprimée par


des règles récursives.

12
Exemple : définition des expressions:

1 – tout identificateur est une expression


2 – tout nombre est une expression
3 – si e1 et e2 sont des expressions, alors:

e1 + e2 est une expression


e1 * e2 est une expression
(e1) est une expression

Les règles 1 et 2 sont des règles de base (non récursives) tandis que la règle 3 définit des
expressions en terme d’opérateurs appliqués à d’autres expressions

13
position := initiale + vitesse * 60

1 : position , initiale et vitesse sont des expressions


2 : 60 est une expression
3 : vitesse * 60 est une expression
3 : initiale + vitesse * 60 est une expression

Instruction d’affectation

identificateur
:= expression

position
expression + expression

identificateur
*
expression expression
initiale
Arbre syntaxique
identificateur nombre

vitesse 60
14
On peut définir les instructions récursivement par des règles comme les suivantes

1 – si id1 est un identificateur et e2 est une expression alors


id1 := e2 est une instruction

2 – si e1 est une expression et i2 est une instruction alors

tant que (e1) faire i2

si (e1) alors i2

sont des instructions

15
Analyse sémantique
Cette phase contrôle si le programme source contient des erreurs sémantiques et
Collecte des informations destinées à la production de code

Exemple: contrôle de type: :=

position +

:=
initiale *
position +
vitesse 60

initiale *
Arbre abstrait
vitesse EntierVersRéel

60

L’analyse sémantique insère une conversion d’entier vers réel 16


Phases d’un compilateur

Programme source

Analyseur lexical

Analyseur syntaxique

Analyseur sémantique
Gestionnaire de la Gestionnaire d’erreurs
table des symboles Générateur de code intermédiaire

Optimiseur de code

Générateur de code

Programme cible
Organisation logique

17
Regroupement de phases

Phase frontale: Front-End

Dépend du langage source et comprend:


l’analyse lexicale,
l’analyse syntaxique
la création de la table des symboles,
l’analyse sémantique
la création de code intermédiaire.

Phase intermédiaire: Middle-End


optimisation de code

Phase finale : Back-End

Dépend de la machine cible et du langage intermédiaire et comprend la production


de code

18
19
Chapitre 2: Analyse lexicale
Unités lexicales, modèles et lexèmes
Chaînes et langages (définitions)
Opérations sur les langages
Expressions régulières
Diagramme de transition
Automates Finis
Automates finis déterministes
Automates avec sortie (Transducteurs)
Lex : langage de spécification
d’analyseurs lexicaux

20
Chapitre 2: Analyse lexicale

L’analyseur lexical constitue la première phase d’un compilateur. Sa tâche principale est de lire
Les caractères d’entrée et de produire comme résultats des entités lexicales.

Unité lexicale analyseur


Programme analyseur syntaxique
source lexical
Obtenir prochaine unité
lexicale

Table des
symboles

Interaction entre un analyseur lexical et un analyseur syntaxique


21
On divise souvent les analyseurs lexicaux en deux phases successives:

Phase de lecture: « Lecteur » (amélioration de l’interface avec l’utilisateur)

- élimination des espaces et commentaires (blanc, \t, \n…)


- relation entre les messages d’erreurs et le programme source
- numérotation des lignes
- copie du programme source en y intégrant les messages d’erreurs
- implantation des mécanismes de préprocesseur

Phase d’analyse lexicale: mécanismes plus complexes.

22
Unités lexicales, modèles et lexèmes

Exemple: const pi = 3.1416;

Unités lexicales Lexèmes description des Modèles

const const const

if if if

Oprel < <= > >= <> = < <= > >= <> =

id pi compte a1 lettre suivie de lettres ou de chiffres

nb 3.1416 0 6.02E23 toute constante numérique

littéral  bonjour  tous caractères entre etsauf 

23
Attributs des unités lexicales

Exemple: Soit l’instruction fortran suivante: E = M * C ** 2

Les unités lexicales et les valeurs d’attributs sont données sous forme de couples:

<id, pointeur vers l’entrée de la table des symboles associée à E>


<op_affectation, >
<id, pointeur vers l’entrée de la table des symboles associée à M>
<op_multiplication, >
<id, pointeur vers l’entrée de la table des symboles associée à C>
<op_exponentiation, >
<nb, valeur entière 2>

24
Spécification des unités lexicales

Chaînes et langages (définitions)


* Un alphabet est un ensemble fini de symboles.

• Une chaîne (mot ou phrase) sur un alphabet est une séquence de symboles extraits de
cet ensemble.

* La chaine vide  est une chaine spéciale de longueur 0.

* préfixe d’une chaine s: une chaine obtenue en supprimant un nombre quelconque


(éventuellement nul) de symboles en fin de s

suffixe d’une chaine s: une chaine obtenue en supprimant un nombre quelconque


(éventuellement nul) de symboles en début de s

sous-chaine de s: une chaine obtenue en supprimant un préfixe et un suffixe de s

* tout préfixe et tout suffixe de s est une sous-chaine de s


mais toute sous-chaine n’est pas forcement préfixe ou suffixe

25
* préfixe, suffixe ou sous-chaine propre de s: Toute chaine non vide x qui est respectivement,
préfixe, suffixe ou sous-chaine de s telle que s  x

• sous-suite de s: toute chaine obtenue en supprimant un nombre quelconque


(éventuellement nul) de symboles non nécessairement consécutifs de s.

* Un langage est un ensemble quelconque de chaines construites sur un alphabet fixé.

exemples: {} ou 
ensemble des programmes c syntaxiquement bien écrits
phrases françaises grammaticalement correctes.

* concaténation: soient a et b deux chaines:


ab est la concaténation de a et de b
s = s = s (est l’élément neutre pour la concaténation)

* Exponentiation de chaine:
s0 = 
s1 = s
Et pour i>0
si = si-1s

26
Opérations sur les langages

Opération Définition

Union L U M = {s | s  L ou s  M}

concaténation LM = {st | s  L et t  M}

fermeture de Kleene de L
L* i0 Li
fermeture positive de L
L i1 Li

27
Expressions régulières

Une expression régulière permet de définir un langage.


exemple:
lettre (lettre chiffre )*

Chaque expression régulière r dénote un langage L(r)


Un langage dénoté par une expression régulière est un ensemble régulier

Règles définissant les expressions régulières:


1 -  est une expression régulière qui dénote {}
2 - si a est un symbole de l’alphabet S alors a est une expression régulière qui dénote {a}
3 – supposons que r et s soient deux expressions régulières dénotant les langages L(r) et
L(s) :
(a) (r ) ( s) est une expression régulière dénotant L( r )  L( s )

(b) ( r )( s ) est une expression régulière dénotant L( r ) L( s )

(c) (r )* est une expression régulière dénotant L((r )* )

(d) (r ) est une expression régulière dénotant L(r )


28
Règles de priorité:

1 – l’opérateur unaire * a la plus haute priorité et est associatif à gauche

2 – la concaténation a la deuxième plus haute priorité et est associative à gauche

3 - | a la plus faible priorité et est associatif à gauche

Exemple: est équivalente à


a bc *
(a) ((b)* (c))

29
Exemples

1 – l’expression régulière a | b dénote l’ensemble {a,b}

2 – (a|b)(a|b) dénote l’ensemble {aa | ab | ba | bb}

3 – a* dénote {,a,aa,aaa,…}

4 – (a|b)* équivalente à (a*b*)* ensemble quelconque de a ou de b

5 – a|a*b dénote l’ensemble {a, b, ab, aab , aaab, …}

30
Si deux expressions r et s dénotent le même langage, on écrit r = s

Ex: (a | b) = (b | a)

Définitions régulières:
On souhaite définir des expressions régulières en utilisant des noms.

Si S est un alphabet de symboles de base, alors une définition régulière est une suite de
définitions de la forme:

D1 –--> r1
D2 –--> r2
…..
Dn –-> rn

Où :
chaque di est un nom distinct
chaque ri est une expression régulière sur les symboles S U {d1,d2,…,di-1}

31
Propriétés algébriques des expressions régulières

Axiome Description

r|s = s|r | est commutatif

r | (s|t) = (r|s) | t | est associatif

(rs)t = r(st) la concaténation est associative

r(s|t) = rs| rt la concaténation est distributive par rapport à |

r = r
r=r  est l’élément neutre pour la concaténation

r* = (r | )*

r** =r*

32
Exemple: Les identificateurs

lettre –--> A|B|…|Z|a|b|…|z

chiffre –--> 0|1|…|9

identif –--> lettre(lettre|chiffre)*

Exemple: les nombres sans signe en pascal

chiffre –--> 0|1|…|9


chiffres –--> chiffre chiffre*
fraction-opt –--> . chiffres|
exposant-opt –--> (E(+|-|)chiffres)|
nb –--> chiffres fraction-opt exposant-opt

33
Notations abrégées

1- « Au moins une instance » est représentée par l’opérateur unaire postfixe +

r* = r+ | 
r+ = r*r
2 – « zéro ou une instance » est représentée par l’opérateur unaire postfixe ?

r? = r|
Exemple:
chiffre –--> 0|1|…|9
chiffres –--> chiffre +
fraction-opt –--> (. chiffres) ?
exposant-opt–--> (E(+|-)? chiffres)?
nb –--> chiffres fraction-opt exposant-opt

3 – « classes de caractères »

Exemples:
[abc] dénote l’expression régulière a|b|c
[a-z] dénote l’expression régulière a|b|c|…|z
[A-Za-z][A-Za-z0-9]* dénote les identificateurs

34
Reconnaissance des unités lexicales

Considérons le fragment de grammaire suivant:

instr –--> si expr alors instr | si expr alors instr sinon instr | 
expr –--> terme oprel terme | terme
term –--> id | nb
si –--> si
alors –--> alors
sinon –--> sinon
oprel –--> < | > | <= | >= |= | <>
id –--> lettre(lettre|chiffre)*
nb –--> chiffre+(. chiffre+)? (E(+|-)? chiffre+)?

délim –--> blanc | tabulation | fin de ligne


bl –--> délim+

35
Modèles d’expressions régulières pour les léxèmes

Expression régulière unité lexicale valeur d’attribut

bl - -
si si -
alors alors -
sinon sinon -
id id pointeur vers une entrée de la table
nb nb pointeur vers une entrée de la table
< oprel PPQ
<= oprel PPE
= oprel EGA
<> oprel DIF
> oprel PGQ
>= oprel PGE

36
Diagramme de transition

début < = 2 Retourne(oprel, PPE)


0 1

>
3 Retourne(oprel, DIF)

autre * Retourne(oprel, PPQ)


= 4
5 Retourne(oprel, EGA)

> =
6 7 Retourne(oprel, PGE)

autre *
8 Retourne(oprel, PGQ)

Diagramme de transition pour l’unité lexicale oprel


37
Lettre ou chiffre

*
début lettre autre 11
9 10 Retourne(unilexid(), rangerid())

Diagramme de transition pour les identificateurs

Exemple: reconnaisseur pour des nombres sans signes Nb → chiffre+ (. chiffre+)? (E(+|-)? chiffre+)?

chif chif chif

début . chif E +ou- chif *


12
chif
13 14 15 16 17 18 autre 19
chif
E

chif chif

début chif . chif autre


* chif
20 21 22 23 24

début chif *
25 26 autre 27
38
délim

début délim *
28 29 autre 30

39
Automates Finis
Définitions:

Reconnaisseur:

Un reconnaisseur pour un langage est un programme qui prend en entrée une chaine x et
répond « oui » si x est une phrase du langage et « non » sinon.

Automate fini : c’est un diagramme de transition généralisé qui représente un


reconnaisseur qui « reconnait » une expression régulière

40
Automates finis non déterministes

Un AFN est un modèle mathématique qui consiste en:

1 – un ensemble d’états E;
2 – un ensemble de symboles d’entrée S (alphabet);
3 – une fonction de transition, qui fait correspondre des couples état-symbole à des
ensembles d’états;
4 – un état e0 considéré comme état de départ ou état initial;
5 – un ensemble d’états F distingués comme états d’acceptation ou états finaux.

Représentation: graphe de transition


a

début a b b
0 1 2 3

b (a|b)*abb
41
Représentation en machine:

Table de transition : une ligne pour chaque état et une colonne pour
chaque symbole plus éventuellement 

Etat symbole d’entrée


a b a

0 {0,1} {0} début a b b


1 - {2} 0 1 2 3
2 - {3}
b (a|b)*abb
42

Le langage défini par un AFN est l’ensemble des chaines d’entrée qu’il accepte.

42
a

a
1 2

début b
0

 b
3 4

aa*|bb*

43
Construction d’un AFN à partir d’une expression régulière

Algorithme:
Donnée: Une expression régulière r sur un alphabet 
Résultat: un AFN N qui reconnait L(r)

1- pour , construire l’AFN: début 


i f

2- pour a  S, construire l’AFN début a


i f

3- soient N(s) et N(t) les AFN pour les expressions régulières s et t.

(a) pour s|t construire l’AFN N(s|t)


N(s) 

f
début
i

 N(t)
44
(b) pour st construire l’AFN N(st)

début
i N(s) N(t) f

(c) pour l’expression régulière s* construire l’AFN N(s*)


début  N(s) f
i

45
Automates finis déterministes

Un AFD est un cas particulier d’automate fini non déterministe dans lequel:

1 – aucun état n’a de -transition


et
2 – pour chaque état e et chaque symbole d’entrée a, il y a au plus un arc étiqueté a qui
quitte e.

b
b

début a b b
0 1 2 3
a
a
a
(a|b)*abb
46
Simulation d’un AFD

Données: une chaine d’entrée x terminée par un caractère de fin de fichier (EOF).
un AFD D avec un état de départ e0 et un ensemble d’états d’acceptation F.
Résultat: réponse « oui » si D accepte x; « non » dans le cas contraire.

Outils:
transiter(e,c) donne l’état vers lequel il y a une transition depuis l’état e sur le
caractère d’entrée c.

carsuiv() retourne le prochain caractère de la chaine d’entrée x.

e:=e0;
c:=carsuiv();
tant que c<> EOF faire
e:=transiter(e,c);
c:=carsuiv();
fin;
si e appartient à F alors retourner « oui »
sinon retourner « non »;

47
Transformation d’un AFN en AFD

Trouver l’-clôture de s:


(s)= {s} U {s’ /  s → s1 … →sn →s’}

(T) = UsT (s)

Algorithme de calcul de (T)

(T) ← T

tant qu’il existe un sommet t  (T) ; t → u

et u  (T) faire (T) ←(T) U {u}

48
Déterminisation d’un AFN

Donnée: un AFN → Résultat: un AFD

Structures de données nécessaires:

- un automate en entrée A (matrice de transition) :


sommets , arcs et symboles étiquetant les arcs

- une file d’attente contenant des sommets avec les fonctions


ajouter(), défiler(), file_vide() …

- automate en sortie A’ avec des fonctions de construction d’automate:


(ajouter_1_sommet(), ajouter_1_arc())

49
Algorithme:

ajouter((s0)) dans la file; /*cette clôture deviendra le sommet d’entrée de A’*/


tant que non(file_vide()) faire
début
défiler(X); /* X est le sommet en tête de file */
pour tout symbole  faire
début
créer un nouveau sommet X’ tel que
α
X '← {s∈ A /∃ x ∈ X ,(x → s )∈A };
X '← ϵ( X ');
α
ajouter l ' arc ( X → X ')dans A '
si X ' ∉sommets de A ' alors ajouter ( X ' )dans la file .
fin
fin

50
 (a|b)*abb

a
2 3
 

  a b b
6 7 8 9 10
0 1
 b
4 5 


(s) a b
a
I a {0,1,2,4,7}=I {2,3,6,7,1,4,8}=II {4,5,6,1,7,2}=III
II
a II II {4,5,6,7,1,2,9}=IV
b
a
III II III
b
a IV II {5,10,6,7,1,2,4}=V
III
b
IV V II III
b b

51
Minimisation

Soit A un automate fini déterministe;


S un ensemble de sommets
et F l’ensemble des états finaux.

On partitionne l’automate comme suit:

1 – M0 = {S\F, F}
2 – On construit des partitions Mi+1 à partir de Mi en utilisant l’algorithme suivant:

Algorithme:
début
pour tout élément pj de Mi faire
partitionner pj en sous ensembles p’ j /
si s et t sont 2 sommets  pj  Mi alors
pour toute lettre  ,
(s,) et (t,) sont dans un même ensemble pk alors ajouter s et t à p’j
et Mi+1={p’1,p’2,….,p’n}
arrêter quand Mi = Mi+1
fin
52
a
1 a
2
M0= (1,2,3,4) (5)
b a
a M1= (1,2,3) (4) (5)
b M2 = (1,3) (2) (4) (5)
a M3 = (1,3) (2) (4) (5)
3
4
b
b b
a
5 1,3 a
2
a
(1,a)=(2) (1,b)=(3)
a
(2,a)=(2) (2,b)=(4)
b
(3,a)=(2) (3,b)=(3) a
(4,a)=(2) (4,b)=(5)
(5,a)=(2) (5,b)=(3) 4
b b
5

53
Automates avec sortie (Transducteurs)

Un transducteur réalise deux fonctions: reconnaissance et traduction

Définition:
deux alphabets: X alphabet d’entrée et Y alphabet de sortie
un ensemble d’états S
un ensemble d’arcs définis par : un état origine et un état extrémité
un symbole d’entrée dans X*
un symbole de sortie dans Y*
un état initial s0
un ensemble d’états terminaux F  S

Exemple: e2 e4
e1
X={a,b} Y={x,y} S={1,2} (b,x) (a,x)
(a,xy)
Arcs:
e1=(s1,s2,a,xy) 2
1 e3
e2=(s1,s1,b,x)
(b,y)
e3=(s2,s1,b,y)
e4=(s2,s2,a,x)
(a b b b a a , x y y x x x y x)
54
Construction d’un petit analyseur lexical

Programme source → traduction → chaîne formées d’entités lexicales.

. Lecture
. Recherche d’entités
. Formation de la chaîne de sortie
. Elimination des informations inutiles
. Détection de certaines erreurs

55
Entité Code Valeur
Begin 1 -

End 2 -

If 3 -

Then 4 -

Else 5 -

Identificateur 6 Adresse de l’identificateur dans la table des symboles

Constante 7 Adresse de la constante dans la table des symboles


< 8 1
<= 8 2
<> 8 4
= 8 3
> 8 5
>= 8 6
OR 9 1
AND 9 2

Identificateur → lettre(lettre | chiffre | _)*


Séparateur → CR | espace
56
Exemple:
if testvar <= 100 or testvar < milieu then

0 8 12
t e s t v a r 1 0 0 m i l i e u

(3,-) (6,0) (8,2) (7,8) (9,1) (6,0) (8,1) (6,12) (4,-)

57
(sep,)
(b,) (e,) (i,) (n,) (sep,retourner(1,-))
(g,)
1 2 3 4 5 6 1

(e,) (n,) (d,) (sep,retourner(2,-))


7 8 9 1
(l,) (s,) (e,) (sep,retourner(5,-))
(i,) 10 11 12 1
(f,) (sep,retourner(3,-))
13 14 1
(t,) (h,) (e,) (n,) (sep,retourner(4,-))
15 16 17 18 1
(sep,retourner(6,ajoutersymb()))
19 1
(autre lettre |ch | _,)

(lettre|ch|_ ,)
(sep, retourner(6,ajoutersymb())
(sep,retourner(7,ajoutersymb()))
20 1

(ch ,) (sep,)


(< ,) (=,retourner(8,2))
21 22 1
(>,retourner(8,4)) (sep,)
23 1
(sep,retourner(8,1))
1
(= , retourner(8,3)) (sep,)
24 1

(=,retourner(8,6)) (sep,)
(> ,) 25 26 1
(=,retourner(8,5)) (sep,)
1
58

Vous aimerez peut-être aussi