Vous êtes sur la page 1sur 61

Universit Sidi Mohamed Ben Abdellah

Facult des Sciences Dhar El-Mehraz Fs


Dpartement dInformatique

Principes et Techniques de
Compilation

Par Noureddine Chenfour

1995-2010

Principes et Techniques de Compilation, N. Chenfour


1. Introduction

1.1 Historique et dfinitions


1.1.1 Dfinition
Un compilateur est un outil logiciel qui lit un programme source crit dans un
langage donn et le traduit en un programme correspondant crit dans un autre
langage. Cette opration est effectue en signalant toute prsence derreur dans le
programme source.

1.1.2 Premiers Compilateurs


Les premiers compilateurs ont t ralis trs difficilement cause du manque
dune dmarche prcise est automatise. En effet parmi les premiers travaux effectu
dans ce domaine taient des programmes de traduction dexpressions arithmtiques en
code machine. Cependant, le langage dassemblage a demeur le premier outil
permettant dcrire des programmes de plus en plus importants.
Au dbut des annes 50, le compilateur FORTRAN (FORmula TRANslation) tait en
fin ralis. Avec ce langage de programmation on pouvait crire des programmes en
utilisant une syntaxe plus volue et simple manipuler.
Lexprience de ralisation du compilateur Fortran conduit au dveloppement de
plusieurs techniques de construction systmatiques dun compilateur, qui seront
tudies dans ce cours. Ce qui a facilit par la suite la ralisation dune multitude de
compilateurs. Le schma suivant montre lvolution des compilateurs travers
diffrents domaines. On peut remarquer une amlioration structurelle au niveau de
chaque nouveau langage.

Principes et Techniques de Compilation, N. Chenfour 2


Fortran
Cobol

Algol 60 Lisp (1956-58)

Simula 67 Commun Lisp

Pascal Ada Smaltalk 80


Langage C

Objective C
Turbo Pascal

C++
Turbo Pascal
For Windows
Visual C++ Boland C++
Langage
JAVA

1.1.3 Schma symbolique dun Compilateur

1.1.3.1 Langage binaire


Cest du code envoy vers lintrieur de la machine (microprocesseur,
mmoire,..) travers les bus, ayant une signification donne (calcul, recherche, )
traduite par une configuration du systme lectronique interne et aboutissant au
rsultat dsir.
Exemple :
Le code : 0001 chargement
0010 opration daddition
0011 registre AX
Les variables sont aussi dsignes par leurs adresses mmoires. On considre une
variable X dadresse 1000. Pour envoyer au microprocesseur la commande de charger
la variable X dans le registre AX on crit :
0001 0011 1000
qui peut se lire charger dans le registre AX la valeur de la variable X.

Principes et Techniques de Compilation, N. Chenfour 3


1.1.3.2 Langage dassemblage
Un code en langage dassemblage est une version mnmonique du code
machine ou langage binaire, dans lequel on emploi des mots significatifs au lieu du
code binaire pour designer les oprateurs, ainsi que des noms pour reprer les adresses
mmoires (variables) et les registres (AX, BX, ).
Exemple :
MOV AX, X
ADD AX, Y
MOV Z, AX

1.1.3.3 Assembleur
Cest le premier module pouvant tre considr comme un compilateur (de
base), qui fait la traduction dun programme crit dans le langage dassemblage en
son quivalent en code machine. La forme la plus simple dun assembleur effectue
deux passes sur le texte dentre.
- 1re passe : Consiste lire le fichier dentre et assigner des adresses
mmoires au identificateurs qui seront stocks dans une table appele
Table de Symboles.
Exemple :
Table de Symboles
X 1000
Y 1010
Z 1100

- 2me passe : Consiste relire le texte est traduire chaque code opration
(exemple MOV) et chaque nom de registre en la suite binaire qui le
reprsente, et chaque identificateur en son adresse mmoire indique dans
la table des symboles.
Exemple :
Le code assembleur de lexemple prcdent sera traduit comme suit :
0001 0011 1000
0010 0011 1010
0001 1100 0011

1.1.3.4 Interprte ou interprteur


Un interprteur ne produit pas du code final comme le cas des compilateurs,
mais il procde lui mme lexcution des instructions du programme source aprs
leur interprtation. Il existe plusieurs langage qui disposent dun interprteur au lieu
dun compilateur.
Exemple :
Basic, Dbase, Lisp.
Principes et Techniques de Compilation, N. Chenfour 4
1.1.3.5 Schma dun Compilateur
Un compilateur reoit le code dentre du programme source et le transforme
en code machine. Cette opration et ralise soit directement soit en traduisant tout
dabord le code source en langage dassemblage qui sera dlivr lassembleur qui le
traduit son tour en code machine.

Programme Code Cible en


Source Compilateur Langage Machine

Programme en
Traducteur Langage dassemblage Assembleur

1.2 Environnement dun Compilateur


Pour quun compilateur puisse tre complet et parvenir gnrer du code
machine excutable, dautres modules doivent tre ajouts celui-ci sans en faire
partie. Cette vision apporte une modularit de haut niveau facilitant le travail la fois
au programmeur (lutilisateur du langage) grce aux instructions du prprocesseur
ainsi quau ralisateur du compilateur qui dispose dj de deux module spars :
lassembleur et lditeur de lien.

Squelette du
programme source

Prprocesseur
Code En Langage
Compilateur dAssemblage

Code translatable
.OBJ Assembleur

Editeur de Lien

Code Machine
Excutable .EXE

Principes et Techniques de Compilation, N. Chenfour 5


1.2.1 Le prprocesseur
Un programme source peut tre divis en modules sur des fichiers spars. La
tache de reconstitution du programme source est dlivre un outils ne faisant pas
partie du compilateur : le prprocesseur. Celui-ci soccupe aussi du dveloppement
des abrviations ou macro-dfinitions (situes en gnral en tte du programme) en
instructions du langage source. Ainsi, en langage C par exemple les instructions du
prprocesseur sont prsentes par le symbole # (#include , #define ) et doivent tre
transformes avant que le compilateur dmarre son traitement. En effet, les
instructions du prprocesseur ne respectent pas la syntaxe du langage et doivent alors
suivre un pr-traitement lavance.

1.2.2 Editeur de lien (chargeur-relieur)


Aprs la phase de compilation on obtient du code en langage machine
translatable (.obj). Ce code ncessite un traitement supplmentaire avant dtre
excutable. Il sagit de ldition de lien (Linkage) qui est confie lditeur de lien
dont la tache est de relier le code machine obtenu des routines prcompiles des
bibliothque du langage. Une autre charge de lditeur de lien est la translation des
adresses des diffrents codes lis. En effet les adresses dun code .obj commence
initialement ladresse 0, et doivent tre translates pour autoriser la fusion des
diffrents code et aussi pouvoir occuper leur emplacement dexcution en mmoire.

1.3 Phases dun Compilateur


1.3.1 Dfinition dune phase
Une phase est une opration transformant le programme dune reprsentation
une autre. Cette transformation peut tre seulement logique, c..d une opration qui ne
cre pas de fichiers intermdiaires mais seulement une nouvelle connaissance ou
dcomposition du programme.
Un compilateur typique peut tre dcompos en six phases reprsentes dans le
schma ci-aprs. Les trois premires phases constituent une premire grande tape du
compilateur : lanalyse. pendant cette tape, le compilateur se contente danalyser
(lexicalement, syntaxiquement et smantiquement) le code source pour le prparer
ltape suivante. La deuxime tape regroupe les phases restantes et sera appele
phase de synthse. Lors de cette tape le compilateur gnre le code cible
correspondant.

Principes et Techniques de Compilation, N. Chenfour 6


Programme Source

Analyse
Analyse Lexicale

Analyse Syntaxique

Analyse Smantique
Table des Gestion des
Symboles Synthse Erreurs
Gnration de Code
Intermdiaire
Optimisation de Code

Gnration de code Final

Programme Cible

1.3.2 Dfinition dune passe


Il arrive souvent que lon regroupe les activits de plusieurs phases dans un
seul module appel passe. Chaque passe est en gnral caractrise par une relecture
du fichier source et une production dun nouveau fichier.
Il existe une grande varit de compilateurs, mais en gnral on en distingue deux
type :
- Compilateurs une passe.
- Compilateur multi-passes.
Il est prfrable de nutiliser quun nombre rduit de passes (deux par exemple) pour
rduire le temps de compilation.

1.3.3 Analyseur lexical (scanner)


Lanalyseur lexical constitue la premire phase du compilateur. Sa tache
principale est disoler en fonction de rgles lexicales simples une suite dentits
primaires ou units lexicales appeles lexmes, composant le programme crit dans
un langage donn.

Principes et Techniques de Compilation, N. Chenfour 7


1.3.4 Analyseur syntaxique (parser)
Cest un module du compilateur qui vrifie que les entits en entre
apparaissent conformment aux rgles dfinissant la syntaxe du langage. Il regroupe
les lexmes en structures grammaticales pouvant tre reprsentes par un arbre
syntaxique.

