0% ont trouvé ce document utile (0 vote)
232 vues50 pages

Introduction À La Compilation: Alexis Nasr Carlos Ramisch Sylvain Sené

Le document présente une introduction à la compilation, abordant les concepts fondamentaux tels que l'analyse syntaxique, l'analyse lexicale, et la génération de code. Il décrit également le rôle d'un compilateur, les étapes de la compilation, et fournit des exemples de grammaires formelles. Enfin, il souligne l'importance de la table des symboles et de la représentation intermédiaire dans le processus de compilation.

Transféré par

Abdati Abdo
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
232 vues50 pages

Introduction À La Compilation: Alexis Nasr Carlos Ramisch Sylvain Sené

Le document présente une introduction à la compilation, abordant les concepts fondamentaux tels que l'analyse syntaxique, l'analyse lexicale, et la génération de code. Il décrit également le rôle d'un compilateur, les étapes de la compilation, et fournit des exemples de grammaires formelles. Enfin, il souligne l'importance de la table des symboles et de la représentation intermédiaire dans le processus de compilation.

Transféré par

Abdati Abdo
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Introduction à la Compilation

Alexis Nasr
Carlos Ramisch
Sylvain Sené

Compilation – L3 Informatique
Département Informatique et Interactions
Aix Marseille Université

1 / 49
Infos pratiques

10 cours, 10 séances de TD et 10 séances de TP


Emploi du temps :
Consulter l’ENT
Évaluation :
Partiel (33.33%)
Projet (33.33%) – 2 parties
Examen final (33.33%)
Page web du cours : Ametice

2 / 49
Bibliographie

Alfred Aho, Monica Lam, Ravi Sethi et Jeffrey Ullman


Compilateurs principes, techniques et outils, 2ème édition.
Pearson Education, 2007
Andrew Appel Modern compiler implementation in C.
Cambridge University Press, 1998
John Hopcroft, Rajeev Motwani, Jeffrey Ullman Introduction to
Automata Theory, Languages and Computation, 2ème édition
Pearson Education International, 2001.

3 / 49
Plan

Introduction à la compilation
Processeurs de langages
Analyse syntaxique
Analyse lexicale
Traduction dirigée par la syntaxe
Table des symboles
Analyse sémantique
Production de code

Le projet
Le langage L
Assembleur X86
Structure du compilateur
Étapes

4 / 49
Compilateur

Un compilateur est un programme


1 qui lit un autre programme rédigé dans un langage de
programmation, appelé langage source
2 et qui le traduit dans un autre langage, le langage cible.
Le compilateur signale de plus toute erreur contenue dans le
programme source
Lorsque le programme cible est un programme exécutable, en
langage machine, l’utilisateur peut ensuite le faire exécuter afin
de traiter des données et de produire des résultats.

5 / 49
Compilateur / interpréteur

programme source

compilateur

données programme cible résultat

6 / 49
Compilateur / interpréteur

programme source

interpréteur

données programme cible résultat

Un interpréteur est un programme qui effectue lui-même les


opérations spécifiées par le programme source directement sur les
données fournies par l’utilisateur.

6 / 49
Exemple
programme source programme cible
f:
entier $d; push ebp
mov ebp, esp
f(entier $a, entier $b) sub esp, 8
entier $c, entier $k; mov ebx, [ebp + 12]
{ push ebx
$k = $a + $b; mov ebx, [ebp + 8]
retour $k; push ebx
} ...
main:
main() push ebp
{ mov ebp, esp
$d = 7; sub esp, 8
ecrire(f($d, 2) + 1); push 7
} pop ebx
mov [$d], ebx
...

7 / 49
Nécessité d’une analyse syntaxique

A l’exception de quelques cas (rares), la traduction ne peut être


faite “mot à mot”
Le programme source doit être décomposé en composants
pertinents ou constructions du langage source.
La traduction d’une construction dépend de la position qu’elle
occupe au sein du programme.

8 / 49
Décomposition d’une définition de fonction

entier $d; /* variable globale */

f /* nom de la fonction */
(entier $a, entier $b) /* paramètres de la fonction */
entier $c, entier $k; /* variables locales */
{ /* debut du corps de la fonction */
$k = /* affectation */
$a + $b; /* expression arithmétique */
retour $k; /* valeur de retour */
} /* fin du corps de la fonction */

