SlideShare une entreprise Scribd logo
Remerciements
En préambule à ce projet nous remerciant ALLAH qui nous aide et nous donne la patience
et le courage durant ces langues années d’étude.
Nous souhaitant adresser nos remerciements les plus sincères aux personnes qui nous ont
apporté leur aide et qui ont contribué à l’élaboration de ce mémoire ainsi qu’à la réussite de
cette formidable année universitaire.
Ces remerciements vont tout d’abord au corps professoral et administratif de l’institut
supérieure d’informatique et mathématique Monastir pour la richesse et la qualité de leur
enseignement et qui déploient de grands efforts pour assurer à leurs étudiants une formation
actualisée.
Nous tenant à remercier sincèrement Monsieur, Mohamed Graeit, qui, en tant que enca-
dreur de notre projet de fin d’études, il s’est toujours montré à l’écoute et très disponible
tout au long de la réalisation de ce projet, ainsi pour l’inspiration, l’aide et le temps qu’ils
ont bien voulu nous consacrer et sans lui ce projet n’aurait jamais vu le jour.
On n’oublie pas nos parents pour leur contribution, leur soutien et leur patience.
Enfin, nous adressons nos plus sincères remerciements à tous nos proches et amies, qui
nous ont toujours soutenue et encouragée au cours de la réalisation de ce projet. Merci à tous
et à toutes.
i
Dédicaces
Je dédie ce travail
À MES CHERS PARENTS
Aucune dédicace ne saurait exprimer mon respect, mon amour éternel et ma considéra-
tion pour les sacrifices que vous avez consenti pour mon instruction et mon bien être.
Je vous remercie pour tout le soutien et l’amour que vous me portez depuis mon enfance
et j’espère que votre bénédiction m’accompagne toujours.
Puisse Dieu, le Très Haut, vous accorder santé, bonheur et longue vie et faire en sorte
que jamais je ne vous déçoive.
À MES DEUX CHERS ET ADORABLES
SOEURS
En témoignage de mon affection fraternelle, de ma profonde tendresse et reconnaissance,
je vous souhaite une vie pleine de bonheur et de succès et que Dieu, le tout puissant, vous
protége et vous garde.
À MES AMIS
En souvenir de notre sincère et profonde amitié et des moments agréables que nous avons
passés ensemble.
Veuillez trouver dans ce travail l’expression de mon respect le plus profond et mon affec-
tion la plus sincère.
À TOUTES LES PERSONNES QUI ONT
PARTICIPÉ A L’ÉLABORATION DE CE
TRAVAIL, À TOUS CEUX QUE J’AI OMIS
DE CITER
Ben Belgacem Yahya
ii
Dédicaces
Je dédis ce modeste travail comme un témoignage d’affectation, de respect d’admiration
à :
À Ma MÉRE
Tu m’as donné la vie, la tendresse et le courage pour réussir. Tout ce que je peux t’offrir
ne pourra exprimer l’amour et la reconnaissance que je te porte. En témoignage, je t’offre ce
modeste travail pour te remercier pour tes sacrifices et pour l’affection dont tu m’as toujours
entouré.
À Mon PERE
L’épaule solide, l’oeil attentif compréhensif et la personne la plus digne de mon estime et
de mon respect. Aucune dédicace ne saurait exprimer mes sentiments, que Dieu te préserve
et te procure santé et longue vie.
À MES FRERES ET MES SOEURS
À MES CHERS AMIES
À CELLE QUI M’INSPIRE TOUJOURS
Bouein Aymen
iii
Table des figures
1 Principe de compilateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
1.1 Exemple de compilation d’une instruction . . . . . . . . . . . . . . . . . . . 4
1.2 Couple Flex Bison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1 Principe de compilateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 Caractère spéciaux de Flex . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3 Un tampon d’entrée en deux moitiés . . . . . . . . . . . . . . . . . . . . . . 9
2.4 Exemple de diagramme de transition . . . . . . . . . . . . . . . . . . . . . . 10
2.5 Diagramme de transition des opérateur . . . . . . . . . . . . . . . . . . . . . 11
2.6 Diagramme de transition des identificateur . . . . . . . . . . . . . . . . . . . 12
2.7 Diagramme de transition des chaines des caractères . . . . . . . . . . . . . . 13
2.8 Diagramme de transition des caractères . . . . . . . . . . . . . . . . . . . . . 14
2.9 Diagramme de transition des entier et réel . . . . . . . . . . . . . . . . . . . 14
2.10 Différence entre les mots clé et les identificateurs . . . . . . . . . . . . . . . 16
3.1 Analyse syntaxique descendante de id + id * id . . . . . . . . . . . . . . . . 23
3.2 Analyse syntaxique ascendante de id * id . . . . . . . . . . . . . . . . . . . . 24
3.3 Analyse syntaxique par décalage-réduction sur l’entrée id1 * id2 . . . . . . . 25
3.4 Structure de table de symbole au niveau de sous-programme . . . . . . . . . 26
3.5 Structure détaillé de table de symbole aux niveau de sous-programme . . . . 27
3.6 Un tampon d’entrée en deux moitiés . . . . . . . . . . . . . . . . . . . . . . 39
5.1 Les directives de porteur de donnée . . . . . . . . . . . . . . . . . . . . . . . 55
5.2 Code assembleur de l’affichage des caractères et chaine des caractères . . . . 55
5.3 Lecture de caractére et chaine des caractéres à partie de console . . . . . . . 57
6.1 Diagramme de cas d’utilisation . . . . . . . . . . . . . . . . . . . . . . . . . 61
6.2 Diagramme de séquence «Exécution code source» . . . . . . . . . . . . . . . 63
6.3 Diagramme de classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
7.1 Logo Qt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.2 Etude de l’interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
7.3 Etude de l’interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
7.4 Fonctionnement de zone traitement de code . . . . . . . . . . . . . . . . . . 70
7.5 Traitement des erreurs de compilation . . . . . . . . . . . . . . . . . . . . . . 71
iv
Listings
1 Hello World avec C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
2 Hello World avec Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
3 Hello World avec Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xii
2.1 Faux boucle for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2 Implémentation Flex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.1 Grammaire déclaration de donnée . . . . . . . . . . . . . . . . . . . . . . . . 28
3.2 Grammaire boucle conditionnelle C++ et Java . . . . . . . . . . . . . . . . . 29
3.3 Instruction Switch C++ et Java . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.4 Grammaire Boucle for C++ et Java . . . . . . . . . . . . . . . . . . . . . . . 30
3.5 Grammaire Boucle while C++ et Java . . . . . . . . . . . . . . . . . . . . . 30
3.6 Grammaire Boucle Do-while C++ et Java . . . . . . . . . . . . . . . . . . . 30
3.7 Grammaire déclarative de donné VB.NET . . . . . . . . . . . . . . . . . . . 30
3.8 Grammaire boucle conditionnelle VB.NET . . . . . . . . . . . . . . . . . . . 31
3.9 Grammaire boucle For VB.NET . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.10 Grammaire boucle Do-While VB.NET . . . . . . . . . . . . . . . . . . . . . 31
3.11 Grammaire boucle While VB.NET . . . . . . . . . . . . . . . . . . . . . . . 31
3.12 Importation de langage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.13 déclaration de donné . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.14 description préalable de grammaire de lecture de variable . . . . . . . . . . . 33
3.15 grammaire de lecture de variable . . . . . . . . . . . . . . . . . . . . . . . . 33
3.16 Grammaire d’affichage de donnée . . . . . . . . . . . . . . . . . . . . . . . . 34
3.17 Grammaire d’affectation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.18 Grammaire boucle for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.19 Grammaire instruction select . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.20 Implémentation table de symbole . . . . . . . . . . . . . . . . . . . . . . . . 37
3.21 Entête des sous programme ralative à table de symbole . . . . . . . . . . . . 37
3.22 Implémentation Bibliothèque . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.23 Entête des sous programme ralative aux Bibliothèque . . . . . . . . . . . . . 38
3.24 Association de type à STR_EXPR et EXPR décrite lors de l’affectation . . 40
3.25 Associer les priorités des opérateurs arithmétique . . . . . . . . . . . . . . . 40
3.26 Indicateur d’erreur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.27 Déclaration de l’axiome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.1 Installation de porteur de donnée aprés verification sémantique . . . . . . . . 44
4.2 Insertion de commande sémantique d’ajout de donnée . . . . . . . . . . . . . 44
4.3 Insertion de commande sémantique Vérification de l’existance de donnée . . 44
4.4 Insertion de commande sémantique de vérification de l’existence de donnée . 45
4.5 Vérification de l’existence de donnée lors de l’affectation . . . . . . . . . . . 45
5.1 Hello World Tasm assembleur . . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.2 Structure d’une fichier Tasm vide . . . . . . . . . . . . . . . . . . . . . . . . 53
v
LISTINGS
5.3 Générateur de code machine . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.4 L’envoie de valeur des unitées lexicale caractere et chaine . . . . . . . . . . . 56
vi
Table des matières
Introduction x
1 Contexte et état de l’art 1
1.1 Phase d’analyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.1 Analyseur lexicale : . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.2 Analyseur syntaxique : . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.3 Analyseur sémantique : . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Phase de synthése : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.1 Production de code intermediaries : . . . . . . . . . . . . . . . . . . 3
1.2.2 Optimisation de code : . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.3 Production de code : . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Phases logiques de la compilation d’une instruction . . . . . . . . . . . . . . 4
1.4 Couple Flex Bison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4.1 Flex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4.2 Bison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2 Analyse lexicale 6
2.1 Le rôle de l’analyseur lexical . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1.1 Unités lexicales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1.2 Motif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.3 Lexème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.4 Erreur lexical . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2 Spécification des unités lexicales . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2.1 Expression régulières . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2.2 Mémorisation du texte d’entrée (couple de tampons) . . . . . . . . . 9
2.2.3 Diagramme de transition . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2.4 Les automates à état finie . . . . . . . . . . . . . . . . . . . . . . . . 11
2.3 Conception et Implémentation d’analyseur lexicales . . . . . . . . . . . . . . 12
2.3.1 Conception d’analyseur lexical . . . . . . . . . . . . . . . . . . . . . . 12
2.3.2 Implémentation d’analyseur lexical . . . . . . . . . . . . . . . . . . . 17
2.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3 Analyse syntaxique 19
3.1 rôle analyseur syntaxique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.1 Gestion des erreurs de syntaxe . . . . . . . . . . . . . . . . . . . . . . 20
3.1.2 Stratégie de rattrapage des erreurs . . . . . . . . . . . . . . . . . . . 20
3.2 Grammaire non contextuelle . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2.1 Définition formelle des grammaire non contextuelle . . . . . . . . . . 21
vii
TABLE DES MATIÈRES
3.2.2 Arbre d’analyse et dérivation . . . . . . . . . . . . . . . . . . . . . . 22
3.3 Analyse syntaxique descendante . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.3.1 Analyse syntaxique par descente récursive . . . . . . . . . . . . . . . 23
3.3.2 Grammaire LL(1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.4 Analyse syntaxique ascendante . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.4.1 Analyse syntaxique par décalage-réduction . . . . . . . . . . . . . . . 24
3.5 Conception et implémentation d’analyseur syntaxique . . . . . . . . . . . . . 25
3.5.1 Conception d’analyseur syntaxique . . . . . . . . . . . . . . . . . . . 25
3.5.2 Implémentation d’analyseur syntaxique . . . . . . . . . . . . . . . . . 37
3.6 Coclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4 Analyse sémantique 42
4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.2 Installation et vérification de l’existence des sous programme et porteurs des
données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.2.1 Les sous programmes . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.2.2 Porteur de donné . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.3 Vérification sémantique des instructions d’affectation . . . . . . . . . . . . . 45
4.4 Vérification sémantique d’allocation de mémoire avant l’étape de l’exécution 46
4.5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5 Génération de code assembleur 48
5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.2 Etude de générateur de code cible . . . . . . . . . . . . . . . . . . . . . . . . 49
5.2.1 Coût d’un programme et cout des instructions . . . . . . . . . . . . . 49
5.2.2 Jeu d’instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.3 Architecture 8086 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.3.1 Les registres Généraux . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.3.2 Les registres segment . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.4 Choix de l’assembleur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.5 Turbo assembler Tasm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.5.2 Structure de fichier assembleur Tasm . . . . . . . . . . . . . . . . . . 53
5.6 Génération du code machine relative à la code source . . . . . . . . . . . . . 53
5.6.1 Association de mémoire aux niveau de porteur de donnée . . . . . . . 54
5.6.2 Affichage de donnée sous le console . . . . . . . . . . . . . . . . . . . 55
5.6.3 Récupération de donnée à traver le console . . . . . . . . . . . . . . . 56
5.7 Conclution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
6 Conception d’interface compilateur 58
6.1 introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.2 Conception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.2.1 Capture des besoins . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
6.2.2 Methodologie de conception . . . . . . . . . . . . . . . . . . . . . . . 60
6.2.3 Diagramme de cas d’utilisation . . . . . . . . . . . . . . . . . . . . . 61
6.2.4 Diagramme de séquence . . . . . . . . . . . . . . . . . . . . . . . . . 62
6.2.5 Diagramme de classes . . . . . . . . . . . . . . . . . . . . . . . . . . 63
6.3 Interconnexion interface et compilateur . . . . . . . . . . . . . . . . . . . . . 64
6.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
viii
TABLE DES MATIÈRES
7 Réalisation et test 66
7.1 introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.2 Environnement logiciel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.2.1 QT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.3 Travail réalisé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
7.3.1 Etude de répartition des composants de l’interface . . . . . . . . . . . 68
7.3.2 Capture d’écran de notre interface principale . . . . . . . . . . . . . . 69
7.3.3 Capture d’écran de fonctionnement de zone traitement de code . . . . 69
7.3.4 Capture d’écran de traitement des erreurs de compilation . . . . . . . 70
7.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Conclusion et perspectives 72
Bibliographie 74
ix
Introduction
La programmation, d’après le Nouveau Petit Robert 1
, recouvre « l’élaboration et la codi-
fication de la suite d’opérations formant un programme », un programme, aussi appelé
un logiciel, étant « l’ensemble des instructions rédigé dans un langage de programmation
permettant à un système informatique d’exécuter une tâche donnée ».
Cette définition souligne le rôle essentiel du langage de programmation comme vecteur de
communication entre le programmeur et l’ordinateur. Cependant, elle ne fait pas apparaître la
grande diversité des nombreux langages de programmation existants, un seul de ces langages
est directement exécutable par les circuits de l’ordinateur : il s’agit du langage machine
lorsqu’il se présente sous forme de nombres (les «0 et 1» bien connus du grand public), ou
encore du langage assembleur lorsqu’il se présente sous forme textuelle.
Ces langages machine ou assembleur sont dits «de bas niveau», car les ordres exprimés
dans ces langages manipulent directement les composants de l’ordinateur que sont les re-
gistres, la mémoire et les périphériques.
Quel que soit le langage dans lequel un programmeur écrit ses logiciels, il faut savoir passer
de ce langage de plus ou moins haut niveau au langage de la machine. La compilation est le
processus qui traduit un langage de programmation vers le langage machine. Cette traduction
est effectuée automatiquement par un programme appelé compilateur, qui produit du code
machine, les grandes différences d’expressivité entre un langage de programmation de haut
niveau et un langage machine ou assembleur rendent très difficile la transformation directe
entre les deux langages.
Nous allons explorer à quel point un compilateur est conçu et organisé. Nous allons voir
que ses principales composantes impliquent une sorte de système expert, à l’aide des règles
de production. Le principal défi dans un compilateur donner un sens à une longue séquence
de caractères dans un fichier source. C’est un problème difficile en informatique, en fait, c’est
une forme d’intelligence artificielle : comment faire correspondre quelque chose qui est claire
et sensée à un être humain dans quelque chose qui est clair et sensible à une machine comme
l’indique la figure 1.
1. Le Nouveau Petit Robert est un dictionnaire de langue française, publié par les dictionnaires le Robert,
Reconnais par sont richesse et possibilité de rechercher à travers le web.
x
Introduction générale
compilateurE E
c
erreur
input file output File
Figure 1 – Principe de compilateur
Un langage de programmation de haut niveau définie un abstraction : le programmeur
exprime un algorithme en utilisant le langage et le compilateur doit traduire ce programme
vers le langage cible. De façon général, il est plus facile de programmer en utilisant les
langages de plus haut niveau, mais on obtient des programmes cibles qui s’exécutent plus
lentement.
Le programmeur qui utilise un langage de plus bas niveau a plus de contrôle pour les
calculs et qui peut ensuite écrire des codes plus efficace. Malheureusement, les programmes
de bas niveau sont plus difficiles à écrire et surtout moins portable et plus difficiles à faire
évoluer. De nos jour, on remarque l’apparition de plusieurs langages de programmation dans
plusieurs domaines informatique. Mais la question que se pose " Qu’elle est le meilleur lan-
gage ? " bien sûr la réponse de cette question dépend principalement à cette de question "
Qu’elle est le domaine d’application du langage ? ".
Toutes les fois ou un langage de programmation est apparaitre, elle supplante d’autre en
terme de popularité, l’évolution s’est faite vers des niveaux d’abstraction supérieures, C fut
le langage prédominant pour la programmation système dans les années 1980, pour les projet
démarrés dans les années 1990, le choix se porta souvent vers C++, JAVA, introduit en 1995
gagna rapidement en popularité a la fin de la décennie [1] .
Le meilleure bénéfice de programmeation haut niveau est l’apparition des nouveaux outils
ou bien l’amélioration des anciens, qui sont bien équipés d’un syntaxe qui est de plus en plus
proche d’eux.
L’évolution de syntaxe de programmation est ascendant au niveau de simplicité et d’effica-
cité, on peut distinger cette évolution, lorsque on fait un étude comparatif entre C++,Java[3]
et Python[2] induquée dans les listings 1,2 et 3 .
1 #include <iostream.h>
2 int main ()
3 {
4 cout << "Hello World" ;
5 return 0
6 }
Listing 1 – Hello World avec C++
1 #include <iostream.h>
2 public class Hello
3 {
4 public static void main (String args)
5 {
6 System.out.println("Hello World") ;
7 } }
Listing 2 – Hello World avec Java
xi
Introduction générale
1 print("hello World")
Listing 3 – Hello World avec Python
La contrainte du temps et l’acheminement de l’apparition des langages de programmation
n’est pas une raison de jugement entre les langages de programmation et de distinguer les
fonctionnalités. Cependant, que java qui apparaitre après c++ ne supporte pas la notion de
pointeur et de multihéritage qui sont fournies avec leur prédécesseur.
xii
Chapitre 1
Contexte et état de l’art
Sommaire
1.1 Phase d’analyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.1 Analyseur lexicale : . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.2 Analyseur syntaxique : . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.3 Analyseur sémantique : . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Phase de synthése : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.1 Production de code intermediaries : . . . . . . . . . . . . . . . . 3
1.2.2 Optimisation de code : . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.3 Production de code : . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Phases logiques de la compilation d’une instruction . . . . . . . . . . . . 4
1.4 Couple Flex Bison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4.1 Flex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4.2 Bison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Résumé chapitre
Au niveau de ce chapitre nous étudions le processus de compilation, les différentes
phases inclues dans ce processus, les différents analyseurs permettant la transformation
d’une instruction décrite dans un langage de haut niveau à son équivalente de code
machine.
1
CHAPITRE 1. CONTEXTE ET ÉTAT DE L’ART
N ous avons jusqu’à ici considéré un compilateur comme une boite noire qui transforme
un programme source en un programme cible sémantiquement équivalent. Ouvrons un
peu cette boite nous distinguons deux parties dans cette transformation :
Phase d’analyse
La phase d’analyse permet principalement de décomposer le programme source en des
constituants, tout en associant à chacun une structure grammaticale, elle utilise ensuite cette
structure pour détecter si le programme source est syntaxiquement mal formé ou sémanti-
quement incorrecte. Elle accumule également diverses informations qu’elles conservent dans
une structure de données nommée table de symbole, elle est constituée principalement de
trois analyseur
Analyseur lexicale :
Le mot «lexicale» dans le sens traditionnel du terme signifie «se rapportant à des paroles»,
sur le plan des langages de programmation, les mots sont des objets comme noms de variables,
les numéros, les mots clés, etc. Ces mots sont traditionnellement appelés jetons.
Un analyseur lexical aura en entrée une chaîne des caractères de l’individu, sont principale
rôle et de diviser cette chaîne en unité lexicale. En outre, il va filtrer tout ce que sépare les
jetons (ce qu’on appelle caractère superflus).
L’objectif principal de l’analyse lexicale est de rendre la vie plus facile par la suite à
l’analyseur syntaxique. En théorie, le travail qui est effectué lors de l’analyse lexicale peut
faire partie intégrante de l’analyse syntaxique.
Analyseur syntaxique :
L’analyseur syntaxique est à peu près l’équivalent de vérifier du texte ordinaire écrit dans
un langage naturel est grammaticalement correct (sans se soucier de sens).
Le but de l’analyse de syntaxe est de vérifier que nous avons une séquence valide de jetons
envoyée par l’analyseur lexical, notez que cette séquence n’a pas besoin d’avoir un sens.
La correspondance entre le programme et les règles syntaxique est généralement hiérar-
chique, et peut être spécifiée par un arbre de dérivation pour le programme pour y utilisé
dans la phase de génération de code.
Analyseur sémantique :
L’analyse syntaxique vérife seulement que le programme se compose des jetons disposés
dans une combinaison valide de syntaxe. Maintenant, nous allons passer à l’analyse séman-
tique, où nous plongeons profondément afin de vérifier si elles forment un ensemble logique
d’instructions.
Pour qu’un programme puisse être sémantiquement valide, toutes les variables, fonctions,
classes, etc, doivent être correctement définis. Les expressions et les variables doivent être
utilisées de manière que le respect du système de type, de contrôle d’accès doivent être
respectés, et ainsi de suite.
L’analyse sémantique est l’avant-dernière phase avant la fin de la dernière chance du
compilateur pour éliminer les programmes incorrectes. Nous avons besoin d’être assurer que
le programme est suffisamment solide pour continuer à la génération de code.
2
CHAPITRE 1. CONTEXTE ET ÉTAT DE L’ART
Phase de synthése :
La partie de synthèse (back-end) construit le programme cible souhaité à partir de la
représentation intermédiaire et les informations dans la table des symboles.
Production de code intermediaries :
Au cours de la traduction d’un programme source en code machine pour une machine
cible, un compilateur peut générer un code de langue de niveau moyen, il est connu sous le
nom de code intermédiaire et texte intermédiaire. La complexité de ce code se trouve entre
le code de la langue source et le code objet.
Le code intermédiaire peut être représenté sous la forme d’un arbre de syntaxe à trois
adresses de code, cette représentation doit avoir deux propriétés importantes : elle doit être
facile à produire à partir de l’arbre syntaxique et facile à traduire en langage cible.
Optimisation de code :
La phase d’optimisation de code indépendante de la machine tente d’améliorer le code in-
termédiaire afin d’avoir un meilleur code cible. En général, meilleur signifie plus rapide. Mais
on peut viser d’autres objectifs, comme un code final plus court ou consommant peu d’éner-
gie. Quelques optimisations simples peuvent améliorer efficacement le temps d’exécution du
programme cible sans retarder trop la compilation.
Production de code :
Le générateur du code prend en entrée une représentation intermédiaire du programme
source et la réécrit dans un langage cible. Si le langage cible est un code machine, à chaque
variable de programme on fait correspondre un registre ou une adresse de mémoire. Ensuite
les instructions intermédiaires sont traduites en séquence d’instruction machine qui effectuent
la même tache.
3
CHAPITRE 1. CONTEXTE ET ÉTAT DE L’ART
Phases logiques de la compilation d’une instruction
c
Analyseur lexical
c
Position = Initiale + Vitesse * 60
<id,1> <=> <id,2> <+> <id,3> <*> <60>
Analyseur syntaxique
c
=
<id,1>
¨¨ €€
+
<id,2>
¨¨ €€
*
<id,3>
¨¨ €€
60
Analyseur sémantique
c
=
<id,1>
¨¨ €€
+
<id,2>
¨¨ €€
*
<id,3>
¨¨ €€
intToFloat
60
Génération de code intermédiaire
c
t1 = intToFloat(60)
t2 = id,3 * t1
t3 = id2 + t2
id1 = t3
Optimiseur de code
c
t1 = id,3 * 60.0
id1 = id2 + t1
Générateur de code
c
LDF R2, id,3
MULF R2, R2, 60.0
LDF R1, id2
ADDF R1, R1, R2
STF id1, R1
Table de symbole
Position1 ...
Initiale2 ...
Vitesse3 ...
Figure 1.1 – Exemple de compilation d’une instruction
4
CHAPITRE 1. CONTEXTE ET ÉTAT DE L’ART
Couple Flex Bison
Lex 1
et YACC 2
sont des outils Linux qui engendrent des programmes d’analyse du texte.
Les programmes générés offrent des fonctionnalités de reconnaissance, de structuration, de
traduction d’un texte écrit dans un langage donné.
Flex et Bison nouveauté de lex et yacc sont des outils de construction de programme qui
gèrent d’entrées structurées, ils ont l’origine des outils de construction des compilateur.
Flex
Flex (abréviation de Fast Lexical Analyzer) est un outil conçu à l’aide du développement
du compilateur. En particulier, flex est un outil qui s’occupe principalement à l’étape première
de la réalisation de compilateur. Comme étant un analyseur lexical, flex est un programme
qui reconnaît les modèles lexicales du texte fournie en entrée, ou son entrée standard est le
nom de fichier donné pour une description d’un scanner à générer sous la forme d’extension
".l", la description est à la forme de paires d’expressions régulières et de code C appelée règles.
Flex génère en sortie un fichier source C "lex.yy.c" par défaut ,ce fichier après avoir compiler
et générer leur exécutable analyse son entrée pour les occurrences de modèle lexicale, chaque
fois qu’elle en trouve un, il exécute le code C correspondant [4].
Bison
Bison est un outil qui s’occupe principalement à la deuxième étape de réalisation de
compilateur, comme étant un analyseur syntaxique, bison est un programme qui vérifier
le rangement des modèles lexicales envoyé par flex. Cependant flex et bison travaillent la
main dans main puisque bison appelle flex à chaque fois qu’il veut un nouveau modèles
lexicale. Bison doit être décrit par une grammaire, cela signifie que vous spécifiez un ou
plusieurs regroupements syntaxiques et donner des règles pour les construires à partir de ces
regroupements. Il prend comme entrée un fichier d’extension ".y" contenant ces regroupement
grammaticales et fournit en sortie deux fichiers portant leur nom : la première contient le
code C de l’analyseur (analyseur.tab.c) et la deuxième contient la définition des codes des
modèles lexicales (analyseur.tab.h), afin qu’elle puissent être partagée par les deux premiers
analyseur comme l’induque la figure 1.2 [5].
compilateur C
FLEXE
E
c
input File
EEa.exe
Bison.tab.c + Bison.tab.h
Flex.l
Lex.yy.c
BISONE
Bison.y
E
Figure 1.2 – Couple Flex Bison
1. Lexical parser
2. Yet Another Compiler Compiler
5
Chapitre 2
Analyse lexicale
Sommaire
2.1 Le rôle de l’analyseur lexical . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1.1 Unités lexicales . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1.2 Motif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.3 Lexème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.4 Erreur lexical . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2 Spécification des unités lexicales . . . . . . . . . . . . . . . . . . . . . . . 8
2.2.1 Expression régulières . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2.2 Mémorisation du texte d’entrée (couple de tampons) . . . . . . . 9
2.2.3 Diagramme de transition . . . . . . . . . . . . . . . . . . . . . . 10
2.2.4 Les automates à état finie . . . . . . . . . . . . . . . . . . . . . . 11
2.3 Conception et Implémentation d’analyseur lexicales . . . . . . . . . . . . 12
2.3.1 Conception d’analyseur lexical . . . . . . . . . . . . . . . . . . . . 12
2.3.2 Implémentation d’analyseur lexical . . . . . . . . . . . . . . . . . 17
2.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Résumé chapitre
Au niveau de ce chapitre nous étudions la décomposition de texte source en des mots
selon une structure de successivité des caractères, les outils de détection et de revoie de
ces mots à l’analyseur suivant, la réservation des mots clé choisie pour le fonctionnement
de compilateur.
6
CHAPITRE 2. ANALYSE LEXICALE
Le rôle de l’analyseur lexical
L’analyse lexicale est la première phase d’un compilateur, la principale tâche accomplie
par cette phase consiste à identifier l’ensemble des mots d’un langage valide qui se pro-
duit dans un flux d’entrée 1
. Cependant, l’analyseur lexical agit comme une interface entre
le programme source à compiler et la suite du compilateur, il lit les caractères constituent le
programme source et les regroupés en lexèmes. L’analyseur lexical convertit ces lexèmes en
un flux des mots valides de la langue, mieux connues sous les noms d’unités lexicales (Tokens).
L’analyseur syntaxique et l’analyseur lexical travail main dans la main, dans le sens que
à chaque fois l’analyseur syntaxique a besoin de plus jeton, il demande à l’analyseur lexical
qui est à son tour numériser le flux d’entrée restantes et retourne le jeton produisant ensuite.
L’idée est expliquée dans la figure 2.1.
analyseur lexicale Suite de complilateur
Table de symbole
E
E
'
Jeton
demande de jeton
Source
¨
¨¨¨
¨¨¨¨
¨¨¨B
r
rrr
rrr
rrrr‰r
rrr
rrr
rrrrj
¨
¨¨¨
¨¨¨
¨¨¨¨%
Figure 2.1 – Principe de compilateur
En dehors de cela, l’analyseur lexical participe également à la création et à la maintenance
de la Table Symbole. C’est parce que, il est le premier module d’identifier l’apparition d’un
symbole, s’il est défini pour la première fois, il doit l’installer dans la table de symbole.
L’analyseur lexical est également responsable pour enlever les cosmétiques du programme
comme des espaces blancs supplémentaires, commentaires, etc.
Unités lexicales
Une unité lexicale est un couple constitué d’un nom lexicale et d’une valeur d’attribut
optionnelle. Le nom d’unité lexicale est un symbole abstrait représentant leur type lexicale.
Les noms d’unité lexicale sont les symboles d’entrée que traite l’analyseur syntaxique. Nous
écrivons généralement les noms d’unités lexicales en caractère gras et nous les désignerons
souvent à partir de leur noms.
1. Le flux d’entrée est l’ensemble des caractères de programme source.
7
CHAPITRE 2. ANALYSE LEXICALE
Motif
Un motif est une description de la forme que les lexèmes d’une unité lexicale donnée
peuvent prendre. Dans le cas d’une unité lexicale de type mot clé, le motif est simplement la
séquence de caractère qui forme le mot clé. Pour les identificateurs et d’autres types d’unités
lexicales, le motif est une structure plus complexe qui reconnait de nombreuses chaines des
caractères.
Lexème
Un lexème est une séquence de caractère dans le programme source qui est reconnue par
les motifs d’une unité lexicale, il est identifié par l’analyseur lexical comme une instance de
cette unité lexicale.
Erreur lexical
Il est difficile pour l’analyseur lexicale de dire sans l’aide des autres composants, qu’il
y a une erreur dans le code source. Par exemple si la chaine "Foor" est reconnait pour la
première fois dans un programme C dans le contexte décrit dans la Listing 2.1.
1 foor (int i =0;i<5;i++)
2 cout << i ;
Listing 2.1 – Faux boucle for
Un analyseur lexicale ne peut pas dire si foor est une orthographe erronée du mot clé for ou
un identificateur de fonction non déclaré.
Puisque foor est un lexème pour l’unité lexicale id. L’analyseur lexicale doit retourner
l’unité lexicale id à l’analyseur syntaxique et laisse une autre phase de compilateur gérer une
erreur due à la permutation des deux lettres.
Spécification des unités lexicales
Expression régulières
Les expression régulières sont les ensembles de toutes les constantes entières ou l’ensemble
de tous les noms de variables ou les ensembles des chaînes, où les lettres individuelles sont
prises à partir d’un alphabet.
Un tel ensemble de chaîne est appelée un langage. Pour les entiers, l’alphabet se compose
de chiffres de 0-9, les noms de variables de l’alphabet contient à la fois des lettres et des
chiffres (et peut-être quelques-uns d’autres caractères, tels que tiret bas).
Étant donné un alphabet, nous allons décrire des ensembles de chaînes de caractères par
des expressions régulières. Une notation algébrique qui est compact et facile pour les humains
à utiliser et à comprendre [6].
8
CHAPITRE 2. ANALYSE LEXICALE
Expression régulières reconnue par Flex
Les expressions régulières acceptées par Flex paraissent souvent comme les autres expres-
sions régulières on peut distinguer quelques différences au niveau de représentation et des
caractères spéciaux indique dans la figure 2.2.
Caractère Signification
+ Un ou plusieurs fois
* 0 ou plusieurs fois
? 0 ou un fois
- Intervalle d’ensemble
Caractère Signification
| Union
" Valeur littérale des carac.
. Tout car sauf fin de ligne
Complément d’ensemble
Figure 2.2 – Caractère spéciaux de Flex
Mémorisation du texte d’entrée (couple de tampons)
Il existe des cas ou l’analyseur lexical doit lire en avance quelque caractère. Une partie im-
portante du temps est consacré au déplacement des caractères. Il existe plusieurs techniques
spéciales de mémorisation permettant de réduire le coût lié au traitement des caractères
du texte d’entrée. Cependant, les techniques sont dépendantes des paramètres du systèmes.
Nous présentons dans ce qui suit les principes reliés à la reconnaissance des unités lexicales
comme l’indique le fique 2.3.
x = a 1 + 3 EOF
T
c
Avant
Head
Figure 2.3 – Un tampon d’entrée en deux moitiés
L’idée est d’utiliser un tampon divisé en deux moitiés de N caractère. N peut être le
nombre de caractère dans un bloc de disque 2
, s’il reste moins que N caractères en entrée, un
caractère spécial EOF (End Of File) est placé dans le tampon après les caractères d’entrée.
Par exemple le développeur doit gérer deux pointeurs vers le tampon d’entrée. L’ensemble
de caractères situés entre les deux pointeurs constituent le lexème en cours.
2. Le bloc de disque (en anglais cluster) est la plus petite unité de stockage d’un système de fichiers.
9
CHAPITRE 2. ANALYSE LEXICALE
Au départ les deux pointeurs Head et Avant désignent le premier caractère du prochain
lexème à trouver :
L’un appelé le pointeur Avant, lit en avant jusqu’à trouver un modèle, une fois que le
prochain lexème est reconnu, le pointeur Avant est positionné sur le caractère à sa droite,
après le traitement de ce lexème, les deux pointeurs sont positionnés sur le caractère qui suit
immédiatement le lexème.
Si le pointeur Avant est sur le point de dépasser la marque de moitié, la moitié droite est
remplie avec N nouveaux caractères d’entrée, si le pointeur Avant est sur le point de dépas-
ser l’extrémité droite du tampon, la partie gauche est remplie avec N nouveaux caractères
d’entrées, et le pointeur Avant poursuit circulairement au début du tampon.
Diagramme de transition
Les diagrammes de transition sont une étape préparatoire pour la réalisation d’un analy-
seur lexical. Cette étape consiste principalement à convertir les motifs exprimés sous forme
d’une expression régulière en organigramme stylisé (diagramme de transition).
Les diagrammes de transition comprennent un ensemble des nœuds ou des cercles appelés
états, chaque état représente une condition qui peut être réalisée pendant le parcours de
l’entrée à la recherche d’un lexème qui soit reconnu par un ou plusieurs motifs. Des arcs
relient un état du diagramme de transition à un autre, chaque arc est étiqueté par un symbole
ou un ensemble de symbole, si l’on est dans un état ’0’ et si le symbole d’entrée suivant est
’a’ on cherche un arc qui part de ’0’ et qui est étiqueté par ’a’, le passage d’un état à un état
et totalement relatif à l’incrémentation du pointeur Avant lors de lecture de caractère.
0start 1
a
Figure 2.4 – Exemple de diagramme de transition
On distingue deux types d’états permettant de référencer la progression de l’étape de
reconnaissance des unités lexicales :
- Un état désigné comme étant l’état de départ ou état initial : il est indiqué par un arc,
étiqueté "start" qui ne vient d’aucun arc, le diagramme de transition part de l’état initial,
avant toute lecture de symbole d’entrées.
- Certains états sont dits d’acceptation ou finaux, ces indiquent d’un lexème à été trouvé.
On indique toujours un état final par double cercle et si une action doit être effectué (typi-
quement, transmettre une unité lexicale et une valeur d’attribut à l’analyseur syntaxique)
on attache cette action à l’état final.
Parfois, nous ne somme pas obligé de revenir en arrière en décrémentant le pointeur Avant
par un pas en cas où le lexème n’inclut pas le symbole qui nous a amenés à l’état final, alors
10
CHAPITRE 2. ANALYSE LEXICALE
on ajoute le symbole "*" à l’état final.
La figure 2.5 montre le diagramme traduise la reconnaissance des unités lexicales INFEG,
DIFF, INF, EGAL, SUPEG, SUP et IDENTIF respectivement définie par les expressions
régulières <=, <>, <, =, >=, >.
0start 1 2
3
4
5
6 7
8
<
=
>
=
>
autre
autre
= Return(SUPEGAL)
Return(SUP)
Return(INF)
Return(DIFF)
Return(INFEGAL)
Return(EGAL)
*
*
Figure 2.5 – Diagramme de transition des opérateur
Les automates à état finie
Les expressions régulières sont pratique pour spécifier des jetons lexicaux, mais nous
avons besoin d’un formalisme qui peut être réalisé par un ordinateur comme un programme
informatique. Pour cela, nous pouvons utiliser des automates finis.
Un automate finie est un ensemble finie d’états et des arcs conduisant d’un état à un
autre. Comme étant une spécification de diagramme des transition. Les automates à état
finie sont répartie en des états(terminaux et non-terminaux), chaque état est marqué par un
symbole qui représente l’état courant [6].
Les automates à état finie non déterministe
Un automate finie non déterministe (AFN) est celui qui a un choix d’arêtes étiquetées
avec le même symbole sortir de l’état ou il peut avoir des bords spéciaux marqués avec la
lettre grecque epsilon qui peut être suivie sans passer de n’importe quel symbole de l’entrée
[6] .
Les automate à état finie déterministe
Les Automates non déterministes sont comme mentionnés plus haut, pas tout à fait proche
de "la machine" que nous le souhaiterions. Par conséquent, nous introduisons maintenant
11
CHAPITRE 2. ANALYSE LEXICALE
une forme plus restreinte des automates finie : L’automate finie déterministe, ou (AFD) est
un automate à état finie déterministe, mais qui obéissent à un certain nombre de restrictions
supplémentaires :
— Il n’y à pas epsilon-transitions.
— Deux transitions ne peuvent pas être étiquetées par le même état.
Cela signifie que nous n’avons jamais le choix entre plusieurs cotés d’états : le symbole
d’entrée suivant déterminer de façon unique la transition. C’est pourquoi ces automates sont
appelés déterministe.
Conception et Implémentation d’analyseur lexicales
Conception d’analyseur lexical
L’étape de conception consiste à définir les expressions régulière pour les différentes unités
lexicales, cette définition suivie d’une automate déterministe représentée sous forme d’un
diagramme de transition pour mieux comprendre l’étape de récupération de ces unités et
leur méthode de reconnaissance.
Les identificateurs :
Un identificateur est un suite de caractère et de nombre qui ne doit pas commencer par
un nombre ou caractère réservé (les opérateurs . . . ) et qui peut contenir un caractère de
séparation ’_’ (tiré bas).
Le diagramme de transition représenté dans la figure 2.6, décrit la manipulation des
identificateurs au niveau de l’analyseur lexicale.
0start 1
a-z A-Z
_
a-z A-Z
0-9
_
Figure 2.6 – Diagramme de transition des identificateur
L’expression régulière permet de reconnaître un identificateur est la suivante :
ident [a-zA-Z_] ([0-9a-zA-Z_])*
Expression régulière flex
Tout en respectant les contraintes au niveau de l’identificateur, On doit l’associer un nom
significatif pour qu’on puisse référencer ultérieurement dans l’analyseur syntaxique, dans
notre cas ident désigne un occurrence d’un lexème au niveau de code source. La deuxième
partie de l’expression flex désigne l’expression régulière habituelle qu’on trouve répartie lo-
giquement en deux parties :
12
CHAPITRE 2. ANALYSE LEXICALE
— La première décrit l’obligation de commencement par une lettre ou tiré bas.
— La deuxième représente la libération de choix aux développeurs.
Les chaines des caractères :
Une chaine des caractères est une suite de caractères qui sont éliminées par deux ca-
ractères spéciaux réservés pour leur récupération(""). Le problème majeur est qu’on peut
trouver un mot clé réservé au fonctionnement de compilateur (if ) dans la suite de caractère
de chaine, donc il est souvent important de déclarer l’analyseur lexicale du l’importance de
sauter à la position de deuxième séparateur sans tenir compte à l’intérieur de chaine.
Le diagramme de transition représenté ce dessus, décrit la manipulation des chaines des
caractères aux niveau de l’analyseur lexicale.
0start 1 3
"
a-z A-Z
0-9
"
Figure 2.7 – Diagramme de transition des chaines des caractères
L’expression régulière permet de reconnaître une chaine des caractères est la suivante :
"""(.)+""" { return(CHAINE) ; }
Expression régulière flex
Nous référençons ce séquencement limité des caractères par le nom d’unité lexicale chaine.
La première partie désigne tous les caractères sauf le retour à la ligne (au niveau de dia-
gramme de transition ci-dessus, a-z, A-Z désigne toutes les occurances des caractére puisque
nous pouvons pas traité tous les cas ).
Le premier guillemet élimine tous les chances pour renvoyer une autre unité à l’intérieur
de chaîne puisque le pointeur avant est initialisé et qui bascule directemant à la position de
deuxiéme guillemet.
Les caractères :
Les caractères sont des cas particuliers de chaine de caractère. Ils sont tout simplement
une chaine de longueur un. Mais la question qui se pose "est ce que l’analyseur lexicale va
envoyer une unité lexical qui référence une chaine de caractère ou bien un caractère ", deux
réponses possible pour cette question :
— La solution JAVA consiste à les distingués par les séparateur c’est à dire pour les
chaines de caractères on doit l’éliminer par les "" et pour les caractères par ”.
13
CHAPITRE 2. ANALYSE LEXICALE
— L’autre solution est de renvoyer deux unités lexicales distinctes référencées les chaines
des caractères et les caractère et laisser la distinction s’appuie à l’analyseur séman-
tique pour décrire le comportement de l’unité lexical, puisque une chaine de caractère
peut contenir un caractère et l’inverse est faux.
Le diagramme de transition représenté dans la figure 2.9, décrit la manipulation des caractères
au niveau de l’analyseur lexicale.
0start 1 3 4
"
a-z A-Z
0-9 "
Figure 2.8 – Diagramme de transition des caractères
L’expression régulière permet de reconnaître un caractère est la suivante :
""".""" { return(CARACTERE) ; }
Expression reguliere flex
L’unité lexicale CARACTERE se réfère à l’existence d’un caractère, leur expression ré-
gulière paraît comme celle de chaine de caractères (a-z A-Z et 0-9 désigne tous caractéres)
mais sans avoir la possibilité d’écrire plusieurs caractères.
Les entiers et réels :
Les entiers sont le séquencement des chiffres sans aucun séparateur entre eux. Les réels
sont deux entiers séparés par un point. D’après les règles arithmétiques, un réel peut contenir
un entier ce qui cause un problème au niveau de l’analyseur lexicale. Aux niveau de cette
phase en va les distingue par leur unité lexicale. La vérification de sémantique de l’apparition
de ces deux unités ce fait au niveau de l’analyseur sémantique.
Le diagramme de transition représenté ce dessus, décrit la manipulation des entiers et les
réels aux niveau de l’analyseur lexicale.
0start 1 3 4
0-9
0-9
.
0-9
0-9
Figure 2.9 – Diagramme de transition des entier et réel
L’expression régulière permet de reconnaître un entier ou réel est la suivante :
14
CHAPITRE 2. ANALYSE LEXICALE
nbr [0-9]+
entier nbr
reel entier.nbr
Expression reguliere flex
Les deux unités lexicales entier et reel réfèrents successivement les entiers et les réels.
Les opérateurs arithmétique et opérateurs logique
Les opérateurs arithmétiques restent inchangables au niveau des instructions arithmé-
tique. Le traitement des opérateurs logique se diffère d’un compilateur à un autre.
Pour garantir la bonne fonctionnement de compilateur multi-langages on doit associer les
différentes représentations de ces opérateur l’un à l’autre.
L’analyseur lexicale doit renvoyer la même unité lexicale, lorsqu’il rencontre la même
signification des lexèmes, par exemple le lexème OR aux niveau de VB.NET est équivalant
à celui aux niveau de C++, cet exemple est pratique à la totalité des opérateurs logique.
Les mots clés :
les mots clés sont les mots réservés à la fonctionnement de compilateur. Ils sont considéré
par l’analyseur syntaxique comme étant des identificateurs (ils aient l’air d’identificateur )
car ils ont le même motif d’expression régulière.
La reconnaissance de mot clé et des identificateurs représentent un problème, est il y’a
deux façons de traiter les mots réservé qui ont l’air d’identificateur :
— Charger les mots réservés dans une table de symbole dès le départ, un champs d’en-
trées de la table de symbole indique que les chaines ne sont jamais des identificateurs
ordinaires et indique qu’elle unité lexicale le représente.
— Créer des diagrammes de transition représentant graphiquement les différences entre
les identificateurs et les mots réservées.
Le diagramme de transition représenté dans la figure 2.10, décrit un exemple de manipu-
lation des identificateurs par rapport aux mots réservées au niveau de l’analyseur lexicale.
15
CHAPITRE 2. ANALYSE LEXICALE
0start
2
4 IF
5INT
1 6
7
8
9
17
13
14
STEP
Identificateur
15
16
12 STRING
3 10
Entier
11 REEL
i
0-9
s
a-z
sauf i, s
t a-z sauf t
a-z
Return
f a-z sauf f,nn
t
a-zsauft
e
r
a-z
saufr,e
n
g
a-zsaufg
p
a-zreturn
i
a-zsaufi
i
Return
a-z
Return
0-9 .
Return
0-9
0-9
return
a-z
Return
a-z
Return
Figure 2.10 – Différence entre les mots clé et les identificateurs
16
CHAPITRE 2. ANALYSE LEXICALE
Implémentation d’analyseur lexical
Puisque l’analyseur lexicale a le contrôle sur le flux d’entrée, il doit être attaché à l’amélio-
ration qui nécessite de compilateur. L’analyseur lexicale doit se référer à la ligne courant pour
bien identifier les erreurs lexicales ou bien syntaxiques, le listing 2.2 représente un example
non-complet d’implémentation d’analyseur lexicale.
1 %{
2 #include <stdlib.h>
3 #include "compilateur.h"
4 int line =1;
5 %}
6
7 %x IN_COMMENT
8
9 blanc [ t]+
10 nbr [0 -9]+
11 entier {nbr}
12 reel {entier }.{ nbr}
13 ident [a-zA -Z_]([0 -9a-zA -Z_])*
14
15 %%
16
17 """(.)+""" { strcpy(yylval.Tstr ,yytext);
18 return(CHAINE); }
19
20 "//"(.)+"" { strcpy(yylval.Tstr ,yytext);
21 return(COMM); }
22
23 <INITIAL > {
24 "/*" BEGIN(IN_COMMENT);
25 return(COMMPL);
26 }
27 <IN_COMMENT >{
28 "*/" BEGIN(INITIAL);
29 n line ++;
30 }
31
32 {a}{d}{d} return(ADD);
33 {v}{o}{i}{d} return(VOID);
34 {m}{a}{i}{n} return(MAIN);
35
36 {i}{n}{t}{e}{g}{e}{r} return(DEC_ENTIER);
37 {i}{n}{t} return(DEC_ENTIER);
38 {r}{e}{a}{l} return(DEC_REEL);
39 {f}{l}{o}{a}{t} return(DEC_REEL);
40 {c}{h}{a}{r} return(DEC_CARA);
41 {s}{t}{r}{i}{n}{g} return(DEC_CHAINE);
42
43 {w}{r}{i}{t}{e} return(WRITE);
44 {r}{e}{a}{d} return(READ);
45
46 {t}{h}{e}{n} return(THEN);
47 {e}{n}{d}{i}{f} return(ENDIF);
48 {e}{l}{s}{e} return(ELSE);
49 {i}{f} return(IF);
50
51 . return(POINT);
17
CHAPITRE 2. ANALYSE LEXICALE
52 ":" return(DEUXPOINT) ;
53
54 n {line ++;}
55
56 "=" return(AFFECT);
57
58 "(" return(PARG);
59 ")" return(PARD);
60
61 ">" return(OP);
62 "<" return(OP);
63
64 " <=" return(OP);
65 " >=" return(OP);
66
67 "&&" return(SEP);
68 "||" return(SEP);
69
70 "+" return(PLUS);
71 "-" return(MOIN);
72 "*" return(MULT);
73 %%
Listing 2.2 – Implémentation Flex
Conclusion
Nous avons vu que l’analyse lexicale est le première contact de code source avec le com-
pilateur, puisque il lit l’entrée caractère par caractère et produit en sortie un flux d’unités
lexicales en tenir compte des expressions régulière de ces unités.
18
Chapitre 3
Analyse syntaxique
Sommaire
3.1 rôle analyseur syntaxique . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.1 Gestion des erreurs de syntaxe . . . . . . . . . . . . . . . . . . . . 20
3.1.2 Stratégie de rattrapage des erreurs . . . . . . . . . . . . . . . . . 20
3.2 Grammaire non contextuelle . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2.1 Définition formelle des grammaire non contextuelle . . . . . . . . 21
3.2.2 Arbre d’analyse et dérivation . . . . . . . . . . . . . . . . . . . . 22
3.3 Analyse syntaxique descendante . . . . . . . . . . . . . . . . . . . . . . . 22
3.3.1 Analyse syntaxique par descente récursive . . . . . . . . . . . . . 23
3.3.2 Grammaire LL(1) . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.4 Analyse syntaxique ascendante . . . . . . . . . . . . . . . . . . . . . . . . 23
3.4.1 Analyse syntaxique par décalage-réduction . . . . . . . . . . . . . 24
3.5 Conception et implémentation d’analyseur syntaxique . . . . . . . . . . . 25
3.5.1 Conception d’analyseur syntaxique . . . . . . . . . . . . . . . . . 25
3.5.2 Implémentation d’analyseur syntaxique . . . . . . . . . . . . . . . 37
3.6 Coclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Résumé chapitre
Au niveau de ce chapitre nous étudions le rôle de l’analyseur syntaxique, la stratégie de
rattrapage des erreurs grammaticales, les différents types de fonctionnement des analy-
seurs syntaxiques, la possibilité de mélanger les déférents langages de programmation
ainsi d’introduire un nouveau syntaxe propre à notre travail.
19
CHAPITRE 3. ANALYSE SYNTAXIQUE
rôle analyseur syntaxique
A près que l’analyseur lexicale divise l’entrée en jetons, le but de l’analyse syntaxique
(également connu sous le nom Parsing ) est de recombiner ces jetons et de découvrir
la structure de texte à utilisé pour déterminer si oui ou non un texte conforme à un format
attendu.
Il s’agit de créer une représentation intermédiaire arborescente qui dépeint la structure
grammaticale du flot d’unité. Cette transformation est envoyée à la suite de processus de
compilation pour traiter ultérieurement (vérification sémantiquement). En plus de trouver
la structure du texte d’entrée l’analyse syntaxique doit également rejeter les textes invalides
par rapport aux erreurs de syntaxe.
Gestion des erreurs de syntaxe
La gestion des erreurs est déléguée au concepteur du compilateur qui prévoit la gestion des
erreurs dés le départ pourront à la fois de simplifier la structure du compilateur et améliorer sa
gestion des erreur. Les erreurs de programmation habituelle peuvent se présenter à différents
niveaux :
— Les erreurs lexicales comprennent les fautes d’orthographe dans les identificateurs, les
guillemets manquants autour d’elles destiné à constituer une chaine de caractère.
— Les erreurs syntaxiques : elles comprennent les fautes de syntaxe telles que les point
virgules mal placés ou les accolades manquantes.
— Les erreurs sémantiques : elles comprennent les erreurs sémantique telles que les in-
cohérences de type entre opérateur et opérande.
— Les erreurs logiques peuvent être de toute nature commençant par les fautes de rai-
sonnement de la part du programmeur jusqu’à l’utilisation de l’opérateur d’affectation
à la place de l’opérateur de comparaison == dans un code C. Le programme conte-
nant = peut être bien formé ; cependant, il pourrait bien ne pas refléter l’intention du
programmeur.
Une autre raison de mettre l’accent sur le rattrapage d’erreur pendant l’analyse syntaxique
est que de nombreuses erreurs paraissent sous la forme d’erreurs de syntaxe, quelles que soient
leurs causes, ils sont donc détecte lorsque l’analyseur syntaxique ne peut se poursuivre.
Les analyseurs syntaxiques modernes doivent équiper d’un gestionnaire d’erreur qui est
fondé pour l’échappement des erreurs énoncer précédemment : - signaler la présence d’un
erreur de façon claire et précise. - Se rattraper après chaque erreur suffisamment vite pour
détecter des erreurs ultérieures.
Stratégie de rattrapage des erreurs
La stratégie de rattrapage d’erreur décrit la réaction de compilateur après la détection
d’une erreur :
20
CHAPITRE 3. ANALYSE SYNTAXIQUE
Rattrapage en mode panique
Avec cette méthode, quand l’analyseur syntaxique découvre une erreur, il élimine les sym-
boles d’entrée les un après les autre jusqu’à on récent un qui appartient à un ensemble des
unités lexicales de synchronisation. Habituellement, les unités lexicales de synchronisation
sont des éliminateurs, tels que le point virgule.
Le concepteur du compilateur doit sélectionner les unités lexicales de synchronisation
appropriées au langage source, bien que le rattrapage au mode panique dépasse en générale
une partie considérable du texte source sans y chercher d’autre erreur[1] .
Rattrapage au niveau du syntagme
Lorsque l’analyseur syntaxique découvre une erreur, il peut effectuer des corrections lo-
cale sur le reste de l’entré, c’est-à-dire remplacer un préfixe du texte source restant par une
chaine qu’il lui permet de continuer.
Le rattrapage au niveau de syntagme a été utilisé dans différent compilateur à rattrapage
d’erreurs, car il peut corriger n’importe quelle chaine d’entrée. Son majeur défaut est qu’il a
du mal à faire face à des situation dans les quelles la véritable erreur eu lieu avant le point
de détection [1].
Grammaire non contextuelle
Une grammaire est définie par un ensemble de symbole terminal (les entrées). Un ensemble
de non-terminal (les symbole représentant des construction syntaxique) et un ensemble de
production, chacun indiquant un moyen selon lequel des chaînes représentées par un non-
terminal peuvent être construite à partir de symboles terminaux.
Définition formelle des grammaire non contextuelle
Nous avons vu qu’une grammaire non contextuelle est constituée de terminaux, de non-
terminaux, d’un symbole de départ et de productions :
- Les terminaux sont les symboles de base dont sont formées les chaînes. Le terme nom
unité lexicale est un synonyme de terminal. Nous utilisons fréquemment le raccourci unité
lexicale à la place de terminal lorsqu’il sera clair que nous ne parlons que de nom d’unité
lexicale.
- Les non-terminaux sont des variables syntaxiques qui dénotent des ensembles de chaîne.
Les chaines dénotées par les non-terminaux aident à définir le langage défini par la grammaire.
Les non-terminaux imposent une structure hiérarchique au langage, qui est la clé de l’analyse
syntaxique.
- Les productions d’une grammaire définissent la façon dont terminaux et non-terminaux
peuvent être combinés pour former des chaînes. Chaque production consiste en premier : Un
non-terminal appelé la tête ou la partie gauche de la production. Le symbole, Parfois : :=
a été utilisé plutôt que la flèche. Un corps ou partie droite est constitué d’un ou plusieurs
terminal ou non-terminal. Les composantes de la partie droite décrivent une des manières
dont le chaines du non-terminal de partie gauche peuvent être construites.
21
CHAPITRE 3. ANALYSE SYNTAXIQUE
Convention de notation
Pour éviter d’avoir toujours préciser que " ces symboles sont les terminaux ", " ces sym-
boles sont les non-terminaux ", les convention de notation suivante à propret des grammaire
seront désormais utilisées dans ce rapport, si une modification aura lieu, un message d’aver-
tissement sera écrit avant la section.
Les symboles suivants sont des terminaux :
— Les lettres minuscules.
— Les symboles d’opérations tels que +, - etc.
— Les signes de ponctuations tels que point, point-virgule etc.
— Les chiffres.
Les symboles suivants sont des non-terminaux :
— Les lettres majuscule.
— La lettre S, qui, quand elle est utilisé,est généralement le symbole de départ.
— Les mot en minuscule et italique.
— Les lettres grecques.
Dérivation
L’idée de base de dérivation est de considérer que les productions des règles de réécriture :
Chaque fois que nous avons un non-terminal, on peut remplacer cela par le côté droit de toute
production dans lequel le non-terminal apparaît sur le côté gauche. Nous pouvons le faire
n’importe où dans une séquence de symboles terminaux et non-terminaux et répéter jusqu’à
ce faisant.
La séquence résultant des terminaux est une chaîne de caractères dans le langage défini
par la grammaire. Formellement, nous définissons la relation de dérivation =>.
Arbre d’analyse et dérivation
Un arbre d’analyse est la représentation graphique d’une dérivation qui ne garde pas trace
de l’ordre dans lequel les productions ont été appliquées pour remplacer les non-terminaux.
Chaque nœud d’un arbre d’analyse représente l’application d’une production. Le nœud
est étiqueté par le non-terminal de la partie gauche de la production, les fils du nœud sont
étiqueté, de gauche à droite, par les symboles de la partie de la production par laquelle le
non-terminal a été remplacé pendant la dérivation.
Analyse syntaxique descendante
Un analyseur descendant commence en construisant le nœud racine de l’arbre, qu’il sait
devoir étiqueter avec le symbole de départ. Il construit ensuite les nœuds de l’arbre syntaxique
en pré-ordre. Ce qui signifie que la racine d’un sous-arbre est constitué avant tous ses nœuds
descendantes [9].
22
CHAPITRE 3. ANALYSE SYNTAXIQUE
De façon équivalente, l’analyseur syntaxique descendant peut être vue comme la recherche
d’une dérivation gauche pour une chaine d’entrée.
Soit la grammaire :
E → T E’
E’ → + T E’ |
T → F T’
T’ → * F T’ |
F → ( E ) | id
E
   dd
T
  
F
id
T’
E’ ˆˆˆˆˆˆ
+
   dd
T T’
F
id
   dd
T’
   dd
* F T’
id
Figure 3.1 – Analyse syntaxique descendante de id + id * id
A chaque étape d’une analyse descendante, le problème clé est celui du choix de la pro-
duction à appliquer pour un certain non-terminal.
Une fois qu’une production choisie, le reste du processus d’analyse syntaxique consiste à re-
connaître dans la chaîne d’entrée les symboles terminaux de la partie droite de la production.
Analyse syntaxique par descente récursive
Une descente récursive, dans le cas général peut nécessiter des retours en arrière, c’est-à-
dire qu’elle peut avoir à parcourir plusieurs fois certaines portions de l’entrée. Cependant, les
retours en arrière sont rarement nécessaire pour effectuer l’analyse syntaxique de construction
de langage de programmation.
Grammaire LL(1)
Les analyseurs syntaxiques par descente récursive qui ne nécessitent par le retour en
arrière, peuvent être construit pour une classe de grammaire que l’on a appelé LL(1). Le
premier L dans LL(1) provient du sens de parcours à droite (en anglais Left). Le second
L vient de fait que l’on construite une dérivation gauche (en anglais Leftmost dérivation).
Le 1 indique que l’on n’utilise qu’un seul symbole de pré-vision à chaque étape de l’analyse
syntaxique pour prendre les décisions sur les actions à effectuer [1].
Analyse syntaxique ascendante
Une analyse syntaxique ascendante ( en anglais, bottom-up) correspond à la construction
d’un arbre d’analyse pour une chaîne d’entrée en partant des feuilles et en remontant jusqu’à
la racine (le haut ).
23
CHAPITRE 3. ANALYSE SYNTAXIQUE
Il est utile de décrire l’analyse syntaxique comme étant le processus de construction des
arbres d’analyse, bien qu’une partie frontale puisse en réalité effectuer une traduction directe,
sans construction explicite de l’arbre [1].
Soit la grammaire :
E → E + T | T
T → T * F | F
F → ( E ) | id
Analyse ascendant de l’instruction id * id :
id * id F * id
id
T * id
F
id
T * F
F
id
id
T
   dd
T * F
F
id
id
E
T
   dd
T * F
F
id
id
Figure 3.2 – Analyse syntaxique ascendante de id * id
Les chaines de cette suite sont formées à partir des racines de tous les sous-arbres. La suite
commence par la chaîne d’entrée id * id. La première réduction produit F * id en réduisant
le id le plus à gauche en F, à l’aide de la production F → id. La seconde réduction produit
T * id en réduisant F en T.
Nous avons maintenant le choix entre réduire la chaîne T, qui est la partie droite de E →
T,et réduire la chaine composée du second id, qui est la partie droite de F → id. Plutôt que
de réduire T en E, le second id est réduit en F, ce qui donne la chaîne T * F. Cette chaîne
se réduit alors en T. L’analyse syntaxique se termine par la réduction de T en E, le symbole
de départ.
Analyse syntaxique par décalage-réduction
On peut voir que l’analyse ascendante comme étant un processus de réduction d’un flux
d’unité lexicale vers le symbole de départ de la grammaire. A chaque étape de réduction,
une sous-chaîne particulière, reconnue par la partie droite d’une production, est remplacée
le non-terminal de partie gauche de cette production.
L’analyse syntaxique par décalage-réduction est une forme d’analyse syntaxique ascendante
ou une pile stocke des symboles grammaticaux et ou un tompon d’entrée stocke la partie
de la chaîne restant. Le symbole $ indique le fond de la pile ainsi que l’extrémité droite de
l’entrée.
Bien que les opérations de base soient le décalage et la réduction, un analyseur syntaxique
par décalage- réduction peut effectuer en réalité quatre action : (1) décaler, (2) réduire, (3)
accepter, (4) erreur.
1. Décaler le symbole d’entrée suivant depuis l’entrée vers le sommet de la pile.
2. Réduire, l’extrémité droite de la chaine à réduire doit être au sommet de la pile. Repérer
l’extrémité gauche de la chaine à réduire au sein de la pile et décider du non-terminal qui
24
CHAPITRE 3. ANALYSE SYNTAXIQUE
doit remplacer cette chaîne.
3. Accepter, annoncer le succès de l’analyse syntaxique.
4. Erreur, Si une erreur de syntaxe est trouvée [1].
La figure décrite ce dessus, montre le principe de fonctionnement de l’analyseur syntaxique
par décalage-réduction en manipulant l’instruction id1 * id2 :
Pile Entrée Action
$ id1 * id2 $ décaler
$ id1 * id2 $ réduire par F → id
$ F * id2 $ réduire par T → F
$ T * id2 $ décaler
$ T * id2 $ décaler
$ T * id2 $ réduire par F → id
$ T * F $ réduire par T → T * F
$ $ réduire par E → T
$ $ accepter
Figure 3.3 – Analyse syntaxique par décalage-réduction sur l’entrée id1 * id2
L’analyseur syntaxique charge l’instruction id1 * id2 dans la chaine d’entrée tout en
initialisant la pile à vide et appliqué l’action décaler pour envoyer le lexème id1 à la pile,
le choix de l’action ce fait par rapport à l’entête de pile, dans la deuxième instruction la
réduction de non-terminal id1 par la partie gauche de dérivation, et ainsi de suite jusqu’à
traité l’entrée et vidage de la pile ou bien trouvé un lexème qui ne correspond à aucune
dérivation.
Conception et implémentation d’analyseur syntaxique
Conception d’analyseur syntaxique
table de symbole
Une table de symbole ( ou liste de noms) peut être vu comme un tableau extensible d’ar-
ticle, qui peut être indexé par une chaîne au lieu d’un entier. La chaîne est l’identificateur,
et l’article associer contient les informations rassemblées sur cet identificateur plus précis les
article sont les propriétés de l’identificateur comme leur type, nature . . .
Lorsqu’ on appelle le table de symbole avec le nom de l’identificateur, il renvoie un article
de type information, et une référence sur les autres identificateurs. Le concepteur du compi-
lateur choisit le type de l’information relatif à l’identificateur de manière à pouvoir y utiliser
tout-au-long de processus de compilation.
25
CHAPITRE 3. ANALYSE SYNTAXIQUE
Structure de table de symbole
Le table de symbole comme il décrit si-dessous représente un espace de travail virtuelle,
qui serve également à stoker les objets relatif au bon fonctionnement de l’analyseur syn-
taxique, une ou plusieurs contrainte relié aux ces objet qui nous incite le plus de sauvegarder
dans une structure compréhensible et facile à manipuler :
Les sous programme
Comme son nom l’indique, les sous programme représente un programme qui fonctionne
indépendant au programme principale, ce qui implique qu’ils ont leur propre caractéristique
donc ils doivent traiter à part pour distinguer leur propre données et leur inusité d’existence.
Les sous programme doivent avoir un identifiant unique pour lui référencer tout-ou-long de
l’analyse syntaxique, cette identificateur doit être attacher aux argument du sous-programme.
Le schéma représenté si-dessous peut nous donner une illustration d’enregistrement de
sous programme et de distinction entre eux .
Sous-programme 1
c
E
E Type de Retour
' Liste des données primitives
Sous-programme Suivant
Sous-programme 2
E
E Type de Retour
' Liste des données primitives
c
  ©  ©  ©
Figure 3.4 – Structure de table de symbole au niveau de sous-programme
Les informations relatives à chaque sous-programme paré nous facile à distingué :
— Le type de retour : chaque sous-programme doit effectué une certaine fonctionnalité
pour facilité la tache de développement et de diminué le code à exécuter, selon cette
fonctionnalité elle peut nous renvoie une résultat après traitement de cette cas et selon
l’existence de résultat en peut jugé de type de sous programme.
— Liste de donnée primitive : Les données primitive sont les porteurs de donné au niveau
de code source, chaque sous-programme contient leur propre porteurs de donnée qui
sont répartie on deux catégorie.
26
CHAPITRE 3. ANALYSE SYNTAXIQUE
Porteur de donné de Types primitifs
Pour respecter les notions des identificateur selon leur visibilité et son apparition dans le
syntaxe générale, il faut les organiser selon une structure qui nous garantie de vérifier leur
existence et de récupérer ces informations.
Le schéma représenté si-dessous peut nous donner une illustration de travail de table de
symbole
Sous-programme 1
c
E
E Type de Retour
E
Liste des données primitives
Donnée 1 E
Nature de donnée
E
Type de donnée
E Donnée 2
E
dd‚
dd‚
dd‚
Sous-programme Suivant
Sous-programme 2
E
E Type de Retour
Liste des données primitivesE Donnée 1 E
Nature de donnée
E
Type de donnée
E
dd‚
dd‚
dd‚
c
  ©  ©  ©
Figure 3.5 – Structure détaillé de table de symbole aux niveau de sous-programme
Les informations relatives à un identificateur peut se distinguer selon leur utilités dans la
processus de compilation, ces informations sont principalement utile pour décrire la séman-
tique de l’analyse syntaxique, et dans certaine cas le bon déroulement de ce type d’analyseur.
Les informations relatives à un identificateur :
— Nom de donnée : Chaîne de caractère qui est de l’origine le lexème trouvé lors de
l’analyse lexicale il doit être unique comme l’indique la structure décrit s’est dessous,
et qui suit le motif d’identificateur de l’unité lexical.
— Type de donnée : il représente la façon d’enregistrement de l’identificateur dans la mé-
moire, de plus il est un champs très utile dans la processus de l’analyse syntaxique cas
il va contenir une signification d’un lexème placé selon un syntaxe prédéfinie, Exemple
le mot clé "int" signifie que l’identificateur ou suite d’identificateur situés juste après
ce lexème sont de type entier.
— Nature de donnée : La nature de l’identificateur représente le comportement de l’iden-
tificateur suit à son premier occurrence il est destiné principalement pour distinguer
entre les variable et les constante, et de vérifier le sémantique des expressions.
27
CHAPITRE 3. ANALYSE SYNTAXIQUE
Conception d’un compilateur multi-langage
Le rôle principale de multi-compilateur est de faire un mélange de syntaxe des compila-
teur les plus populaires, c’est à dire de suivre une dérivation selon le choix de développer, de
plus de migrer leur puissant fonctionnalité l’une à l’autre.
L’idée de ce mélange peut être traitée lors de séparation de grammaire de langage des
compilateur, et laisser l’analyseur syntaxique vise le ligne de code souhaité traiter par rap-
port leur propre grammaire.
C++ et java1
Déclaration de donnée :
1 DECLARATION -> DECLARATION_TYPE IDENTIFICATEURS INITIALISATION ;
2 -> DECLARATION_TYPE [entier] IDENTIFICATEUR INITIALISATION ;
3
4 IDENTIFICATEURS -> identificateur
5 -> identificateur , IDENTIFICATEURS
6
7 INITIALISATION -> epsilon
8 -> = Identificateur
9 -> = entier
10 -> = reel
11 -> = chaine
12 -> = caractere
13
14 DECLARATION_TYPE -> int "type = entier"
15 -> real "type = reel "
16 -> char "type = caractere"
Listing 3.1 – Grammaire déclaration de donnée
Les mots écrivent en minuscule lors de la dérivation de non-terminal INITIALISATION
représente les lexèmes envoyer par l’analyseur lexicale.
La séparation entre DECLARATION et DECLARATION_TYPE est à pour utilité de
diminué la dérivation de grammaire et de facilité la récupération de type de donnée, l’ajout
aux niveau de table de symbole nécessite un couple de nom de donné et leur type ainsi que
leur nature.
La nature de donnée est récupérer à travers la dérivation c’est-à-dire le ligne de code nous
donne une impression sur la nature de donnée, le nom d’identificateur ou bien dans notre cas
la possibilité de déclarer plusieurs identificateurs en un seul ligne de grammaire, le type de
ou des identificateurs doit précéder leur nom.
L’étape d’ajout ce fait réellement lors de dérivation de non-terminal IDENTIFICATEUR.
28
CHAPITRE 3. ANALYSE SYNTAXIQUE
Boucle conditionnelle :
1 IF_INST -> if ( CONDITION ) { COMMANDE_SEQ } ;
2 -> if ( CONDITION ) { COMMANDE_SEQ } else IF_INST
3 -> if ( CONDITION ) { COMMANDE_SEQ } else { COMMANDE_SEQ } ;
4
5 CONDITION -> identificateur OP COND_DROITE SEP CONDITION
6 -> identificateur OP COND_DROITE
7 -> ( identificateur OP COND_DROITE ) SEP CONDITION
8 -> ( identificateur OP COND_DROITE )
9
10 COND_DROITE -> identificateur
11 -> entier
12 -> reel
13 -> chaine
14 -> caractere
15
16 OP -> <
17 -> <=
18 -> >
19 -> >=
20 -> ==
21 -> !=
22
23 SEP -> &&
24 -> ||
Listing 3.2 – Grammaire boucle conditionnelle C++ et Java
Les opérateurs (OP) et séparateurs (SEP) non-terminaux représentent deux regroupe-
ment des lexèmes passées par le même valeur lors de phase d’analyse lexicale.
Jusqu’à ici le valeur des opérateurs nous intéressons pas, ce qui nous intéressons pour
le moment est que ces non-terminal forment bien notre description textuelle de l’analyseur
syntaxique (grammaire).
Instruction Switch :
1 SWITCH_INST -> switch ( VALEUR_DE_TEST ) { CASES DEFAULTS }
2
3 VALEUR_DE_TEST -> identificateur
4 -> EXPRESSION
5 CASES -> epsilon
6 -> case VALEUR : COMMANDE_SEQ break ; CASES
7 -> default : COMMANDE_SEQ break ;
8
9 VALEUR -> entier
10 -> reel
11 -> caractere
12 -> chaine de caractere
Listing 3.3 – Instruction Switch C++ et Java
Les parenthèses qui suivent le mot clé "switch" indiquent une expression dont la valeur
est testée successivement par chacun des case.
29
CHAPITRE 3. ANALYSE SYNTAXIQUE
Lorsque l’expression testée est égale à une des valeurs suivant un case, la liste d’ins-
tructions qui suit celui-ci est exécutée. Le mot clé break indique la sortie de la structure
conditionnelle. Le mot clé default précède la liste d’instructions qui sera exécutée si l’expres-
sion n’est jamais égale à une des valeurs.
Boucle For :
1 FOR_INST -> for ( DECLARATION CONDITION ; AFFECT ) { COMMANDE_SEQ } ;
Listing 3.4 – Grammaire Boucle for C++ et Java
Les paramètres de boucle indiquée dans la grammaire ci-dessus parées différentes à celle de
boucle répétitif (for) habituelle puisque le point-vergues ne figure pas entre les non-terminaux
DECLARATION et CONDITION, mais lorsque en examine attentivement le non-terminal
DECLARATION en peut distingué l’existence des points lors de l’analyse.
Boucle do-while :
1 DO_INST -> do { COMMANDE_SEQ } while ( CONDITION ) ;
Listing 3.5 – Grammaire Boucle while C++ et Java
Boucle while :
1 WHILE_INST -> while ( CONDITION ) { COMMANDE_SEQ } ;
Listing 3.6 – Grammaire Boucle Do-while C++ et Java
Grammaire VB.NET2
Déclaration de donnée :
1 DECLARATION -> dim IDENTIFICATEURS as DECLARATION_TYPE INITIALISATION
2
3 IDENTIFICATEURS -> identificateur
4 -> identificateur , IDENTIFICATEUR
5
6 DECLARATION_TYPE -> integer "type = entier"
7 -> real "type = reel"
8 -> caractere "type = caractere"
9 -> string "type = chaine de caractere"
Listing 3.7 – Grammaire déclarative de donné VB.NET
Comme l’indique la grammaire décrite ci-dessus il est impossible d’ajouter l’identificateur aux
niveau de table de symbole lors de dérivation de non-terminal IDENTIFICATEUR puisque
l’analyseur syntaxique n’a pas collecté les informations nécessaires pour l’insertion aux niveau
de table de symbole.
L’analyseur syntaxique doit rapporté l’ajout après la récupération de type de l’identifi-
cateur.
30
CHAPITRE 3. ANALYSE SYNTAXIQUE
Boucle conditionnelle :
1 IF_INST -> CONDITION_VB then COMMANDE_SEQ else COMMANDE_SEQ endif
2 -> CONDITION_VB then COMMANDE_SEQ end if
3
4 CONDITION_VB -> identificateur OP COND_DROITE SEP CONDITION_VB
5 -> identificateur OP COND_DROITE
6
7 SEP -> and
8 -> or
9
10 OP -> <
11 -> <=
12 -> >
13 -> >=
14 -> ==
15 -> !=
Listing 3.8 – Grammaire boucle conditionnelle VB.NET
Boucle For :
1 FOR_INST -> for identificateur INITIALISATION to DONNEE step DONNEE
COMMANDE_SEQ next
2
3 DONNEE -> identificateur
4 -> entier
5 -> reel
6 -> chaine
7 -> caractere
Listing 3.9 – Grammaire boucle For VB.NET
Boucle do-while :
1 DO_INST -> do COMMANDE_SEQ loop TYPE_LOOP CONDITION COMMANDE_SEQ
2
3 TYPE_LOOP -> while
4 -> until
Listing 3.10 – Grammaire boucle Do-While VB.NET
Le boucle répétitif do-while représente deux possibilités de continuations de l’exécutions
while et until, while représente la continuité si la condition est vrai et l’autre invoque la sortie
de boucle si la condition est faut.
Boucle while :
1 WHILE_INST -> while CONDITION_VB COMMANDE_SEQ end while
2
3 CONDITION_VB -> identificateur OP COND_DROITE SEP CONDITION_VB
4 -> identificateur OP COND_DROITE
Listing 3.11 – Grammaire boucle While VB.NET
31
CHAPITRE 3. ANALYSE SYNTAXIQUE
Choix de language : Bibliothèque
Comme tout les langages de programmation moderne chaque appelle à une fonctionnalité
prédéfinie nécessite l’importation de son propre bibliothèque, de ce principe l’utilisation d’un
tels langages est accordée à l’importation de leur syntaxe.
1 IMPORT -> epsilon
2 -> add " identificateur " IMPORT
Listing 3.12 – Importation de langage
l’identificateur délimité par les deux " représente le nom de langage voulue importé.
La distinction de syntaxe selon le choix prédéfinie représente un avantage pour les langages
de programmation, pour nous la bibliothèque ne stocke pas les fonctionnalités prédéfinie mais
elle exprime le comportement de l’analyseur lors la phase de l’analyse pour gagner le temps
lors de choix de l’ensemble de grammaire avant de commencer.
Grammaire de notre compilateu3
Déclaration de donnée :
Cette section représente la façon ou le développeur peut insérer ces porteurs de donnée en
indiquent de deux façons la nature de ces données, la déclaration en C++ et Java représente
un repère de choix des instructions de déclaration, donc nous gardons leur grammaire en
éliminant seulement les point-virgule.
Le principe de compilateur multi-langage peut augmenté le bénéfice de développer, en
peut remarquer ce gain lorsque en met l’accent à la déclaration et la manipulation de chaine
de caractère qui est déclaré comme étant un tableur de caractères qu’elle est costumé en java
et VB.NET avec leur propre type "String".
De plus la possibilité de déclaration normale de donnée, nous fournissons un mécanisme qui
permet de déclarer un ou plusieurs identificateur à partir d’un autre qui précède en hiérarchie
de code source ou bien en passant un valeur et laisser l’analyseur syntaxique conclut leur type.
1 DECLARATION -> DECLARATION_TYPE IDENTIFICATEUR INITIALISATION
2 -> type IDENTIFICATEURS comme DONNEE
3
4 DONNEE -> identificateur
5 -> entier
6 -> reel
7 -> chaine
8 ->caractere
9
10 DECLARATION_TYPE -> int
11 -> real
12 -> char
13 -> string
14
15 IDENTIFICATEURS -> identificateur
16 -> identificateur , IDENTIFICATEURS
17
32
CHAPITRE 3. ANALYSE SYNTAXIQUE
18 INITIALISATION -> epsilon
19 -> = Identificateur
20 -> = entier
21 -> = reel
22 -> = chaine
23 -> = caractere
Listing 3.13 – déclaration de donné
Les trois lignes de code représentées ci-dessus donnent une vision de l’avantage de choix :
int a
type i comme a => type de i est un entier
type j comme 1.2 => type de j est un réel
Lecture des variables :
Cette partie représente l’ensemble des outils qui permet aux développeurs de gérer les
données récupérer à partie de clavier lors de l’étape de l’exécution elle est attachée égale-
ment à la phase de génération de code donc elle doit être décrite d’une façon qui facilite leur
manipulation lors des autres phases de compilation, de plus, elle doit être facile et compré-
hensible dans le choix de leur grammaire, l’utilisation de mot clé significative pour rendre
compte leur fonctionnalité pour cela en à choisir le mot clé «read».
La grammaire d’écrite dans le listing 3.14 représente une proposition de lecture de va-
riable :
1 LECTURE_VARIABLE -> read identificateur
2 -> read identificateur , LECTURE_VARIABLE
Listing 3.14 – description préalable de grammaire de lecture de variable
Cette représentation nécessite un complémentaire de façon qu’elle peut distingué l’allo-
cation mémoire de deux identificateurs passait en même temps.
Dans l’habitude la lecture d’une variable est précèder par un message d’affirmation, c’est
pour cela en à améliorer la grammaire décrite dans le listing 3.14 pour qu’elle garantie aux
développer d’affermer l’utilisateur en un seul ligne de code :
1 LECTURE -> read LECTURE_VARIABLE
2
3 LECTURE_VARIABLE -> AFFERMATION identificateur
4 -> AFFERMATION identificateur , LECTURE_VARIABLE
5
6 AFFERMATION -> epsilon
7 -> chaine :
Listing 3.15 – grammaire de lecture de variable
Les deux lignes de codes représentées ci-dessous donnent une vision de l’avantage de
choix :
read "Entrer a" : a
read "Entrer a" : a , b
33
CHAPITRE 3. ANALYSE SYNTAXIQUE
Affichage de donné :
Cette partie représente l’ensemble d’outils qui permet aux développeurs de gérer l’affi-
chage des données et de renvoyer les résultat, elle doit être capable de renvoyer les données
récupérés lors de l’écriture de données , les types de données ainsi que les instructions ma-
thématiques.
Elle doit être attacher à un mot clé significatif pour décrire son fonctionnalité, le mot
choisie est «white», Le retour à la ligne est décrit par le mot clé « NL».
La grammaire d’écrite das la listing 3.16 représente une proposition d’affichage des ins-
truction :
1 AFFICHAGE -> write INSTRUCTIONS
2
3 INSTRUCTIONS -> INSTRUCTION
4 -> INSTRUCTION , INSTRUCTIONS
5
6 INSTRUCTION -> nl
7 -> identificateur
8 -> entier
9 -> reel
10 -> chaine
11 -> caractere
12 -> EXPRESSION
Listing 3.16 – Grammaire d’affichage de donnée
Les ligne de code représentées ci-dessus donnent une vision de l’avantage de choix :
write nl
write " a = " ,a
write nl , " b = " , b
write nl , " a + b = " , a + b
Affectation :
Cette partie représente une description de changement de contenue des variables, comme
nous avons parlées aux niveaux de table de symbole qui permet de stocker les informations
relative aux comportement des identificateurs et non pas à stoker leur contenue cependant
le contenue est stoké aux niveau de mémoire dans des registres de donnée, donc on doit
préciser à l’analyseur syntaxique le séquencement des identificateur pour nous fournir la ré-
partition ou bien le s’enfuit des erreurs après la conversion du code source à langage machine.
Le listing 3.17 décrit la grammaire d’aafectation.
1 AFFECTATION -> identificateur = STR_EXP
2 -> identificateur = EXP
3
4 STR_EXP -> chaine
5 -> caractere
6
7 EXP ->identificateur
8 ->entier
34
CHAPITRE 3. ANALYSE SYNTAXIQUE
9 ->reel
10 ->EXP OP_AR EXP
11 -> - EXP
12 -> ( EXP )
13
14 OP_AR -> +
15 -> -
16 -> ^
17 -> *
18 -> /
Listing 3.17 – Grammaire d’affectation
Les lignes des codes représentées ci-dessous donnent une vision de l’avantage de choix :
a = "****"
a = -1
a = a +( b - (c - a))
string a
a = a + "****" => cette fausse instruction est traitée syntaxiquement
int a
a = "****" => cette fausse instruction est traitée sémantiquement
Les priorités des opérateurs ainsi que les parenthèses doit être prennent en considération
lors de l’analyse syntaxique.
Boucle For :
Cette partie représente une description de proposition de boucle itératif "for", cette repré-
sentation est basé sur le syntaxe des langages choisie comme référence et qui sont décrivent
dans la section précédente (C++,Java,VB.net).
La première idée est d’éliminer les parenthèses ainsi que les points virgule de boucle for
aux niveau de C++ est Java, la deuxième est de rattacher les phases de l’initialisation, condi-
tion et incrimination l’une à l’autre avec l’ajout des éliminateurs pour faciliter la distinction
entre le compteur et leur paramètre.
Le listing 3.18 décrit la grammaire de notre proposition de boucle For.
1 INST_FOR -> for DECLARATIONS :: INSTRUCTION : CONDITONS : INSTRUCTION {
COMM_SEQ }
2
3 DECLARATIONS -> identificateur
4 -> DECLARATION
5
6 INSTRUCTION -> identificateur
7 -> entier
8 -> reel
9 -> chaine
10 -> caractere
11 -> EXPRESSION
12
35
CHAPITRE 3. ANALYSE SYNTAXIQUE
13 CONDITION -> INSTRUCTION
14 -> CONDITION
Listing 3.18 – Grammaire boucle for
Les lignes de codes représentées ci-dessous donnent une vision sur l’avantage de choix :
for int i : : 0 : i > 5 : 1 {}
for i : : i = 0 : 5 : i = i +1 {}
for i : : 0 : i > 3 and test = true : 1
{
for int j : : j = i : j > 100 : 2
{
Write nl ," j = ", j
}
}
Les vérifications de compatibilités de type ainsi que les conditions ne font pas partie à la
fonctionnalité de l’analyseur syntaxique, les erreurs de mal placement des instructions interne
dans le boucle "for" sont gérer dans le chapitre président " l’analyseur sémantique ".
Instruction select :
Cette partie représente une description de proposition de l’instruction select (Swith en
C++ et Java), elle est basé essentiellement à l’instruction select de VB.net avec quelques
modifications au niveau des mots clé reversées aux distinction entre les sous partie (cases).
Le listing 3.19 décrit la grammaire de notre proposition de boucle Select.
1 SELECT_INST -> select VALEUR { CASES }
2
3 VALEUR -> identificateur
4 -> EXPRESSION
5
6 CASES -> :: INSTRUCTION : COMMAND_SEQ
7 -> :: INSTRUCTION to INSTRUCTION : COMMAND_SEQ
8 -> :: INSTRUCTION : COMMAND_SEQ CASES
9
10 INSTRUCTION -> identificateur
11 -> entier
12 -> reel
13 -> chaine
14 -> caractere
15 -> EXPRESSION
Listing 3.19 – Grammaire instruction select
Les lignes des codes représentées ci-dessous donnent une vision sur l’avantage de choix :
select a
{
: : 1 : write "a = 1"
36
CHAPITRE 3. ANALYSE SYNTAXIQUE
: : 5 : write "a = 5"
: : 2 to 3 : write "Valeur entre 1 et 3"
}
Implémentation d’analyseur syntaxique
table de symbole
Le code C représenté dans le listing 3.20 représente une implémentation de principe
de table de symbole décrit dans la section conception, et comme on à dit que le table de
symbole doit gérer les données et leur présence dans les méthodes c’est pour ce la les deux
structure sym_node abréviation de Symbole_node et sym_node_methode abréviation de
Symbole_node_methode sont invoquées.
1 typedef struct sym_node
2 {
3 char name [50];
4 int type;
5 struct sym_node *next;
6
7 }sym_node;
8
9 typedef struct sym_node_methode
10 {
11 char name [50];
12 int type;
13 struct sym_node *liste_var;
14 struct sym_node_methode *next;
15
16 } sym_node_methode ;
Listing 3.20 – Implémentation table de symbole
La manipulation de table de symbole nécessite des sous programmes pour gérer leur
entrées ainsi que leur sortie, le code C décrit dans le listing 3.21 illustre les entêtes des sous
programme de manipulation.
1 sym_node_methode *put_meth(char *meth_name , int meth_type)
2 sym_node_methode *get_meth(char *meth_name)
3 int get_meth_type(char *meth_name)
4
5 sym_node *put_sym_donn(char *nom_meth ,char *sym_name , int sym_type)
6 sym_node *get_sym_donn(char *nom_meth ,char *sym_name)
7 int get_sym_donn_type (char *nom_meth ,char *sym_name)
8 int get_sym_donn_nature (char *nom_meth ,char *sym_name)
Listing 3.21 – Entête des sous programme ralative à table de symbole
Les sous programmes responsable à la manipulation des méthodes :
— put_meth : Elle représente le sous programme responsable de l’ajout d’une mé-
thode au niveau de table de symbole, leur type de retour est un pointeur de type
sym_node_methode qui référence aux nouveau table de symbole.
37
CHAPITRE 3. ANALYSE SYNTAXIQUE
— get_meth : Elle représente le sous programme responsable à l’envoie de méthode par
rapport à son nom.
— get_meth_type : Elle représente le sous programme responsable à l’envoie de type
de méthode par rapport à leur nom, le type est référencé par un indice unique tels
que 0 pour les sous programmes qui ne renvois pas de résultat ou bien 1,2,3,4 pour
les entier, les réels,les caractères et chaines de caractères dans l’ordre.
Les sous programmes responsable à la manipulation des données :
— put_sym_donn : Elle représente le sous programme responsable à l’ajout de donnée
au niveau d’une méthode passé en paramètre l’eur type de retour est un pointeur de
type sym_node qui référence à la liste de donnée de cette méthode.
— get_sym_donn : Elle représente le sous programme responsable à l’envoi de liste de
variable à partir de nom de méthode.
— get_sym_donn_type : Elle représente le sous programme responsable à l’envoie de
type de donnée au niveau de méthode passée en paramètre qui à le même principe de
retour de méthode.
— get_sym_donn_nature : Elle représente le sous programme responsable à l’envoie
de nature de donnée au niveau de méthode passé en paramètre qui renvoie l’entier 5
lorsque le type est un variable, 6 si le type de retour est un constante.
Bibiliothéque
Le code C d’écrit dans le listing 3.22 représente une impression de principe de fonction-
nement de bibliothèque
1 typedef struct bib_node
2 {
3 char name [50];
4 struct bib_node *next;
5 }bib_node;
Listing 3.22 – Implémentation Bibliothèque
La manipulation de bibliothèque nécessite des sous programmes pour gérer leur entrées
ainsi que leur sortie, le code C décrit dans le listing .23 illustre les entêtes des sous programme
de manipulation.
1 bib_node *put_bib(char *bib_name)
2 bib_node *get_bib(char *bib_name)
Listing 3.23 – Entête des sous programme ralative aux Bibliothèque
Ces sous programmes représente une description de dérivation de analyseur syntaxique
contrairement aux table de symbole qui représente une vision sémantique de notre compila-
teur :
— put_bib : elle représente un sous programme qui gérer l’entrée à la premier référence
de bibliothèque leur occurrences en générale au premier de dérivation de syntaxe pour
38
CHAPITRE 3. ANALYSE SYNTAXIQUE
bien garantir leur meilleur complexité.
— get_bib ; elle représente un sous programme qui gérer la partie de test de validation de
syntaxe c’est-à-dire de vérifier la possibilité d’utilisation de syntaxe par le développer.
Bison(implémentation de grammaire )
Après avoir étudier et comprendre le principe de table de symbole et la bibliothèque notre
analyseur syntaxique doit avoir un lien dynamique entre ces deux composants, et de bien
contrôler leur instances.
structure bison Code C générer
% {
Pré code C
% }
Définitions et options
% %
Règles de production
% %
Post code C
Déclarations
Copie du post code C
int yyparse(void)
{ Copie du code C }
Tables d’analyse
Règles de production
Copie du pré code C
Figure 3.6 – Un tampon d’entrée en deux moitiés
L’analyse syntaxique se compose par deux principaux phases, La première représente un
étude préalable et l’établissement de lien avec l’analyseur lexicale et le deuxième représente
la phase de dérivation de grammaire décrite lors de l’implémentation .
• étude préalable
Il représente les outils de travail ainsi quelque condition que l’analyseur syntaxique
doit le prenne en considération.
• Instanciation de table de symbole et bibliothèque :
L’analyseur syntaxique doit conserver d’une et une seul instance de table de symbole
et de bibliothèque, pour ne pas tombé dans le cas ou plusieurs variable portent le
même nom, ainsi de pouvoir récupérer les problème lors de l’analyse.
Les erreurs traitées par l’analyseur syntaxe sont globalement des fautes de syntaxe
lors de dérivation, mais en doit conservé une architecture pour intégrer l’analyseur
sémantique .
39
CHAPITRE 3. ANALYSE SYNTAXIQUE
• Affirmation des unités lexicale terminaux :
L’analyseur syntaxique doit être avertisse qu’il y’a des mots non dérivable lors de
phase d’analyse et qu’il doit remonté dans l’arbre de dérivation pour qu’il puissent
continuée leur travail.
Ce séquencement représente les suites des unité lexicale, ils doivent avoir le même
suite de caractère décrite lors de l’implémentation de l’analyseur lexicale (valeur entre
accolade suit la commande return).
• Association de type à STR_EXPR et EXPR décrite lors de l’affectation :
Comme en à dit lors de décrire la grammaire de l’affectation, et le table de symbole
établie dans le choix de notre langage, chaque porteur de donnée doit avoir un type
encapsulé sous un entier prédéfinie l’accent ce met maintenant sur les parties droite
de signe d’affectation de l’expression, l’analyseur syntaxique doit être capable de re-
tourner le type de résultat finale de l’expression lors de dérivation.
1 %type <Tint > STR_EXP
2 %type <Tint > EXP
Listing 3.24 – Association de type à STR_EXPR et EXPR décrite lors de l’affectation
• Associer les priorités des opérateurs arithmétique :
Il est important de déclarer l’analyseur syntaxique de respecté les priorités des opéra-
teurs arithmétique, ces opérateurs se distinct en deux partie ou la dérivation ce faite de
manière normale de sous expression avant le symbole arithmétique jusqu’à atteindre
l’autre symbole ou bien fin de ligne, l’autre partie représente un saut de dérivation
vers la partie droite.
Lors de dérivation normale les opérateurs arithmétiques en aussi leur propre priorité,
aux niveau de bison il est importé de déclarer les opérateurs selon leur priorité par
rapport à l’hiérarchie de l’apparence dans le code.
1 %left MULT DIVS
2 %left PLUS MOIN
3 %right PUIS
4 %left NEG
Listing 3.25 – Associer les priorités des opérateurs arithmétique
• Indicateur d’erreur :
Il est obligatoire de compter le nombre des erreurs du lors de l’analyse syntaxique, l’in-
dicateur des l’erreurs est attaché au variable "ligne" déclarer lors de l’analyse lexicale
est qui incrémente lors de retourne à la ligne, respectant le principe de continuité de
dérivation lors de récupération des erreurs chaque erreur doit traité à part c’est-à-dire
de conservé une partie propre à celle ci.
Dans cette phase de processus de compilation, en doit seulement déclarer l’indicateur
de ligne de l’erreur est de l’envoyer à un sous-programme spécifique pour le traiter
comme erreur de syntaxe, les autres erreurs sont décrivent au niveau de chapitre sui-
vant.
40
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation
Conception et implémentation d'un nouveau langage de programmation

Contenu connexe

Tendances

Rapport de Stage PFE - Développement d'un Projet ALTEN MAROC Concernant le Sy...
Rapport de Stage PFE - Développement d'un Projet ALTEN MAROC Concernant le Sy...Rapport de Stage PFE - Développement d'un Projet ALTEN MAROC Concernant le Sy...
Rapport de Stage PFE - Développement d'un Projet ALTEN MAROC Concernant le Sy...tayebbousfiha1
 
Présentation (Mémoire fin étude )
Présentation (Mémoire  fin étude )Présentation (Mémoire  fin étude )
Présentation (Mémoire fin étude )Ramzi Noumairi
 
Méthodes agiles vs méthodes classiques
Méthodes agiles vs méthodes classiquesMéthodes agiles vs méthodes classiques
Méthodes agiles vs méthodes classiquesSirine Barguaoui
 
Présentation projet de fin d'étude
Présentation projet de fin d'étudePrésentation projet de fin d'étude
Présentation projet de fin d'étudeDonia Hammami
 
Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...
Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...
Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...mouafekmazia
 
Rapport pfe Conceptionet Developpement d'une Application web et Mobile
Rapport pfe Conceptionet Developpement d'une Application web et  Mobile Rapport pfe Conceptionet Developpement d'une Application web et  Mobile
Rapport pfe Conceptionet Developpement d'une Application web et Mobile Raoua Bennasr
 
Présentation PFE: Système de gestion des réclamations et interventions clients
Présentation PFE: Système de gestion des réclamations et interventions clientsPrésentation PFE: Système de gestion des réclamations et interventions clients
Présentation PFE: Système de gestion des réclamations et interventions clientsMohamed Ayoub OUERTATANI
 
Méthodologie 2 Track Unified Process
Méthodologie 2 Track Unified ProcessMéthodologie 2 Track Unified Process
Méthodologie 2 Track Unified ProcessZakaria Bouazza
 
Présentation PFE "Refonte et déploiement d’une solution de messagerie en util...
Présentation PFE "Refonte et déploiement d’une solution de messagerie en util...Présentation PFE "Refonte et déploiement d’une solution de messagerie en util...
Présentation PFE "Refonte et déploiement d’une solution de messagerie en util...Nawres Farhat
 
RapportPFE_IngenieurInformatique_ESPRIT
RapportPFE_IngenieurInformatique_ESPRITRapportPFE_IngenieurInformatique_ESPRIT
RapportPFE_IngenieurInformatique_ESPRITLina Meddeb
 
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...Nawres Farhat
 
gestion de magasin vente matériels informatique
gestion de magasin vente matériels informatiquegestion de magasin vente matériels informatique
gestion de magasin vente matériels informatiqueOussama Yoshiki
 
Cours Génie Logiciel - Cours 2 - Cycles de vie
Cours Génie Logiciel - Cours 2 - Cycles de vieCours Génie Logiciel - Cours 2 - Cycles de vie
Cours Génie Logiciel - Cours 2 - Cycles de vieMohammed Amine Mostefai
 
Soutenance Elhadj Bah | Diplôme d'ingénieur de conception en Informatique | E...
Soutenance Elhadj Bah | Diplôme d'ingénieur de conception en Informatique | E...Soutenance Elhadj Bah | Diplôme d'ingénieur de conception en Informatique | E...
Soutenance Elhadj Bah | Diplôme d'ingénieur de conception en Informatique | E...Elhadj Mamadou Aliou BAH
 

Tendances (20)

Rapport de Stage PFE - Développement d'un Projet ALTEN MAROC Concernant le Sy...
Rapport de Stage PFE - Développement d'un Projet ALTEN MAROC Concernant le Sy...Rapport de Stage PFE - Développement d'un Projet ALTEN MAROC Concernant le Sy...
Rapport de Stage PFE - Développement d'un Projet ALTEN MAROC Concernant le Sy...
 
Présentation (Mémoire fin étude )
Présentation (Mémoire  fin étude )Présentation (Mémoire  fin étude )
Présentation (Mémoire fin étude )
 
Méthodes agiles vs méthodes classiques
Méthodes agiles vs méthodes classiquesMéthodes agiles vs méthodes classiques
Méthodes agiles vs méthodes classiques
 
Présentation projet de fin d'étude
Présentation projet de fin d'étudePrésentation projet de fin d'étude
Présentation projet de fin d'étude
 
Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...
Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...
Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...
 
Modele-elearning
Modele-elearningModele-elearning
Modele-elearning
 
Rapport pfe Conceptionet Developpement d'une Application web et Mobile
Rapport pfe Conceptionet Developpement d'une Application web et  Mobile Rapport pfe Conceptionet Developpement d'une Application web et  Mobile
Rapport pfe Conceptionet Developpement d'une Application web et Mobile
 
software engineering
software engineeringsoftware engineering
software engineering
 
Présentation PFE: Système de gestion des réclamations et interventions clients
Présentation PFE: Système de gestion des réclamations et interventions clientsPrésentation PFE: Système de gestion des réclamations et interventions clients
Présentation PFE: Système de gestion des réclamations et interventions clients
 
gestion de projet
gestion de projetgestion de projet
gestion de projet
 
CM processus-unifie
CM processus-unifieCM processus-unifie
CM processus-unifie
 
Méthodologie 2 Track Unified Process
Méthodologie 2 Track Unified ProcessMéthodologie 2 Track Unified Process
Méthodologie 2 Track Unified Process
 
Présentation PFE "Refonte et déploiement d’une solution de messagerie en util...
Présentation PFE "Refonte et déploiement d’une solution de messagerie en util...Présentation PFE "Refonte et déploiement d’une solution de messagerie en util...
Présentation PFE "Refonte et déploiement d’une solution de messagerie en util...
 
RapportPFE_IngenieurInformatique_ESPRIT
RapportPFE_IngenieurInformatique_ESPRITRapportPFE_IngenieurInformatique_ESPRIT
RapportPFE_IngenieurInformatique_ESPRIT
 
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
 
Présentation PFE
Présentation PFEPrésentation PFE
Présentation PFE
 
gestion de magasin vente matériels informatique
gestion de magasin vente matériels informatiquegestion de magasin vente matériels informatique
gestion de magasin vente matériels informatique
 
Cours Génie Logiciel - Cours 2 - Cycles de vie
Cours Génie Logiciel - Cours 2 - Cycles de vieCours Génie Logiciel - Cours 2 - Cycles de vie
Cours Génie Logiciel - Cours 2 - Cycles de vie
 
Soutenance Elhadj Bah | Diplôme d'ingénieur de conception en Informatique | E...
Soutenance Elhadj Bah | Diplôme d'ingénieur de conception en Informatique | E...Soutenance Elhadj Bah | Diplôme d'ingénieur de conception en Informatique | E...
Soutenance Elhadj Bah | Diplôme d'ingénieur de conception en Informatique | E...
 
présentation PFE (2)
présentation PFE (2)présentation PFE (2)
présentation PFE (2)
 

Similaire à Conception et implémentation d'un nouveau langage de programmation

courspython3.pdf
courspython3.pdfcourspython3.pdf
courspython3.pdfDendouga1
 
Cours achirecture des ordi 1
Cours achirecture des ordi 1Cours achirecture des ordi 1
Cours achirecture des ordi 1fofanaabou
 
Rapport de Mémoire Master Recherche
Rapport de Mémoire Master RechercheRapport de Mémoire Master Recherche
Rapport de Mémoire Master RechercheRouâa Ben Hammouda
 
Android VoIP/SIP Softphone
Android VoIP/SIP SoftphoneAndroid VoIP/SIP Softphone
Android VoIP/SIP SoftphoneHamza Lazaar
 
pfe_rapport_poste_licence_LFIG.pdf
pfe_rapport_poste_licence_LFIG.pdfpfe_rapport_poste_licence_LFIG.pdf
pfe_rapport_poste_licence_LFIG.pdfnesrine haloui
 
Cours mass pascalllllllllllle
Cours mass pascalllllllllllleCours mass pascalllllllllllle
Cours mass pascalllllllllllleChawki Riadh
 
Projet Passerelle sécurisée intelligente pour l'internet des objets
Projet Passerelle sécurisée intelligente pour l'internet des objetsProjet Passerelle sécurisée intelligente pour l'internet des objets
Projet Passerelle sécurisée intelligente pour l'internet des objetsUniversité de Rennes 1
 
Liste instruction
Liste instructionListe instruction
Liste instructionAli Fsahi
 
formation_latex
formation_latexformation_latex
formation_latexBui Loi
 
Implémentation de la QoS au sein d'un IP/MPLS - Rapport
Implémentation de la QoS au sein d'un IP/MPLS - RapportImplémentation de la QoS au sein d'un IP/MPLS - Rapport
Implémentation de la QoS au sein d'un IP/MPLS - RapportRihab Chebbah
 
Annexes Logiciel Pl7
Annexes Logiciel Pl7Annexes Logiciel Pl7
Annexes Logiciel Pl7youri59490
 
réaliser une plateforme d’automatisation et de génération des rapports de test
réaliser une plateforme d’automatisation et de génération des rapports de testréaliser une plateforme d’automatisation et de génération des rapports de test
réaliser une plateforme d’automatisation et de génération des rapports de testahmed oumezzine
 
LaTeX Document de démonstration
LaTeX Document de démonstrationLaTeX Document de démonstration
LaTeX Document de démonstration📡 Vincent Isoz
 

Similaire à Conception et implémentation d'un nouveau langage de programmation (20)

courspython3.pdf
courspython3.pdfcourspython3.pdf
courspython3.pdf
 
Cours achirecture des ordi 1
Cours achirecture des ordi 1Cours achirecture des ordi 1
Cours achirecture des ordi 1
 
Rapport de Mémoire Master Recherche
Rapport de Mémoire Master RechercheRapport de Mémoire Master Recherche
Rapport de Mémoire Master Recherche
 
Android VoIP/SIP Softphone
Android VoIP/SIP SoftphoneAndroid VoIP/SIP Softphone
Android VoIP/SIP Softphone
 
Belwafi bilel
Belwafi bilelBelwafi bilel
Belwafi bilel
 
Belwafi bilel
Belwafi bilelBelwafi bilel
Belwafi bilel
 
pfe_rapport_poste_licence_LFIG.pdf
pfe_rapport_poste_licence_LFIG.pdfpfe_rapport_poste_licence_LFIG.pdf
pfe_rapport_poste_licence_LFIG.pdf
 
Cours mass pascalllllllllllle
Cours mass pascalllllllllllleCours mass pascalllllllllllle
Cours mass pascalllllllllllle
 
Tp sgbd gsi
Tp sgbd gsiTp sgbd gsi
Tp sgbd gsi
 
Projet Passerelle sécurisée intelligente pour l'internet des objets
Projet Passerelle sécurisée intelligente pour l'internet des objetsProjet Passerelle sécurisée intelligente pour l'internet des objets
Projet Passerelle sécurisée intelligente pour l'internet des objets
 
Twido guide de programmation
Twido guide de programmationTwido guide de programmation
Twido guide de programmation
 
Liste instruction
Liste instructionListe instruction
Liste instruction
 
formation_latex
formation_latexformation_latex
formation_latex
 
Implémentation de la QoS au sein d'un IP/MPLS - Rapport
Implémentation de la QoS au sein d'un IP/MPLS - RapportImplémentation de la QoS au sein d'un IP/MPLS - Rapport
Implémentation de la QoS au sein d'un IP/MPLS - Rapport
 
Guide latex.
Guide latex.Guide latex.
Guide latex.
 
Introduction à MATLAB
Introduction à MATLABIntroduction à MATLAB
Introduction à MATLAB
 
Algo
AlgoAlgo
Algo
 
Annexes Logiciel Pl7
Annexes Logiciel Pl7Annexes Logiciel Pl7
Annexes Logiciel Pl7
 
réaliser une plateforme d’automatisation et de génération des rapports de test
réaliser une plateforme d’automatisation et de génération des rapports de testréaliser une plateforme d’automatisation et de génération des rapports de test
réaliser une plateforme d’automatisation et de génération des rapports de test
 
LaTeX Document de démonstration
LaTeX Document de démonstrationLaTeX Document de démonstration
LaTeX Document de démonstration
 

Dernier

Protéger l'intégrité de son environnement numérique
Protéger l'intégrité de son environnement numériqueProtéger l'intégrité de son environnement numérique
Protéger l'intégrité de son environnement numériquePaperjam_redaction
 
Modèles de contrôle d accès_ RBAC (Role Based Access Control).pdf
Modèles de contrôle d accès_ RBAC (Role Based Access Control).pdfModèles de contrôle d accès_ RBAC (Role Based Access Control).pdf
Modèles de contrôle d accès_ RBAC (Role Based Access Control).pdfHajer Boujezza
 
Slides du webinaire de l'Infopole sur l'IA
Slides du webinaire de l'Infopole sur l'IASlides du webinaire de l'Infopole sur l'IA
Slides du webinaire de l'Infopole sur l'IAInfopole1
 
Augmentez vos conversions en ligne : les techniques et outils qui marchent vr...
Augmentez vos conversions en ligne : les techniques et outils qui marchent vr...Augmentez vos conversions en ligne : les techniques et outils qui marchent vr...
Augmentez vos conversions en ligne : les techniques et outils qui marchent vr...OsharaInc
 
Contrôle d’accès et Gestion des identités: Terminologies et Protocoles d’auth...
Contrôle d’accès et Gestion des identités: Terminologies et Protocoles d’auth...Contrôle d’accès et Gestion des identités: Terminologies et Protocoles d’auth...
Contrôle d’accès et Gestion des identités: Terminologies et Protocoles d’auth...Hajer Boujezza
 
cours Systèmes de Gestion des Identités.pdf
cours Systèmes de Gestion des Identités.pdfcours Systèmes de Gestion des Identités.pdf
cours Systèmes de Gestion des Identités.pdfHajer Boujezza
 

Dernier (6)

Protéger l'intégrité de son environnement numérique
Protéger l'intégrité de son environnement numériqueProtéger l'intégrité de son environnement numérique
Protéger l'intégrité de son environnement numérique
 
Modèles de contrôle d accès_ RBAC (Role Based Access Control).pdf
Modèles de contrôle d accès_ RBAC (Role Based Access Control).pdfModèles de contrôle d accès_ RBAC (Role Based Access Control).pdf
Modèles de contrôle d accès_ RBAC (Role Based Access Control).pdf
 
Slides du webinaire de l'Infopole sur l'IA
Slides du webinaire de l'Infopole sur l'IASlides du webinaire de l'Infopole sur l'IA
Slides du webinaire de l'Infopole sur l'IA
 
Augmentez vos conversions en ligne : les techniques et outils qui marchent vr...
Augmentez vos conversions en ligne : les techniques et outils qui marchent vr...Augmentez vos conversions en ligne : les techniques et outils qui marchent vr...
Augmentez vos conversions en ligne : les techniques et outils qui marchent vr...
 
Contrôle d’accès et Gestion des identités: Terminologies et Protocoles d’auth...
Contrôle d’accès et Gestion des identités: Terminologies et Protocoles d’auth...Contrôle d’accès et Gestion des identités: Terminologies et Protocoles d’auth...
Contrôle d’accès et Gestion des identités: Terminologies et Protocoles d’auth...
 
cours Systèmes de Gestion des Identités.pdf
cours Systèmes de Gestion des Identités.pdfcours Systèmes de Gestion des Identités.pdf
cours Systèmes de Gestion des Identités.pdf
 

Conception et implémentation d'un nouveau langage de programmation

  • 1. Remerciements En préambule à ce projet nous remerciant ALLAH qui nous aide et nous donne la patience et le courage durant ces langues années d’étude. Nous souhaitant adresser nos remerciements les plus sincères aux personnes qui nous ont apporté leur aide et qui ont contribué à l’élaboration de ce mémoire ainsi qu’à la réussite de cette formidable année universitaire. Ces remerciements vont tout d’abord au corps professoral et administratif de l’institut supérieure d’informatique et mathématique Monastir pour la richesse et la qualité de leur enseignement et qui déploient de grands efforts pour assurer à leurs étudiants une formation actualisée. Nous tenant à remercier sincèrement Monsieur, Mohamed Graeit, qui, en tant que enca- dreur de notre projet de fin d’études, il s’est toujours montré à l’écoute et très disponible tout au long de la réalisation de ce projet, ainsi pour l’inspiration, l’aide et le temps qu’ils ont bien voulu nous consacrer et sans lui ce projet n’aurait jamais vu le jour. On n’oublie pas nos parents pour leur contribution, leur soutien et leur patience. Enfin, nous adressons nos plus sincères remerciements à tous nos proches et amies, qui nous ont toujours soutenue et encouragée au cours de la réalisation de ce projet. Merci à tous et à toutes. i
  • 2. Dédicaces Je dédie ce travail À MES CHERS PARENTS Aucune dédicace ne saurait exprimer mon respect, mon amour éternel et ma considéra- tion pour les sacrifices que vous avez consenti pour mon instruction et mon bien être. Je vous remercie pour tout le soutien et l’amour que vous me portez depuis mon enfance et j’espère que votre bénédiction m’accompagne toujours. Puisse Dieu, le Très Haut, vous accorder santé, bonheur et longue vie et faire en sorte que jamais je ne vous déçoive. À MES DEUX CHERS ET ADORABLES SOEURS En témoignage de mon affection fraternelle, de ma profonde tendresse et reconnaissance, je vous souhaite une vie pleine de bonheur et de succès et que Dieu, le tout puissant, vous protége et vous garde. À MES AMIS En souvenir de notre sincère et profonde amitié et des moments agréables que nous avons passés ensemble. Veuillez trouver dans ce travail l’expression de mon respect le plus profond et mon affec- tion la plus sincère. À TOUTES LES PERSONNES QUI ONT PARTICIPÉ A L’ÉLABORATION DE CE TRAVAIL, À TOUS CEUX QUE J’AI OMIS DE CITER Ben Belgacem Yahya ii
  • 3. Dédicaces Je dédis ce modeste travail comme un témoignage d’affectation, de respect d’admiration à : À Ma MÉRE Tu m’as donné la vie, la tendresse et le courage pour réussir. Tout ce que je peux t’offrir ne pourra exprimer l’amour et la reconnaissance que je te porte. En témoignage, je t’offre ce modeste travail pour te remercier pour tes sacrifices et pour l’affection dont tu m’as toujours entouré. À Mon PERE L’épaule solide, l’oeil attentif compréhensif et la personne la plus digne de mon estime et de mon respect. Aucune dédicace ne saurait exprimer mes sentiments, que Dieu te préserve et te procure santé et longue vie. À MES FRERES ET MES SOEURS À MES CHERS AMIES À CELLE QUI M’INSPIRE TOUJOURS Bouein Aymen iii
  • 4. Table des figures 1 Principe de compilateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi 1.1 Exemple de compilation d’une instruction . . . . . . . . . . . . . . . . . . . 4 1.2 Couple Flex Bison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2.1 Principe de compilateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.2 Caractère spéciaux de Flex . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.3 Un tampon d’entrée en deux moitiés . . . . . . . . . . . . . . . . . . . . . . 9 2.4 Exemple de diagramme de transition . . . . . . . . . . . . . . . . . . . . . . 10 2.5 Diagramme de transition des opérateur . . . . . . . . . . . . . . . . . . . . . 11 2.6 Diagramme de transition des identificateur . . . . . . . . . . . . . . . . . . . 12 2.7 Diagramme de transition des chaines des caractères . . . . . . . . . . . . . . 13 2.8 Diagramme de transition des caractères . . . . . . . . . . . . . . . . . . . . . 14 2.9 Diagramme de transition des entier et réel . . . . . . . . . . . . . . . . . . . 14 2.10 Différence entre les mots clé et les identificateurs . . . . . . . . . . . . . . . 16 3.1 Analyse syntaxique descendante de id + id * id . . . . . . . . . . . . . . . . 23 3.2 Analyse syntaxique ascendante de id * id . . . . . . . . . . . . . . . . . . . . 24 3.3 Analyse syntaxique par décalage-réduction sur l’entrée id1 * id2 . . . . . . . 25 3.4 Structure de table de symbole au niveau de sous-programme . . . . . . . . . 26 3.5 Structure détaillé de table de symbole aux niveau de sous-programme . . . . 27 3.6 Un tampon d’entrée en deux moitiés . . . . . . . . . . . . . . . . . . . . . . 39 5.1 Les directives de porteur de donnée . . . . . . . . . . . . . . . . . . . . . . . 55 5.2 Code assembleur de l’affichage des caractères et chaine des caractères . . . . 55 5.3 Lecture de caractére et chaine des caractéres à partie de console . . . . . . . 57 6.1 Diagramme de cas d’utilisation . . . . . . . . . . . . . . . . . . . . . . . . . 61 6.2 Diagramme de séquence «Exécution code source» . . . . . . . . . . . . . . . 63 6.3 Diagramme de classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 7.1 Logo Qt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 7.2 Etude de l’interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 7.3 Etude de l’interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 7.4 Fonctionnement de zone traitement de code . . . . . . . . . . . . . . . . . . 70 7.5 Traitement des erreurs de compilation . . . . . . . . . . . . . . . . . . . . . . 71 iv
  • 5. Listings 1 Hello World avec C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi 2 Hello World avec Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi 3 Hello World avec Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xii 2.1 Faux boucle for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.2 Implémentation Flex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.1 Grammaire déclaration de donnée . . . . . . . . . . . . . . . . . . . . . . . . 28 3.2 Grammaire boucle conditionnelle C++ et Java . . . . . . . . . . . . . . . . . 29 3.3 Instruction Switch C++ et Java . . . . . . . . . . . . . . . . . . . . . . . . . 29 3.4 Grammaire Boucle for C++ et Java . . . . . . . . . . . . . . . . . . . . . . . 30 3.5 Grammaire Boucle while C++ et Java . . . . . . . . . . . . . . . . . . . . . 30 3.6 Grammaire Boucle Do-while C++ et Java . . . . . . . . . . . . . . . . . . . 30 3.7 Grammaire déclarative de donné VB.NET . . . . . . . . . . . . . . . . . . . 30 3.8 Grammaire boucle conditionnelle VB.NET . . . . . . . . . . . . . . . . . . . 31 3.9 Grammaire boucle For VB.NET . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.10 Grammaire boucle Do-While VB.NET . . . . . . . . . . . . . . . . . . . . . 31 3.11 Grammaire boucle While VB.NET . . . . . . . . . . . . . . . . . . . . . . . 31 3.12 Importation de langage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3.13 déclaration de donné . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3.14 description préalable de grammaire de lecture de variable . . . . . . . . . . . 33 3.15 grammaire de lecture de variable . . . . . . . . . . . . . . . . . . . . . . . . 33 3.16 Grammaire d’affichage de donnée . . . . . . . . . . . . . . . . . . . . . . . . 34 3.17 Grammaire d’affectation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 3.18 Grammaire boucle for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 3.19 Grammaire instruction select . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 3.20 Implémentation table de symbole . . . . . . . . . . . . . . . . . . . . . . . . 37 3.21 Entête des sous programme ralative à table de symbole . . . . . . . . . . . . 37 3.22 Implémentation Bibliothèque . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 3.23 Entête des sous programme ralative aux Bibliothèque . . . . . . . . . . . . . 38 3.24 Association de type à STR_EXPR et EXPR décrite lors de l’affectation . . 40 3.25 Associer les priorités des opérateurs arithmétique . . . . . . . . . . . . . . . 40 3.26 Indicateur d’erreur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 3.27 Déclaration de l’axiome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 4.1 Installation de porteur de donnée aprés verification sémantique . . . . . . . . 44 4.2 Insertion de commande sémantique d’ajout de donnée . . . . . . . . . . . . . 44 4.3 Insertion de commande sémantique Vérification de l’existance de donnée . . 44 4.4 Insertion de commande sémantique de vérification de l’existence de donnée . 45 4.5 Vérification de l’existence de donnée lors de l’affectation . . . . . . . . . . . 45 5.1 Hello World Tasm assembleur . . . . . . . . . . . . . . . . . . . . . . . . . . 52 5.2 Structure d’une fichier Tasm vide . . . . . . . . . . . . . . . . . . . . . . . . 53 v
  • 6. LISTINGS 5.3 Générateur de code machine . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 5.4 L’envoie de valeur des unitées lexicale caractere et chaine . . . . . . . . . . . 56 vi
  • 7. Table des matières Introduction x 1 Contexte et état de l’art 1 1.1 Phase d’analyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.1.1 Analyseur lexicale : . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.1.2 Analyseur syntaxique : . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.1.3 Analyseur sémantique : . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.2 Phase de synthése : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2.1 Production de code intermediaries : . . . . . . . . . . . . . . . . . . 3 1.2.2 Optimisation de code : . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2.3 Production de code : . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.3 Phases logiques de la compilation d’une instruction . . . . . . . . . . . . . . 4 1.4 Couple Flex Bison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.4.1 Flex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.4.2 Bison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2 Analyse lexicale 6 2.1 Le rôle de l’analyseur lexical . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.1.1 Unités lexicales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.1.2 Motif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.1.3 Lexème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.1.4 Erreur lexical . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.2 Spécification des unités lexicales . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.2.1 Expression régulières . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.2.2 Mémorisation du texte d’entrée (couple de tampons) . . . . . . . . . 9 2.2.3 Diagramme de transition . . . . . . . . . . . . . . . . . . . . . . . . 10 2.2.4 Les automates à état finie . . . . . . . . . . . . . . . . . . . . . . . . 11 2.3 Conception et Implémentation d’analyseur lexicales . . . . . . . . . . . . . . 12 2.3.1 Conception d’analyseur lexical . . . . . . . . . . . . . . . . . . . . . . 12 2.3.2 Implémentation d’analyseur lexical . . . . . . . . . . . . . . . . . . . 17 2.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 3 Analyse syntaxique 19 3.1 rôle analyseur syntaxique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.1.1 Gestion des erreurs de syntaxe . . . . . . . . . . . . . . . . . . . . . . 20 3.1.2 Stratégie de rattrapage des erreurs . . . . . . . . . . . . . . . . . . . 20 3.2 Grammaire non contextuelle . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 3.2.1 Définition formelle des grammaire non contextuelle . . . . . . . . . . 21 vii
  • 8. TABLE DES MATIÈRES 3.2.2 Arbre d’analyse et dérivation . . . . . . . . . . . . . . . . . . . . . . 22 3.3 Analyse syntaxique descendante . . . . . . . . . . . . . . . . . . . . . . . . . 22 3.3.1 Analyse syntaxique par descente récursive . . . . . . . . . . . . . . . 23 3.3.2 Grammaire LL(1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.4 Analyse syntaxique ascendante . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.4.1 Analyse syntaxique par décalage-réduction . . . . . . . . . . . . . . . 24 3.5 Conception et implémentation d’analyseur syntaxique . . . . . . . . . . . . . 25 3.5.1 Conception d’analyseur syntaxique . . . . . . . . . . . . . . . . . . . 25 3.5.2 Implémentation d’analyseur syntaxique . . . . . . . . . . . . . . . . . 37 3.6 Coclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 4 Analyse sémantique 42 4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 4.2 Installation et vérification de l’existence des sous programme et porteurs des données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 4.2.1 Les sous programmes . . . . . . . . . . . . . . . . . . . . . . . . . . 43 4.2.2 Porteur de donné . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 4.3 Vérification sémantique des instructions d’affectation . . . . . . . . . . . . . 45 4.4 Vérification sémantique d’allocation de mémoire avant l’étape de l’exécution 46 4.5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 5 Génération de code assembleur 48 5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 5.2 Etude de générateur de code cible . . . . . . . . . . . . . . . . . . . . . . . . 49 5.2.1 Coût d’un programme et cout des instructions . . . . . . . . . . . . . 49 5.2.2 Jeu d’instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 5.3 Architecture 8086 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 5.3.1 Les registres Généraux . . . . . . . . . . . . . . . . . . . . . . . . . . 51 5.3.2 Les registres segment . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 5.4 Choix de l’assembleur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 5.5 Turbo assembler Tasm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 5.5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 5.5.2 Structure de fichier assembleur Tasm . . . . . . . . . . . . . . . . . . 53 5.6 Génération du code machine relative à la code source . . . . . . . . . . . . . 53 5.6.1 Association de mémoire aux niveau de porteur de donnée . . . . . . . 54 5.6.2 Affichage de donnée sous le console . . . . . . . . . . . . . . . . . . . 55 5.6.3 Récupération de donnée à traver le console . . . . . . . . . . . . . . . 56 5.7 Conclution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 6 Conception d’interface compilateur 58 6.1 introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 6.2 Conception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 6.2.1 Capture des besoins . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 6.2.2 Methodologie de conception . . . . . . . . . . . . . . . . . . . . . . . 60 6.2.3 Diagramme de cas d’utilisation . . . . . . . . . . . . . . . . . . . . . 61 6.2.4 Diagramme de séquence . . . . . . . . . . . . . . . . . . . . . . . . . 62 6.2.5 Diagramme de classes . . . . . . . . . . . . . . . . . . . . . . . . . . 63 6.3 Interconnexion interface et compilateur . . . . . . . . . . . . . . . . . . . . . 64 6.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 viii
  • 9. TABLE DES MATIÈRES 7 Réalisation et test 66 7.1 introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 7.2 Environnement logiciel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 7.2.1 QT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 7.3 Travail réalisé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 7.3.1 Etude de répartition des composants de l’interface . . . . . . . . . . . 68 7.3.2 Capture d’écran de notre interface principale . . . . . . . . . . . . . . 69 7.3.3 Capture d’écran de fonctionnement de zone traitement de code . . . . 69 7.3.4 Capture d’écran de traitement des erreurs de compilation . . . . . . . 70 7.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Conclusion et perspectives 72 Bibliographie 74 ix
  • 10. Introduction La programmation, d’après le Nouveau Petit Robert 1 , recouvre « l’élaboration et la codi- fication de la suite d’opérations formant un programme », un programme, aussi appelé un logiciel, étant « l’ensemble des instructions rédigé dans un langage de programmation permettant à un système informatique d’exécuter une tâche donnée ». Cette définition souligne le rôle essentiel du langage de programmation comme vecteur de communication entre le programmeur et l’ordinateur. Cependant, elle ne fait pas apparaître la grande diversité des nombreux langages de programmation existants, un seul de ces langages est directement exécutable par les circuits de l’ordinateur : il s’agit du langage machine lorsqu’il se présente sous forme de nombres (les «0 et 1» bien connus du grand public), ou encore du langage assembleur lorsqu’il se présente sous forme textuelle. Ces langages machine ou assembleur sont dits «de bas niveau», car les ordres exprimés dans ces langages manipulent directement les composants de l’ordinateur que sont les re- gistres, la mémoire et les périphériques. Quel que soit le langage dans lequel un programmeur écrit ses logiciels, il faut savoir passer de ce langage de plus ou moins haut niveau au langage de la machine. La compilation est le processus qui traduit un langage de programmation vers le langage machine. Cette traduction est effectuée automatiquement par un programme appelé compilateur, qui produit du code machine, les grandes différences d’expressivité entre un langage de programmation de haut niveau et un langage machine ou assembleur rendent très difficile la transformation directe entre les deux langages. Nous allons explorer à quel point un compilateur est conçu et organisé. Nous allons voir que ses principales composantes impliquent une sorte de système expert, à l’aide des règles de production. Le principal défi dans un compilateur donner un sens à une longue séquence de caractères dans un fichier source. C’est un problème difficile en informatique, en fait, c’est une forme d’intelligence artificielle : comment faire correspondre quelque chose qui est claire et sensée à un être humain dans quelque chose qui est clair et sensible à une machine comme l’indique la figure 1. 1. Le Nouveau Petit Robert est un dictionnaire de langue française, publié par les dictionnaires le Robert, Reconnais par sont richesse et possibilité de rechercher à travers le web. x
  • 11. Introduction générale compilateurE E c erreur input file output File Figure 1 – Principe de compilateur Un langage de programmation de haut niveau définie un abstraction : le programmeur exprime un algorithme en utilisant le langage et le compilateur doit traduire ce programme vers le langage cible. De façon général, il est plus facile de programmer en utilisant les langages de plus haut niveau, mais on obtient des programmes cibles qui s’exécutent plus lentement. Le programmeur qui utilise un langage de plus bas niveau a plus de contrôle pour les calculs et qui peut ensuite écrire des codes plus efficace. Malheureusement, les programmes de bas niveau sont plus difficiles à écrire et surtout moins portable et plus difficiles à faire évoluer. De nos jour, on remarque l’apparition de plusieurs langages de programmation dans plusieurs domaines informatique. Mais la question que se pose " Qu’elle est le meilleur lan- gage ? " bien sûr la réponse de cette question dépend principalement à cette de question " Qu’elle est le domaine d’application du langage ? ". Toutes les fois ou un langage de programmation est apparaitre, elle supplante d’autre en terme de popularité, l’évolution s’est faite vers des niveaux d’abstraction supérieures, C fut le langage prédominant pour la programmation système dans les années 1980, pour les projet démarrés dans les années 1990, le choix se porta souvent vers C++, JAVA, introduit en 1995 gagna rapidement en popularité a la fin de la décennie [1] . Le meilleure bénéfice de programmeation haut niveau est l’apparition des nouveaux outils ou bien l’amélioration des anciens, qui sont bien équipés d’un syntaxe qui est de plus en plus proche d’eux. L’évolution de syntaxe de programmation est ascendant au niveau de simplicité et d’effica- cité, on peut distinger cette évolution, lorsque on fait un étude comparatif entre C++,Java[3] et Python[2] induquée dans les listings 1,2 et 3 . 1 #include <iostream.h> 2 int main () 3 { 4 cout << "Hello World" ; 5 return 0 6 } Listing 1 – Hello World avec C++ 1 #include <iostream.h> 2 public class Hello 3 { 4 public static void main (String args) 5 { 6 System.out.println("Hello World") ; 7 } } Listing 2 – Hello World avec Java xi
  • 12. Introduction générale 1 print("hello World") Listing 3 – Hello World avec Python La contrainte du temps et l’acheminement de l’apparition des langages de programmation n’est pas une raison de jugement entre les langages de programmation et de distinguer les fonctionnalités. Cependant, que java qui apparaitre après c++ ne supporte pas la notion de pointeur et de multihéritage qui sont fournies avec leur prédécesseur. xii
  • 13. Chapitre 1 Contexte et état de l’art Sommaire 1.1 Phase d’analyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.1.1 Analyseur lexicale : . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.1.2 Analyseur syntaxique : . . . . . . . . . . . . . . . . . . . . . . . . 2 1.1.3 Analyseur sémantique : . . . . . . . . . . . . . . . . . . . . . . . 2 1.2 Phase de synthése : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2.1 Production de code intermediaries : . . . . . . . . . . . . . . . . 3 1.2.2 Optimisation de code : . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2.3 Production de code : . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.3 Phases logiques de la compilation d’une instruction . . . . . . . . . . . . 4 1.4 Couple Flex Bison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.4.1 Flex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.4.2 Bison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Résumé chapitre Au niveau de ce chapitre nous étudions le processus de compilation, les différentes phases inclues dans ce processus, les différents analyseurs permettant la transformation d’une instruction décrite dans un langage de haut niveau à son équivalente de code machine. 1
  • 14. CHAPITRE 1. CONTEXTE ET ÉTAT DE L’ART N ous avons jusqu’à ici considéré un compilateur comme une boite noire qui transforme un programme source en un programme cible sémantiquement équivalent. Ouvrons un peu cette boite nous distinguons deux parties dans cette transformation : Phase d’analyse La phase d’analyse permet principalement de décomposer le programme source en des constituants, tout en associant à chacun une structure grammaticale, elle utilise ensuite cette structure pour détecter si le programme source est syntaxiquement mal formé ou sémanti- quement incorrecte. Elle accumule également diverses informations qu’elles conservent dans une structure de données nommée table de symbole, elle est constituée principalement de trois analyseur Analyseur lexicale : Le mot «lexicale» dans le sens traditionnel du terme signifie «se rapportant à des paroles», sur le plan des langages de programmation, les mots sont des objets comme noms de variables, les numéros, les mots clés, etc. Ces mots sont traditionnellement appelés jetons. Un analyseur lexical aura en entrée une chaîne des caractères de l’individu, sont principale rôle et de diviser cette chaîne en unité lexicale. En outre, il va filtrer tout ce que sépare les jetons (ce qu’on appelle caractère superflus). L’objectif principal de l’analyse lexicale est de rendre la vie plus facile par la suite à l’analyseur syntaxique. En théorie, le travail qui est effectué lors de l’analyse lexicale peut faire partie intégrante de l’analyse syntaxique. Analyseur syntaxique : L’analyseur syntaxique est à peu près l’équivalent de vérifier du texte ordinaire écrit dans un langage naturel est grammaticalement correct (sans se soucier de sens). Le but de l’analyse de syntaxe est de vérifier que nous avons une séquence valide de jetons envoyée par l’analyseur lexical, notez que cette séquence n’a pas besoin d’avoir un sens. La correspondance entre le programme et les règles syntaxique est généralement hiérar- chique, et peut être spécifiée par un arbre de dérivation pour le programme pour y utilisé dans la phase de génération de code. Analyseur sémantique : L’analyse syntaxique vérife seulement que le programme se compose des jetons disposés dans une combinaison valide de syntaxe. Maintenant, nous allons passer à l’analyse séman- tique, où nous plongeons profondément afin de vérifier si elles forment un ensemble logique d’instructions. Pour qu’un programme puisse être sémantiquement valide, toutes les variables, fonctions, classes, etc, doivent être correctement définis. Les expressions et les variables doivent être utilisées de manière que le respect du système de type, de contrôle d’accès doivent être respectés, et ainsi de suite. L’analyse sémantique est l’avant-dernière phase avant la fin de la dernière chance du compilateur pour éliminer les programmes incorrectes. Nous avons besoin d’être assurer que le programme est suffisamment solide pour continuer à la génération de code. 2
  • 15. CHAPITRE 1. CONTEXTE ET ÉTAT DE L’ART Phase de synthése : La partie de synthèse (back-end) construit le programme cible souhaité à partir de la représentation intermédiaire et les informations dans la table des symboles. Production de code intermediaries : Au cours de la traduction d’un programme source en code machine pour une machine cible, un compilateur peut générer un code de langue de niveau moyen, il est connu sous le nom de code intermédiaire et texte intermédiaire. La complexité de ce code se trouve entre le code de la langue source et le code objet. Le code intermédiaire peut être représenté sous la forme d’un arbre de syntaxe à trois adresses de code, cette représentation doit avoir deux propriétés importantes : elle doit être facile à produire à partir de l’arbre syntaxique et facile à traduire en langage cible. Optimisation de code : La phase d’optimisation de code indépendante de la machine tente d’améliorer le code in- termédiaire afin d’avoir un meilleur code cible. En général, meilleur signifie plus rapide. Mais on peut viser d’autres objectifs, comme un code final plus court ou consommant peu d’éner- gie. Quelques optimisations simples peuvent améliorer efficacement le temps d’exécution du programme cible sans retarder trop la compilation. Production de code : Le générateur du code prend en entrée une représentation intermédiaire du programme source et la réécrit dans un langage cible. Si le langage cible est un code machine, à chaque variable de programme on fait correspondre un registre ou une adresse de mémoire. Ensuite les instructions intermédiaires sont traduites en séquence d’instruction machine qui effectuent la même tache. 3
  • 16. CHAPITRE 1. CONTEXTE ET ÉTAT DE L’ART Phases logiques de la compilation d’une instruction c Analyseur lexical c Position = Initiale + Vitesse * 60 <id,1> <=> <id,2> <+> <id,3> <*> <60> Analyseur syntaxique c = <id,1> ¨¨ €€ + <id,2> ¨¨ €€ * <id,3> ¨¨ €€ 60 Analyseur sémantique c = <id,1> ¨¨ €€ + <id,2> ¨¨ €€ * <id,3> ¨¨ €€ intToFloat 60 Génération de code intermédiaire c t1 = intToFloat(60) t2 = id,3 * t1 t3 = id2 + t2 id1 = t3 Optimiseur de code c t1 = id,3 * 60.0 id1 = id2 + t1 Générateur de code c LDF R2, id,3 MULF R2, R2, 60.0 LDF R1, id2 ADDF R1, R1, R2 STF id1, R1 Table de symbole Position1 ... Initiale2 ... Vitesse3 ... Figure 1.1 – Exemple de compilation d’une instruction 4
  • 17. CHAPITRE 1. CONTEXTE ET ÉTAT DE L’ART Couple Flex Bison Lex 1 et YACC 2 sont des outils Linux qui engendrent des programmes d’analyse du texte. Les programmes générés offrent des fonctionnalités de reconnaissance, de structuration, de traduction d’un texte écrit dans un langage donné. Flex et Bison nouveauté de lex et yacc sont des outils de construction de programme qui gèrent d’entrées structurées, ils ont l’origine des outils de construction des compilateur. Flex Flex (abréviation de Fast Lexical Analyzer) est un outil conçu à l’aide du développement du compilateur. En particulier, flex est un outil qui s’occupe principalement à l’étape première de la réalisation de compilateur. Comme étant un analyseur lexical, flex est un programme qui reconnaît les modèles lexicales du texte fournie en entrée, ou son entrée standard est le nom de fichier donné pour une description d’un scanner à générer sous la forme d’extension ".l", la description est à la forme de paires d’expressions régulières et de code C appelée règles. Flex génère en sortie un fichier source C "lex.yy.c" par défaut ,ce fichier après avoir compiler et générer leur exécutable analyse son entrée pour les occurrences de modèle lexicale, chaque fois qu’elle en trouve un, il exécute le code C correspondant [4]. Bison Bison est un outil qui s’occupe principalement à la deuxième étape de réalisation de compilateur, comme étant un analyseur syntaxique, bison est un programme qui vérifier le rangement des modèles lexicales envoyé par flex. Cependant flex et bison travaillent la main dans main puisque bison appelle flex à chaque fois qu’il veut un nouveau modèles lexicale. Bison doit être décrit par une grammaire, cela signifie que vous spécifiez un ou plusieurs regroupements syntaxiques et donner des règles pour les construires à partir de ces regroupements. Il prend comme entrée un fichier d’extension ".y" contenant ces regroupement grammaticales et fournit en sortie deux fichiers portant leur nom : la première contient le code C de l’analyseur (analyseur.tab.c) et la deuxième contient la définition des codes des modèles lexicales (analyseur.tab.h), afin qu’elle puissent être partagée par les deux premiers analyseur comme l’induque la figure 1.2 [5]. compilateur C FLEXE E c input File EEa.exe Bison.tab.c + Bison.tab.h Flex.l Lex.yy.c BISONE Bison.y E Figure 1.2 – Couple Flex Bison 1. Lexical parser 2. Yet Another Compiler Compiler 5
  • 18. Chapitre 2 Analyse lexicale Sommaire 2.1 Le rôle de l’analyseur lexical . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.1.1 Unités lexicales . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.1.2 Motif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.1.3 Lexème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.1.4 Erreur lexical . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.2 Spécification des unités lexicales . . . . . . . . . . . . . . . . . . . . . . . 8 2.2.1 Expression régulières . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.2.2 Mémorisation du texte d’entrée (couple de tampons) . . . . . . . 9 2.2.3 Diagramme de transition . . . . . . . . . . . . . . . . . . . . . . 10 2.2.4 Les automates à état finie . . . . . . . . . . . . . . . . . . . . . . 11 2.3 Conception et Implémentation d’analyseur lexicales . . . . . . . . . . . . 12 2.3.1 Conception d’analyseur lexical . . . . . . . . . . . . . . . . . . . . 12 2.3.2 Implémentation d’analyseur lexical . . . . . . . . . . . . . . . . . 17 2.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Résumé chapitre Au niveau de ce chapitre nous étudions la décomposition de texte source en des mots selon une structure de successivité des caractères, les outils de détection et de revoie de ces mots à l’analyseur suivant, la réservation des mots clé choisie pour le fonctionnement de compilateur. 6
  • 19. CHAPITRE 2. ANALYSE LEXICALE Le rôle de l’analyseur lexical L’analyse lexicale est la première phase d’un compilateur, la principale tâche accomplie par cette phase consiste à identifier l’ensemble des mots d’un langage valide qui se pro- duit dans un flux d’entrée 1 . Cependant, l’analyseur lexical agit comme une interface entre le programme source à compiler et la suite du compilateur, il lit les caractères constituent le programme source et les regroupés en lexèmes. L’analyseur lexical convertit ces lexèmes en un flux des mots valides de la langue, mieux connues sous les noms d’unités lexicales (Tokens). L’analyseur syntaxique et l’analyseur lexical travail main dans la main, dans le sens que à chaque fois l’analyseur syntaxique a besoin de plus jeton, il demande à l’analyseur lexical qui est à son tour numériser le flux d’entrée restantes et retourne le jeton produisant ensuite. L’idée est expliquée dans la figure 2.1. analyseur lexicale Suite de complilateur Table de symbole E E ' Jeton demande de jeton Source ¨ ¨¨¨ ¨¨¨¨ ¨¨¨B r rrr rrr rrrr‰r rrr rrr rrrrj ¨ ¨¨¨ ¨¨¨ ¨¨¨¨% Figure 2.1 – Principe de compilateur En dehors de cela, l’analyseur lexical participe également à la création et à la maintenance de la Table Symbole. C’est parce que, il est le premier module d’identifier l’apparition d’un symbole, s’il est défini pour la première fois, il doit l’installer dans la table de symbole. L’analyseur lexical est également responsable pour enlever les cosmétiques du programme comme des espaces blancs supplémentaires, commentaires, etc. Unités lexicales Une unité lexicale est un couple constitué d’un nom lexicale et d’une valeur d’attribut optionnelle. Le nom d’unité lexicale est un symbole abstrait représentant leur type lexicale. Les noms d’unité lexicale sont les symboles d’entrée que traite l’analyseur syntaxique. Nous écrivons généralement les noms d’unités lexicales en caractère gras et nous les désignerons souvent à partir de leur noms. 1. Le flux d’entrée est l’ensemble des caractères de programme source. 7
  • 20. CHAPITRE 2. ANALYSE LEXICALE Motif Un motif est une description de la forme que les lexèmes d’une unité lexicale donnée peuvent prendre. Dans le cas d’une unité lexicale de type mot clé, le motif est simplement la séquence de caractère qui forme le mot clé. Pour les identificateurs et d’autres types d’unités lexicales, le motif est une structure plus complexe qui reconnait de nombreuses chaines des caractères. Lexème Un lexème est une séquence de caractère dans le programme source qui est reconnue par les motifs d’une unité lexicale, il est identifié par l’analyseur lexical comme une instance de cette unité lexicale. Erreur lexical Il est difficile pour l’analyseur lexicale de dire sans l’aide des autres composants, qu’il y a une erreur dans le code source. Par exemple si la chaine "Foor" est reconnait pour la première fois dans un programme C dans le contexte décrit dans la Listing 2.1. 1 foor (int i =0;i<5;i++) 2 cout << i ; Listing 2.1 – Faux boucle for Un analyseur lexicale ne peut pas dire si foor est une orthographe erronée du mot clé for ou un identificateur de fonction non déclaré. Puisque foor est un lexème pour l’unité lexicale id. L’analyseur lexicale doit retourner l’unité lexicale id à l’analyseur syntaxique et laisse une autre phase de compilateur gérer une erreur due à la permutation des deux lettres. Spécification des unités lexicales Expression régulières Les expression régulières sont les ensembles de toutes les constantes entières ou l’ensemble de tous les noms de variables ou les ensembles des chaînes, où les lettres individuelles sont prises à partir d’un alphabet. Un tel ensemble de chaîne est appelée un langage. Pour les entiers, l’alphabet se compose de chiffres de 0-9, les noms de variables de l’alphabet contient à la fois des lettres et des chiffres (et peut-être quelques-uns d’autres caractères, tels que tiret bas). Étant donné un alphabet, nous allons décrire des ensembles de chaînes de caractères par des expressions régulières. Une notation algébrique qui est compact et facile pour les humains à utiliser et à comprendre [6]. 8
  • 21. CHAPITRE 2. ANALYSE LEXICALE Expression régulières reconnue par Flex Les expressions régulières acceptées par Flex paraissent souvent comme les autres expres- sions régulières on peut distinguer quelques différences au niveau de représentation et des caractères spéciaux indique dans la figure 2.2. Caractère Signification + Un ou plusieurs fois * 0 ou plusieurs fois ? 0 ou un fois - Intervalle d’ensemble Caractère Signification | Union " Valeur littérale des carac. . Tout car sauf fin de ligne Complément d’ensemble Figure 2.2 – Caractère spéciaux de Flex Mémorisation du texte d’entrée (couple de tampons) Il existe des cas ou l’analyseur lexical doit lire en avance quelque caractère. Une partie im- portante du temps est consacré au déplacement des caractères. Il existe plusieurs techniques spéciales de mémorisation permettant de réduire le coût lié au traitement des caractères du texte d’entrée. Cependant, les techniques sont dépendantes des paramètres du systèmes. Nous présentons dans ce qui suit les principes reliés à la reconnaissance des unités lexicales comme l’indique le fique 2.3. x = a 1 + 3 EOF T c Avant Head Figure 2.3 – Un tampon d’entrée en deux moitiés L’idée est d’utiliser un tampon divisé en deux moitiés de N caractère. N peut être le nombre de caractère dans un bloc de disque 2 , s’il reste moins que N caractères en entrée, un caractère spécial EOF (End Of File) est placé dans le tampon après les caractères d’entrée. Par exemple le développeur doit gérer deux pointeurs vers le tampon d’entrée. L’ensemble de caractères situés entre les deux pointeurs constituent le lexème en cours. 2. Le bloc de disque (en anglais cluster) est la plus petite unité de stockage d’un système de fichiers. 9
  • 22. CHAPITRE 2. ANALYSE LEXICALE Au départ les deux pointeurs Head et Avant désignent le premier caractère du prochain lexème à trouver : L’un appelé le pointeur Avant, lit en avant jusqu’à trouver un modèle, une fois que le prochain lexème est reconnu, le pointeur Avant est positionné sur le caractère à sa droite, après le traitement de ce lexème, les deux pointeurs sont positionnés sur le caractère qui suit immédiatement le lexème. Si le pointeur Avant est sur le point de dépasser la marque de moitié, la moitié droite est remplie avec N nouveaux caractères d’entrée, si le pointeur Avant est sur le point de dépas- ser l’extrémité droite du tampon, la partie gauche est remplie avec N nouveaux caractères d’entrées, et le pointeur Avant poursuit circulairement au début du tampon. Diagramme de transition Les diagrammes de transition sont une étape préparatoire pour la réalisation d’un analy- seur lexical. Cette étape consiste principalement à convertir les motifs exprimés sous forme d’une expression régulière en organigramme stylisé (diagramme de transition). Les diagrammes de transition comprennent un ensemble des nœuds ou des cercles appelés états, chaque état représente une condition qui peut être réalisée pendant le parcours de l’entrée à la recherche d’un lexème qui soit reconnu par un ou plusieurs motifs. Des arcs relient un état du diagramme de transition à un autre, chaque arc est étiqueté par un symbole ou un ensemble de symbole, si l’on est dans un état ’0’ et si le symbole d’entrée suivant est ’a’ on cherche un arc qui part de ’0’ et qui est étiqueté par ’a’, le passage d’un état à un état et totalement relatif à l’incrémentation du pointeur Avant lors de lecture de caractère. 0start 1 a Figure 2.4 – Exemple de diagramme de transition On distingue deux types d’états permettant de référencer la progression de l’étape de reconnaissance des unités lexicales : - Un état désigné comme étant l’état de départ ou état initial : il est indiqué par un arc, étiqueté "start" qui ne vient d’aucun arc, le diagramme de transition part de l’état initial, avant toute lecture de symbole d’entrées. - Certains états sont dits d’acceptation ou finaux, ces indiquent d’un lexème à été trouvé. On indique toujours un état final par double cercle et si une action doit être effectué (typi- quement, transmettre une unité lexicale et une valeur d’attribut à l’analyseur syntaxique) on attache cette action à l’état final. Parfois, nous ne somme pas obligé de revenir en arrière en décrémentant le pointeur Avant par un pas en cas où le lexème n’inclut pas le symbole qui nous a amenés à l’état final, alors 10
  • 23. CHAPITRE 2. ANALYSE LEXICALE on ajoute le symbole "*" à l’état final. La figure 2.5 montre le diagramme traduise la reconnaissance des unités lexicales INFEG, DIFF, INF, EGAL, SUPEG, SUP et IDENTIF respectivement définie par les expressions régulières <=, <>, <, =, >=, >. 0start 1 2 3 4 5 6 7 8 < = > = > autre autre = Return(SUPEGAL) Return(SUP) Return(INF) Return(DIFF) Return(INFEGAL) Return(EGAL) * * Figure 2.5 – Diagramme de transition des opérateur Les automates à état finie Les expressions régulières sont pratique pour spécifier des jetons lexicaux, mais nous avons besoin d’un formalisme qui peut être réalisé par un ordinateur comme un programme informatique. Pour cela, nous pouvons utiliser des automates finis. Un automate finie est un ensemble finie d’états et des arcs conduisant d’un état à un autre. Comme étant une spécification de diagramme des transition. Les automates à état finie sont répartie en des états(terminaux et non-terminaux), chaque état est marqué par un symbole qui représente l’état courant [6]. Les automates à état finie non déterministe Un automate finie non déterministe (AFN) est celui qui a un choix d’arêtes étiquetées avec le même symbole sortir de l’état ou il peut avoir des bords spéciaux marqués avec la lettre grecque epsilon qui peut être suivie sans passer de n’importe quel symbole de l’entrée [6] . Les automate à état finie déterministe Les Automates non déterministes sont comme mentionnés plus haut, pas tout à fait proche de "la machine" que nous le souhaiterions. Par conséquent, nous introduisons maintenant 11
  • 24. CHAPITRE 2. ANALYSE LEXICALE une forme plus restreinte des automates finie : L’automate finie déterministe, ou (AFD) est un automate à état finie déterministe, mais qui obéissent à un certain nombre de restrictions supplémentaires : — Il n’y à pas epsilon-transitions. — Deux transitions ne peuvent pas être étiquetées par le même état. Cela signifie que nous n’avons jamais le choix entre plusieurs cotés d’états : le symbole d’entrée suivant déterminer de façon unique la transition. C’est pourquoi ces automates sont appelés déterministe. Conception et Implémentation d’analyseur lexicales Conception d’analyseur lexical L’étape de conception consiste à définir les expressions régulière pour les différentes unités lexicales, cette définition suivie d’une automate déterministe représentée sous forme d’un diagramme de transition pour mieux comprendre l’étape de récupération de ces unités et leur méthode de reconnaissance. Les identificateurs : Un identificateur est un suite de caractère et de nombre qui ne doit pas commencer par un nombre ou caractère réservé (les opérateurs . . . ) et qui peut contenir un caractère de séparation ’_’ (tiré bas). Le diagramme de transition représenté dans la figure 2.6, décrit la manipulation des identificateurs au niveau de l’analyseur lexicale. 0start 1 a-z A-Z _ a-z A-Z 0-9 _ Figure 2.6 – Diagramme de transition des identificateur L’expression régulière permet de reconnaître un identificateur est la suivante : ident [a-zA-Z_] ([0-9a-zA-Z_])* Expression régulière flex Tout en respectant les contraintes au niveau de l’identificateur, On doit l’associer un nom significatif pour qu’on puisse référencer ultérieurement dans l’analyseur syntaxique, dans notre cas ident désigne un occurrence d’un lexème au niveau de code source. La deuxième partie de l’expression flex désigne l’expression régulière habituelle qu’on trouve répartie lo- giquement en deux parties : 12
  • 25. CHAPITRE 2. ANALYSE LEXICALE — La première décrit l’obligation de commencement par une lettre ou tiré bas. — La deuxième représente la libération de choix aux développeurs. Les chaines des caractères : Une chaine des caractères est une suite de caractères qui sont éliminées par deux ca- ractères spéciaux réservés pour leur récupération(""). Le problème majeur est qu’on peut trouver un mot clé réservé au fonctionnement de compilateur (if ) dans la suite de caractère de chaine, donc il est souvent important de déclarer l’analyseur lexicale du l’importance de sauter à la position de deuxième séparateur sans tenir compte à l’intérieur de chaine. Le diagramme de transition représenté ce dessus, décrit la manipulation des chaines des caractères aux niveau de l’analyseur lexicale. 0start 1 3 " a-z A-Z 0-9 " Figure 2.7 – Diagramme de transition des chaines des caractères L’expression régulière permet de reconnaître une chaine des caractères est la suivante : """(.)+""" { return(CHAINE) ; } Expression régulière flex Nous référençons ce séquencement limité des caractères par le nom d’unité lexicale chaine. La première partie désigne tous les caractères sauf le retour à la ligne (au niveau de dia- gramme de transition ci-dessus, a-z, A-Z désigne toutes les occurances des caractére puisque nous pouvons pas traité tous les cas ). Le premier guillemet élimine tous les chances pour renvoyer une autre unité à l’intérieur de chaîne puisque le pointeur avant est initialisé et qui bascule directemant à la position de deuxiéme guillemet. Les caractères : Les caractères sont des cas particuliers de chaine de caractère. Ils sont tout simplement une chaine de longueur un. Mais la question qui se pose "est ce que l’analyseur lexicale va envoyer une unité lexical qui référence une chaine de caractère ou bien un caractère ", deux réponses possible pour cette question : — La solution JAVA consiste à les distingués par les séparateur c’est à dire pour les chaines de caractères on doit l’éliminer par les "" et pour les caractères par ”. 13
  • 26. CHAPITRE 2. ANALYSE LEXICALE — L’autre solution est de renvoyer deux unités lexicales distinctes référencées les chaines des caractères et les caractère et laisser la distinction s’appuie à l’analyseur séman- tique pour décrire le comportement de l’unité lexical, puisque une chaine de caractère peut contenir un caractère et l’inverse est faux. Le diagramme de transition représenté dans la figure 2.9, décrit la manipulation des caractères au niveau de l’analyseur lexicale. 0start 1 3 4 " a-z A-Z 0-9 " Figure 2.8 – Diagramme de transition des caractères L’expression régulière permet de reconnaître un caractère est la suivante : """.""" { return(CARACTERE) ; } Expression reguliere flex L’unité lexicale CARACTERE se réfère à l’existence d’un caractère, leur expression ré- gulière paraît comme celle de chaine de caractères (a-z A-Z et 0-9 désigne tous caractéres) mais sans avoir la possibilité d’écrire plusieurs caractères. Les entiers et réels : Les entiers sont le séquencement des chiffres sans aucun séparateur entre eux. Les réels sont deux entiers séparés par un point. D’après les règles arithmétiques, un réel peut contenir un entier ce qui cause un problème au niveau de l’analyseur lexicale. Aux niveau de cette phase en va les distingue par leur unité lexicale. La vérification de sémantique de l’apparition de ces deux unités ce fait au niveau de l’analyseur sémantique. Le diagramme de transition représenté ce dessus, décrit la manipulation des entiers et les réels aux niveau de l’analyseur lexicale. 0start 1 3 4 0-9 0-9 . 0-9 0-9 Figure 2.9 – Diagramme de transition des entier et réel L’expression régulière permet de reconnaître un entier ou réel est la suivante : 14
  • 27. CHAPITRE 2. ANALYSE LEXICALE nbr [0-9]+ entier nbr reel entier.nbr Expression reguliere flex Les deux unités lexicales entier et reel réfèrents successivement les entiers et les réels. Les opérateurs arithmétique et opérateurs logique Les opérateurs arithmétiques restent inchangables au niveau des instructions arithmé- tique. Le traitement des opérateurs logique se diffère d’un compilateur à un autre. Pour garantir la bonne fonctionnement de compilateur multi-langages on doit associer les différentes représentations de ces opérateur l’un à l’autre. L’analyseur lexicale doit renvoyer la même unité lexicale, lorsqu’il rencontre la même signification des lexèmes, par exemple le lexème OR aux niveau de VB.NET est équivalant à celui aux niveau de C++, cet exemple est pratique à la totalité des opérateurs logique. Les mots clés : les mots clés sont les mots réservés à la fonctionnement de compilateur. Ils sont considéré par l’analyseur syntaxique comme étant des identificateurs (ils aient l’air d’identificateur ) car ils ont le même motif d’expression régulière. La reconnaissance de mot clé et des identificateurs représentent un problème, est il y’a deux façons de traiter les mots réservé qui ont l’air d’identificateur : — Charger les mots réservés dans une table de symbole dès le départ, un champs d’en- trées de la table de symbole indique que les chaines ne sont jamais des identificateurs ordinaires et indique qu’elle unité lexicale le représente. — Créer des diagrammes de transition représentant graphiquement les différences entre les identificateurs et les mots réservées. Le diagramme de transition représenté dans la figure 2.10, décrit un exemple de manipu- lation des identificateurs par rapport aux mots réservées au niveau de l’analyseur lexicale. 15
  • 28. CHAPITRE 2. ANALYSE LEXICALE 0start 2 4 IF 5INT 1 6 7 8 9 17 13 14 STEP Identificateur 15 16 12 STRING 3 10 Entier 11 REEL i 0-9 s a-z sauf i, s t a-z sauf t a-z Return f a-z sauf f,nn t a-zsauft e r a-z saufr,e n g a-zsaufg p a-zreturn i a-zsaufi i Return a-z Return 0-9 . Return 0-9 0-9 return a-z Return a-z Return Figure 2.10 – Différence entre les mots clé et les identificateurs 16
  • 29. CHAPITRE 2. ANALYSE LEXICALE Implémentation d’analyseur lexical Puisque l’analyseur lexicale a le contrôle sur le flux d’entrée, il doit être attaché à l’amélio- ration qui nécessite de compilateur. L’analyseur lexicale doit se référer à la ligne courant pour bien identifier les erreurs lexicales ou bien syntaxiques, le listing 2.2 représente un example non-complet d’implémentation d’analyseur lexicale. 1 %{ 2 #include <stdlib.h> 3 #include "compilateur.h" 4 int line =1; 5 %} 6 7 %x IN_COMMENT 8 9 blanc [ t]+ 10 nbr [0 -9]+ 11 entier {nbr} 12 reel {entier }.{ nbr} 13 ident [a-zA -Z_]([0 -9a-zA -Z_])* 14 15 %% 16 17 """(.)+""" { strcpy(yylval.Tstr ,yytext); 18 return(CHAINE); } 19 20 "//"(.)+"" { strcpy(yylval.Tstr ,yytext); 21 return(COMM); } 22 23 <INITIAL > { 24 "/*" BEGIN(IN_COMMENT); 25 return(COMMPL); 26 } 27 <IN_COMMENT >{ 28 "*/" BEGIN(INITIAL); 29 n line ++; 30 } 31 32 {a}{d}{d} return(ADD); 33 {v}{o}{i}{d} return(VOID); 34 {m}{a}{i}{n} return(MAIN); 35 36 {i}{n}{t}{e}{g}{e}{r} return(DEC_ENTIER); 37 {i}{n}{t} return(DEC_ENTIER); 38 {r}{e}{a}{l} return(DEC_REEL); 39 {f}{l}{o}{a}{t} return(DEC_REEL); 40 {c}{h}{a}{r} return(DEC_CARA); 41 {s}{t}{r}{i}{n}{g} return(DEC_CHAINE); 42 43 {w}{r}{i}{t}{e} return(WRITE); 44 {r}{e}{a}{d} return(READ); 45 46 {t}{h}{e}{n} return(THEN); 47 {e}{n}{d}{i}{f} return(ENDIF); 48 {e}{l}{s}{e} return(ELSE); 49 {i}{f} return(IF); 50 51 . return(POINT); 17
  • 30. CHAPITRE 2. ANALYSE LEXICALE 52 ":" return(DEUXPOINT) ; 53 54 n {line ++;} 55 56 "=" return(AFFECT); 57 58 "(" return(PARG); 59 ")" return(PARD); 60 61 ">" return(OP); 62 "<" return(OP); 63 64 " <=" return(OP); 65 " >=" return(OP); 66 67 "&&" return(SEP); 68 "||" return(SEP); 69 70 "+" return(PLUS); 71 "-" return(MOIN); 72 "*" return(MULT); 73 %% Listing 2.2 – Implémentation Flex Conclusion Nous avons vu que l’analyse lexicale est le première contact de code source avec le com- pilateur, puisque il lit l’entrée caractère par caractère et produit en sortie un flux d’unités lexicales en tenir compte des expressions régulière de ces unités. 18
  • 31. Chapitre 3 Analyse syntaxique Sommaire 3.1 rôle analyseur syntaxique . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.1.1 Gestion des erreurs de syntaxe . . . . . . . . . . . . . . . . . . . . 20 3.1.2 Stratégie de rattrapage des erreurs . . . . . . . . . . . . . . . . . 20 3.2 Grammaire non contextuelle . . . . . . . . . . . . . . . . . . . . . . . . . 21 3.2.1 Définition formelle des grammaire non contextuelle . . . . . . . . 21 3.2.2 Arbre d’analyse et dérivation . . . . . . . . . . . . . . . . . . . . 22 3.3 Analyse syntaxique descendante . . . . . . . . . . . . . . . . . . . . . . . 22 3.3.1 Analyse syntaxique par descente récursive . . . . . . . . . . . . . 23 3.3.2 Grammaire LL(1) . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.4 Analyse syntaxique ascendante . . . . . . . . . . . . . . . . . . . . . . . . 23 3.4.1 Analyse syntaxique par décalage-réduction . . . . . . . . . . . . . 24 3.5 Conception et implémentation d’analyseur syntaxique . . . . . . . . . . . 25 3.5.1 Conception d’analyseur syntaxique . . . . . . . . . . . . . . . . . 25 3.5.2 Implémentation d’analyseur syntaxique . . . . . . . . . . . . . . . 37 3.6 Coclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 Résumé chapitre Au niveau de ce chapitre nous étudions le rôle de l’analyseur syntaxique, la stratégie de rattrapage des erreurs grammaticales, les différents types de fonctionnement des analy- seurs syntaxiques, la possibilité de mélanger les déférents langages de programmation ainsi d’introduire un nouveau syntaxe propre à notre travail. 19
  • 32. CHAPITRE 3. ANALYSE SYNTAXIQUE rôle analyseur syntaxique A près que l’analyseur lexicale divise l’entrée en jetons, le but de l’analyse syntaxique (également connu sous le nom Parsing ) est de recombiner ces jetons et de découvrir la structure de texte à utilisé pour déterminer si oui ou non un texte conforme à un format attendu. Il s’agit de créer une représentation intermédiaire arborescente qui dépeint la structure grammaticale du flot d’unité. Cette transformation est envoyée à la suite de processus de compilation pour traiter ultérieurement (vérification sémantiquement). En plus de trouver la structure du texte d’entrée l’analyse syntaxique doit également rejeter les textes invalides par rapport aux erreurs de syntaxe. Gestion des erreurs de syntaxe La gestion des erreurs est déléguée au concepteur du compilateur qui prévoit la gestion des erreurs dés le départ pourront à la fois de simplifier la structure du compilateur et améliorer sa gestion des erreur. Les erreurs de programmation habituelle peuvent se présenter à différents niveaux : — Les erreurs lexicales comprennent les fautes d’orthographe dans les identificateurs, les guillemets manquants autour d’elles destiné à constituer une chaine de caractère. — Les erreurs syntaxiques : elles comprennent les fautes de syntaxe telles que les point virgules mal placés ou les accolades manquantes. — Les erreurs sémantiques : elles comprennent les erreurs sémantique telles que les in- cohérences de type entre opérateur et opérande. — Les erreurs logiques peuvent être de toute nature commençant par les fautes de rai- sonnement de la part du programmeur jusqu’à l’utilisation de l’opérateur d’affectation à la place de l’opérateur de comparaison == dans un code C. Le programme conte- nant = peut être bien formé ; cependant, il pourrait bien ne pas refléter l’intention du programmeur. Une autre raison de mettre l’accent sur le rattrapage d’erreur pendant l’analyse syntaxique est que de nombreuses erreurs paraissent sous la forme d’erreurs de syntaxe, quelles que soient leurs causes, ils sont donc détecte lorsque l’analyseur syntaxique ne peut se poursuivre. Les analyseurs syntaxiques modernes doivent équiper d’un gestionnaire d’erreur qui est fondé pour l’échappement des erreurs énoncer précédemment : - signaler la présence d’un erreur de façon claire et précise. - Se rattraper après chaque erreur suffisamment vite pour détecter des erreurs ultérieures. Stratégie de rattrapage des erreurs La stratégie de rattrapage d’erreur décrit la réaction de compilateur après la détection d’une erreur : 20
  • 33. CHAPITRE 3. ANALYSE SYNTAXIQUE Rattrapage en mode panique Avec cette méthode, quand l’analyseur syntaxique découvre une erreur, il élimine les sym- boles d’entrée les un après les autre jusqu’à on récent un qui appartient à un ensemble des unités lexicales de synchronisation. Habituellement, les unités lexicales de synchronisation sont des éliminateurs, tels que le point virgule. Le concepteur du compilateur doit sélectionner les unités lexicales de synchronisation appropriées au langage source, bien que le rattrapage au mode panique dépasse en générale une partie considérable du texte source sans y chercher d’autre erreur[1] . Rattrapage au niveau du syntagme Lorsque l’analyseur syntaxique découvre une erreur, il peut effectuer des corrections lo- cale sur le reste de l’entré, c’est-à-dire remplacer un préfixe du texte source restant par une chaine qu’il lui permet de continuer. Le rattrapage au niveau de syntagme a été utilisé dans différent compilateur à rattrapage d’erreurs, car il peut corriger n’importe quelle chaine d’entrée. Son majeur défaut est qu’il a du mal à faire face à des situation dans les quelles la véritable erreur eu lieu avant le point de détection [1]. Grammaire non contextuelle Une grammaire est définie par un ensemble de symbole terminal (les entrées). Un ensemble de non-terminal (les symbole représentant des construction syntaxique) et un ensemble de production, chacun indiquant un moyen selon lequel des chaînes représentées par un non- terminal peuvent être construite à partir de symboles terminaux. Définition formelle des grammaire non contextuelle Nous avons vu qu’une grammaire non contextuelle est constituée de terminaux, de non- terminaux, d’un symbole de départ et de productions : - Les terminaux sont les symboles de base dont sont formées les chaînes. Le terme nom unité lexicale est un synonyme de terminal. Nous utilisons fréquemment le raccourci unité lexicale à la place de terminal lorsqu’il sera clair que nous ne parlons que de nom d’unité lexicale. - Les non-terminaux sont des variables syntaxiques qui dénotent des ensembles de chaîne. Les chaines dénotées par les non-terminaux aident à définir le langage défini par la grammaire. Les non-terminaux imposent une structure hiérarchique au langage, qui est la clé de l’analyse syntaxique. - Les productions d’une grammaire définissent la façon dont terminaux et non-terminaux peuvent être combinés pour former des chaînes. Chaque production consiste en premier : Un non-terminal appelé la tête ou la partie gauche de la production. Le symbole, Parfois : := a été utilisé plutôt que la flèche. Un corps ou partie droite est constitué d’un ou plusieurs terminal ou non-terminal. Les composantes de la partie droite décrivent une des manières dont le chaines du non-terminal de partie gauche peuvent être construites. 21
  • 34. CHAPITRE 3. ANALYSE SYNTAXIQUE Convention de notation Pour éviter d’avoir toujours préciser que " ces symboles sont les terminaux ", " ces sym- boles sont les non-terminaux ", les convention de notation suivante à propret des grammaire seront désormais utilisées dans ce rapport, si une modification aura lieu, un message d’aver- tissement sera écrit avant la section. Les symboles suivants sont des terminaux : — Les lettres minuscules. — Les symboles d’opérations tels que +, - etc. — Les signes de ponctuations tels que point, point-virgule etc. — Les chiffres. Les symboles suivants sont des non-terminaux : — Les lettres majuscule. — La lettre S, qui, quand elle est utilisé,est généralement le symbole de départ. — Les mot en minuscule et italique. — Les lettres grecques. Dérivation L’idée de base de dérivation est de considérer que les productions des règles de réécriture : Chaque fois que nous avons un non-terminal, on peut remplacer cela par le côté droit de toute production dans lequel le non-terminal apparaît sur le côté gauche. Nous pouvons le faire n’importe où dans une séquence de symboles terminaux et non-terminaux et répéter jusqu’à ce faisant. La séquence résultant des terminaux est une chaîne de caractères dans le langage défini par la grammaire. Formellement, nous définissons la relation de dérivation =>. Arbre d’analyse et dérivation Un arbre d’analyse est la représentation graphique d’une dérivation qui ne garde pas trace de l’ordre dans lequel les productions ont été appliquées pour remplacer les non-terminaux. Chaque nœud d’un arbre d’analyse représente l’application d’une production. Le nœud est étiqueté par le non-terminal de la partie gauche de la production, les fils du nœud sont étiqueté, de gauche à droite, par les symboles de la partie de la production par laquelle le non-terminal a été remplacé pendant la dérivation. Analyse syntaxique descendante Un analyseur descendant commence en construisant le nœud racine de l’arbre, qu’il sait devoir étiqueter avec le symbole de départ. Il construit ensuite les nœuds de l’arbre syntaxique en pré-ordre. Ce qui signifie que la racine d’un sous-arbre est constitué avant tous ses nœuds descendantes [9]. 22
  • 35. CHAPITRE 3. ANALYSE SYNTAXIQUE De façon équivalente, l’analyseur syntaxique descendant peut être vue comme la recherche d’une dérivation gauche pour une chaine d’entrée. Soit la grammaire : E → T E’ E’ → + T E’ | T → F T’ T’ → * F T’ | F → ( E ) | id E    dd T    F id T’ E’ ˆˆˆˆˆˆ +    dd T T’ F id    dd T’    dd * F T’ id Figure 3.1 – Analyse syntaxique descendante de id + id * id A chaque étape d’une analyse descendante, le problème clé est celui du choix de la pro- duction à appliquer pour un certain non-terminal. Une fois qu’une production choisie, le reste du processus d’analyse syntaxique consiste à re- connaître dans la chaîne d’entrée les symboles terminaux de la partie droite de la production. Analyse syntaxique par descente récursive Une descente récursive, dans le cas général peut nécessiter des retours en arrière, c’est-à- dire qu’elle peut avoir à parcourir plusieurs fois certaines portions de l’entrée. Cependant, les retours en arrière sont rarement nécessaire pour effectuer l’analyse syntaxique de construction de langage de programmation. Grammaire LL(1) Les analyseurs syntaxiques par descente récursive qui ne nécessitent par le retour en arrière, peuvent être construit pour une classe de grammaire que l’on a appelé LL(1). Le premier L dans LL(1) provient du sens de parcours à droite (en anglais Left). Le second L vient de fait que l’on construite une dérivation gauche (en anglais Leftmost dérivation). Le 1 indique que l’on n’utilise qu’un seul symbole de pré-vision à chaque étape de l’analyse syntaxique pour prendre les décisions sur les actions à effectuer [1]. Analyse syntaxique ascendante Une analyse syntaxique ascendante ( en anglais, bottom-up) correspond à la construction d’un arbre d’analyse pour une chaîne d’entrée en partant des feuilles et en remontant jusqu’à la racine (le haut ). 23
  • 36. CHAPITRE 3. ANALYSE SYNTAXIQUE Il est utile de décrire l’analyse syntaxique comme étant le processus de construction des arbres d’analyse, bien qu’une partie frontale puisse en réalité effectuer une traduction directe, sans construction explicite de l’arbre [1]. Soit la grammaire : E → E + T | T T → T * F | F F → ( E ) | id Analyse ascendant de l’instruction id * id : id * id F * id id T * id F id T * F F id id T    dd T * F F id id E T    dd T * F F id id Figure 3.2 – Analyse syntaxique ascendante de id * id Les chaines de cette suite sont formées à partir des racines de tous les sous-arbres. La suite commence par la chaîne d’entrée id * id. La première réduction produit F * id en réduisant le id le plus à gauche en F, à l’aide de la production F → id. La seconde réduction produit T * id en réduisant F en T. Nous avons maintenant le choix entre réduire la chaîne T, qui est la partie droite de E → T,et réduire la chaine composée du second id, qui est la partie droite de F → id. Plutôt que de réduire T en E, le second id est réduit en F, ce qui donne la chaîne T * F. Cette chaîne se réduit alors en T. L’analyse syntaxique se termine par la réduction de T en E, le symbole de départ. Analyse syntaxique par décalage-réduction On peut voir que l’analyse ascendante comme étant un processus de réduction d’un flux d’unité lexicale vers le symbole de départ de la grammaire. A chaque étape de réduction, une sous-chaîne particulière, reconnue par la partie droite d’une production, est remplacée le non-terminal de partie gauche de cette production. L’analyse syntaxique par décalage-réduction est une forme d’analyse syntaxique ascendante ou une pile stocke des symboles grammaticaux et ou un tompon d’entrée stocke la partie de la chaîne restant. Le symbole $ indique le fond de la pile ainsi que l’extrémité droite de l’entrée. Bien que les opérations de base soient le décalage et la réduction, un analyseur syntaxique par décalage- réduction peut effectuer en réalité quatre action : (1) décaler, (2) réduire, (3) accepter, (4) erreur. 1. Décaler le symbole d’entrée suivant depuis l’entrée vers le sommet de la pile. 2. Réduire, l’extrémité droite de la chaine à réduire doit être au sommet de la pile. Repérer l’extrémité gauche de la chaine à réduire au sein de la pile et décider du non-terminal qui 24
  • 37. CHAPITRE 3. ANALYSE SYNTAXIQUE doit remplacer cette chaîne. 3. Accepter, annoncer le succès de l’analyse syntaxique. 4. Erreur, Si une erreur de syntaxe est trouvée [1]. La figure décrite ce dessus, montre le principe de fonctionnement de l’analyseur syntaxique par décalage-réduction en manipulant l’instruction id1 * id2 : Pile Entrée Action $ id1 * id2 $ décaler $ id1 * id2 $ réduire par F → id $ F * id2 $ réduire par T → F $ T * id2 $ décaler $ T * id2 $ décaler $ T * id2 $ réduire par F → id $ T * F $ réduire par T → T * F $ $ réduire par E → T $ $ accepter Figure 3.3 – Analyse syntaxique par décalage-réduction sur l’entrée id1 * id2 L’analyseur syntaxique charge l’instruction id1 * id2 dans la chaine d’entrée tout en initialisant la pile à vide et appliqué l’action décaler pour envoyer le lexème id1 à la pile, le choix de l’action ce fait par rapport à l’entête de pile, dans la deuxième instruction la réduction de non-terminal id1 par la partie gauche de dérivation, et ainsi de suite jusqu’à traité l’entrée et vidage de la pile ou bien trouvé un lexème qui ne correspond à aucune dérivation. Conception et implémentation d’analyseur syntaxique Conception d’analyseur syntaxique table de symbole Une table de symbole ( ou liste de noms) peut être vu comme un tableau extensible d’ar- ticle, qui peut être indexé par une chaîne au lieu d’un entier. La chaîne est l’identificateur, et l’article associer contient les informations rassemblées sur cet identificateur plus précis les article sont les propriétés de l’identificateur comme leur type, nature . . . Lorsqu’ on appelle le table de symbole avec le nom de l’identificateur, il renvoie un article de type information, et une référence sur les autres identificateurs. Le concepteur du compi- lateur choisit le type de l’information relatif à l’identificateur de manière à pouvoir y utiliser tout-au-long de processus de compilation. 25
  • 38. CHAPITRE 3. ANALYSE SYNTAXIQUE Structure de table de symbole Le table de symbole comme il décrit si-dessous représente un espace de travail virtuelle, qui serve également à stoker les objets relatif au bon fonctionnement de l’analyseur syn- taxique, une ou plusieurs contrainte relié aux ces objet qui nous incite le plus de sauvegarder dans une structure compréhensible et facile à manipuler : Les sous programme Comme son nom l’indique, les sous programme représente un programme qui fonctionne indépendant au programme principale, ce qui implique qu’ils ont leur propre caractéristique donc ils doivent traiter à part pour distinguer leur propre données et leur inusité d’existence. Les sous programme doivent avoir un identifiant unique pour lui référencer tout-ou-long de l’analyse syntaxique, cette identificateur doit être attacher aux argument du sous-programme. Le schéma représenté si-dessous peut nous donner une illustration d’enregistrement de sous programme et de distinction entre eux . Sous-programme 1 c E E Type de Retour ' Liste des données primitives Sous-programme Suivant Sous-programme 2 E E Type de Retour ' Liste des données primitives c   ©  ©  © Figure 3.4 – Structure de table de symbole au niveau de sous-programme Les informations relatives à chaque sous-programme paré nous facile à distingué : — Le type de retour : chaque sous-programme doit effectué une certaine fonctionnalité pour facilité la tache de développement et de diminué le code à exécuter, selon cette fonctionnalité elle peut nous renvoie une résultat après traitement de cette cas et selon l’existence de résultat en peut jugé de type de sous programme. — Liste de donnée primitive : Les données primitive sont les porteurs de donné au niveau de code source, chaque sous-programme contient leur propre porteurs de donnée qui sont répartie on deux catégorie. 26
  • 39. CHAPITRE 3. ANALYSE SYNTAXIQUE Porteur de donné de Types primitifs Pour respecter les notions des identificateur selon leur visibilité et son apparition dans le syntaxe générale, il faut les organiser selon une structure qui nous garantie de vérifier leur existence et de récupérer ces informations. Le schéma représenté si-dessous peut nous donner une illustration de travail de table de symbole Sous-programme 1 c E E Type de Retour E Liste des données primitives Donnée 1 E Nature de donnée E Type de donnée E Donnée 2 E dd‚ dd‚ dd‚ Sous-programme Suivant Sous-programme 2 E E Type de Retour Liste des données primitivesE Donnée 1 E Nature de donnée E Type de donnée E dd‚ dd‚ dd‚ c   ©  ©  © Figure 3.5 – Structure détaillé de table de symbole aux niveau de sous-programme Les informations relatives à un identificateur peut se distinguer selon leur utilités dans la processus de compilation, ces informations sont principalement utile pour décrire la séman- tique de l’analyse syntaxique, et dans certaine cas le bon déroulement de ce type d’analyseur. Les informations relatives à un identificateur : — Nom de donnée : Chaîne de caractère qui est de l’origine le lexème trouvé lors de l’analyse lexicale il doit être unique comme l’indique la structure décrit s’est dessous, et qui suit le motif d’identificateur de l’unité lexical. — Type de donnée : il représente la façon d’enregistrement de l’identificateur dans la mé- moire, de plus il est un champs très utile dans la processus de l’analyse syntaxique cas il va contenir une signification d’un lexème placé selon un syntaxe prédéfinie, Exemple le mot clé "int" signifie que l’identificateur ou suite d’identificateur situés juste après ce lexème sont de type entier. — Nature de donnée : La nature de l’identificateur représente le comportement de l’iden- tificateur suit à son premier occurrence il est destiné principalement pour distinguer entre les variable et les constante, et de vérifier le sémantique des expressions. 27
  • 40. CHAPITRE 3. ANALYSE SYNTAXIQUE Conception d’un compilateur multi-langage Le rôle principale de multi-compilateur est de faire un mélange de syntaxe des compila- teur les plus populaires, c’est à dire de suivre une dérivation selon le choix de développer, de plus de migrer leur puissant fonctionnalité l’une à l’autre. L’idée de ce mélange peut être traitée lors de séparation de grammaire de langage des compilateur, et laisser l’analyseur syntaxique vise le ligne de code souhaité traiter par rap- port leur propre grammaire. C++ et java1 Déclaration de donnée : 1 DECLARATION -> DECLARATION_TYPE IDENTIFICATEURS INITIALISATION ; 2 -> DECLARATION_TYPE [entier] IDENTIFICATEUR INITIALISATION ; 3 4 IDENTIFICATEURS -> identificateur 5 -> identificateur , IDENTIFICATEURS 6 7 INITIALISATION -> epsilon 8 -> = Identificateur 9 -> = entier 10 -> = reel 11 -> = chaine 12 -> = caractere 13 14 DECLARATION_TYPE -> int "type = entier" 15 -> real "type = reel " 16 -> char "type = caractere" Listing 3.1 – Grammaire déclaration de donnée Les mots écrivent en minuscule lors de la dérivation de non-terminal INITIALISATION représente les lexèmes envoyer par l’analyseur lexicale. La séparation entre DECLARATION et DECLARATION_TYPE est à pour utilité de diminué la dérivation de grammaire et de facilité la récupération de type de donnée, l’ajout aux niveau de table de symbole nécessite un couple de nom de donné et leur type ainsi que leur nature. La nature de donnée est récupérer à travers la dérivation c’est-à-dire le ligne de code nous donne une impression sur la nature de donnée, le nom d’identificateur ou bien dans notre cas la possibilité de déclarer plusieurs identificateurs en un seul ligne de grammaire, le type de ou des identificateurs doit précéder leur nom. L’étape d’ajout ce fait réellement lors de dérivation de non-terminal IDENTIFICATEUR. 28
  • 41. CHAPITRE 3. ANALYSE SYNTAXIQUE Boucle conditionnelle : 1 IF_INST -> if ( CONDITION ) { COMMANDE_SEQ } ; 2 -> if ( CONDITION ) { COMMANDE_SEQ } else IF_INST 3 -> if ( CONDITION ) { COMMANDE_SEQ } else { COMMANDE_SEQ } ; 4 5 CONDITION -> identificateur OP COND_DROITE SEP CONDITION 6 -> identificateur OP COND_DROITE 7 -> ( identificateur OP COND_DROITE ) SEP CONDITION 8 -> ( identificateur OP COND_DROITE ) 9 10 COND_DROITE -> identificateur 11 -> entier 12 -> reel 13 -> chaine 14 -> caractere 15 16 OP -> < 17 -> <= 18 -> > 19 -> >= 20 -> == 21 -> != 22 23 SEP -> && 24 -> || Listing 3.2 – Grammaire boucle conditionnelle C++ et Java Les opérateurs (OP) et séparateurs (SEP) non-terminaux représentent deux regroupe- ment des lexèmes passées par le même valeur lors de phase d’analyse lexicale. Jusqu’à ici le valeur des opérateurs nous intéressons pas, ce qui nous intéressons pour le moment est que ces non-terminal forment bien notre description textuelle de l’analyseur syntaxique (grammaire). Instruction Switch : 1 SWITCH_INST -> switch ( VALEUR_DE_TEST ) { CASES DEFAULTS } 2 3 VALEUR_DE_TEST -> identificateur 4 -> EXPRESSION 5 CASES -> epsilon 6 -> case VALEUR : COMMANDE_SEQ break ; CASES 7 -> default : COMMANDE_SEQ break ; 8 9 VALEUR -> entier 10 -> reel 11 -> caractere 12 -> chaine de caractere Listing 3.3 – Instruction Switch C++ et Java Les parenthèses qui suivent le mot clé "switch" indiquent une expression dont la valeur est testée successivement par chacun des case. 29
  • 42. CHAPITRE 3. ANALYSE SYNTAXIQUE Lorsque l’expression testée est égale à une des valeurs suivant un case, la liste d’ins- tructions qui suit celui-ci est exécutée. Le mot clé break indique la sortie de la structure conditionnelle. Le mot clé default précède la liste d’instructions qui sera exécutée si l’expres- sion n’est jamais égale à une des valeurs. Boucle For : 1 FOR_INST -> for ( DECLARATION CONDITION ; AFFECT ) { COMMANDE_SEQ } ; Listing 3.4 – Grammaire Boucle for C++ et Java Les paramètres de boucle indiquée dans la grammaire ci-dessus parées différentes à celle de boucle répétitif (for) habituelle puisque le point-vergues ne figure pas entre les non-terminaux DECLARATION et CONDITION, mais lorsque en examine attentivement le non-terminal DECLARATION en peut distingué l’existence des points lors de l’analyse. Boucle do-while : 1 DO_INST -> do { COMMANDE_SEQ } while ( CONDITION ) ; Listing 3.5 – Grammaire Boucle while C++ et Java Boucle while : 1 WHILE_INST -> while ( CONDITION ) { COMMANDE_SEQ } ; Listing 3.6 – Grammaire Boucle Do-while C++ et Java Grammaire VB.NET2 Déclaration de donnée : 1 DECLARATION -> dim IDENTIFICATEURS as DECLARATION_TYPE INITIALISATION 2 3 IDENTIFICATEURS -> identificateur 4 -> identificateur , IDENTIFICATEUR 5 6 DECLARATION_TYPE -> integer "type = entier" 7 -> real "type = reel" 8 -> caractere "type = caractere" 9 -> string "type = chaine de caractere" Listing 3.7 – Grammaire déclarative de donné VB.NET Comme l’indique la grammaire décrite ci-dessus il est impossible d’ajouter l’identificateur aux niveau de table de symbole lors de dérivation de non-terminal IDENTIFICATEUR puisque l’analyseur syntaxique n’a pas collecté les informations nécessaires pour l’insertion aux niveau de table de symbole. L’analyseur syntaxique doit rapporté l’ajout après la récupération de type de l’identifi- cateur. 30
  • 43. CHAPITRE 3. ANALYSE SYNTAXIQUE Boucle conditionnelle : 1 IF_INST -> CONDITION_VB then COMMANDE_SEQ else COMMANDE_SEQ endif 2 -> CONDITION_VB then COMMANDE_SEQ end if 3 4 CONDITION_VB -> identificateur OP COND_DROITE SEP CONDITION_VB 5 -> identificateur OP COND_DROITE 6 7 SEP -> and 8 -> or 9 10 OP -> < 11 -> <= 12 -> > 13 -> >= 14 -> == 15 -> != Listing 3.8 – Grammaire boucle conditionnelle VB.NET Boucle For : 1 FOR_INST -> for identificateur INITIALISATION to DONNEE step DONNEE COMMANDE_SEQ next 2 3 DONNEE -> identificateur 4 -> entier 5 -> reel 6 -> chaine 7 -> caractere Listing 3.9 – Grammaire boucle For VB.NET Boucle do-while : 1 DO_INST -> do COMMANDE_SEQ loop TYPE_LOOP CONDITION COMMANDE_SEQ 2 3 TYPE_LOOP -> while 4 -> until Listing 3.10 – Grammaire boucle Do-While VB.NET Le boucle répétitif do-while représente deux possibilités de continuations de l’exécutions while et until, while représente la continuité si la condition est vrai et l’autre invoque la sortie de boucle si la condition est faut. Boucle while : 1 WHILE_INST -> while CONDITION_VB COMMANDE_SEQ end while 2 3 CONDITION_VB -> identificateur OP COND_DROITE SEP CONDITION_VB 4 -> identificateur OP COND_DROITE Listing 3.11 – Grammaire boucle While VB.NET 31
  • 44. CHAPITRE 3. ANALYSE SYNTAXIQUE Choix de language : Bibliothèque Comme tout les langages de programmation moderne chaque appelle à une fonctionnalité prédéfinie nécessite l’importation de son propre bibliothèque, de ce principe l’utilisation d’un tels langages est accordée à l’importation de leur syntaxe. 1 IMPORT -> epsilon 2 -> add " identificateur " IMPORT Listing 3.12 – Importation de langage l’identificateur délimité par les deux " représente le nom de langage voulue importé. La distinction de syntaxe selon le choix prédéfinie représente un avantage pour les langages de programmation, pour nous la bibliothèque ne stocke pas les fonctionnalités prédéfinie mais elle exprime le comportement de l’analyseur lors la phase de l’analyse pour gagner le temps lors de choix de l’ensemble de grammaire avant de commencer. Grammaire de notre compilateu3 Déclaration de donnée : Cette section représente la façon ou le développeur peut insérer ces porteurs de donnée en indiquent de deux façons la nature de ces données, la déclaration en C++ et Java représente un repère de choix des instructions de déclaration, donc nous gardons leur grammaire en éliminant seulement les point-virgule. Le principe de compilateur multi-langage peut augmenté le bénéfice de développer, en peut remarquer ce gain lorsque en met l’accent à la déclaration et la manipulation de chaine de caractère qui est déclaré comme étant un tableur de caractères qu’elle est costumé en java et VB.NET avec leur propre type "String". De plus la possibilité de déclaration normale de donnée, nous fournissons un mécanisme qui permet de déclarer un ou plusieurs identificateur à partir d’un autre qui précède en hiérarchie de code source ou bien en passant un valeur et laisser l’analyseur syntaxique conclut leur type. 1 DECLARATION -> DECLARATION_TYPE IDENTIFICATEUR INITIALISATION 2 -> type IDENTIFICATEURS comme DONNEE 3 4 DONNEE -> identificateur 5 -> entier 6 -> reel 7 -> chaine 8 ->caractere 9 10 DECLARATION_TYPE -> int 11 -> real 12 -> char 13 -> string 14 15 IDENTIFICATEURS -> identificateur 16 -> identificateur , IDENTIFICATEURS 17 32
  • 45. CHAPITRE 3. ANALYSE SYNTAXIQUE 18 INITIALISATION -> epsilon 19 -> = Identificateur 20 -> = entier 21 -> = reel 22 -> = chaine 23 -> = caractere Listing 3.13 – déclaration de donné Les trois lignes de code représentées ci-dessus donnent une vision de l’avantage de choix : int a type i comme a => type de i est un entier type j comme 1.2 => type de j est un réel Lecture des variables : Cette partie représente l’ensemble des outils qui permet aux développeurs de gérer les données récupérer à partie de clavier lors de l’étape de l’exécution elle est attachée égale- ment à la phase de génération de code donc elle doit être décrite d’une façon qui facilite leur manipulation lors des autres phases de compilation, de plus, elle doit être facile et compré- hensible dans le choix de leur grammaire, l’utilisation de mot clé significative pour rendre compte leur fonctionnalité pour cela en à choisir le mot clé «read». La grammaire d’écrite dans le listing 3.14 représente une proposition de lecture de va- riable : 1 LECTURE_VARIABLE -> read identificateur 2 -> read identificateur , LECTURE_VARIABLE Listing 3.14 – description préalable de grammaire de lecture de variable Cette représentation nécessite un complémentaire de façon qu’elle peut distingué l’allo- cation mémoire de deux identificateurs passait en même temps. Dans l’habitude la lecture d’une variable est précèder par un message d’affirmation, c’est pour cela en à améliorer la grammaire décrite dans le listing 3.14 pour qu’elle garantie aux développer d’affermer l’utilisateur en un seul ligne de code : 1 LECTURE -> read LECTURE_VARIABLE 2 3 LECTURE_VARIABLE -> AFFERMATION identificateur 4 -> AFFERMATION identificateur , LECTURE_VARIABLE 5 6 AFFERMATION -> epsilon 7 -> chaine : Listing 3.15 – grammaire de lecture de variable Les deux lignes de codes représentées ci-dessous donnent une vision de l’avantage de choix : read "Entrer a" : a read "Entrer a" : a , b 33
  • 46. CHAPITRE 3. ANALYSE SYNTAXIQUE Affichage de donné : Cette partie représente l’ensemble d’outils qui permet aux développeurs de gérer l’affi- chage des données et de renvoyer les résultat, elle doit être capable de renvoyer les données récupérés lors de l’écriture de données , les types de données ainsi que les instructions ma- thématiques. Elle doit être attacher à un mot clé significatif pour décrire son fonctionnalité, le mot choisie est «white», Le retour à la ligne est décrit par le mot clé « NL». La grammaire d’écrite das la listing 3.16 représente une proposition d’affichage des ins- truction : 1 AFFICHAGE -> write INSTRUCTIONS 2 3 INSTRUCTIONS -> INSTRUCTION 4 -> INSTRUCTION , INSTRUCTIONS 5 6 INSTRUCTION -> nl 7 -> identificateur 8 -> entier 9 -> reel 10 -> chaine 11 -> caractere 12 -> EXPRESSION Listing 3.16 – Grammaire d’affichage de donnée Les ligne de code représentées ci-dessus donnent une vision de l’avantage de choix : write nl write " a = " ,a write nl , " b = " , b write nl , " a + b = " , a + b Affectation : Cette partie représente une description de changement de contenue des variables, comme nous avons parlées aux niveaux de table de symbole qui permet de stocker les informations relative aux comportement des identificateurs et non pas à stoker leur contenue cependant le contenue est stoké aux niveau de mémoire dans des registres de donnée, donc on doit préciser à l’analyseur syntaxique le séquencement des identificateur pour nous fournir la ré- partition ou bien le s’enfuit des erreurs après la conversion du code source à langage machine. Le listing 3.17 décrit la grammaire d’aafectation. 1 AFFECTATION -> identificateur = STR_EXP 2 -> identificateur = EXP 3 4 STR_EXP -> chaine 5 -> caractere 6 7 EXP ->identificateur 8 ->entier 34
  • 47. CHAPITRE 3. ANALYSE SYNTAXIQUE 9 ->reel 10 ->EXP OP_AR EXP 11 -> - EXP 12 -> ( EXP ) 13 14 OP_AR -> + 15 -> - 16 -> ^ 17 -> * 18 -> / Listing 3.17 – Grammaire d’affectation Les lignes des codes représentées ci-dessous donnent une vision de l’avantage de choix : a = "****" a = -1 a = a +( b - (c - a)) string a a = a + "****" => cette fausse instruction est traitée syntaxiquement int a a = "****" => cette fausse instruction est traitée sémantiquement Les priorités des opérateurs ainsi que les parenthèses doit être prennent en considération lors de l’analyse syntaxique. Boucle For : Cette partie représente une description de proposition de boucle itératif "for", cette repré- sentation est basé sur le syntaxe des langages choisie comme référence et qui sont décrivent dans la section précédente (C++,Java,VB.net). La première idée est d’éliminer les parenthèses ainsi que les points virgule de boucle for aux niveau de C++ est Java, la deuxième est de rattacher les phases de l’initialisation, condi- tion et incrimination l’une à l’autre avec l’ajout des éliminateurs pour faciliter la distinction entre le compteur et leur paramètre. Le listing 3.18 décrit la grammaire de notre proposition de boucle For. 1 INST_FOR -> for DECLARATIONS :: INSTRUCTION : CONDITONS : INSTRUCTION { COMM_SEQ } 2 3 DECLARATIONS -> identificateur 4 -> DECLARATION 5 6 INSTRUCTION -> identificateur 7 -> entier 8 -> reel 9 -> chaine 10 -> caractere 11 -> EXPRESSION 12 35
  • 48. CHAPITRE 3. ANALYSE SYNTAXIQUE 13 CONDITION -> INSTRUCTION 14 -> CONDITION Listing 3.18 – Grammaire boucle for Les lignes de codes représentées ci-dessous donnent une vision sur l’avantage de choix : for int i : : 0 : i > 5 : 1 {} for i : : i = 0 : 5 : i = i +1 {} for i : : 0 : i > 3 and test = true : 1 { for int j : : j = i : j > 100 : 2 { Write nl ," j = ", j } } Les vérifications de compatibilités de type ainsi que les conditions ne font pas partie à la fonctionnalité de l’analyseur syntaxique, les erreurs de mal placement des instructions interne dans le boucle "for" sont gérer dans le chapitre président " l’analyseur sémantique ". Instruction select : Cette partie représente une description de proposition de l’instruction select (Swith en C++ et Java), elle est basé essentiellement à l’instruction select de VB.net avec quelques modifications au niveau des mots clé reversées aux distinction entre les sous partie (cases). Le listing 3.19 décrit la grammaire de notre proposition de boucle Select. 1 SELECT_INST -> select VALEUR { CASES } 2 3 VALEUR -> identificateur 4 -> EXPRESSION 5 6 CASES -> :: INSTRUCTION : COMMAND_SEQ 7 -> :: INSTRUCTION to INSTRUCTION : COMMAND_SEQ 8 -> :: INSTRUCTION : COMMAND_SEQ CASES 9 10 INSTRUCTION -> identificateur 11 -> entier 12 -> reel 13 -> chaine 14 -> caractere 15 -> EXPRESSION Listing 3.19 – Grammaire instruction select Les lignes des codes représentées ci-dessous donnent une vision sur l’avantage de choix : select a { : : 1 : write "a = 1" 36
  • 49. CHAPITRE 3. ANALYSE SYNTAXIQUE : : 5 : write "a = 5" : : 2 to 3 : write "Valeur entre 1 et 3" } Implémentation d’analyseur syntaxique table de symbole Le code C représenté dans le listing 3.20 représente une implémentation de principe de table de symbole décrit dans la section conception, et comme on à dit que le table de symbole doit gérer les données et leur présence dans les méthodes c’est pour ce la les deux structure sym_node abréviation de Symbole_node et sym_node_methode abréviation de Symbole_node_methode sont invoquées. 1 typedef struct sym_node 2 { 3 char name [50]; 4 int type; 5 struct sym_node *next; 6 7 }sym_node; 8 9 typedef struct sym_node_methode 10 { 11 char name [50]; 12 int type; 13 struct sym_node *liste_var; 14 struct sym_node_methode *next; 15 16 } sym_node_methode ; Listing 3.20 – Implémentation table de symbole La manipulation de table de symbole nécessite des sous programmes pour gérer leur entrées ainsi que leur sortie, le code C décrit dans le listing 3.21 illustre les entêtes des sous programme de manipulation. 1 sym_node_methode *put_meth(char *meth_name , int meth_type) 2 sym_node_methode *get_meth(char *meth_name) 3 int get_meth_type(char *meth_name) 4 5 sym_node *put_sym_donn(char *nom_meth ,char *sym_name , int sym_type) 6 sym_node *get_sym_donn(char *nom_meth ,char *sym_name) 7 int get_sym_donn_type (char *nom_meth ,char *sym_name) 8 int get_sym_donn_nature (char *nom_meth ,char *sym_name) Listing 3.21 – Entête des sous programme ralative à table de symbole Les sous programmes responsable à la manipulation des méthodes : — put_meth : Elle représente le sous programme responsable de l’ajout d’une mé- thode au niveau de table de symbole, leur type de retour est un pointeur de type sym_node_methode qui référence aux nouveau table de symbole. 37
  • 50. CHAPITRE 3. ANALYSE SYNTAXIQUE — get_meth : Elle représente le sous programme responsable à l’envoie de méthode par rapport à son nom. — get_meth_type : Elle représente le sous programme responsable à l’envoie de type de méthode par rapport à leur nom, le type est référencé par un indice unique tels que 0 pour les sous programmes qui ne renvois pas de résultat ou bien 1,2,3,4 pour les entier, les réels,les caractères et chaines de caractères dans l’ordre. Les sous programmes responsable à la manipulation des données : — put_sym_donn : Elle représente le sous programme responsable à l’ajout de donnée au niveau d’une méthode passé en paramètre l’eur type de retour est un pointeur de type sym_node qui référence à la liste de donnée de cette méthode. — get_sym_donn : Elle représente le sous programme responsable à l’envoi de liste de variable à partir de nom de méthode. — get_sym_donn_type : Elle représente le sous programme responsable à l’envoie de type de donnée au niveau de méthode passée en paramètre qui à le même principe de retour de méthode. — get_sym_donn_nature : Elle représente le sous programme responsable à l’envoie de nature de donnée au niveau de méthode passé en paramètre qui renvoie l’entier 5 lorsque le type est un variable, 6 si le type de retour est un constante. Bibiliothéque Le code C d’écrit dans le listing 3.22 représente une impression de principe de fonction- nement de bibliothèque 1 typedef struct bib_node 2 { 3 char name [50]; 4 struct bib_node *next; 5 }bib_node; Listing 3.22 – Implémentation Bibliothèque La manipulation de bibliothèque nécessite des sous programmes pour gérer leur entrées ainsi que leur sortie, le code C décrit dans le listing .23 illustre les entêtes des sous programme de manipulation. 1 bib_node *put_bib(char *bib_name) 2 bib_node *get_bib(char *bib_name) Listing 3.23 – Entête des sous programme ralative aux Bibliothèque Ces sous programmes représente une description de dérivation de analyseur syntaxique contrairement aux table de symbole qui représente une vision sémantique de notre compila- teur : — put_bib : elle représente un sous programme qui gérer l’entrée à la premier référence de bibliothèque leur occurrences en générale au premier de dérivation de syntaxe pour 38
  • 51. CHAPITRE 3. ANALYSE SYNTAXIQUE bien garantir leur meilleur complexité. — get_bib ; elle représente un sous programme qui gérer la partie de test de validation de syntaxe c’est-à-dire de vérifier la possibilité d’utilisation de syntaxe par le développer. Bison(implémentation de grammaire ) Après avoir étudier et comprendre le principe de table de symbole et la bibliothèque notre analyseur syntaxique doit avoir un lien dynamique entre ces deux composants, et de bien contrôler leur instances. structure bison Code C générer % { Pré code C % } Définitions et options % % Règles de production % % Post code C Déclarations Copie du post code C int yyparse(void) { Copie du code C } Tables d’analyse Règles de production Copie du pré code C Figure 3.6 – Un tampon d’entrée en deux moitiés L’analyse syntaxique se compose par deux principaux phases, La première représente un étude préalable et l’établissement de lien avec l’analyseur lexicale et le deuxième représente la phase de dérivation de grammaire décrite lors de l’implémentation . • étude préalable Il représente les outils de travail ainsi quelque condition que l’analyseur syntaxique doit le prenne en considération. • Instanciation de table de symbole et bibliothèque : L’analyseur syntaxique doit conserver d’une et une seul instance de table de symbole et de bibliothèque, pour ne pas tombé dans le cas ou plusieurs variable portent le même nom, ainsi de pouvoir récupérer les problème lors de l’analyse. Les erreurs traitées par l’analyseur syntaxe sont globalement des fautes de syntaxe lors de dérivation, mais en doit conservé une architecture pour intégrer l’analyseur sémantique . 39
  • 52. CHAPITRE 3. ANALYSE SYNTAXIQUE • Affirmation des unités lexicale terminaux : L’analyseur syntaxique doit être avertisse qu’il y’a des mots non dérivable lors de phase d’analyse et qu’il doit remonté dans l’arbre de dérivation pour qu’il puissent continuée leur travail. Ce séquencement représente les suites des unité lexicale, ils doivent avoir le même suite de caractère décrite lors de l’implémentation de l’analyseur lexicale (valeur entre accolade suit la commande return). • Association de type à STR_EXPR et EXPR décrite lors de l’affectation : Comme en à dit lors de décrire la grammaire de l’affectation, et le table de symbole établie dans le choix de notre langage, chaque porteur de donnée doit avoir un type encapsulé sous un entier prédéfinie l’accent ce met maintenant sur les parties droite de signe d’affectation de l’expression, l’analyseur syntaxique doit être capable de re- tourner le type de résultat finale de l’expression lors de dérivation. 1 %type <Tint > STR_EXP 2 %type <Tint > EXP Listing 3.24 – Association de type à STR_EXPR et EXPR décrite lors de l’affectation • Associer les priorités des opérateurs arithmétique : Il est important de déclarer l’analyseur syntaxique de respecté les priorités des opéra- teurs arithmétique, ces opérateurs se distinct en deux partie ou la dérivation ce faite de manière normale de sous expression avant le symbole arithmétique jusqu’à atteindre l’autre symbole ou bien fin de ligne, l’autre partie représente un saut de dérivation vers la partie droite. Lors de dérivation normale les opérateurs arithmétiques en aussi leur propre priorité, aux niveau de bison il est importé de déclarer les opérateurs selon leur priorité par rapport à l’hiérarchie de l’apparence dans le code. 1 %left MULT DIVS 2 %left PLUS MOIN 3 %right PUIS 4 %left NEG Listing 3.25 – Associer les priorités des opérateurs arithmétique • Indicateur d’erreur : Il est obligatoire de compter le nombre des erreurs du lors de l’analyse syntaxique, l’in- dicateur des l’erreurs est attaché au variable "ligne" déclarer lors de l’analyse lexicale est qui incrémente lors de retourne à la ligne, respectant le principe de continuité de dérivation lors de récupération des erreurs chaque erreur doit traité à part c’est-à-dire de conservé une partie propre à celle ci. Dans cette phase de processus de compilation, en doit seulement déclarer l’indicateur de ligne de l’erreur est de l’envoyer à un sous-programme spécifique pour le traiter comme erreur de syntaxe, les autres erreurs sont décrivent au niveau de chapitre sui- vant. 40