1.3.5 Analyseur smantique


Il est charg de contrler les structures syntaxiquement correctes pour vrifier
si elles ont un sens logique dans le programme. Le contrle de type (correspondance
de type) constitue la tache principale de ce module.

1.3.6 Gnrateur de code intermdiaire


Il transforme le programme ainsi analys en une reprsentation intermdiaire
partir de laquelle il sera ensuite plus facile de gnrer nimporte quelle type de code
final.

1.3.7 Optimiseur de code


Ce module a pour but damliorer le code intermdiaire de faon ce que le
code machine rsultant sera plus rapide excuter. Pour cela certaines instructions
seront remplaces par dautres ou limines dans le cas de redondance.

1.3.8 Gnrateur de code final


Cest la phase finale dun compilateur, qui consiste la production du code
final partir du code intermdiaire. Exp : code machine, code en langage
dassemblage.

1.3.9 Traitement des erreurs


Au cours des phases de la compilation dun programme, toute prsence
derreur doit tre signale et traite de faon ce que la compilation puisse continuer
et que dautres erreurs puissent tre dtectes.

1.4 Outils pour la construction automatique dun


compilateur
Grce la prsence de mthodes systmatiques pour la construction dun compilateur,
deux outils complmentaires ont t dvelopps pour la construction automatique
dun compilateur laide dune simple spcification des units lexicales et de la
syntaxe du langage.

1.4.1 Constructeur dun analyseur lexical (Lex)


Lex est un outil pour la construction automatique dun analyseur lexical. Il
reoit un fichier de spcification des diffrentes units lexicales du langage laide de
la notation des expressions rgulires, et il produit un programme (source) qui permet
de faire lanalyse lexicale dun fichier dentre.

Principes et Techniques de Compilation, N. Chenfour 8


1.4.2 Constructeur danalyseur syntaxique (YACC)
YACC (Yet Another Compiler Compiler) Dj un compilateur de
compilateur) est un outil permettant de construire dune manire automatique un
analyseur syntaxique dans lequel on peut aussi intgrer toutes les phases dun
compilateur jusqu la gnration de code. Ainsi YACC reoit une spcification de la
syntaxe du langage fonde sur la notation des grammaires, et il travail en
collaboration avec Lex qui lui fourni le module danalyse lexicale.

Principes et Techniques de Compilation, N. Chenfour 9


Chapitre 2

Analyse Lexicale

2.1 Dfinition
Un analyseur lexical constitue la premire phase dun compilateur. Cest une
machine dont la matire premire est lensemble des caractres du texte compiler et
dont la sortie est une squence dunits lexicales que lanalyseur syntaxique rcupre
ensuite. Les units lexicales produites et plus prcisment les identificateurs seront
stockes dans une table appele table des symboles.
Remarques :
1 - Lopration de lecture du texte source doit tre accompagne de taches
supplmentaires selon le langage tudi. Par exemple liminer les blancs du texte
ou convertir le texte en majuscule.
2 - Lanalyseur lexical doit signaler toute prsence derreur dans le texte dentre.
Il ne doit pas sarrter devant la premire erreur rencontre, mais il doit tre
capable de continuer le traitement du programme source et en dtecter dautres.
Peut derreurs sont dtectables ce niveau car lanalyseur lexical une vision trs
restreinte sur le programme source. Quelques erreurs pouvant tre dtectes ce
niveau sont :
- Un caractre nappartenant pas lalphabet du langage,
- Un commentaire non ferm,
- Une chane de caractre non termine
- Une constante caractre contenant plus que 1 ou 2 caractres.

2.2 Lexmes et Units lexicales


Lanalyseur reoit en ente une squence de caractres tirs partir dun
fichier texte, quil doit rassembler unit par unit chacune avec sa dfinition. Les
units extraites du fichier sont appeles des lexmes. Soit par exemple le fichier
contenant la ligne suivante :
Alpha,20.5 "traitement par les Afd"
Les lexmes quon peut extraire sont les suivants :
- Alpha qui est un identificateur

Principes et Techniques de Compilation, N. Chenfour 10


- , qui est un symbole
- 20.5 un nombre
- "traitement par les Afd" qui est une chane littrale.
Le type de chacune des units constitue toute une classe laquelle il peut appartenir
diffrents lexmes. Par exemple la classe des identificateurs contient tous les
identificateurs quon peut imaginer respectant seulement la rgle : suite de caractres
alphanumriques dbutant par un caractre alphabtique. Une classe de lexmes (de
mme catgorie) constitue se quon appelle une unit lexicale. A chaque lexme on
associe alors une unit lexicale bien dtermine. Une mme unit lexicale peut tre
associe plusieurs lexmes. Comme exemple dunits lexicales on peut citer :
identificateur, nombre, symbole, chane littrale, sparateur, oprateur de relation,
oprateur arithmtique, mot cl, etc.
On dfini alors une unit lexicale comme un symbole qui reprsente une
classe dentits tires partir du fichier source et obissant une mme rgle. Lunit
lexicale est donc un symbole terminal qui rentre dans la constitution du vocabulaire
du langage source.
Un lexme est une suite de caractres du programme source qui constitue une
entit lmentaire reprsentant une unit lexicale donne.
Exemple :
Lexme Unit lexicale
Alpha Identificateur
While Mot cl
20.5 Nombre
Avant donc de commencer lanalyse dun fichier texte, il est ncessaire de
prciser quelles sont les units lexicales quon peut accepter. Celles-ci seront alors
dcrites par lintermdiaire dune reprsentation adquate qui sapprte tre
implmenter sous forme de programme danalyse. la meilleure notation utilise est
celle des expressions rgulires. Les avantages dune expression rgulire sont les
suivants :
1- Une expression rgulire est une notation simple et universelle.
2- Une expression rgulire peut tre transforme systmatiquement en un
programme danalyse. Cette transformation passe par les tapes suivantes :
- Transformation Expression Rgulire  Automate Fini Non dterministe (AFN)
- Transformation AFN  Automate Fini Dterministe (AFD)
- Transformation AFD  Programme danalyse
Les trois transformations sont systmatiques et peuvent tre compltement
automatises.

Principes et Techniques de Compilation, N. Chenfour 11


2.3 Expressions rgulires

2.3.1 Alphabet
Cest un ensemble fini et non vide dlments appels des symboles ou
caractres.
Exemples :
A = { 0, 1 } Alphabet binaire pour la construction du langage machine.
A = {a, b, c, !, %} est aussi un alphabet.

2.3.2 Chane
Cest une squence finie de symboles tirs dun alphabet donn pour
constituer une seule entit.
Exemple :
Soit lalphabet A = { a, b, c, d, e } ,
, a, abc, bbe, dd sont des chanes de lalphabet A.

2.3.3 Oprateurs de base


2.3.3.1 Oprateur de Concatnation : .
La concatnation de deux chanes est une chane forme par les symboles de la
premire chane suivi de ceux de la deuxime. On note :
S1 . S2 ou tout simplement : S1 S2

2.3.3.2 Oprateur dUnion : |


On utilise loprateur dunion | pour designer lune ou lautre de deux
chanes.
Exemple :
abc | ce signifie lune des deux chanes.

2.3.3.3 Oprateur de Fermeture : *


loprateur de fermeture * est utilis pour designer la concatnation dune
chane avec elle mme un nombre quelconque de fois (ventuellement nul => ).
Exemple :
(ab) * signifie : | ab | abab | ababab ...

2.3.4 Oprateurs supplmentaires


2.3.4.1 Oprateur de Fermeture positive : +
loprateur de fermeture positive + est utilis pour designer la concatnation
dune chane avec elle mme une, 2 ou plusieurs fois.
Principes et Techniques de Compilation, N. Chenfour 12
(S)+ note aussi S+ signifie : S | S S | S S S
S+ est quivalente : S S*
S* est quivalente : | S+

2.3.4.2 Oprateur doption : ?


loprateur doption ? est utilis pour dsigner la chane sur laquelle il est
appliqu .
( S )? note aussi S ? signifie : S |

2.3.5 Expression rgulire


Une expression rgulire est une notation utilise pour la description dune
unit lexicale dun langage. Toutes les units dun langage dit rgulier sont dnots
par des expressions rgulires.
Pour un alphabet A donn, les expressions rgulires sont formes par les rgles
suivantes :
1) et les lments de A sont des expressions rgulires.
+
2) Si et sont deux expressions rgulires alors | , , ()*, () et
() ? sont des expressions rgulires.

2.3.6 Dfinition rgulire


pour des commodits de notation on peut avoir besoin de donner des noms aux
expressions rgulires et de dfinir des expressions rgulires en fonction de ces
noms. Une dfinition rgulire est une suite de dfinitions de la forme :
d1 exp1
d2 exp2

dn expn
Avec di est le nom qui va reprsenter lexpression rgulire expi, et expi tant dfinie
sur les symboles de base de lalphabet ainsi que les noms dexpressions dfinies avant
di, cd expi est une expression rgulire sur A {d1, , di-1}.
Les di sont alors les units lexicales du langage.
Exemple :
lettre a | b | | z | A | | Z
chiffre 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
id lettre (lettre | chiffre)*