9 / 49
Deux parties d’un compilateur

La traduction du programme source en programme cible se


décompose en deux étapes :
L’analyse, réalisée par la partie frontale du compilateur, qui
découpe le programme source en ses constituants ;
détecte des erreurs de syntaxe ou de sémantique ;
produit une représentation intermédiaire du programme source ;
conserve dans une table des symboles diverses informations sur les
procédures et variables du programme source.
La génération, réalisée par la partie finale du compilateur, qui
construit le programme cible à partir de la représentation
intermédiaire et de la table des symboles

10 / 49
Deux parties d’un compilateur

programme source

analyse

représentation intermédiaire

génération

programme cible

11 / 49
Nature de la représentation intermédiaire

La conception d’une bonne RI est un compromis :


Elle doit être raisonnablement facile à produire à partir du
programme source.
Elle doit être raisonnablement facile à traduire vers le langage
cible.
Elle doit donc être raisonnablement éloignée (ou raisonnablement
proche) du langage source et du langage cible.

12 / 49
Economie

Une RI judicieusement définie permet de constuire un compilateur


pour le langage L et la machine M en combinant :
un analyseur pour le langage L
un générateur pour la machine M
Economie : on obtient m × n compilateurs en écrivant seulement m
analyseurs et n générateurs

13 / 49
Portabilité

langage C langage L langage Pascal

analyse C analyse L analyse Pascal

représentation intermédiaire

génération X86 génération MIPS génération 68K

assembleur x86 assembleur MIPS assembleur 68K

14 / 49
Syntaxe du langage source

Le programme source vérifie un certain nombre de contraintes


syntaxiques.
L’ensemble de ces contraintes est appelé grammaire du langage
source.
Si le programme ne respecte pas la grammaire du langage, il est
considéré incorrect et le processus de compilation échoue.

15 / 49
Description de la grammaire du langage source

Littéraire
Un programme est une suite de définitions de fonction
Une définition de fonction est composée
du nom de la fonction suivie de ses arguments
suivie de la declaration de ses variables internes
suivie d’un bloc d’instructions
Une instruction est . . .
Formelle
programme → listeDecFonc ’.’
listeDecFonc → decFonc listeDecFonc
listeDecFonc →
decFonc → ID_FCT listeParam listeDecVar ’ ;’ instrBloc
...

16 / 49
Grammaires formelles

Les contraintes syntaxiques sont représentées sous la forme de


règles de réécriture.
La règle A → BC nous dit que le symbole A peut se réécrire
comme la suite des deux symboles B et C.
L’ensemble des règles de réécriture constitue la grammaire du
langage.
La grammaire d’un langage L permet de générer tous les
programmes corrects écrits en L et seulement ceux-ci

17 / 49
Notations et Terminologie

Dans la règle A → α
A est appelé partie gauche de la règle.
α est appelé partie droite de la règle.
Lorsque plusieurs règles partagent la même partie gauche :

A → α1 , A → α2 , . . . , A → αn
On les note :

A → α1 | α2 | . . . | αn

18 / 49
Grammaire partielle des expressions arithmétiques

EXPRESSION → EXPRESSION OP2 EXPRESSION


OP2 → +|-|*|/
EXPRESSION → NOMBRE
EXPRESSION → ( EXPRESSION )
NOMBRE → CHIFFRE | CHIFFRE NOMBRE
CHIFFRE → 0|1|2|3|4|5|6|7|8|9
Les symboles EXPRESSION, OP2, NOMBRE, CHIFFRE sont
appelés symboles non terminaux de la grammaire
Les symboles +, -, *, /, (, ), 0, 1 , ..., 9 sont appelés symboles
terminaux de la grammaire

19 / 49
Avantages des grammaires formelles

Une grammaire formelle :


Pousse le concepteur d’un langage à en décrire la syntaxe de
manière exhaustive.
Permet de répondre automatiquement à la question
mon programme est-il correct ? à l’aide d’un analyseur syntaxique.
Fournit, à l’issue de l’analyse, une représentation explicite de
l’organisation du programme en constructions (structure
syntaxique du programme).
Cette représentation est utile pour la suite du processus de
compilation.

20 / 49
Dérivation d’une expression arithmétique

