Académique Documents
Professionnel Documents
Culture Documents
Cours
De Compilation
Version 1
1
Contenu
I.1. Langages ....................................................................................................................................................................................... 5
I.2. Opérations sur les langages ....................................................................................................................................................... 5
I.3. Expression régulières ................................................................................................................................................................. 6
I.3.1 Définition .............................................................................................................................................................................. 6
I.3.2 Propriétés .............................................................................................................................................................................. 6
I.3.3 Diagramme régulier ............................................................................................................................................................. 6
II.1. Automate d'états Finis Non déterministe : AFN................................................................................................................. 8
II.1.1 Définition ............................................................................................................................................................................ 8
II.1.2 Graphe d'un automate....................................................................................................................................................... 8
II.2. Automate d’états Fini Déterministe AFD ............................................................................................................................ 9
II.2.1 Définition ............................................................................................................................................................................ 9
II.2.2 Simulation d'un AFD (Algorithme) ................................................................................................................................ 9
II.3. Liaison entre une expression régulière et un automate .................................................................................................... 10
II.3.1. Diagramme régulier associé à un automate ................................................................................................................ 10
II.3.2 Automate associé à un diagramme régulier ................................................................................................................. 10
II.3.3 Langage régulier associé à un automate .............................................................................................................. 11
III.1. Définitions de base ................................................................................................................................................................ 13
III.2 Arbre de dérivation ................................................................................................................................................................ 14
III.3 Ambiguïté ................................................................................................................................................................................. 14
III.4. Productions particulières ...................................................................................................................................................... 15
Partie 2
I.1. Introduction ............................................................................................................................................................................... 17
I.2. La structure d'un compilateur ................................................................................................................................................. 17
I.2.1 Analyse lexical .................................................................................................................................................................... 17
I.2.2 Analyse syntaxique ............................................................................................................................................................ 17
I.2.3 La production du code objet ........................................................................................................................................... 17
2-4 L'optimisation du code ....................................................................................................................................................... 18
2.5 La gestion de la table des symboles ................................................................................................................................... 18
2.6 Le traitement des erreurs .................................................................................................................................................... 18
II.1. Introduction ............................................................................................................................................................................. 19
II.2. Approche algorithmique ........................................................................................................................................................ 19
II.3 Automates.................................................................................................................................................................................. 21
II.3.1 Introduction ...................................................................................................................................................................... 21
II.3.2 Générateur d'analyseur syntaxique ................................................................................................................................ 22
III.1. Introduction............................................................................................................................................................................ 23
III.1.1 La méthode ascendante ................................................................................................................................................. 23
III.1.2 La méthode descendante............................................................................................................................................... 24
III.1.3 Déterminisme et ambiguïté .......................................................................................................................................... 25
III.1.4 Classe de grammaire LL(1) ........................................................................................................................................... 25
III.1.4.1. Premiers et suivants .............................................................................................................................................. 25
III.1.4.2 Classe de grammaire LL(1) ................................................................................................................................... 26
III.2. Descente récursive................................................................................................................................................................. 26
III.2.1 Construction de l'arbre syntaxique .............................................................................................................................. 29
III.2.1.1. Représentation de l'arbre: liens explicites (pointeurs) ............................................................................ 29
III.2.1.2 Représentation de l'arbre: liens implicites .......................................................................................................... 32
III.3. Analyse syntaxique prédictive .............................................................................................................................................. 35
III.3.1 Simulation ........................................................................................................................................................................ 35
III.3.2 Construction de la table de transition ......................................................................................................................... 36
III.3.3.Construction de l’arbre syntaxique .............................................................................................................................. 38
Partie 3
I.I. Introduction ............................................................................................................................................................................... 40
I.2. Contrôles sémantiques ............................................................................................................................................................. 40
I.2.1. Variable non déclarée ....................................................................................................................................................... 40
I.2.2 Variable non affectée ........................................................................................................................................................ 40
I.2.3 Conflits entre types ........................................................................................................................................................... 41
I.3. Arbre sémantique: coloration de l'arbre syntaxique ............................................................................................................ 41
2
I.3.1 Instruction affectation ...................................................................................................................................................... 41
I.3.2 Instruction conditionnelle ................................................................................................................................................ 42
I.3.2 Instruction itérative ........................................................................................................................................................... 42
II.1. introduction .............................................................................................................................................................................. 44
II.2. Algorithme générale d'un interpréteur ................................................................................................................................. 44
II.3. Exemple .................................................................................................................................................................................... 45
III.1. Introduction............................................................................................................................................................................ 48
III.2. Déclarations ............................................................................................................................................................................ 48
III.3. Algorithme générale d'un générateur de code machine .................................................................................................. 50
III.3.1 Méthode itérative: liens implicites ............................................................................................................................... 50
III.3.2 Méthode itérative : liens implicites .............................................................................................................................. 50
III.4. Exemple: Instruction d'affectation ..................................................................................................................................... 51
III.4.1 Expression sans parenthèses et sans priorité entre les opérateurs ........................................................................ 51
IV.1. Introduction ............................................................................................................................................................................ 53
IV.2. Structure de données ............................................................................................................................................................. 53
IV.3. Grammaire ......................................................................................................................................................................... 54
3
Partie 1
Introduction à la théorie des langages
4
Chapitre 1
Définitions et concept de base
I.1. Langages
Qu'est-ce qu'un langage ? Le dictionnaire Larousse répond «emploi de la parole pour exprimer
les idées. Tout moyen de communiquer la pensée »
Chomsky (1957) donne une définition formelle: « un langage L(G) engendré par une
grammaire G est l'ensemble de toutes les phrases possible, c'est à dire l'ensemble de toutes les
formes syntaxiques constituées uniquement des symboles terminaux ».
Aho et Ulllmm (1973) ont donné des définitions aux termes suivants:
Un vocabulaire ou alphabet V est un ensemble non vide de symboles.
Exemple: lettre= {A, B,…,Z} ; chiffre= { 0, 1, . . . ,9 } et binaire={ 0, 1} sont des alphabets .
Une chaîne (phrase ou mot) α sur un alphabet est une séquence finie de symboles extraits de
V. On note la longueur d’une chaine |α|. La chaine vide est désignée par l’un des symboles ^
ou ε.
Exemple : |banane|=6 la chaine banane a pour longueur 6. Remarquons aussi que |ε|= 0.
Un langage désigne un ensemble quelconque de chaines construites sur un alphabet fixé.
Exemple: {ε} est langage vide ; Pascal dont l'alphabet V={ program, begin, if, then ... end }
est un langage ; la langue française est un langage (langage naturel).
Si α et β sont deux chaines alors on définit :
la concaténation de α et β : αβ, par exemple α= porte et β= mine alors αβ=portemine.
αε=εα=α : ε est l’élément neutre pour la concaténation.
si on considère la concaténation comme un produit, alors : α0=ε et ∀𝑖 > 0 αi= αi-1 α et
comme εα=α alors α1=α.
I.2. Opérations sur les langages
A partir des langages bien définit, on construit d’autres langage en appliquant les opérations
décrites par le tableau ci-dessous:
Opération Définition
Union de L et M notée 𝐿 ∪ 𝑀 ou L+M 𝐿 ∪ 𝑀 = {𝛼 / 𝛼𝜖𝐿 𝑜𝑢 𝛼 ∈ 𝑀 }
Concaténation de L et M notée LM 𝐿𝑀 = {𝛼𝛽 / 𝛼𝜖𝐿 𝑒𝑡 𝛽 ∈ 𝑀 }
*
Fermeture de Kleene de L notée L 𝑖=∞ 𝑖
𝐿∗ = 𝑈𝑖=𝑛 𝐿
+
Fermeture positive de L notée L 𝑖=∞
𝐿 = 𝑈𝑖=1 𝐿𝑖
+
5
I.3. Expression régulières
I.3.1 Définition
Dans cette section, on va présenter une notation, appelée expressions régulières, qui nous
permettra de définir avec précision les langages de ce genre.
Exemple : En Pascal un identificateur est définit comme suivant : lettre(lettre |chiffre)*.
Voici les règles qui définissent les expressions régulières sur un alphabet v :
1. ε est une expression régulière qui dénote le langage L = {ε}.
2. Si 𝑎 ∈ 𝑉, alors a est une expression régulière qui dénote le langage L ={ a}.
3. Supposons que r et s soient des expressions régulières dénotant les langages L (s) et L(r) :
(𝑟) ∪ (𝑠) est une expression régulière dénotant 𝐿(𝑟) ∪ 𝐿(𝑠)
(𝑟)(𝑠) est une expression régulière dénotant L(r)L(s)
(𝑟)∗ est une expression régulière dénotant L(r).
(r) est une expression régulière dénotant L(r).
Exemple: Soit V= {a,b} alors
a|b est une expression régulière dénotant L={a,b} ;
(a|b) (a|b)=aa|ab|ba|bb est une expression régulière dénotant L={aa,ab,ba,bb} ;
a* est une expression régulière dénotant L={ε, a, aa, aaa, …} ;
(a|b)* est une expression régulière dénotant L={ε, a, aa, aa, …,b,bb,…,ab,aab,…,ba,bba,…} ;
a|a*b dénote L={a,b,ab,aab,aaab,…} ;
Si deux expressions r et s régulières dénotent le même langage, on dit que r et s sont
équivalentes et on écrit r=s. Par exemple (a|b)=(b|a)
I.3.2 Propriétés
Les expressions régulières obéissent à un certain nombre de propriétés algébriques:
Axiome Description
r|s=s|r | est commutatif
r|(s|t)=(r|s)|(r|t) | est associatif
(rs)t=r(st) La concaténation est associative
r(s|t)=rs|rt La concaténation est distributive à gauche par rapport à |
(s|t)r=sr|tr La concaténation est distributive à droite par rapport à |
εr=rε=r ε est l’élément neutre pour la concaténation
r*=(r|ε)* Relation entre * et ε
r** * est idempotent
Pour commodités de notation on donne des noms aux expressions régulières:
di → ri qui se lit: l'expression régulière ri a pour nom di
Exemples :
Pour lettre ={A=, 8 , . . . , Z , a , b , . . . , Z} on a lettre → A|B|...|Z|a|b|…|z .
Pour chiffre = (0, 2, ..., 9) on a chiffre → 0|1|2|2|…|9.
Pour un identificateur on écrit: id → lette (lettre |chiffre)*.
I.3.3 Diagramme régulier
Un diagramme régulier D sur l’alphabet V est un quintuple (P, I, F, ψ, μ) :
1. P est un ensemble fini non vide appelé ensemble des places ;
6
2. I ⊂ P P appelé ensembles des places initiales,
3. F ⊂ P ensembles des places finales ;
4. ψ : P →P qui associe à chaque place p un sous-ensemble ψ(p) ⊂ P, noté p!
5. μ : P →V application qui associe à chaque place p un élément μ(p) ∈ 𝑉 appelé marque de p
Exemple: Soit l'expression régulière A→ (al ac)+|bc, le diagramme correspondant est :
Proposition 1 : si deux langages L(r) et L(s) sur l'alphabet V sont représentables chacun par un
diagramme régulier alors :
1. 𝐿(𝑟) ∪ 𝐿(𝑠) = 𝐿(𝑟) + 𝐿(𝑠) est représentable par un diagramme régulier ;
2. L(r)L(s) est représentable par un diagramme régulier;
3. (L(r))+ est représentable par un diagramme régulier;
Tout langage régulier sur un alphabet V peut être représenté par un diagramme régulier
Proposition 2 : Tout langage régulier sur un alphabet V peut être représenté par un diagramme
régulier.
7
Chapitre 2
Automates d'états finis
8
II.2. Automate d’états Fini Déterministe AFD
II.2.1 Définition
Un AFD est un cas particulier de l'AFN dans lequel:
1. Aucun état n'a de ε-transition: ∀ 𝑞𝜖𝐸, il n’existe pas e ∈ 𝐸,/ 𝑒𝜀 → 𝑞
2. Si ea →q et ea →p, alors p=q: il y a au plus un arc étiqueté a qui quitte e.
Un AFD accepte une chaine d'entrée s si et seulement s'il existe au moins un chemin dans le
graphe de transition entre l'état de départ et un état final.
II.2.2 Simulation d'un AFD (Algorithme)
Données: Une chaine d'entrée x et un AFD D = (E, ∑, e0 T, F).
Résultat: La réponse « oui » si D accepte x, « non » sinon
debut
etat=e0
Répéter
sym=Symbole() ;
etat=Transit[etat,sym] ;
Jusqu’à (etat ∈ 𝐹) ou(etat=erreur)
si (etat=erreur) alors afficher( « non » sinon afficher « oui » ) ;
Fin
S1 S2 Sl Sp
0
1
.
.
i
.
.
n-1
Transit est la matrice de transition de l'AFD; elle est de la forme:
L'entrée d'une ligne représente un état, celle d'une colonne représente le numéro symbole.
un élément de la matrice est soit un état, soit un code d’erreur.
Le rôle de la fonction Symbole est simplement le codage des symboles:
fonction Symbole( s : caractère) :entier
code : entier0
debut
selon s faire
‘s1’ : code=1 ;
‘sj’ : code =j ;
.
.
‘sp’ : code =p ;
finselon
Symbole=code ;
finfonct
Exemple : Soit AFD qui accepte le langage (a|b)*abb
9
II.3. Liaison entre une expression régulière et un automate
II.3.1. Diagramme régulier associé à un automate
A tout automate A=(E, ∑, e0, T, F), on peut associer un diagramme régulier D=(P, I ,F,ψ,μ)
qui de façon évidente représente le même langage. Pour fixer les idées, nous considérons
l’automate suivant :
10
L’ensemble des sommets du graphe de transition E est l’ensemble des places du diagramme
régulier P augmenté d’un élément e0 distinct de toutes les places E=P+{e0}
L’ensemble des transitions du graphe T est construit selon les règles suivantes :
11
Lt(1-a-b)=Lzb
c’est à dire
𝐿𝑧 𝑏
𝐿𝑡 = = 𝐿𝑧 𝑏(1 + (𝑎 + 𝑏)2 + ⋯ + (𝑎 + 𝑏)𝑛 + ⋯ ) = 𝐿𝑧 𝑏(𝑎 + 𝑏)∗
(1 − (𝑎 + 𝑏))
or Lz=Lya donc 𝐿𝑡 = 𝐿𝑦 𝑎𝑏(𝑎 + 𝑏)∗
et 𝐿𝑧 = 𝑎 ∗ 𝑏(𝑏 + 𝑎2 )∗ 𝑎
Attention la multiplication n’est pas commutative
12
Chapitre 3
Les Grammaires
13
De ces 4 types, le plus important pour nous est le type 2. En effet, une grammaire indépendante
du contexte peut être utilisée pour spécifier la structure syntaxique des langages de programmation
et la base des schémas de traduction.
III.2 Arbre de dérivation
Un arbre de dérivation D (ou arbre syntaxique) pour une grammaire G(VT,VN,S,P) est arbre
ordonné dont les nœuds appartiennent à 𝑉𝑇 ∪ 𝑉𝑁 ∪ {𝜀} et tel que:
S est la racine de D.
Si les Di (i=1..k) sont les sous arbres de racines Xi et les Xi sont les descendants directs de la
racine de D alors (S → X1X2…Xk ) ∈ P.
𝑋𝑖 ∈ 𝑉𝑁 ⇒ 𝐷𝑖 est arbre de dérivation pour G(VT,VN,S,P)
𝑋𝑖 ∈ 𝑉𝑇 ⇒ 𝐷𝑖 est le nœud Xi
D1 est le seul sous arbre issu de la racine de D1 et la racine de D1 est ε : (S→ε) 𝜖 P.
14
E→E+E
E→E*E
E→(E)
E→ id
G est ambigus, car dans la phrase « a+b*c », elle ne spécifie ni l'associativité ni la priorité des
opérateurs + et *. On a donc pour cette phrase au moins deux arbres de dérivations :
15
Partie Il
Analyse des chaines
16
Chapitre 1
Etapes d'un compilateur
I.1. Introduction
L'analyse syntaxique peut être définie comme la détermination de l'arbre syntaxique d’une
chaine d'entrée donnée.
Cette analyse doit déterminer si la chaine d’entrée est syntaxiquement correcte, c'est à dire si
elle peut être dérivée par les productions du langage.
Il faut distinguer la syntaxe qui détermine si la chaine appartient au langage de la sémantique
qui analyse le sens de la chaîne.
Enfin, en général ce ne sont pas les chaines d'un programme source qui constituent l'entrée de
l'analyseur syntaxique, mais les chaines de sortie d'un premier analyseur : l'analyseur lexical
Cette brève introduction à la théorie des langages permet maintenant une description plus
complète d'un compilateur.
I.2. La structure d'un compilateur
Un compilateur peut être subdivisé en différentes phases:
1. L'analyse lexicale.
2. L’analyse syntaxique.
3. La production du code objet
4. t'optimisation du code.
5. La gestion d'une table des symboles.
6. le traitement d’erreurs.
Nous distinguerons les passes qui nécessitent à chaque fois un lecture du texte source des
phases qui constituent des opérations logiquement distinctes.
I.2.1 Analyse lexical
Son rôle est de lire le texte, de former des entités (tokens), d’éliminer les informations inutiles
(blancs, commentaires,...) et de présenter une chaine d’entrée à l’analyseur syntaxique.
I.2.2 Analyse syntaxique
Son rôle est de construire l'arbre syntaxique de deux manières différentes:
Analyse syntaxique ascendante (bottom up):
L'analyseur cherche, à partir de la phrase et à l’aide des règles de la grammaire, à remonter
à l'élément initial (on monte des feuilles vers la racine).
Analyse syntaxique descendante (top down)
L’analyseur cherche, à partir de l'élément initial et à l'aide des règles de la grammaire, à former
la phase donnée (on descend de la racine vers les feuilles).
I.2.3 La production du code objet
Le but final d'un compilateur est la production d'un texte en langage objet. Ce dernier peut
être un code intermédiaire, le code machine d'un ordinateur fictif. le code machine d'une machine
réelle (langage d'assemblage ou binaire) ou du macro code
17
2-4 L'optimisation du code
Le code produit par le compilateur doit être performant. C’est-à-dire rapide à l’exécution et
peu couteux en place mémoire. Nous pouvons distinguer ;
Les optimisations indépendantes de la machine ;
Les optimisations dépendantes de la machine.
2.5 La gestion de la table des symboles
Un compilateur doit construire, modifier et consulter une table des identificateurs tout au long
de son action. L'accès à cette table doit être très rapide et se baser sur des techniques telles que la
recherche dichotomique (binaire), les arbres binaires ou le <hash coding>.
2.6 Le traitement des erreurs
Un compilateur doit détecter des erreurs lexicales, syntaxiques ou sémantiques, donner des
diagnostics clairs et précis et être capable de poursuivre l'analyse du texte source.
18
Chapitre 2.
Analyse lexicographique
II.1. Introduction
L'analyse lexicale consiste à segmenter un texte source en un ensemble de mots que l'on
appelle traditionnellement « tokens »(leur terme exact est « lexème », ce qui signifie unité lexicale).
Il s'agit d'une part de déterminer la suite des caractères comprenant le token, et d'autre part
d’identifier le type de token (identificateur, nombre, opérateur, etc.).
Par exemple le texte suivant:
Totol :=T25+2.5*Totol ;
L'analyseur lexical doit être capable de comprendre qu'il s'agit de la suite de tokens suivants
Ident Toto1
Affectation :=
Identf T25
Op.arith +
Flottant 2.5
Op.arith *
Ident Toto1
Séparateur ;
Comment faire ? Nous envisagerons d'abord des techniques simples d:ns lesquelles l'analyseur
lexical sera construit « à la main ». Puis, nous verrons que cette analyse peut être formalisée par
l'intermédiaire d'automates finis. Enfin, Nous essayerons d'en dégager une technique générale
pour construire ce que l’on appelle des générateurs d'analyseurs (ex : le programme lex sur Unix).
II.2. Approche algorithmique
L'approche algorithmique consiste à traiter le problème directement en essayant d'écrire
directement à partir d'une idée intuitive de ce qu'est un mot.
On suppose que l'on dispose des fonctions suivantes:
Lire(car) : lit un caractère car à partir du clavier ou d'un fichier.
Chiffre(car) : teste si le caractère car et un chiffre.
Lettre(car) : teste si le caractère car est un caractère.
L’exemple 1 présente une action traduisant l’analyseur lexicale d’un langage dont l’alphabet
contient :
les identificateurs, les constantes entières;
les symboles de comparaison : <,>, ≤,≥, == et !=
les opérateurs : +,-,* et /
le symbole d’affectation : =,
la ponctuation: , et ; ...
L’exemple 2 présente est une fonction en langage C traduisant l'analyseur lexicale d'un langage
dont l'alphabet est semblable est celui de l'exemple 1. Les fonctions Lire(car), Chiffre(car) et
19
Lettre(car) sont remplacées respectivement par les instructions car=getc(pf), isdigit(car) et
isalpha(car).
Exemple 1 Exemple 2
20
II.3 Automates
II.3.1 Introduction
Idée: on considère que lire un caractère peut faire passer d'un état dans un autre. Par exemple :
si je viens de lire le symbole = et suis à l'état 5, alors je passe à l'état 8. Les automates sont
souvent donnés sous la forme d'un graphe : les états sont les nœuds du graphe et les arcs
correspondent à la fonction de transition.
Graphe d’automate
Matrice de transition
, ; . % L C > > = | + - * / ≠
T 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
0 1 1 1 2 3 4 5 5 5 5 6 6 6 6 -1
1 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
2 2 2 2 7 2 2 2 2 2 2 2 2 2 2 2
3 9 9 9 9 3 3 9 9 9 9 9 9 9 9 9
4 9 9 9 9 9 4 9 9 9 9 9 9 9 9 9
5 9 9 9 9 9 9 9 9 8 9 9 9 9 9 9
6 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
7 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
8 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
Action Lexico
us=^ ; /*initialisation de l’unité lexicale à vide */
Etat=0 ; /* on commence à l’état intial 0 */
Répéter
Lire(car) ;
Sym=Symbole(car) ;
Etat=T[Etat, Sym] ;
Selon Etat faire
1 : us=us+car ; /* ponctuations : , ; et . */
2:; /*commentaire */
3 : us=us+car ; /*identificateur */
4 :us=us+car ; /* nombre entier */
5 : us=us+car ; /* >,<,= et | */
6: us=us+car ; /* operateurs +,-,* et / */
7: ; /fin commentaire */
8: us=us+car ; /* ≥ , ≤, == et != */
9 : si car ∈ {‘ ‘, \n, \t, fin fichier} alors ecrire(« Erreur Lexicale ») ;
21
-1 : ecrire(« Erreur lexicale ») ;
FinSelon
Jusqu’à (Etat=-1) ou (Etat=9) ; /*Etats finaux */
Fin Action
Remarque : la fonction symbole fait correspondre à chaque symbole un numéro
II.3.2 Générateur d'analyseur syntaxique
A partir des expressions régulières, on peut définir des automates qui reconnaissent le lexique
d’un langage particulier. Et -il existe des algorithmes permettant de passer d'une expression
régulière à un automate.
Malheureusement, il est difficile d’écrire simplement les automates qui correspondent à une
expression régulière un peu compliquée. Pour cela, on utilise souvent un générateur d’automates
finis déterministes comme par exemple lex sous Unix
Pour plus de détail sur lex, exécuter la commande" man lex" sous Unix.
22
Chapitre 3
Analyse Syntaxique
III.1. Introduction
Définition intuitive: l’analyse syntaxique est l'une des opérations majeures d’un compilateur
qui consiste à indiquer si un texte est grammaticalement correct et à en tirer une représentation
interne, que l'on appelle arbre syntaxique ou arbre abstrait.
Définition formelle: Soit G=(VN,VT,P,S) la grammaire d'un langage L et 𝑥 ∈ 𝑉𝑟∗ une chaîne,
l'analyse syntaxique de L est le processus d'établissement d'une correspondance entre l’axiome S
et la chaine terminale x.
A l'issue de ce processus on a deux possibilités:
𝑥 ∈ 𝐿(𝐺) : on peut construire l'arbre syntaxique associé à la chaîne terminale.
𝑥 ∈ 𝐿(𝐺) : la chaine est refusée
23
Régle de réduction Chaine intermédiaires Arbre Syntaxique
E→a (a=(b+a))
E→b (E=(b+a))
E→a (E=(E+a))
E→(E+E) (E=(E+E))
R→E=E (E=E)
R→B (B)
A→B A
(a= (b+a))
Parmi les techniques ascendantes, on trouve:
La présidence d'opérateur (Floyd. 1963)
La simple précédence (W irth, 1966)
La précédence faible (lchbiah et Morse, 1970)
Les matrices de transitions (Sarnelsone t Bauer, I960)
Les analyseurs LR(k) (Aho et Johnson1,1974, Aho et Ullman, 1973).
L'entier k dans les analyseurs LR(k) désigne que pour une chaine terminale x, il suffit de
connaître k éléments à partir de l'élément courant pour décider sans ambiguïté de la règle de
production à appliquer. Il existe des générateurs d’analyseurs syntaxiques ascendants LR (l), dont
le plus connu est le yacc (Yer another compiler compiler) sous unix. Pour plus d'informations sur
le yacc tapez la commande suivante sur un terminal unix: man yacc
III.1.2 La méthode descendante
Dans la méthode descendante on part de l'axiome de la grammaire pour arriver à la chaîne
donnée par la dérivation la plus à gauche.
Exemple :
Soit G=(VN,VT,P,S) avec VN={<ESS>, <CH>}, Vr={0,1,…,9}, S={<ESS>}
et
P={<ESS> ::=<CH>, <ESS> :=<CH><ESS>, <CH> :=0|1|…|9 } une grammaire
et
x=7346 une chaine à analyser.
Les étapes de processus d’analyse syntaxique de la chaine x=7346 est résumé par le
tableau suivant :
Règles appliquées Chaine intermédiaires ESS syntaxique
<ESS> :=<CH><ESS> <ESS>
<ESS> :=7 <CH><ESS>
<ESS> :=<CH><ESS> 7<ESS>
<ESS> :=3 7<CH><ESS>
<ESS> :=<CH><ESS> 7 3 <ESS>
<ESS> :=4 7 3 <CH> <ESS>
<ESS> :=<CH> 7 3 4 <ESS>
<ESS>:=6 7 3 4 <CH>
6 3 4 6
24
La descente récursive (Lucas, 1961; Wirth, l97l)
Les analyseurs LL(k) dite prédictives ( Knuth,l 97l) qui sont des versions non récursives de la
descente récursive.
L'entier k dans les analyseurs LL(k) désigne que pour une chaîne terminale x, il suffit de
connaitre k éléments à partir de l'élément courant pour décider sans ambigüité de la règle de
production à appliquer.
III.1.3 Déterminisme et ambiguïté
Analyseur syntaxique non déterministe : on ne dispose pas de critères pour choisir la règle
à appliquer. Dans ce cas, on n’aura pas plusieurs arbres syntaxiques possibles pour une même
chaine terminale.
Analyseur syntaxique déterministe : on dispose de critères permettant de choisir sans
ambigüité la règle de production à appliquer à chaque fois que le problème de choix se pose.
L'arbre syntaxique est unique dans ce cas.
Grammaire ambiguë : si l’analyseur syntaxique est non déterministe, on dit que la grammaire
associée est ambiguë.
Exemple :
Soit G=({S,A}, {a,b,c,+,$} ,{S’ :=S$, S :=A+A, A :=S|a|b|c},S’ ) et la chaine x=a+b+c;
Pour cette chaine, on deux arbre syntaxiques dans la grammaire est ambiguë.
25
III.1.4.2 Classe de grammaire LL(1)
Soit G=(VN,VT,P,S) , 𝛼𝑖 𝜖𝑉 ∗ , 𝑖 = 1 à 𝑛 𝑒𝑡 𝐴 ∈ 𝑉𝑁
𝑃𝑟𝑒𝑚(𝛼𝑖 ) ∩ 𝑃𝑟𝑒𝑚(𝛼𝑗 ) = { }, 𝑖 ≠ 𝑗 𝑒𝑡 𝛼𝑖 , 𝛼𝑗 ≠ { }
𝐺 𝑒𝑠𝑡 𝐿𝐿(1) ⇔ ∀𝐴 → 𝛼1 |𝛼2 | … 𝛼𝑛 {
𝑆𝑖 ∃𝑖 𝛼𝑖 →∗ ^^𝑎𝑙𝑜𝑟𝑠 𝑃𝑟𝑒𝑚(𝛼𝑗 ) ∩ 𝑆𝑢𝑖𝑣(𝐴) = { }, ∀𝑖 ≠ 𝑗
Donc, pour rendre une grammaire LL(1), il faut transformer les règles citées de la façon
suivante :
𝐴 → Aβ|α ⟹ A → αX et X → ^|βX
𝐴 → Bα|Bβ ⟹ A → BX et X → α|β
Autre : Erreur ;
26
finSelon
FinSi
Fin
Exemples
(1) <prog> ::= ‘debut’<ListeInst>’fin’
(2) <ListeInst> ::= <Inst>|<Inst>’ ;’<ListeInst>
(3) <Inst> ::= idf ‘ :=’<expa>
(4) <expa> ::= <expa1>|<expa>’+’ <expa1>|<expa>’-’ <expa1>
(5) <expa1> ::= <expa2>|<expa1>’*’ <expa2>|<expa1>’/’ <expa2>
(6) <expa2> ::= ‘(‘ <expa> ‘)’ | idf| cste
Transformons d’abord la grammaire pour qu’elle soit LL(1). En effet, les regles (2), (4) et (5)
ne sont pas LL(1). En appliquant les transformations vues dans le paragraphe 1.4.2, la grammaire
devient :
(1) <program> ::= ‘debut ‘ <liste inst> ‘fin’
(2’) <list inst> ::= <instruction><suite inst>
(2’’) <suite inst> ::= ^|’ ;’ <liste inst>
(3) <instruction> ::= idf ‘ :=’ <expa>
(4’) <expa> ::= <expa1><suite expa1>
(4’’) <suite expa1> ::= ^|’+’<expa1><suite expa1> |’-‘<expa1><suite expa 1>
(5’) <expa1> ::= <expa2><suite expa2>
(5’’) <suite expa 2> ::= ^|’*’<expa2><suite expa2>|’/’<expa2><suite expa2>
(6) <expa2> ::= ‘(‘<expa>’)’|idf|cste
27
Action SuiteExpa1
Si us≠’fin’ et us ≠’ ;’ alors
Si us=’+’ alors
Lexico(us) ;
Expa1 ;
SuiteExpa1 ;
Sinon
Si us=’-‘ alors
Lexico(us) ;
Expa1 ;
SuiteExpa1 ;
Sinon Erreur(‘+ ou – attendu ‘) ;
Finsi
Finsi
Fin
Action ListeInst
Instruction ;
SuiteInst ;
Fin
Action Expa
Expa1 ;
SuiteExpa1 ;
Fin
Action Expa1
Expa2 ;
SuiteExpa2 ;
Fin
Action SuiteExpa2
Si us ∉{‘fin’, ‘+’,’-‘} alors
Si us=’*’ alors
Lexico(us) ;
Expa2 ;
SuiteExpa2 ;
Sinon
Si us=’/’ alors
Lexico(us) ;
Expa2 ;
SuiteExpa2 ;
Sinon Erreur(‘* ou / attendu’) ;
FinSi
FinSi
Fin
Action Expa2
Si identif(us) ou conste(us) alors
Lexico(us) ;
Sinon
Si us=’(‘ alors
Lexico(us) ;
Expa ;
Si us=’)’ alors Lexico(us)
Sinon Erreur(‘) attendu’) ;
28
Sinon Erreur(‘opérande ou ( attendu’) ;
FinSi
Fin
III.2.1 Construction de l'arbre syntaxique
En vérifiant la syntaxe d’un programme, on en profite pour rassembler le maximum
d’informations sous forme des structures de données qui permettent ultérieurement d’être
indépendant de l’analyseur syntaxique et de faciliter les autres phases de construction d’un
compilateur telles que l’analyse sémantique, la génération de code et l’optimisation de code.
Ces structures sont en générale :
Une ou plusieurs tables des symboles, qui rassemblent les informations sur les variables, les
constantes, les noms des procédures et des fonctions, les étiquettes, .... En générale, il s'agit
d'informations sur la partie déclarative d'un programme.
Un arbre syntaxique, qui représente la partie dynamique du programme. En générale, il s'agit
de la liste d'instructions
Cette traduction ce fait par l'insertion des appels d'actions supplémentaires au sein des
procédures de l'analyseur syntaxique, à des endroits adéquats. Ainsi, on associe à chaque règle de
production de la grammaire, une ou plusieurs actions qui permettent d'obtenir l'arbre. Les noms
des actions insérées dans une règle sont traités comme des non terminaux. Lorsque le nom d'une
action suit immédiatement un élément terminal, l'acquisition de l'unité syntaxique suivante suit
l'appel de l'action correspondant au nom de l'action.
Exemple A ::=BafC
B
Si us=’a’ alors
f;
Lexico(us) ;
C
Sinon
Erreur(‘ a attendu’) ;
Finsi
La définition de ces actions nous entraînent à choisir ses structures de données (problème
algorithmique). Ainsi, on a plusieurs stratégies pour représenter l’arbre et les tables des symboles:
représentation de l'arbre avec des liens explicites (pointeurs) ou avec des liens implicites
(tableaux);
représentation des tables avec des liens explicites (pointeurs), avec des liens implicites
(tableaux)
Représentation hybrides où on mélange les deux stratégies
29
(7) <Type> ::= entire f11|reel f12
(8) <ListeInst> ::= <Instruction><SuiteInst>f25
(9) <SuiteInst> ::= ^fnil|’;’<ListeInst>
(10) <Instruction> ::= idf f02 ‘ :=’ <Expa> f26
(11) <Expa> ::= <expa1><SuiteExpa1>f27
(12) <SuiteExpa1> ::= ^fnil | ‘+’<Expa>fplus|‘-’<Expa>fmoins
(13) <Expa1> ::= <Expa2><SuiteExpa2>f28
(14) <SuiteExpa2> ::= ^fnil | ‘*’<Expa1>fmul|‘/’<Expa1>fdiv
(15) <expa2> ::= ‘(‘<exp>’)’|idff03|cstef04|cster f05
Construisons d'abord pour chaque règle le sous arbre correspondant:
Sous arbre Racine Nb fils Valeurs possibles
<prog> Prog 2 {prog}
<ListeDec> Listedec 2 {listedec}U{valeurs possibles d’un nœud <Dec>}
<Dec> Entier/reel 1 {entier, réel }
<ListeVar> Listevar 2 {idf, listevar}
<ListeInst> ListeInst 2 {listeInstr}U{valeur possibles d’un nœud <Instr>
<Inst> Affect 2 {affect>
<expa> Plus/moins 2 {plus, moins}U{valeur possibles d’un nœud <expa1>}
<expa1> Mul/div 2 {mul,div}U{valeurs possibles d’un nœud <expa2> }
<expa2> Idf/cste/cstr 0 {idf,cste,cstr}U{valeurs possibles d’un nœud <Expa> }
Ce tableau, nous amène à définir les structures suivantes:
Déclaration en Pascal Declaration en C
NomNoeud={prog, listedec, listevar, listeinst, Enum NomNoeud
entier, reel, affect, plus, moins, mul, div, idf, cste) { prog,
Pnoeud=^Nœud ; listedec,
Nœud=Record listevar,
Nom :NomNoeud listeinst,
Case Nom of entier,
idf, cste : (val :integer) ; reel,
cstr : (val:reel) affect,
entier, reel :(fils :Pnoeud) ; plus,
prog, affect, moins,
listedec,listevar mul,
listeinst, div,
plus,moins idf,
mul,div : (fg, fd :Pnoeud) ; cste
end ; }
Typedef struct Nœud
{
int Nom ;
Union
{
int idf, cste ;
float cstr ;
struct Nœud*fils ;
struct Nœud*fg,*fd ;
}
}Tnoeud ;
30
p^.fd=pd ;
p^.Nom=prog ;
fin ;
Action f22
Nouveau(p)
p^.fg=pg ;
p^.fd=pd ;
p^.Nom=listedec ;
fin ;
Action f23
p^.fils=pd ;
fin ;
Action f24
Nouveau(p)
p^.fg=pg ;
p^.fd=pd ;
p^.Nom=listevar ;
fin ;
Action f25
Nouveau(p)
p^.fg=pg ;
p^.fd=pd ;
p^.Nom=listeinst ;
fin ;
Action f26
si (fd <>NIL) alors
Nouveau(p) ;
Selon cus faire
plus : p^.Nom=plus ;
moins : p^.Nom=moins ;
Fselon
p^.fg=pg ;
p^.fd=pd ;
Fsi;
fin
Action f27
si (fd <>NIL) alors
Nouveau(p) ;
Selon cus faire
mul : p^.Nom=mul ;
div : p^.Nom=div ;
Fselon
p^.fg=pg ;
p^.fd=pd ;
Fsi;
fin
Action f11
Nouveau(p)
p^.Nom=entier ;
fin ;
Action f12
Nouveau(p)
p^.Nom=réel ;
fin ;
Action f01
Nouveau(p)
31
p^.Nom=idf ;
fin ;
Action f02
Nouveau(p)
p^.Nom=idf ;
fin ;
Action f03
Nouveau(p)
p^.Nom=idf ;
fin ;
Action f04
Nouveau(p)
p^.Nom=cstc ;
p^.Val=ConvEntier(us) ;
fin ;
Action f05
Nouveau(p)
p^.Nom=cstc ;
p^.Val=ConvReel(us) ;
fin ;
Action fnil
p=NIL ;
fin ;
Action fplus
cus=plus ;
fin ;
Action fmoins
cus=mul ;
fin ;
Action fdiv
cus=div ;
fin ;
III.2.1.2 Représentation de l'arbre: liens implicites
Dans ce cas, l’arbre syntaxique est représenté par des tableaux à une ou plusieurs dimensions.
En générale :
la partie dynamique de la grammaire est représentée par un vecteur
la partie statique est représentée par une ou plusieurs tables d’enregistrement (table des
symboles, table des constantes,...)
Et pour faciliter le parcourt et/ou le traitement des informations stockées dans l’arbre, on
représente ce dernier sous sa forme post fixée généralisée:
Voici quelques exemples d'expressions sous forme post fixée:
B+C est remplacée par BC+
A=(A*B+C))-1 est remplacée par AABC+*1:=
Exemple : reprenant l’exemple du paragraphe précédent.
Ecrivons un programme dans ces langages :
debut
entier i,j ;
réel x,y,z ;
i=4,j=9 ;
32
x=0.5 ;
y=x*(i+j) ;
z=y+x*(i-j) ;
fin
a) Déclarations
Les déclarations sont utilisées pour:
indiquer la nature des objets utilisés dans un langage de programmation, ce qui permet de
détecter des opérations interdites et/ou de signaler le besoin d'une conversion
réserver la place en mémoire pour chacun des objets.
D'où les structures suivantes, constituées d’une table des symboles, d’une table des constantes
et d’un vecteur représentant l’arbre :
tds
b) instructions
Représentons l’arbre sous sa forme post fixe
Arbre i 4:= j9:= x0.5:= yxij+*:= zyxij-*/:=
Cet arbre est construit aussi par l’insertion des actions à des endroits adéquats.
(1) <prog> ::= ‘debut’f1<ListeDec><ListeInst>’fin’f2
(2) <ListeDec> ::= <Dec><SuiteDec>
(3) <SuiteDec> ::= ^|<ListeDec>
(4) <Dec> ::= <Type><ListeVar>
(5) <ListeVar> ::= idf ft1 <SuiteVar>
(6) <SuiteVar> ::= ^|’ ;’<ListeVar>
(7) <Type> ::= entier ft2|réel ft3
(8) <ListeInst> ::= <Instruction><SuiteInst>
(9) <SuiteInst> ::= ^|’ ;’<ListeInst>
(10) <Instruction> ::= idf fa1 ‘ :=’ <expa> fa2
(11) <Expa> ::= <Expa1><SuiteExpa1>
(12) <SuiteExpa1> ::= ^|’+’<Expa>fa3|’-’<Expa>fa4
(13) <Expa1> ::= <Expa2><SuiteExpa2>
(14) <SuiteExpa2> ::= ^|’*’<Expa1>fa5|’/’<Expa1>fa6
(15) <Expa2> ::= ‘(‘<Expa>’)’|idffa7|cste fa8|cstr fa9
33
Les actions ftl, ft2 et ft3 rangent un identificateur, son type et sa taille dans la table des
identificateurs tds.
Les actions fa1 à fa9 rangent les codes des opérandes ( idf, cste, cstr) et ceux des opérateurs ( :=,
+, -, *,/).
Les actions fa8 et fa9, rangent en plus les constantes dans la table des constantes tcst.
Action f1
Initialisation d’Arbre,
Initialisation de TabSym;
it=1 ; ic=1 ; ia=i ;
Maxlt=1000 ;
fin ;
Action f2
/* on range dans l’arbre un symbole de fin */
Arbre[ia]=code(‘$’) ;
Fin
Action ft1
/* on range dans la table des symboles d’idf */
tds[it].idf=us ;
tds[it].type=typeidf ;
tds[it].taille=tailleidf ;
it=it+1 ;
Fin ;
Action ft2
typeidf=entier ;
tailleidf=2 ;
Fin ;
Action ft3
typeidf=reel ;
tailleidf=4 ;
Fin ;
Action fa1
iidf=Chercher(us,tds) ;
Arbre(ia)=iidf ;
ia=ia+1 ;
Fin ;
Action fa2
Arbre(ia)=affect ;
ia=ia+1 ;
Fin ;
Action fa3
Arbre(ia)=plus ;
ia=ia+1 ;
Fin ;
Action fa4
Arbre(ia)=moins ;
ia=ia+1 ;
Fin ;
Action fa5
Arbre(ia)=mul ;
ia=ia+1 ;
Fin ;
Action fa6
Arbre(ia)= ;
34
ia=ia+1 ;
Fin ;
Action fa7
iidf=Chercher(us,tds) ;
Arbre(ia)=iidf ;
ia=ia+1 ;
Fin ;
Action fa8
test[ic].val=ConvEntier(us);
Arbre(ia)=MaxIt+ic ;
ic=ic+1;
ia=ia+1 ;
Fin ;
Action fa9
test[ic].val=ConvReel(us);
Arbre(ia)=MaxIt+ic ;
ic=ic+1;
ia=ia+1 ;
Fin ;
D'une autre manière, l'analyseur syntaxique prédictif est simplement un automate à pile.
III.3.1 Simulation
On suppose que la chaine à analyser se termine par un symbole terminal $ et qu'on dispose de
six actions:
Vide(Pile) qui teste si la pile est vide ou non-
Sommet(Pile) qui retourne le symbole (terminal ou non terminal) se trouvant au sommet de la
pile.
Lexico(us) qui est l'analyseur lexicale, donc qui lit le symbole courant us.
Empiler(PileX) qui empile un symbole X dans la pile Pile.
Dépiter (Pile,Y) qui dépile un symbole Y de la pile Pile
Terminal(X) qui teste si un symbole X est un terminal ou un non terminal.
Analyseur prédictif
Debut
Lexico(us);
Empiler ($);
Tant que non( vide(Pile)) faire
X=Sornmet(Pile);
Si Termina(X) alors
Si X=us alors
/* X est le symbole attendu */
Lexico(us) ;
Dépiler(Pile,X);
35
Sinon Erreur(‘us attendu’ ); .
Fsi
Sinon
Si Transition[X,us]='X→Y1Y2…Yk' alors
Dépiler (Pile ;X) ;
Empiler(Pile,Yk);
.
.
Empiler(Pile,Yl);
Sinon Erreur('us attendu\;
Fsi
Fsi
FinTanque
Fin
36
N° Régle de production
1 PROG →’{‘LI’}’
2 LI → I SI
3 SI →^
4 SI → I SI
5 I → ‘;’
6 I → idf ‘=’ E
7 E → F SF
8 SF →^
9 SF → ‘+’ F SF
10 SF → ‘-’ F SF
11 F → P SP
12 SP →^
13 SP → ‘*’ P SP
14 SP → ‘/’ P SP
15 P → idf
16 P → cste
17 P → ‘(‘ E’)’
La table de transition de l'analyseur est
TA { } ; = + - * / ( ) idf cste
PR 1
LI 2 2
I 3 6
SI 3 4 4
E 7 7 7
F 11 11 11
SF 8 8 9 10 8 8 8
P 17 15 16
SP 12 12 12 12 13 14 12 12
Exécution
37
Dépiler, Empiler §}SI SF SP P
Dépiler, Empiler §}SI SF SP idf
Dépiler, Lire §}SI SF SP
Dépiler §}SI SF
Dépiler, Empiler §}SI SF F +
Dépiler, Lire §}SI SF F
Dépiler, Empiler §}SI SF SP P
Dépiler, Empiler §}SI SF SP cste
Dépiler, Lire §}SI SF SP
Dépiler §}SI SF
Dépiler §}SI
Dépiler §}
Dépiler, Lire §
Ecrire les actions permettant de créer l’arbre abstrait pour la grammaire du paragraphe III.3.2 en
utilisant l’analyseur prédictif ?
38
Partie III
Sémantique, génération du code et
interprétation
39
Chapitre 1.
Analyse sémantique
I.I. Introduction
L'analyse sémantique peut être le processus de vérification de la cohérence sémantique d’une
chaine d’entrée donnée.
Cette analyse doit déterminer si la chaîne d’entrée est sémantiquement correcte, c’est-à-dire si
la phrase est grammaticalement correcte ou d’une autre manière si la phrase a un sens.
En réalité, ce ne sont pas les chaines d’un programme source qui constituent l’entrée de
l’analyseur sémantique, mais l’arbre syntaxique construit par l’analyseur syntaxique.
I.2. Contrôles sémantiques
I.2.1. Variable non déclarée
Soit le programme suivant
Début
Entier A, B ;
Lire(A,B) ;
C :=A+B ;
Fin
La variable C n’est pas déclarée ; on a donc deux possibilités :
attribution d’un type à C par défaut
message d’erreur : variable non déclarée.
A B Lire C A B + := $
40
La table des symboles TDS
Idf Type Taille Valauer
A Entier 2 1
B Entier 2 0
Le contrôle sémantique ici, consiste à attribuer une valeur par défaut à la variable B. (B=0).
I.2.3 Conflits entre types
Soit le programme suivant
Début
Entier A, B ;
Réel C ;
Lire(A,B,C) ;
A :=A*(B+C) ;
Fin
La variable A n’aurait du être déclarée réelle et non pas entier, puisque la partie droite de
l’affectation est une expression réelle, on a donc deux possibilités :
notre compilateur autorise les opérations entre variables de type différents et effectue les
conversions correspondantes,
message d’erreur : conflit entre types.
Arbre ARB sous sa forme post fixée est
A B C Lire A A B C + * := $
La table des symboles TDS
Idf Type Taille …
A Entier 2
B Entier 2
C Reel 4
Le contrôle sémantique ici par exemple est l’affichage d’un message d’erreur : conflit entre
types.
I.3. Arbre sémantique: coloration de l'arbre syntaxique
Pratiquement, l’analyseur sémantique parcourt l’arbre syntaxique (abstrait) et suivant
l’opérateur rencontré, il génère un contrôle sémantiquement qui est :
Soit une erreur sémantique,
Soit des modifications apportées dans l’arbre syntaxique et/ou la table des synrboles :
coloration de l’arbre.
L'arbre syntaxique coloré s'appelle l’arbre sémantique.
I.3.1 Instruction affectation
<affectation>:: = <partie gauche> ←<partie droite>
Liens implicites
La forme poste-fixée généralisée (FPF) de l'affectation s’écrit :
<FPF Affect>::= <FPF PG> <FPF PD> ←
Le sous arbre associé:
FPF PG FPF PD ← $
Liens explicites
41
I.3.2 Instruction conditionnelle
<conditionnelle:> ::= si <condition> alors< listeinst>sinon< listeinst>f si
Liens implicites
La forme poste-fixée généralisée (FPF) de l'instruction conditionnelle s’écrit:
<FPF Conditionnel le>::=<FPF Condition> BF <FPF Listeinst> B <FPF Liste inst >
Le sous arbre associé :
Liens explicites
LI : Liste Inst
Liens explicites
42
LI : Liste Inst
43
Chapitre 2.
Interprétation
II.1. introduction
44
opérande(ELMT ) : teste si ELMT est une opérande . ( idf, constant, …)
Traiter Opérande(ELMT): Traite l'opérande (conversion, recherche dans la TDS, Empiler, …)
Traiter Opérateur(ElMT) : Traiter l'opérateur (Empiler, effectuer :+,-,*,/, :=, branchement,
arrêt($), …).
Action Interpréteur
Début
Prendre (ELM'l');
Tanque ELMT <> $ faire
Si Opérande (ELMT) alors
TraiterOpérande(ELMT);
Sinon
TraiterOpérateur(EI.MT);
Fsi
Prendre(ELMT);
Fin Tanque
Fin
II.3. Exemple
Soit un langage contenant des instructions d’affectations, des valeurs entières et réelles, les
tableaux d’entiers à une dimension et les constantes chaines.
NbElt : Égale au nombre d’éléments d’un tableau pour une variable tableau et égale I dans tous les
autres cas.
EmpRel : l’emplacement relatif d’un idf ( resp. d 'une constante) dans la mémoire centrale par rapport
à la base de zone des idf ( resp. des constantes) Debldf ( resp. DebCon):
EmpRef[i]=EmpRef[i-1]+NbEl t[i] * taille[i]
Codage:
Des identificateurs : indice is dans TDS de 1 à 1000
Des constantes : indice dans TDC, is +1000 : 1001 à 2000.
Opérateurs :
45
+ 2001 Addition
- 2002 Soustraction
* 2003 Produit
/ 2004 Division
← 2005 Affectation
T 2006 Opérateur d’
$ 2007
Action interpréteur
Début
ia=1 ;
ip=deblp ;
ELMT=ARBRE[ia] ;
Tant que ELMT<> 2007 faire
Si ELMT ≤ 2000 alors
TraiterOpérande(ELMT) ;
Sinon
TraiterOpérateur(ELMT) ;
Fsi
ia :=ia+1 ;
ELMT= ARBRE[ia] ;
Fin Tanque
Fin
Action TraiterOpérande(ELMT)
Début
Si ELMT >1000 alors
ADR=DcbCon EmpRelC[ELMT-1000] ;
Sinon
ADR=DebIdf+EmpRell[ELMT] ;
Fsi
Empiler(PILE, ADR) ;
Fin
Action TraiterOpérateur(ELMT)
Debut
selon EMT faire
2005 : Dépiler(PILE, ADR2) ;
Dépiler(PILE, ADR1) ;
MC[ADR1]=MC[ADR2] ;
imc=imc+1 ;
2001-2004 : Depiler(PILE, ADR2) ;
Dépiler(PILE,ADR1) ;
Selon ELMT faire
2001 : OPDE=MC[ADR1]+MC[ADR2] ;
2002 : OPDE=MC[ADR1]-MC[ADR2] ;
2003 : OPDE=MC[ADR1]*MC[ADR2] ;
2004 : OPDE=MC[ADR1]/MC[ADR2] ;
fselon
MC[imc]=OPDE ;
46
Empiler(PILE,imc) ;
imc=imc+1 ;
2006 : Dépiler(PILE, ADRi) ;
Dépiler (PILE,ADRT) ;
ADRTi=ADRT+MC[ADRi] ;
Empiler(ADRTi) ;
Fselon
Fin
47
Chapitre 3.
Génération du code machine
III.1. Introduction
Après l’analyse sémantique de l'arbre abstrait, commence la phrase de traduction de ce dernier
en un autre langage généralement proche du langage machine :
Si l'arbre est traduit directement dans le langage de la machine, on parle du code machine. Les
assembleurs 80286 et 68000 sont deux exemples du code machine.
Si l'arbre est traduit en autre code, on parle du code intermédiaire. La construction de l'arbre
lui-même sous forme post-fixée est une génération du code intermédiaire (chapitres
précédents).
On remarque qu’on peut passer par plusieurs générations de codes intermédiaires successives
pour générer le code machine ou pour interpréter le dernier code intermédiaire généré. .
Dans ce chapitre on ne génère que du code machine. On suppose donc qu'on a une machine
qui possède une unité arithmétique et logique, une pile PILEV, une mémoire centrale MC, une
zone de calcul intermédiaire (pointé par imc) et au moins un registre accumulateur Acc:
III.2. Déclarations
Dans les chapitres précédents on a signalé que les déclarations:
. Indiquent la nature des objets utilisés dans un langage de programmation ce qui permet de détecter des
opérations interdites ou de signaler le besoin d'une conversion (Analyse sémantique),
. Réservent la place en mémoire pour chacun des objets (Génération de code).
Soit la grammaire engendrant te langage définit dans l'exemple de chapitre2 :
<PROG> ::= f0<ListeDec>
<ListeDec> ::= f0<Dec><SuiteDec>
<SuiteDec> ::= ^|<ListeDec>
<Dec> ::= entier f1 <Liste Var avec Nb Element> |
reel f2 <Liste Var avec Nb Element> |
chaine f3 <Liste Var avec longeur> ;
<Liste Var avec Nb Element> ::= f4 <Var avec Nb Element> <Suite Var avec Nb Element> ;
<Suite Var avec Nb Element> ::= ^|’ ;’ <Liste Var avec Nb Element>
<Var avec Nb Element> ::= idf f5 <Nb Element>
<Nb Element> ::= idf f6 ‘(‘ cent f6‘)’
<Liste Var avec longeur> ::= f4 <Var avec longueur> <Suite Var avec longueur> ;
<Suite Var avec longueur> ::= ^|’ ;’ <Liste Var longueur>
48
<Liste Var longueur> ::= idf f6 ‘(‘ cent f7‘)’
Entier Xxy
Réel Moy
Entier Varia(100)
Chaine chp(10)
Réel Vach
Action f1
TypeIdf=’entier ‘
TailleIdf=2 ;
Fin
Action f2
TypeIdf=’réel ‘
TailleIdf=4 ;
Fin
Action f3
TypeIdf=chaine ‘
TailleIdf=1 ;
Fin
Action f4
id=id+1 ;
Type[id]= TypeIdf ;
Taille[id]= TailleIdf ;
NbElmt[id]=1;
EmplRel[id]=AdrRel
Fin
Action f5
Si identif( TDS, us) alors
Erreur(1) ;
id=id+1 ;
Sinon
idf[id]=us ;
Fsi
Fin
Action f6
NbElmt[id]=conversion(us) ;
AdrRel=AdrRel+Taille[id]*NbElmt[id] ;
49
Fin
Action f7
Taille[id]=conversion(us) ;
AdrRel=AdrRel+Taille[id] ;
Fin
Action f0
AdrRel=0 ;
…
Fin
Ces actions permettent de remplir la table des symboles TDS.
50
« cste » : id = Chercher (TDS, ELMT)
ADR=Debcon+TDC[ic].EmpRel ;
Retourne(ADR) ;
« ←» : ADR2=GénéreCode(p^.fd) ;
ADR1=GénéreCode(p^.fg) ;
Générer(MC[ADR1]← MC[ADR2]) ;
«+», « -» : ADR2=GénéreCode(p^.fd) ;
«*», «/» : ADR1=GénéreCode(p^.fg) ;
Selon OP faire
‘+’ : générer(MC[imc]←MC[ADR1]+ MC[ADR2]) ;
‘-’ : générer(MC[imc]←MC[ADR1]-MC[ADR2]) ;
‘*’ : générer(MC[imc]←MC[ADR1]* MC[ADR2]) ;
‘/’ : générer(MC[imc]←MC[ADR1]/ MC[ADR2]) ;
fselon
générer(Empiler(PILEV, imc) ;
générer(imc=imc+1) ;
Retourne(imc-1) ;
.
.
.
.
fin selon
Fin
L’action générer consiste à traduire directement l’instruction entre parenthèse en code machine.
Dans ce paragraphe, en suppose que l’expression arithmétique ne comporte aucun parenthèse et que
les opérateurs +, -,* et / ont la même priorité:
<EA> ::= <opérande>f3<Suite>
<suite> ::= ^|’+’f4<opérande>f5<suite>|’-’f4<opérande>f5<suite>
|’*’f4<opérande>f5<suite>|’/’f4<opérande>f5<suite>
Pour simplifier, on génère directement le code machine sans construire l’arbre syntaxique :
Action f1
id= Chercher(TDS, us) ;
AdrG=DebIdf+TDS[id].EmpRel ;
Fin
Action f2
Générer( MC[AdrG]←Acc)
Fin
Action f3
Si identif(us) alors
id= Chercher(TDS, us);
ADR=DabIdf+TDS[id].EmpRel;
Sinon
ic= Chercher(TDC, us);
ADR=DabIdf+TDC[ic].EmpRel;
Fsi
Val=MC[ADR] ;
Générer ( Acc ← Val);
Fin
51
Acton f4
OP=us ;
Fin
Action f5
Si identif(us) alors
id= Chercher(TDS, us);
ADR=DabIdf+TDS[id].EmpRel;
Sinon
ic= Chercher(TDC, us);
ADR=DabIdf+TDC[ic].EmpRel;
Fsi
Val=MC[ADR] ;
Selon OP faire
‘+’ : Generer ( Acc ←Acc+Val) ;
‘-’ : Generer ( Acc ←Acc-Val) ;
‘*’ : Generer ( Acc ←Acc*Val) ;
‘/’ : Generer ( Acc ←Acc/Val) ;
Fselon
Fin
52
Les langages à structures de blocs
IV.1. Introduction
Un langage à structure de blocs, est un langage ou trouve des parties (blocs) indépendantes de
programme c’est-à-dire qui comportent leurs propres déclarations et instructions. Un bloc peut
lui-même comporter d’autres blocs.
Si une variable n’est pas déclarée dans un bloc qui l'utilise, on se sert de la déclaration de la
même variable dans le bloc englobant (de niveau plus petit).
Exemple
Debut
Entier A,B ;
B=3 ;
A=2 ;
A=A+B+1 ;
Debut
Entier A,C ;
A=8 ;
C=2 ;
A=A*C ;
Ecrire(A,B,C) ;
Fin
Le résultat de ce programme est :
Bloc interne A=16, B=3 et C=2
Bloc externe A=4, B=3 et c n’est pas déclarée
IV.2. Structure de données
Pour pouvoir localiser chaque variable d’un bloc donné, il faut une structure stockant les
informations sur les blocs (niveau,...), en plus de la table des symboles classique déjà rencontrée
dans les chapitres précédents. D' où la structure suivante:
53
AdrAlloc : c’est l’adresse d’allocation d’un bloc dans la mémoire centrale
EntIdf : c’est l’entrée du bloc dans la TDS (début des idf du bloc dans la TDS)
FinIdf : c’est la fin du bloc dans la TDS (fin des idf du bloc dans la TDS)
IV.3. Grammaire
<prog> ::= <Bloc>
<Bloc> ::= debut f1 <Liste Dec> f3 <Liste Ins > fin f2
<Liste Ins > ::= <Inst><Suite Ins>
<Suite Ins> ::= ^|’ ;’<List Ins>
<Ins> ::= …..|<Bloc>
Action f0
Niveau=-1 ;
ibloc=0 ;
id=1 ;
AdrLibre=0 ;
Empiler(PileBloc, Niveau+1) ;
Fin
Action f1
Niveau=Niveau+1 ;
ibloc=ibloc+1 ;
Profendeur[ibloc]=Niveau ;
AdrAlloc[ibloc]=AdrLibre ;
EntIdf[ibloc]=id ;
Ainé[ibloc]=0 ;
Frère[ibloc]=0 ;
Si NonVide(PileBloc) alors
Dépiler(PileBloc,Parent) ;
Si Ainé[Parent]=0 alors
Ainé[Parent]=ibloc ;
Sinon
Premier=Ainé [Parent] ;
Tant que Frère [Premier]<>0 faire
Premier= Frere[Premier] ;
Fin Tanque
Frere[Premier]=ibloc ;
Fsi
Fin
Action f2
AdrLibre= AdrAlloc[Sommet(PileBloc)]=id ;
Niveau=Niveau-1 ;
Dépiler (PileBloc,Bidon) ;
Fin
Action f3
FinIdf[Sommet(PileBloc)]=id ;
Fin
54