Principes et Techniques de Compilation, N. Chenfour 13


2.4 Les Automates tats Finis dterministe (AFD)
2.4.1 Dfinition
Un Automate Fini est un diagramme graphique permettant de prciser
schmatiquement les tapes quil faut suivre pour identifier et extraire des lexmes
dont lexpression rgulire est bien dfinie. Il sagit dun ensemble dtats qui indique
la progression dun analyseur lexical sur le texte dentre. Le passage dun tat
lautre est ralis lorsquon accepte un symbole (caractre) bien dtermin.
Les tats sont alors schmatiss par des cercles. Le passage dun tat lautre est
ralis par lintermdiaire dun arc reliant entre les deux tat et tiquet par le
symbole accept.
Le dernier tat sur lequel on se trouve aprs avoir reconnu un lexme est appel tat
final ou tat accepteur. Un tat accepteur est en gnral schmatis par un cercle
double.
Le premier tat avec lequel on dmarre lanalyse est appel tat initial (en gnral
ltat 0) peut tre schmatis laide dun cercle ordinaire point par une pointe de
flche.
b
Exemple 1 :

a b c
0 1 2 4

d c

Cet automate reprsente lexpression rgulire : a ( b+| d ) c


Remarques :
1- Un Automate Fini dispose dun seul tat initial, mais il peut avoir plusieurs
tats accepteurs.
2- Une transition peut tre ralise sur un symbole ou une union de symboles
mais jamais sur une concatnation de symboles
Exemple 2 :
Soit la dfinition rgulire des oprateur de relation C :
oprel < | <= | > | >= | != | ==
Elle est reprsente par lautomate suivant :

<|> 1 =
0 !|= 3
=
2

Principes et Techniques de Compilation, N. Chenfour 14


La transition de ltat 0 vers ltat 1 est ralis si le symbole dentre est < ou >. On
peut noter de la mme manire <,>.

2.4.2 Rgles lmentaires de construction dun automate


A partir des exemples dj traits, il est possible de dduire quelques rgles
lmentaires de construction dun automate partir dune expression rgulire. Elles
peuvent tre nonces comme suit :
1- Si lER est un simple symbole ( s ) :
s
0 1

2- Si lER est une Union de symbole ( s1 | s2 | sn) :

s1 | s2 | sn s1 , s2 , sn
0 1 0 1
Ou encore
3- Si lER est une concatnation de symboles ( s1 s2 sn) :
s1 s2 sn
0 1 2 N

4- Si lER est une fermeture ( s* ) :


s

5- Si lER est une fermeture positive ( s+ ) :


s

s
0 1

En appliquant ces rgles lexpression rgulire suivante :


(a | b)* a b b
on obtient lautomate suivant :
a|b

a b b
0 1 2 3

Principes et Techniques de Compilation, N. Chenfour 15


Cependant celui-ci est Non Dterministe. En effet, partir de ltat 0 si on reoit le
symbole a , le prochain tat peut tre 0 ou 1. Il sagit alors dun non dterminisme :
il nest pas possible de dterminer dune manire unique le prochain tat vers lequel
on va transiter. Lautomate obtenu est appel Automate Fini Non dterministe et
not AFN. En contre partie un AFD (Automate Fini Dterministe) est un automate
dans lequel les dcisions de transition sont uniques. La relation de transition est alors
une fonction. A un tat de dpart et un symbole en entre on associe un seul tat
destination.
Remarque :
Il est parfois plus simple de construire un AFN partir dune expression
rgulire que de construire un AFD.
Pour lexemple prcdent, il est possible de construire un AFD correspondant avec
plus de raisonnement au niveau de chaque tat de lautomate o il est ncessaire de
traiter tous les cas possibles. On obtient lAFD suivant :
b a
a
a
a b b
0 1 2 3

2.4.3 Automates Finis Non dterministes


Un AFN est un automate qui prsente lune des deux situations suivantes :
1- A partir dun mme tat de dpart, il existe deux arc sortant sur le mme symbole,
partant vers deux tats diffrents. s

s e2
e1
En cas particulier : s
e1 e2
s e3

2- Il existe une transition sur le symbole , appele -transition. Celle-ci signifie un


changement dtat sans consommation de symbole. Ce qui est un non
dterminisme : faut-il ou non changer dtat quand rien ne se passe en entre.

e1 e2

2.4.4 Automates Finis Dterministes (AFD)


2.4.4.1 Dfinition 1 :
Un AFD ou encore Automate tats Finis Dterministe est un automate ne prsentant
aucune des deux situations de non dterminisme prcdentes.

Principes et Techniques de Compilation, N. Chenfour 16


2.4.4.2 Dfinition 2 :
Un AFD est un Quintuplet (, e 0 , E, T, A) o :
Alphabet du langage utilis par lautomate

e0 Etat Initial

E Ensemble des tats de lAFD

T Fonction de Transition

A Ensemble des tats Accepteurs

2.4.5 Construction dun AFD partir dune expression


rgulire
La construction passe par 2 tapes :
1. Etape N 1 :
Transformation ER  AFN

2. Etape N 2 :
Transformation AFN  AFD

2.4.5.1 Construction dun AFN partir dune Expression rgulire


Dans la suite les rgles de transformation de base ; qui, appliques rcursivement,
elles permettent de transformer automatiquement nimporte quelle expression
rgulire en un AFN.
Rgle N 1 :
Soit A lalphabet du langage.

Pour tout symbole s appartenant A, lautomate correspondant est le suivant :

e1 s e2

Principes et Techniques de Compilation, N. Chenfour 17


Rgle N 2 :
Soient les deux expressions rgulires suivantes :
ER1 ayant comme AFN : AFN(1)
ER2 ayant comme AFN : AFN(2)
LAFN de la concatnation ER1 . ER2 est le suivant :

I1 AFN(1) F1 I2 AFN(2) F2

Rgle N 3 :
Soient encore les deux expressions rgulires suivantes :
ER1 ayant comme AFN : AFN(1)
ER2 ayant comme AFN : AFN(2)
LAFN de lunion ER1 | ER2 est le suivant :

I1 AFN(1) F1

I F

I2 AFN(2) F2

Principes et Techniques de Compilation, N. Chenfour 18


Rgle N 4 :
Soit lexpression rgulire suivante :
ER1 ayant comme AFN : AFN(1)
LAFN de la fermeture ER1* est le suivant :


I I1 AFN(1) F1 F

2.4.5.2 Construction dun AFD partir dun AFN

Principes et Techniques de Compilation, N. Chenfour 19


2.5 Implmentation dun analyseur lexical
Pour implanter un analyseur lexical, une phase de conception est tout dabord
ncessaire. Pendant cette phase toutes les units lexicales sont spcifies laide de la
notation des expressions rgulires. Ensuite, ces expressions sont transformes en des
AFD (Automates Finis Dterministes). Puis, les AFD sont transforms facilement en
un programme.
La transformation des expressions rgulires en des AFD est une opration qui peut
tre ralise intuitivement comme elle peut tre dveloppe automatiquement par un
programme laide dun passage par des AFN (Automates Finis Non dterministes).

Expression
AFN AFD Programme
Rgulire

Dans une premire partie de ce paragraphe nous prsentons limplantation dun


analyseur Lexical bas sur les AFD. Dans une deuxime partie nous allons faire une
description des algorithmes de construction dun AFD partir dune Expression
Rgulire. Nous supposons alors dans un premier lieu que la transformation des ER
en AFD est une opration vidente.
Extraction dune unit lexicale
Schma gnral de lanalyseur lexical

Schma gnral
Fichier
Source

Tampon

Caractres
U1

U2
Analyseur Units Analyseur
AFD Lexical Lexicales Syntaxique
Un-1
Un

Principes et Techniques de Compilation, N. Chenfour 20


Diagramme de classe

InputTape
+ mark()
+ restore()
+ skip()
+ endOfTape()
+ getNextChar()
+ getToken()
Scanner
+ getNextToken()
DFA Token
+ add()
+ id() + extract() + getName()
+ blanc() + add() + getValue()
+ addKeyword() + setAccepting() + toString()
+ setKeyword() + getName()
+ isKeyword()
+ addType()
+ setType()
+ isType()

CScanner State Transition


+ getNextToken() + isAccepting() + add()
+ nb() + setAccepting() + getNext()
+ comment() + getValue()
+ listteralString() + setValue()
+ + toString

Arc
+ setSource()
+ getTarget()
+ accept()

Fig 2.2 : Diagramme de Classe UML de lanalyseur Lexical

Principes et Techniques de Compilation, N. Chenfour 21


Chapitre 3

Analyse Syntaxique

3.1 Objectif et outils de base