L’expression arithmétique 2 ∗ (3 + 1) est-elle correcte ?


EXPRESSION ⇒ EXPRESSION OP2 EXPRESSION
⇒ NOMBRE OP2 EXPRESSION
⇒ CHIFFRE OP2 EXPRESSION
⇒ 2 OP2 EXPRESSION
⇒ 2 * EXPRESSION
⇒ 2 * ( EXPRESSION )
⇒ 2 * ( EXPRESSION OP2 EXPRESSION)
⇒ 2 * ( NOMBRE OP2 EXPRESSION)
⇒ 2 * ( CHIFFRE OP2 EXPRESSION)
⇒ 2 * ( 3 OP2 EXPRESSION)
⇒ 2 * ( 3 + EXPRESSION)
⇒ 2 * ( 3 + NOMBRE)
⇒ 2 * ( 3 + CHIFFRE)
⇒ 2 * ( 3 + 1)

21 / 49
Arbre de dérivation
EXPRESSION

EXPRESSION OP2 EXPRESSION

NOMBRE * ( EXPRESSION )

CHIFFRE EXPRESSION

2 EXPRESSION OP2 EXPRESSION

NOMBRE + NOMBRE

CHIFFRE CHIFFRE

3 4

22 / 49
Analyse lexicale

Afin de simplifier la grammaire décrivant un langage, on omet


de cette dernière la génération de certaines parties simples du
langage.
Ces dernières sont prises en charge par un analyseur lexical
L’analyseur lexical traite le programme source et fournit le
résultat de son traitement à l’analyseur syntaxique.

23 / 49
Nouvelle grammaire des expressions arithmétiques

EXPRESSION → EXPRESSION OP2 EXPRESSION


Syntaxe EXPRESSION → NOMBRE
EXPRESSION → ( EXPRESSION )
OP2 → +|-|*|/
Lexique NOMBRE → CHIFFRE | CHIFFRE NOMBRE
CHIFFRE → 0|1|2|3|4|5|6|7|8|9

La nouvelle grammaire omet les détails de la génération d’un


NOMBRE et d’un opérateur binaire. Cette partie est à la charge
de l’analyseur lexical.
La frontière entre analyse lexicale et analyse syntaxique est en
partie arbitraire.

24 / 49
Analyseur lexical

Lit le programme source


Reconnaît des séquences de caractères significatives appelées
lexèmes
Pour chaque lexème, l’analyseur lexical émet un couple

(type du lexème, valeur du lexème)

Exemple
(NOMBRE, 123)
Les types de lexèmes sont des symboles, ils constituent les
symboles terminaux de la grammaire du langage.
Les symboles terminaux de la grammaire (ou types de lexèmes)
constituent l’interface entre l’analyseur lexical et l’analyseur
syntaxique. Ils doivent être connus des deux.

25 / 49
Analyseur syntaxique plus simple

EXPRESSION

EXPRESSION OP2,* EXPRESSION

NOMBRE, 2 PO, ( EXPRESSION PF, )

EXPRESSION

EXPRESSION OP2,+ EXPRESSION

NOMBRE, 3 NOMBRE, 4

26 / 49
Traduction dirigée par la syntaxe

La traduction dirigée par la syntaxe est réalisée en attachant des


actions sémantiques aux règles de la grammaire.
Elle repose sur deux concepts :
Les attributs. Un attribut est une quantité quelconque associée à
une construction du langage de programmation.
Exemples :
le type d’une expression
la valeur d’une expression
le nombre d’instructions dans le code généré
Les constructions étant représentées par les symboles de la
grammaire, on associe les attributs à ces derniers.
Notations : A.t est l’attribut t associé au symbole A.

27 / 49
Traduction dirigée par la syntaxe

Les schémas de traduction sont une notation permettant


d’attacher des fragments de programme aux règles de la
grammaire.
Les fragments sont exécutés quand la production est utilisée lors
de l’analyse syntaxique.
Le résultat combiné des exécutions de tous ces fragments, dans
l’ordre induit par l’analyse syntaxique, produit la traduction du
programme auquel ce processus est appliqué.

28 / 49
Traduction — exemple

règle action sémantique


