Académique Documents
Professionnel Documents
Culture Documents
U : 2017/2018
Faculté des sciences SMI : S5
Département d’Informatique Compilation
TP1
Introduction à la compilation
Exercice 1 : Traduction.
Ecrire un programme C qui traduit les entiers décimaux en nombres écrits en chiffres
romains. Puis, inversement traduit les nombres écrits en chiffres romains en entiers
décimaux.
TP2
Analyse lexicale
L'analyseur lexical se présente comme une fonction qui à chaque appel renvoie
comme résultat une unité lexicale.
Unités lexicales :
Les unités lexicales de notre langage sont de plusieurs sortes :
- les mots-clés (si, alors, ...),
- les symboles simples (+, *; ...),
- les symboles doubles (<=, !=, ...),
- les identificateurs et
- les nombres, uniquement entiers.
Chaque unité lexicale est représentée par un nombre entier. Les unités dont le lexème
n'est pas un caractère unique sont représentées par la valeur d'une constante symbolique,
définie comme ceci #define TANTQUE 300. Ces valeurs sont toutes supérieures ou égales
à 256. Les unités lexicales dont le lexème est un caractère unique sont codées par [le code
interne de] ce caractère lui-même, c'est-à-dire un entier inférieur à 256.
Mots clés :
La reconnaissance d'un mot-clé est traitée de la même manière que celle d’un
identificateur. Une fois le lexème formé, celui-ci est recherché dans une table des mots clés
qui associe à chaque [lexème d'un] mot-clé [le code de] l'unité lexicale correspondante, définie
comme ceci : struct { char* lexeme,
int uniteLexicale ;
} MotRes[ ] = {{‘‘si’’ ,SI },{‘‘alors’’,ALORS},{ ‘‘sinon’’,SINON} … } ;
int nbMotRes = sizeof MotRes/sizeof MotRes[0] ;
Identificateurs :
Lorsque l'analyseur lexical rencontre un identificateur son travail doit se limiter à :
- déterminer qu'il s'agit d'un identificateur (ce qui correspond à l'échec de sa recherche
dans la table des mots-clés),
- donner comme résultat la valeur IDENTIFICATEUR (si c'est comme cela qu'on a
nommé la constante correspondante),
- affecter une variable globale, nommée par exemple lexeme, avec la chaîne de
caractères reconnue, a fin que d'autres couches du compilateur puissent l’utiliser
ultérieurement…
TP3
Analyse syntaxique
Idée de base :
Correspondre chaque non-terminal à un appel de fonction et chaque terminal à la
consommation d’un lexème dans un flux. A l’opposé de l’analyseur non récursif, cet
analyseur est écrit en un ensemble de fonctions mutuellement récursives, et est donc
étroitement lié à la grammaire analysée.
Principe :
1. Chaque groupe de productions ayant le même membre gauche S donne lieu à une fonction
reconnaître_S(). Le corps de cette fonction se déduit des membres droits des productions en
question.
2. Lorsque plusieurs productions ont le même membre gauche, le corps de la fonction
correspondante est une conditionnelle (if) ou un aiguillage (switch) qui, d’après le symbole
terminal visible à la fenêtre, sélectionne l’exécution des actions correspondant au membre
droit de la production pertinente.
3. Une séquence de symboles S1S2… Sn dans le membre droit d’une production donne lieu,
dans la fonction correspondante, à une séquence d’instructions traduisant les actions
‘‘reconnaissance de S1’’ ‘‘reconnaissance de S2’’ . . ‘‘reconnaissance de Sn’’.
4. Si Si est un symbole non terminal, l’action ‘‘reconnaissance de Si’’ se réduit à l’appel de
fonction reconnaître_Si().
5. Si Si est un symbole terminal, l’action ‘‘reconnaissance de Si’’ consiste à considérer le
symbole terminal ‘a’ visible à la fenêtre et
– s’ils sont égaux, faire passer la fenêtre sur le symbole suivant,
– sinon, annoncer une erreur (par exemple, afficher ‘‘a attendu’’) .
L’initialisation consiste à :
Positionner la fenêtre sur le premier terminal de la chaîne d’entrée.
On lance l’analyse en appellant la fonction associée à l’axiome de la grammaire.
Terminaison :
– si la fenêtre à terminaux montre la marque de fin de chaîne, l’analyse a réussi,
– sinon la chaîne est erronée.
Algorithme :
si A possède les productions suivantes :
A ! ® A 1 j B1 B2 j ²
avec ® 2 VT et A1; B1; B2 2 VN alors le code de la fonction pour A aura la forme
suivante :
trouverA()
si (motCourant = ®) alors
motCourant = prochainMot() ;
return (trouverA1()) /* A ! ®A1 choisi */
sinon si (motCourant 2 Premier(B1)-f²g )alors
return (trouverB1() ^ trouverB2()) /* A ! B1 B2 choisi */
sinon si (motCourant 2 Suivant(A))
alors return True /* A ! ² choisie */
sinon return False /* erreur */
Travail demandé :
Un analyseur descendant récursif pour la grammaire suivante des expressions
arithmétiques récursive à droite :