Vrifier si les lments qui proviennent de lanalyseur lexical forment une chane
dunits lexicales acceptes ordre est reprsentation par le langage.
La reprsentation du langage est spcifie par une grammaire.
La grammaire est dfinie en gnral laide des units lexicales qui constituent le
vocabulaire terminal, et des nouvelles entits qui dfinissent les constructions du
langage et forment un vocabulaire non terminal.
La premire tache effectuer est la constitution de la grammaire.
Exemple :
E E + T | E -T | T
T T*F|T/F|F
F ( E ) | nombre | identificateur

3.2 Dfinition

Lanalyseur syntaxique est la 2me phase du compilateur. Cest un module qui


reoit en entre une liste de lexmes (units lexicales) extraits par lintermdiaire de
lanalyseur lexical (Scanner) et vrifie si leur ordre dapparition dans le fichier
dentre est conforme la syntaxe prvue par le langage. La syntaxe doit donc tre
dfinie dune manire rgulire et sans ambigut. Ceci ncessite une spcification de
la syntaxe ralise laide dun langage de spcification syntaxique simple et
universelle. Il sagit de la notation des grammaires.

Principes et Techniques de Compilation, N. Chenfour 22


3.3 Les grammaires
3.3.1 Vocabulaire Terminal
Lanalyseur syntaxique reoit une suite de lexmes et dunits lexicales qui
constituent un ensemble dentits lexicales utilises pour dfinir la grammaire du
langage, appel VOCABULAIRE TERMINAL not VT.
Exemple :
VT = {id, nb, :=, begin, end, ...}

3.3.2 Rgles de Production et Vocabulaire Non-Terminal


Pour dfinir la syntaxe du langage, on utilise des rgles syntaxiques appeles
Rgles de Production (ou simplement des Productions). Chaque rgle permet de
fixer un ordre syntaxique bien dtermin au niveau dune construction donne du
langage. Ainsi, chaque construction on associe un nom qui la dtermine et pouvant
tre rutilises pour dfinir dautres constructions du langage. Ce nom est appel un
non-terminal et constitue un lment du VOCABULAIRE NON-TERMINAL not
VN.
Une production sera alors dfinie comme suit :
Partie Gauche  Partie Droite

La partie gauche est le non-terminal, la partie droite est une suite de terminaux et de
non-terminaux fournissant ainsi la structure de la construction syntaxique identifie
par le non terminal gauche.

Exemple : dclaration dune liste dindentificateurs en Pascal


Dec  id LI : type ;
LI  , id LI |
Dans ce cas :
VT = { id : ; , type }
VN = { Dec, LI }
Remarque :
Pour distinguer entre les terminaux et les non-terminaux, ces derniers vont
toujours commencer par une lettre majuscule

3.3.3 Dfinition dune grammaire


Une grammaire est dfinie sous forme dune liste de productions permettant de
couvrir toutes les possibilits syntaxiques du langage. Elle est dfinie rgulirement
comme un quadruplet : G(VT, VN, P, S)
VT : Vocabulaire Terminal
VN : Vocabulaire Non terminal

Principes et Techniques de Compilation, N. Chenfour 23


P : un tableau de productions
S : appel Axiome de la grammaire, est le premier non terminal dfinissant la
premire production de la grammaire.

3.3.4 Rgles dcriture des grammaires


1. Les seuls oprateurs utiliss pour dfinir les grammaires sont :
- la concatnation : .
- Lunion : |

2. Les structures optionnelles sont dfinies dans des productions spares en utilisant
lalternative :
Pascal  Entete . Dec . Corps
Entete  program id ; |

3. Les structures rptes sont dfinies laide de la rcursivit :


Lid  id Rid
Rid  , id Rid |
Rgles gnrales :
Soit une construction rpter :
3.1 Pour raliser * :
A  A|
3.2 Pour raliser + :
A  B
B  B|
Exemple :
Pascal  Entete Dec Corps .
Entete  program id ; |
Dec  D . Dec |
D  var Lid : type ;
Lid  id Rid
Rid  , id Rid |
Corps  begin LI end
LI  Inst LI |
Inst  IA | IIf | IBoucle | .
.
VT = {program id ; . var : type , begin end }
VN = {Pascal, Entete, Dec, D, Lid, Rid, Corps, LI, Inst, IA, IIf, IBoucle}
Axiome = Pascal

Principes et Techniques de Compilation, N. Chenfour 24


Remarque 1 :
Un Non-Terminal peut tre dfini base dun autre Non-Terminal qui sera dfini en
dessous.
Exemple :

A aB|C

B BX|d

X bC|e

Remarque 2 :
Loprateur doption nexiste pas, il est remplac par lalternative

A a|

Remarque 3 :
Les alternatives dune production peuvent tre dfinies sparment :

A B|aC|d

A B
A aC
A d

Remarque 4 :
Les oprateurs de fermeture * et + sont remplacs par la rcursivit

*) * A A|

*) + = . *

+ A B
B B|

Principes et Techniques de Compilation, N. Chenfour 25


3.3.5 Principe dutilisation des grammaires :

3.3.5.1 Drivation :
Soient X, Y V*
On dit que X se drive en Y si le Y peut tre obtenu partir de X par application de 0,
1 ou plusieurs rgles de Production. On crit :

X Y ou X *Y

Exemple :

A aA|bB

B aA|DE

D c|d

E dE|

A aA

aaA

aabB

aabDE forme sententielle

aabdE aabB *a a b d E

aabddE

aabdd Sentence

3.3.5.2 Forme sententielle Protophrase


Cest une phrase de V* qui se drive de laxiome.
Exemple : aBAD

A aA

A b B nest pas une forme sententielle

Principes et Techniques de Compilation, N. Chenfour 26


NB : Une forme sententielle est une forme dinstruction correcte.
Exemple :
-E : if nest pas une forme sententielle de Pascal
-id := E ; est une forme sententielle pour le langage Pascal.
Pour la grammaire prcdente : bDdE

A bB

BDE

BDdE est une forme sententielle

3.3.5.3 Sentence :
Cest une forme sententielle qui appartient Vt*.
Exemple :

Begin
Id := nb * (id + nb ) ;
End.

Est une sentence du langage Pascal.

Exemple : Pour la grammaire prcdente :


- bcd est une sentence

A bD
BDE
bDdE
bcdE
bcd

3.3.5.4 Arbre syntaxique :


Un arbre syntaxique est le schma des drivations ncessaires pour obtenir une
sentence depuis laxiome.
Laxiome va dfinir la racine de larbre. Les feuilles de larbre sont les
constituants de la sentence.

Principes et Techniques de Compilation, N. Chenfour 27


Exp1 :

A Axiome

D E

Sentence d c d E


Exp2 :

DP Var Sd DP |
Sd Ld R
R Ld R|
Sid , id Sid |

Exemple de dclaration :
Analyseur lexical
Var x, y : integer ; Var id, id : type ;
c : char ;
id : type ;
Var z : real ;

VN = { DP, Sd, R, Ld, Sid }


VT = { Var, id,: , type, ; , , }
Axiome : DP

Principes et Techniques de Compilation, N. Chenfour 28


DP

SD DP

Ld R SD
DP
Ld
Sid R
Ld R

Sid Sid

Sid


Var id , id : type ; id : type ; Var id : type ;

3.3.5.5 Grammaire ambigu :


Une grammaire est dite ambigu si une mme sentence correspond deux ou
plusieurs arbres syntaxiques (en utilisant une drivation gauche ).
Exemple : E E + E | E E | E / E | E * E | id | nb | ( E )

Soit la sentence : id + nb * id

E E

E E E E

E E E E

id + nb * id id + nb * id

Faux

Principes et Techniques de Compilation, N. Chenfour 29


Solution :
E E+T|ET|T
T T*F|T/F|F
F nb | id | ( E )

E T

T T F

F F

id + nb * id

 Un seul arbre syntaxique.

3.4 Mthode gnrale


La mthode la plus simple pour la construction de lanalyseur syntaxique est la
mthode rcursive descendante.
 Associer chaque non terminal une fonction boolenne qui vrifie si la
construction est correcte.
 La construction est identifie par la partie droite de la production associ au non
terminal.
Inconvnients :
 Problme de rebroussement.
 Possible uniquement avec quelques grammaires.

Principes et Techniques de Compilation, N. Chenfour 30


3.5 Analyseur prdictif descendant (LL(1))
Le problme de rebroussement est cr par les alternatives :
A 1 | 2 | ... | n
Pour tre dterministe on utilise la notion de Symbole de Prvision.
 Lanalyse prdictive sappuie sur la connaissance des premiers symboles qui
peuvent tre engendrs par les parties droites des productions.
 Dfinir les ensembles First et Follow.
 Construire une table de dcision appele Table dAnalyse dans laquelle sont
rpertories les dcisions de drivation possibles.
 Lanalyseur utilise la table danalyse pour prendre les dcisions de drivation
adquates et gre une Pile dAnalyse explicite pour y sauvegarder lensemble des
noeuds de larbre syntaxique, qui sont en cours de dveloppement. Cette pile
remplace la pile implicite des appels rcursifs dun analyseur avec rebroussement.