E → EOE E.t = E1 .t || E2 .t || O.t
E → (E) E.t = E1 .t
E → N E.t = N.t
O → + O.t = +
O → − O.t = −
N → CN N.t = C.t || N2 .t
N → C N.t = C.t
C → 0 C.t = 0
C → 1 C.t = 1
C → 2 C.t = 2
... ...
C → 9 C.t = 9

29 / 49
Traduction — Exemple

E (2 3 1 + *)

E (2) O (*) E (3 1 +)

N (2) * ( E (3 1 +) )

C (2) E (3) O (+) E (1)

2 N (3) + N (1)

C (3) C (1)

3 1

30 / 49
Attributs synthétisés

Un attribut est dit synthétisé si sa valeur au niveau d’un nœud A


d’un arbre d’analyse est déterminée par les valeurs de cet
attribut au niveau des fils de A et de A lui même.
A
A.t = f (B.t, C.t, D.t)
B C D

Les attributs synthétisés peuvent être évalués au cours d’un


parcours ascendant de l’arbre de dérivation.
Un tel parcours peut être effectué simultanément à la
construction de l’arbre (lors de l’analyse syntaxique).
Dans l’exemple, B.t, C.t et D.t doivent être calculés avant de
calculer A.t

31 / 49
Table des symboles

Elle rassemble toutes les informations utiles concernant les


variables et les fonctions ou procédures du programme.
Pour toute variable, elle garde l’information de :
son nom
son type
sa portée
son adresse en mémoire
Pour toute fonction ou procédure, elle garde l’information de :
son nom
sa portée
le nom et le type de ses arguments, ainsi que leur mode de passage
éventuellement le type du résultat qu’elle fournit
La table des symboles est construite lors de l’analyse syntaxique.

32 / 49
Table de symboles — exemple

programme source
entier $d;
table des symboles
f(entier $a, entier $b)
entier $c, entier $k; id classe type adr args
{ $d globale entier 1
$k = $a + $b; f fonct entier 1 2
retour $k; $a param entier
} $b param entier
$c locale entier
main() $k locale entier
{ main fonct entier 11 0
$d = 7;
ecrire(f($d, 2) + 1);
}

33 / 49
Arbre de dérivation v/s arbre abstrait

L’arbre de dérivation produit par l’analyse syntaxique possède


de nombreux nœuds superflus, qui ne véhiculent pas
d’information.
De plus, la mise au point d’une grammaire nécessite souvent
l’introduction de règles dont le seul but est de simplifier
l’analyse syntaxique.
Un arbre abstrait constitue une interface plus naturelle entre
l’analyse syntaxique et l’analyse sémantique, elle ne garde de la
structure syntaxique que les parties nécessaires à l’analyse
sémantique et à la production de code.
L’arbre abstrait est construit lors de l’analyse syntaxique, en
associant à toute règle de grammaire une action sémantique.

34 / 49
Arbre de dérivation v/s arbre abstrait

EXPRESSION *

EXPRESSION OP2,* EXPRESSION 2 +

NOMBRE, 2 PO, ( EXPRESSION PF, ) 3 1

EXPRESSION

EXPRESSION OP2,+ EXPRESSION

NOMBRE, 3 NOMBRE, 4

35 / 49
Analyse sémantique

L’analyse sémantique utilise l’arbre abstrait, ainsi que la table de


symboles afin d’effectuer un certain nombre de contrôles
sémantiques, parmi lesquels :
vérifier que les variables utilisées ont bien été déclarées.
le contrôle de type : le compilateur vérifie que les opérandes
d’un opérateurs possèdent bien le bon type.
conversions automatiques de types.

36 / 49
Représentation intermédiaire

La production de code consiste à produire une séquence


d’instructions sémantiquement équivalente au programme
source qui pourra être interprétée par une machine donnée.
La production de code est effectuée lors du parcours de la
Représentation intermédiaire (RI) construit à l’issue le l’étape
d’analyse.
Plusieurs choix sont possibles pour la RI :
l’arbre abstrait
une séquence d’instructions élémentaires
...

37 / 49
Exemple

Production de code lors du parcours d’un nœud associé à une


instruction si expr alors instr.

si ⇒ calculer expr
le ranger dans x
arbre SIFAUX x ALLER A suite
arbre
représentant exécuter instr
représentant
expr suite :
instr