Analyseur
Lexical Tampon implicite
ou explicite
t ... t $
Units
Lexicales
N Analyseur Rsultat Analyseur
Smantique
LL(1)
$
TA ... t ...

N ... N
...

Principes et Techniques de Compilation, N. Chenfour 31


Exemple :
Soit la grammaire des expressions arithmtiques suivante :
1. E  T E
2. E  + T E
3. E  - T E
4. E 
5. T  F T
6. T  * F T
7. T  / F T
8. T 
9. F  id
10. F  nb
11. F  ( E )
On note VT : le Vocabulaire Terminal. Pour la grammaire prcdente :
VT = { + , - , * , / , id , nb , ( , ) }

On note VN : le Vocabulaire Non Terminal. Pour la grammaire prcdente :


VN = { E , E , T , T , F }

Le vocabulaire du langage not V est = VT VN.

1. Calcul de First :
Lalgorithme First peut tre appliqu une chane constitue des lments du
vocabulaire V du langage.

First () {
if ( VT ) {
F = { } ;
}
else if ( VN ) {
F = {} ;
Pour toute production [  ] {
F = F First() ;
}
}
else if ( == X1 X2 X3 ... Xn) {
i = 1;
while ( (i < n) && ( First(Xi)) )
F = F First(Xi) \ {};
i++;
}
F = F First(Xi);
}
return F;
}

Principes et Techniques de Compilation, N. Chenfour 32


2. Calcul de Follow :

Lalgorithme Follow ne peut tre appliqu qu un lment X du vocabulaire non


terminal VN.

Follow (X) {
F = {} ;
if ( X est = laxiome de la grammaire ) {
F = {$} ;
}

Pour toute production [ A  X ] {


F = F First() \ {} ;
if ( ( == ) || ( First()) ) {
F = F Follow(A) ;
}
}
}

Exemple :

First Follow

E id , nb , ( $,)

E +,-, $,)

T id , nb , ( +,-,$,)

T *,/, +,-,$,)

F id , nb , ( *,/,+,-,$,)

Principes et Techniques de Compilation, N. Chenfour 33


3. Calcul de la table danalyse LL(1) :

Lalgorithme consiste rpartir les diffrentes productions sur les cellules de la


table danalyse que nous notons TA.

RemplirTableDAnalyse() {
Pour toute production [ A  ]) {
Pour tout lment a (First() \ {}) {
TA[A][a] = [ A  ];
}
if ( == || First()) {
Pour tout lment b (Follow(A)) {
TA[A][b] = [ A  ];
}
}
}
}

Exemple :

TA + - * / id nb ( ) $

E 1 1 1

E 2 3 4 4

T 5 5 5

T 8 8 6 7 8 8

F 9 10 11

Principes et Techniques de Compilation, N. Chenfour 34


4. Analyseur LL(1) :

Lanalyseur LL(1) utilise comme entre :


- La table danalyse que nous allons noter : TA
- La pile danalyse que nous allons noter : PA
- Un objet danalyse lexicale not : scanner la fonction extract() sera utiliser
pour rcuprer une unit lexicale not p (Symbole de Prvision).

boolean LL1(Scanner scanner, TA) {

S
PA = $ ; // o S est laxiome de la grammaire
Token p = scanner.extract() ;
Symbol A = PA.tete() ;
do {
if (A VT) {
if (p.equals(A)) {
if (p.equals("$")) return true;
else {
PA.depiler() ;
p = scanner.extract() ;
}
}
else {
if (p.equals("$")) error("Unexpected EOF ");
else if (A.equals("$")) error("Expected EOF ");
else error("Expected Symbol : " + A);

return false;
}
}
else { // A VN
if ( TA[A][p] == [ A  X1 X2 X3 ... Xn ] ) {
PA.depiler() ;
for (i = N ; i >= 1 ; i--) PA.empiler(Xi) ;
A = PA.tete();
}
else {// TA[A][p] == null
if (p.equals("$")) error("Unexpected EOF ");
else error("Unexpected Symbol " + p);
return false;
}
}
}
while (true) ;
}

Principes et Techniques de Compilation, N. Chenfour 35


3.6 Analyseur LR(1)
3.6.1 principe
Le problme est transform la recherche suivant les tats dun automate
fini non dterministe.
Un tat de lautomate correspond une position dans la partie droite dune
production de la grammaire not : A . , et appel Item. Le point
indique la position de lanalyseur.
Les dcisions sont prises en consultant la table danalyse compose de deux
partie : Action et successeur .

Analyseur
Lexical Tampon implicite
ou explicite
t ... t $
Units
Lexicales

E Analyseur Rsultat Analyseur


Smantique
LR(1)

Dcision
$ ACTION SUCCESSEUR
Etat Terminaux Non Terminaux
Pile des
0
tats
1

Table danalyse
Lanalyseur LR(1) utilise un tampon dentre, une pile dtats et une table
danalyse divise en deux parties : Action et Successeur. Chaque tat E en sommet de
pile combin avec le symbole dentre a possde une entre dans la table de dcision :
Action[E][a], qui dtermine laction effectuer :
- Dcaler E : avancer dans le tampon dentre et empiler un nouvel tat E en sommet
de pile. Nous reprsentons cette dcision par le couple {D, E}.
Principes et Techniques de Compilation, N. Chenfour 36
- Rduire A : qui signifie dpiler un nombre dtats gal au nombre de symboles
qui composent . Et empiler Successeur[F][A], avec F est le nouvel tat en sommet
de pile. Cette entre sera reprsente par le couple {R, A }.
- Echec : lanalyseur dtecte une erreur et peut appeler une procdure de rcupration
sur erreur. Pour garder la mme notation nous reprsentons cette entre par : {E, 0}.
- Succs : signale la fin de lanalyse. Pour garder la mme notation nous reprsentons
cette entre par : {S, 0}.

3.6.2 Algorithme LR(1)


#define Succes 1
#define Echec 0

Initialement Pile ={$}


Algorithme LR(1)
{
GetLex();
Do {
E = Tete(Pile);
a = UL;
if (Action[E][a] = {S, 0 }) return Succes
else if (Action[E][a] = {E, 0}) return Echec
else if (Action[E][a] = {D, E}) {
GetLex();
Empiler(E, Pile);
}
else if (Action[E][a] = {R, A }) {
L = || ; // cardinal de : nombre de symboles
For ( I=1; I<=L; I++) Pop(Pile);
E=Tete(Pile);
Empiler(Successeur[E][A], Pile);
}
}
while (1);
}

Principes et Techniques de Compilation, N. Chenfour 37


3.6.3 Construction de la table danalyse
trois mthodes existent pour la construction de la table danalyse: Simple LR,
LALR, et la meilleure : LR canonique.

3.6.3.1 Construction des tables danalyse SLR


Soit G la grammaire utilise daxiome S.
On considre la grammaire augmente G de G, cd : la grammaire G avec une nouvel
production : S S, et donc un nouvel axiome S.

Algorithme SLR

On note VT le vocabulaire terminal, et VN le vocabulaire non terminal.

Algorithme SLR
{
1- Calculer la collection canonique : C = {I0, I1, , In} de la grammaire G;
2- Pour chaque Ii C associer un tat i;
3- for (i = 1; i n ; i++) {
for (a VT) {
if (Transition(Ii, a) = Ij) Action[i][a] = {D, j};
}
for ( A . Ii, tq A S) {
for ( a Follow(A) ) Action[i][a] = {R, A };
}
if (S S. Ii ) Action [i][$] = {S, 0};

for (X VN) {
if (Transition(Ii, X) = Ij) Successeur[i][X] = j ;
}
}
}

Principes et Techniques de Compilation, N. Chenfour 38


Calcul de la collection canonique
On considre le vocabulaire V = VT VN.
Algorithme Calcul_Collection_Canonique
{
I0 = Fermeture( { S .S});
C = { I0}
Do {
Soit ( I C ) {
for (X V) {
if (Transition(I, X) C) C = C + Transition(I, X) ;
}
}
}
while (! Saturation);
}

Calcul de la Fermeture dun ensemble dItems


Soit un ensemble dItems I.
Algorithme Fermeture ( I )
{
F=I;
Do {
for ( A . B F) {
for ( B , tq B . F) F = F {B .};
}
}
while (! Saturation);
return F;
}

Principes et Techniques de Compilation, N. Chenfour 39


Opration de transition
Soit un ensemble dItems I et soit X V.
Transition( I, X) = Fermeture ( A B . tq A . B I }
Algorithme Transition ( I, X)
{
E = {};
for ( A . B I ) {
E = E { A B . };
}
T = Fermeture( E );
Return T;
}

3.6.3.2 Construction des tables danalyse LR canonique


ici un item sera not [A . , a] . o le a dsigne le symbole terminal qui
vient juste aprs la partie gauche de la production A . a VT {$}. Il faut
alors redfinir les algorithmes Fermeture, Transition, construction de C et
construction des tables danalyse.

Fermeture dun ensemble dItems


Algorithme Fermeture ( I )
{
F=I;
Do {
for ( [A . B , a] F) {
for ( B )
for ( b First( a) ) {
if ( [B ., b] F ) F = F { [B ., b] };
}
}
}
while (! Saturation);
return F;
}

Principes et Techniques de Compilation, N. Chenfour 40


Opration Transition
Transition( I, X) = Fermeture ( [A B . , a] tq [A . B , a] I }
Algorithme Transition ( I, X) {
E = {};
for ( [A . B , a] I ) {
E = E { [A B . , a] };
}
T = Fermeture( E );
Return T;
}

Construction de la collection canonique


Algorithme Calcul_Collection_Canonique {
I0 = Fermeture( { [S .S, $]});
C = { I0}
Do {
Soit ( I C ) {
for (X V) {
if (Transition(I, X) C) C = C + Transition(I, X) ;
}
}
}
while (! Saturation);
}

Construction des tables danalyse


Algorithme LR_Canonique {
1- Calculer la collection canonique : C = {I0, I1, , In} de la grammaire G;
2- Pour chaque Ii C associer un tat i;
3- for (i = 1; i n ; i++) {
for (a VT) {
if (Transition(Ii, a) = Ij) Action[i][a] = {D, j};
}
for ( [A . , a] Ii) {
Action[i][a] = {R, A };
}
if ([S S. , $] Ii ) Action [i][$] = {S, 0};

for (X VN) {
if (Transition(Ii, X) = Ij) Successeur[i][X] = j ;
}
}
}

Principes et Techniques de Compilation, N. Chenfour 41


Chapitre 4

Analyse smantique

4.1 Objectif
Lanalyse smantique consiste contrler la vrification des rgles
concernant le sens logique des expressions syntaxiquement justes.
 Contrle de type.
 Contrle dunicit.
 Contrle du flot dexcution (instruction englobante).

4.2 Traduction dirige par la syntaxe


Lanalyse smantique est effectue laide dune traduction dirig par
la syntaxe
La grammaire est transforme en une grammaire de traduction avec
attributs.
 Des actions smantiques sont associes aux productions de la
grammaire.
 Des attributs sont associs aux symboles de la grammaire.
 Aprs la vrification dune production on excute laction
smantique correspondante.
N1 1 { AS1}
N2 2 { AS2}
4.3 Contrle de type
Dfinition dun systme de typage (dclaration)
des expressions.
Contrle de type
des instructions.
Equivalence structurelle ( C ).
Equivalence de type
Equivalence par nom ( Pascal ).
Principes et Techniques de Compilation, N. Chenfour 42
Contrleur de type

Dfinition de type
Contrle de type Contrle de type des
Constructeurs de des expressions instructions
Types de dclaration
base type

Variables Type Vide


Compatibilit Equivalence (Oui/Non)
de type de type
Casting
Dclaration Implicite Dclaration Explicite Expression
(VB, Lisp, prolog) (Pascal, C, Java)
Compatibilit Table des
entre classe Compatibilits Appels aux
Fonctions fonctions
Base Drive
Table des
types Dclaration Type Fonction Dfinition Rflexive Non
(Prototype) (Corps de la Rflexive Equivalence Equivalence
fonction) par Nom Structurelle
(Pascal) (langage C)
Surcharge Surcharge des
des Fonctions Oprateurs

Table des
Symboles

Principes et Techniques de Compilation, N. Chenfour


Chapitre 5

Gnration du code intermdiaire

5.1 Objectif
Produire partir du code source un code intermdiaire indpendant de
toute exigence matrielle.
La phase de gestion du code finale sera indpendante des particularit
du code source.
Facilit de changement du code final sans avoir toucher la phase
danalyse

5.2 Ralisation
 Choix du code intermdiaire.
 Manire dimplantation.

5.3 Code 3 adresses


suite dinstructions faisant intervenir au maximum 3 adresses:
Rsultat := Oprande1 Opration Oprande2
Gnralisation de cette forme pour englober tout type de construction
du langage.
Structure de donn utilise : enregistrement
 Notion des quadruplets (~ unit syntaxique ~).

Principes et Techniques de Compilation, N. Chenfour


5.4 Implmentation
Sous forme dune traduction dirige par la syntaxe au sein de
lanalyseur smantique.
cration dun temporaire pour chaque oprateur.
Exemple:
x := a + b * c t1 = b * c , t2 = a + t1 , x = t2

Principes et Techniques de Compilation, N. Chenfour 45


6. Optimisation de code
Phase optionnelle.
Optimisation de point de vue temps dexcution
Utilisation optimale des registres.
Traduction des multiplications, si possible, en additions ou dcalages.
Suppression des calculs invariants dans les boucles
nombre dinstructions.

 Ncessite de parcourir plusieurs fois le fichier dentre, en modifiant


chaque fois lordre dvaluation des quadruplets.
 Phase qui augmente le temps de compilation.

Principes et Techniques de Compilation, N. Chenfour 46


7. Gnration de code final
7.1 Choix du code final
Code machine (.obj) :
 Plus compliqu.
 Gestion des adresses.
 Connaissance du matriel.
 Dpendance du matriel.

Code assembleur
 Plus facile gnrer.
 Plus proche du code 3 adresses.
 Existence de lAssembleur.

7.2 Choix de la technique dimplmentation

Analyseur
Syntaxique

Analyseur
Smantique Des Units
C3A
Gnrateur Code
de Code Assembleur
Actions Final
smantiques

Principes et Techniques de Compilation, N. Chenfour 47


Conclusion
Une trs bonne organisation des compilateurs.

Plusieurs techniques permettant limplantation efficace dun trs grand


nombre de compilateurs, et encourageant la conception est le
dveloppement de plusieurs langages volus.

Un ensemble doutils permettant limplantation facile et immdiat des


compilateurs.

Des techniques pouvant tre appliques diffrents domaines.

Tout produit informatique, faisant intervenir des notions de traduction


peut bnficier des techniques de compilation et tre configur suivant
le schma dun compilateur.

Principes et Techniques de Compilation, N. Chenfour 48


Exercices et Travaux Pratiques

Exercices danalyse :
1- Donner une comparaison entre les diffrentes mthodes danalyse syntaxique.
2- Quelle sont les fonctions des deux utilitaires LEX et YACC, leur principe et sur
quelle notion se base chacun des deux utilitaires ?
3- Quest ce quon veut dire par les deux notions : prdictif et sans rebroussement, et
est ce quil y a une diffrence entre ces deux notions ?
4- Est-ce quon peut crire un gnrateur de code intermdiaire spar de lanalyseur
syntaxique ? Faites une comparaison avec le cas dintgration dans celui-ci.
5- Quest ce quune grammaire LR(1) ? Dcrire lanalyseur LR(1).
6- Est-ce quune grammaire LL(1) et forcment LR(1) ?
7- Est-ce quon peut envisager loptimisation de code aprs la phase de gnration de
code final ?
8- Dans quelle phase a-t-on rellement besoin de la table de symbole ? et quelle peut
tre la structure ?
9- Quest ce que le prprocesseur ? Lditeur de lien ? et quelle diffrence existe t-
elle entre un programme .obj et son .exe correspondant ?
10- Est-ce quon peut avoir une ambigut pour lextraction des units lexicales lors
de lanalyse lexicale. Expliquer.
11- Etant donn un langage de programmation. Quelles sont les tapes quon doit
entreprendre avant de commencer la ralisation dun compilateur ?
12- Y a t-il une technique pour le traitement des erreurs syntaxiques ? smantique ?
13- En quoi consiste lanalyse ascendante ? Quest-ce quun manche ? Quest-ce
quune rduction ? Cest quoi Elagage du manche ?
14- Quels sont les inconvnients de lanalyse par prcdence doprateur ? Quest-ce
quune grammaire doprateur ?
15- Quest-ce que le conflit Dcaler/Rduire ? Rduire/Rduire ?
16- Quels sont les conflits quon peut avoir lors de lanalyse syntaxique ascendante ?
est-ce quon peut avoir les mmes problmes en analyse descendante ? Quels sont
les problmes quivalents ?
17- Donner les inconvnients des diffrents analyseurs que vous connaissez.

Principes et Techniques de Compilation, N. Chenfour 49