38 / 49
Code à 3 adresses
Avant d’écrire tout-à-fait le code, on peut passer par une version
simplifiée qui consiste principalement à représenter le programme
sous la forme d’une séquence d’instructions simples
2: load $i
3: load $n
4: loadimm 1
5: moins 3, 4
6: inf 2, 5
tantque $i < $n-1 faire 7: jsifaux 6, 15
{ 8: load $i
$i = $i * 2 + 1; 9: loadimm 2
} 10: fois 8, 9
ecrire(i) 11: loadimm 1
12: plus 10, 11
13: store 12, $i
14: jump 2
15: load $i
16: ecrire 15

39 / 49
Sources

[Link], [Link], [Link] et [Link],


Compilateurs : principes, techniques et outils.
2ème édition. Pearson Education, 2007
[Link],
Modern compiler implementation in C.
Cambridge University Press, 1998
Henri Garreta,
Polycopié du cours de compilation.
[Link]

40 / 49
Projet

Construction en langage C d’un compilateur.


Le langage source appelé L est un langage impératif simple.
Le langage cible est l’assembleur X86. Le code produit est
executé directement par le processeur de l’ordinateur.

41 / 49
Le langage L

Proche du langage C ou de Pascal


quelques caractéristiques :
Types : Le langage L connaît deux types de variables :
Un type simple : le type entier.
Un type dérivé : les tableaux d’entiers.
Variables : Les noms des variables commencent par dollar ($)
Opérateurs : Le langage L connaît les opérateurs suivants :
arithmétiques : +, -, *, /
comparaison : <, =
logiques : & (et), | (ou), ! (non)

42 / 49
Le langage L

Instructions : Le langage L connaît les instructions suivantes :


Instruction vide
;
Bloc d’instructions, délimité par des accolades
{ ... }
Affectation 1
$a = $b + 1;
Instructions de contrôle
si expression alors { ... }
si expression alors { ... } sinon { ... }
tantque expression faire { ... }
Retour de fonction
retour expression ;
Instruction d’appel à fonction simple
fonction( liste d’expressions );

1. Contrairement à C, une affectation n’est pas une expression =⇒ on ne peut écrire


$a = $b = 4
43 / 49
Le langage L

Sous-programmes : un programme L est une suite de


sous-programmes, dont main
Ce sont des fonctions à résultat entier.
Le passage se fait par valeur.
Les fonctions possèdent des variables locales.
Une fonction ne peut pas être déclarée à l’intérieur
d’une autre.
On peut ignorer le résultat rendu par une fonction.
Procédures pré-définies : Les entrées-sorties de valeurs entières se
font à l’aide de deux fonctions prédéfinies :
$a = lire();
ecrire($a);

44 / 49
Exemple

f(entier $a, entier $b) # déclaration d’une fonction à deux arguments


entier $c, entier $k; # déclaration de deux variables locales
{ # début d’un bloc d’instruction
$k = $a + $b; # affectation et expression arithmétique
retour $k; # valeur de retour de la fonction
} # fin du bloc d’instruction

main() # point d’entrée dans le programme


entier $d;
{
$d = f($d, 2); # affectation et appel de fonction
ecrire($d + 1); # appel de la fonction prédéfinie ecrire
}

45 / 49
Assembleur NASM

Langage utilisé par les processeurs X86.


Mémoire séparée en trois parties :
l’espace global (variables)
la zone de code,
la pile.
En plus, registres utilisés dans la plupart des instructions.
registres courants : eax-edx,
pointeur de sommet de pile : esp ...

46 / 49
NASM — exemples

mov eax, [k] charge la variable à l’adresse k dans eax


mov ebx, 1 charge la valeur 1 dans ebx
add eax, ebx addition : eax = eax + ebx
jmp label saute à l’adresse label dans le code

47 / 49
Structure du compilateur
programme source

analyse lexicale

syntaxe

analyse syntaxique

arbre abstrait table des symboles

analyse sémantique

code à 3 adresses

données assembleur résultats

48 / 49
Étapes

TP durée intitulé
1 1 analyseur lexical
2-3 2 analyseur syntaxique
4 1 production de l’arbre abstrait
5 1 évaluation partielle
6 1 analyse sémantique et table des symboles
7-8 2 production de code NASM
9 1 appels à fonction, optimisations
10 1 évaluation finale

49 / 49

Vous aimerez peut-être aussi