Exercice :
Donner les automates tats finis dterministes engendrs par les expressions
rgulires suivantes :
1- (a | b)* a b b
2- 0 (0 | 1)* 0
3- ( ( | 0) 1* )* 0 0
4- (0 0 | 1 1)* 0 1 1
5- 0* 1 0* 1 0* 1 0*
6- ( ( | a ) b* )*
7- (a | b)* a (a (a |b) (a | b)
8- (a | b)* a b (a | b)*
9- (a | b)* a b b (a | b)* a b b
10- (a | b)* a b a b
11- (0 1+ | 0 1+ (0 | 1)+ | (0 | 1)+ 0 1
12- 0+ | 0+ 1 0+ | 0+ (0 | (0 1) )+

TP N 1 :
On demande la ralisation dun analyseur Lexical Turbo Pascal. Lanalyseur
doit savoir extraire toutes les units lexicales dun programme Pascal. Celles-ci seront
ranges dans une liste chane dont les lments sont caractriss par : le lexme,
lunit lexicale, la ligne sur laquelle se trouve le lexme. A la fin du programme, le
contenu de la liste est enregistr dans un fichier texte organis en 3 colonnes spar
par des espaces. Lanalyseur doit signaler toute prsence derreur tout en affichant la
ligne sur laquelle lerreur est rencontr. En fin lanalyseur affiche le nombre derreurs
lexicales trouves.
Les units lexicales identifier sont :
- Les identificateurs
- Les nombres
- Les commentaires (* *) et {} qui sont ignors
- Les Blanc qui sont aussi ignors
- Chanes de caractres
- Oprateurs de relation
- Oprateurs arithmtiques
- Loprateur daffectation
- Les blancs (espace, tabulation et retour chariot) sont ignors
- Les sparateurs : , ; ( ) [ ]
- Les oprateurs logiques
- Les mots cls

Principes et Techniques de Compilation, N. Chenfour 50


On utilisera la fonction suivante :

int AFD(Transition T, Etat A, Ulex NU)


{
int e=0;
char s = Tampon[ReadHead];
int save = ReadHead;
while (T[e][s]!=-1)
{
e=T[e][s];
ReadHead++;
s=Tampon[ReadHead];
}
if (strchr(A,e) && e!=0) {
free(Lexeme);
Lexeme = (char *) malloc(ReadHead save + 1);
strncpy(Lexeme, &Tampon[save], ReadHead save);
Lexeme[ReadHead save ] = 0;
UL = NU;
return 1;
}
else {
ReadHead = save;
return 0;
}
}

avec :
typedef int Transition [MaxEtat][256];
typedef char Etats [MaxEtat];
enum Ulex {id, nb, oprel, ...};

TP N 2 :
Ajouter lanalyseur lexical les fonctionnalits suivantes :
1- Les mots cls sont lus partir dun fichier Texte.
2- Tous les identificateurs seront stocks dans une structure de liste chane.
3- Les autres lexmes sont stocks dans une autre structure de liste chane deux
champs : (Lexme et Unit lexicale).
4- Toutes les erreurs sont stockes dans un fichier texte lex.err , on prcisant
lerreur et sa ligne doccurrence.
5- Les diffrentes units lexicales sont rimprimes lcran avec des couleurs
diffrentes

Principes et Techniques de Compilation, N. Chenfour 51


TP N 3 :
Soit un fichier texte contenant des squences de chiffres et des mots cls
brouills avec des caractres quelconques.
Exemple :
dgdg_-$ebegingte1254787547h*heg
Ecrire un analyseur lexical qui fait la recherche et lextraction de toutes les squences
de chiffres dont le nombre est fixe (10 par exemple) ainsi que tous les mots cls. On
dispose dun fichier texte de mots cls accepts. Le programme gnre un fichier de
sortie sur lequel il reprend uniquement les mots cls et les nombres accepts spars
par des espaces.

TP N 4 :
Ecrire un programme qui lit un fichier texte (en Turbo C++) et transforme
toute occurrence de { en Begin, } en end, printf en write et scanf en read,
dans un nouveau fichier.

TP N 5 :
Ecrire un programme qui reoit en entre le nom dun fichier texte
(programme C) et fait la suppression de tous les commentaires du fichier et met le
rsultat dans un deuxime fichier.

TP N 6 :
Ecrire une fonction qui reoit en paramtre une chane de caractres et vrifie
si elle appartient au langage engendr par la grammaire suivante :
S 0 S 1 | 01

TP N 7 : Ralisation dun Prprocesseur C


1- Ecrire une procdure StrSubst(char *S1, char *S2, char *S) qui remplace
toute occurrence de la chane S1 dans la chane S par la chane S2.
2- Ecrire une procdure FileSubst(char *S1, char *S2, char *Fichier) qui
remplace toute occurrence de S1 dans Fichier par S2.
3- Ecrire une procdure qui reoit en entre un fichier texte (programme C)
contenant des Macros (#define S1 S2) et en construit un nouveau fichier en
remplaant toute occurrence de S1 par S2.
4- Ecrire un programme qui reoit en entre un fichier texte contenant des
instructions (#include "" ) et en construit un nouveau fichier contenant le
programme dentre concatn avec les fichiers spcifis par #include.
5- Dduire la ralisation dun prprocesseur C.
6- Refaite la ralisation du prprocesseur en utilisant un analyseur lexical.

Principes et Techniques de Compilation, N. Chenfour 52


TP N 8 :
Ecrire un programme qui fait lindentation dun programme C. c..d organise
le programme laide des tabulations de manire obtenir un programme sous la
forme :
Main()
{


If ()
{


}

}
le symbole indique des tabulations.

TP N 9 :
Le problme suivant se compose de deux parties :
1- La premire partie consiste choisir des codes pour les diffrentes lettres de
lalphabet. Le code (appel code morse) sera constitu dune squence forme par
les symboles . et condition que le code ne soit pas uniforme (on nassocie pas
le mme nombre de symboles toutes les lette) et de ne pas avoir dambigut
pour les reconnaissance des codes.
Exemple : A = ".-", B = "-..-", etc.
Pour dterminer les codes de manire non ambigu, on propose alors un
algorithme qui dcoule de la mthode de Huffman :
Cela consiste raliser les tapes suivantes :
- Etape 1 : Associer chaque lettre de lalphabet une valeur entre 1 et 26.
Exemple : A  1, B  2,
- Etape 2 : regrouper squentiellement par paires de lettres de plus faibles valeurs.

Principes et Techniques de Compilation, N. Chenfour 53


Exemple :
On prend par exemple les lettres : A, B, C, D et E. et on leur associe
successivement les valeur de 1 5.

15
1
6 0
1 0

3 9
1 0 1 0

1 2 3 4 5

A B C D E

- Etape 3 : on obtient un arbre binaire, on code alors chaque fils gauche par 1 et
chaque fils droit par 0. Le code lue partir de la racine jusqu une feuille donne
le code binaire de la feuille. Dans lexemple on obtient :
A = 111, B = 110, C = 10, D = 01, E = 00
- Etape 4 : On remplace alors chaque 1 par et chaque 0 par ., on obtient :
A = ---, B = --., C = -., D = .-, E = ..
On demande alors de dterminer le code pour les 26 lettres de lalphabet on
appliquant la mthode prcdente. Transformer larbre de huffman en un AFD 26
tats accepteurs.
2- La deuxime partie consiste implmenter un analyseur lexical bas sur lAFD
obtenu en 1. Lanalyseur aura pour objectif de lire un fichier texte cod et de le
dcoder dans un deuxime fichier. la fonction AFD devra retourner chaque appel
ltat accepteur sur lequel on a aboutit. Cet tat sera utilis pour dterminer la
lettre correspondante.

TP N 10 :
Lobjectif de ce TP est limplmentation dun analyseur lexical.
Le travail sera alors divis en deux parties :

Partie N 1 :

Principes et Techniques de Compilation, N. Chenfour 54


1. Classe Scanner
Il sagit dune classe gnrale qui regroupe les fonctionnalits, gnrales et
indpendantes du langage, dun analyseur lexical. La classe Lex peut tre dfinie
laide de la structure suivante :

Class Scanner {
Unsigned char Tampon[MaxLen];
Unsigned char *Lexeme;
int UL;
int PtrDeb,PtrFin,Ltamp;
Fonction *TU ;
FILE *Source;
Public:
Lex();
Lex(char *NomFichier);
Int Refresh(); //Maj Tampon
int AFD(Transition T, Etats A, int idUL)
int Open(char *NomFichier);
void Load(Fonction u1,...);
int GetNext(char *Lexeme, int &UL);
void ErreurLexicale();
int NoMore(); // fin de fichier : UL = '$'
~Lex();
};

La classe Scanner utilise 3 types : Transition, Etats et Fonction qui sont dfinis
comme suit :
#define MaxEtat 25
typedef int Transition[MaxEtat][256];
typedef unsigned char Etats[MaxEtat];
typedef int (*Fonction)();

2. Principales mthodes de la classe


2.1 Mthode AFD
Il sagit de la mthode de base qui permet lanalyse du tampon dentre en
fonction dun automate fini dterministe associ lunit lexicale analyser
2.2 Mthode Refresh
Cette mthode est appele avant chaque tentative dextraction dunit lexicale
pour mettre jour le tampon dentre.
2.3 Mthode Open
Cest la mthode qui ouvre le fichier analyser. Elle doit tre appel avant
toutes les autre fonctions.
2.4 Mthode Load
Cette mthode permet de remplir le tableau des fonction dextractions dunits
lexicales TU. Elle reoit donc en paramtre une liste de noms de fonctions qui se
termine par NULL. Par exemple : identificateur, nombre,
Les fonctions ainsi obtenu seront utilises dans la fonction suivante.

Principes et Techniques de Compilation, N. Chenfour 55


2.5 Mthode GetNext
Il sagit de la fonction danalyse lexicale proprement dit. Elle effectue une
srie dappels au diffrentes fonctions danalyse lexicale (charges dans TU) pour
extraire la prochaine unit lexicale. Celle-ci sera alors retourne en paramtre. Dans le
cas derreur la mthode ErreurLexicale sera alors appele.
2.6 Mthode NoMore
Cest une fonction qui teste sil ny a plus rien analyser.

Partie N 2 :
Afin de tester les fonctionnalits de la classe Lex, on se propose de construire
une nouvelle classe qui se drive de la classe Lex et qui la complte. On remarque en
effet que la classe Lex ne dispose daucune des fonctions lexicales (identificateur,
nombre, etc..). Pour cela on ralise une classe Pascal qui dfinie les principales units
lexicales du langage Pascal.
La classe Pascal se prsente de la manire suivante :

class Pascal:public Lex {


public:
Pascal() {Load(Id,Nb,Oprel, ..., NULL);}
static int Id()
{
Etat A = {1} ;
Transition T ;
...
return AFD(T,A,id) ;
}
static int Nb()
{
...
return AFD(T,A,nb) ;
}
static int Oprel()
{
...
return AFD(T,A,oprel) ;
}
...
};
Les constantes id, nb, oprel sont les units lexicale associes au diffrentes fonctions
et peuvent tre dfinies comme des constantes dans un type numr :
enum {id, nb, oprel, } ;

Principes et Techniques de Compilation, N. Chenfour 56


Comme exemple dapplication, on peut crire le programme suivant :
void main()
{
char *Lexeme ;
int UL ;
Pascal P ;
P.Open("prog01.pas") ;
while (!P.NoMore()) {
if (P.GetNext(Lexeme, UL) ==1) {
Printf("%s : %d\n",Lexeme,UL) ;
}
}
}

TP N 11 :
Lobjectif de ce TP est limplmentation de lalgorithme LL(1) pour la
ralisation dun analyseur syntaxique descendant prdictif.
Le travail sera alors divis en deux parties :

Partie N 1 :

1. Classe LL1
Dans une premire partie du travail, on se propose dimplmenter une classe
LL1 dfinie par lintermdiaire de trois proprits de base qui sont la grammaire, la
table danalyse ainsi quun analyseur lexical. Ces 3 donnes vont constituer lentre
de lanalyseur (fournies donc via le constructeur). Une mthode Parse pouvant tre
appele par lintermdiaire dune instance de la classe LL1 pour analyser le fichier
fourni en paramtre. Elle retourne 0 ou 1 en fonction du rsultat de lanalyse. La
mthode Parse constitue une implmentation de lalgorithme LL(1). La classe LL1
aura alors la structure suivante :

Class LL1 {
Scanner *L;
Grammaire *G;
TabledAanalyse *TA;
Public:
LL1(Lex &L, Grammaire &G, TabledAanalyse
&TA);
int Parse(char *Fichier);
~LL1();
};

On remarque alors que la classe LL1 a besoin de 3 autres classes : Lex, Grammaire et
TabledAnalyse.

Principes et Techniques de Compilation, N. Chenfour 57


2. Classe Scanner
La classe Scanner tant la classe ralise dans le TP N 1.

3. Classe Grammaire
La classe Grammaire est une classe qui permet la construction des
grammaires. Elle est dfinie alors par un Attribut principal : Liste de produits. Elle
contient aussi dautres attributs tels que : laxiome, VT, VN, nombre de production
ainsi que la dsignation littrale de chaque symbole du vocabulaire. La classe
Grammaire fournie aussi une mthode principale : Production qui permet, chaque
appel, dajouter une nouvelle production la grammaire. Lutilisateur de la classe
pourra dfinir un type numr pour le vocabulaire et appeler la mthode par
intermdiaire des nom de constante quil a dfinie.
Exemple :
Soit la grammaire :
E  T E1
E1  + T E1 | - T E1 |

lutilisateur dfinira alors :
enum {E, E1, T, };
Pour construire la grammaire, il ralise les oprations suivantes :
Grammaire G;
G.production(E, T, E1, -1);
G.production(E1, +, T, E1, -1);
G.production(E1, -, T, E1, -1);
G.production(E1, -1);

La classe grammaire peut finalement avoir la structure suivante :


class Grammaire {
int Axiome, NbProd;
ListProd Prod;
int *VT, *VN;
char *Desig[];
public :
Grammaire();
int production(unsigned int pg,...);
//retourne le numro de production
void setAxiome(int S);
void setDesig(int S, char *D);
void afficher();
~Grammaire();
};

Principes et Techniques de Compilation, N. Chenfour 58


La structure ListProd (Liste des productions) est une structure de liste chane
dfinie par lintermdiaire des structure suivantes :
Typedef struct PtrListe { typedef struct { typedef struct Ptr {
int symbole; int pg; int Num;
PtrListe *suc; Chaine pd; Production p;
} *Chaine; } Production; Ptr *suc;
} *ListProd;

4. Classe TabledAnalyse
La classe TabledAnalyse est utilise pour introduire la table danalyse qui
sera utilise (ainsi que la grammaire) par lanalyseur LL1. Celle-ci contient donc une
donne T qui va recevoir le dtail de la table danalyse. Ainsi une nouvelle entre
dans la table danalyse sera ajoute par lintermdiaire de la mthode ajouter qui
reoit 3 paramtres : le non terminal, le terminal et le numro de la production. Le
remplissage de la table danalyse pourra tre fait paralllement celui de la
grammaire.
Exemple :
Pour introduire :
TA[E][(] = E  T E1
TA[E][id] = E  T E1
On peut crire :
Grammaire G;
TabledAnalayse TA;
int N = G.production(E, T, E1, -1);
TA.ajouter(E, (,N);
TA.ajouter(E, id, N);

Finalement la classe TabledAnalyse pourra avoir la structure minimale suivante :

class TabledAanalyse {
int *T;
public:
TabledAanalyse();
void ajouter(int NT,int T,int Num);
void afficher();
~TabledAanalyse();
};

Principes et Techniques de Compilation, N. Chenfour 59


5. Utilisation de la classe LL1
Etant donne maintenant que lon dispose des 4 classes prcdantes lcriture
dun programme danalyse pourra tre ralise comme suit :
Main() {
Lex L ;
Grammaire G ;
TabledAnalyse TA ;
Initialiser (G, TA) ;

LL1 A(L, G, TA);


char NF[80] ;
printf("Entrer le nom du fichier analyser : ") ;
gets(NF) ;
if (A.Parse(NF)) printf("aucune erreur") ;
else printf("Erreurs :") ;
}

Remarques :
Pour accder aux donnes des autres classes partir de lanalyseur LL1, il
pourrait tre ncessaire dajouter dautres mthodes aux diffrentes classes.
6. Test de lanalyseur LL1
Pour tester lanalyseur LL1 obtenu, on demande limplmentation dun
analyseur dexpressions arithmtiques.

Partie N 2 :
Afin de minimiser les efforts de frappe et la ncessit se recompilation des
modules on propose dajouter chacune des deux classes : Grammaire et
TabledAnalyse un constructeur permettant de charger les donnes partir de fichiers.
On ajoute alors la classe Grammaire le constructeur suivant :
Grammaire(char *NF);
Celui-ci va permettre de charger une grammaire quelconque partir dun fichier texte
donn par son nom. La structure du fichier pourra tre la suivante :
4
E  T E1
E1  + T E1
E1  - T E1
E1 
La premire ligne contient le nombre de productions, les lignes suivantes la liste des
productions.
La classe TabledAnalyse aura aussi un nouveau constructeur :

TabledAanalyse(char *NF);

Principes et Techniques de Compilation, N. Chenfour 60


Ce qui offre la possibilit de charger une table danalyse partir dun fichier texte. On
utilisera alors le mme fichier que celui des productions ; seulement les donnes de la
table danalyse viendront juste aprs la dernire production.
Exemple :
Pour crire la grammaire prcdente et reprsenter par exemple :
TA[E][(] = E  T E1
TA[E][id] = E  T E1
TA[E1][+] = E1  + T E1
TA[E1][-] = E1  - T E1
Le fichier aura la structure suivante (la ligne qui spare la grammaire de la table
danalyse ne doit pas figurer dans le fichier, elle est ajoute ici juste lexplication) :
4
E  T E1
E1  + T E1
E1  - T E1
E1 
1 2
E (
E id
2 1
E1 +
3 1
E1 -

La deuxime partie du fichier concernant la table danalyse se lit :


La production n 1 se trouve dans 2 cases :
TA[E][(] et
TA[E][id]
La production n 2 se trouve dans 1 case :
TA[E1][+]
La production n 3 se trouve dans 1 case :
TA[E1][-]

Raliser les deux constructeurs et crire un nouveau programme de test avec la


grammaire des expressions arithmtiques.

Principes et Techniques de Compilation, N. Chenfour 61