Chapitre2. L'analyse Lexicale

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 17

Chapitre 2 : l’analyse lexicale 2023/2024

1. Définition
Un analyseur lexical est un programme qui lit les caractères d’entrée d’un
langage source et produit une suite d’unités lexicales. Il réalise aussi certaines
taches secondaires, telles que la suppression des caractères inutiles (blanc, fin de
ligne, commentaires, ets.) et la gestion des numéros de lignes pour pouvoir
associer à chaque erreur la ligne dans laquelle elle convient. L’analyseur lexical
interagit avec l’analyseur syntaxique comme montre la figure 1.

Programme Analyseur Unité lexicale Analyseur


source lexicale obtenir prochaine syntaxique
Unité lexicale

Table des
symboles

Figure 1 – Interaction entre l’analyseur lexicale et l’analyseur syntaxique

Une unité lexicale est une suite de caractères qui a une signification
collective. Exemple : les chaines <=, >=, <, > sont des opérateurs relationnels.
L’unité lexicale OPREL (à titre d’exemple). Les chaines toto, tab, afficher sont des
identificateurs (de variables, de constantes ou de fonction). Les chaines if, else,
for sont des mots clefs. Les symboles ; . , ( ) sont des séparateurs.
Un modèle est une règle associée à une unité lexicale qui décrit l’ensemble
des chaines de programme qui peuvent correspondre à cette unité lexicale.
Un lexème est une suite de caractères du programme source qui concorde
avec le modèle d’une unité lexicale.
Exemples :
- L’unité lexicale IDENT (identificateur) en C a pour modèle : toute suite non
vide de caractères composée de chiffres, lettres ou de symbole "_" et qui ne
commence pas par un chiffre. Des exemples de lexème pour IDENT sont toto,
tab1, afficher_txt.
- L’unité lexicale NOMBRE (entier signé) à pour modèle : toute suite non vide
de chiffres précédée éventuellement d’un seul caractère parmi {+,-}. Des
lexèmes possibles pour cette unité sont : +215, -88, 765.

1 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024

Pour décrire le modèle d’une unité lexicale, on utilisera les expressions


régulières. Et pour vérifier qu’une suite de caractère est un lexème (concorde
avec le modèle d’une unité lexicale) on pourra utiliser les automates à états finis.
2. Taches effectuées par l’analyseur lexical
L’analyse lexicale effectue un ensemble de taches :
- Lecture de fichier du code source (fichier texte) caractère par
caractère avec éventuellement l’élimination de caractères et
informations inutiles (blanc, tabulation, commentaire, caractère de fin
de ligne,…) pour réduire la représentation du programme. Une erreur
est signalée à ce niveau si un caractère non permis (illégal) par le
langage est rencontré.
- Concaténation de caractères pour former des unités lexicales et
signaler éventuellement une erreur si la chaine dépasse une certaine
taille.
- Association d’un symbole à chaque unité lexicale, cette opération peut
engendrer une erreur si l’unité formée ne correspond à aucune unité
légale du langage.
- Enregistrement de chaque unité lexicale et des informations la
concernant (nom, valeur,…) dans la table des symboles (en invoquant
le gestionnaire de la table des symboles) ou dans un fichier résultat.
Dans ce niveau, il est possible de détecter certaines erreurs telles que
la double déclaration d’un identificateur, utilisation d’un identificateur
sans déclaration préalable, ets.
- Création d’une liaison entre les unités lexicales d’une ligne et la ligne
du fichier la contenant. Cette opération qui se fait par une simple
numérotation des lignes du texte du code source. Permet la
localisation des lignes en cas d’erreurs. Dans certain compilateur,
l’analyse lexicale est chargée de créer une copie du programme source
en y intégrant les messages d’erreurs lexicales.

Les symboles associés aux unités lexicales correspondent à la nature de


celles-ci. On distingue plusieurs catégories de symboles :

2 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024

1. Les mots réservés du langage (if, then, begin pour le langage pascal
par exemple).
2. Les constantes (3, 3.14, true, ’bonjour’,…).
3. Les identificateurs qui peuvent être des noms de variables, de
fonctions, de procédures, ets…
4. Les symboles spéciaux, en tenant compte des possibilités
d’assemblage de caractères tels que <, >, <=, >=, :, :=, +, -, /, *.
5. Les séparateurs tels que le point (.) et le point-virgule (;).

3. Langages réguliers et expressions régulières


La spécification ou la description des unités lexicales peut être effectuée en
utilisant une notation appelée expressions régulières. Une expression régulière
est construite à partir d’expressions régulières plus simples, en utilisant un
ensemble de règles de définition qui spécifiant comment le langage est formé.

Définitions

1. Un alphabet A est un ensemble fini des symboles. L’alphabet binaire {0,1} et les
codes ASCII sont des exemples d'alphabets
2. Une chaine, est une séquence finie de symboles. Le terme mot est également
utilisé.
3. Un langage régulier L sur un alphabet A est définit récursivement de la manière
suivante :
- {ε} est un langage régulier sur A.
- Si a est une lettre de A, alors {a} est un langage régulier sur A.

Opérations sur les langages

Union(𝑳 ∪ 𝑴) :

𝐿 ∪ 𝑀 = {s | s ∈ L ou s ∈ M}

Concaténation (𝑳𝑴):

𝐿 𝑀 = {s | s ∈ L et s ∈ M}

Fermeture de Kleene (𝑳∗ ) ∶

3 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024
+∞

𝐿 = ⋃ 𝐿𝑖

𝑖=0

Fermeture positive (𝑳+ ) :


+∞

𝐿 = ⋃ 𝐿𝑖
+

𝑖=1

Exemples :
- Si B = {0,1},

B + est l'ensemble des nombres binaires d'au moins un chiffre.

- Si C = {0,1,2,3,4,5,6,7,8,9},

𝐶 4 est l'ensemle des nombres de 4 chiffres.

- Si K = {a, … , z, A, … , Z},

𝐾(𝐾 ∪ 𝐶)∗ est l'ensemble des mots commençant par une lettre puis composés
d'un nombre quelconque de lettres et chiffres.

4. Une expression régulière r est construite récursivement à partir d'union


(notée|), de concaténation, et de fermeture. Elle définit un langage L(r).
- ε est une expression régulière qui dénote L(ε) = {ε}.
- a ∈ A , alors a est une expression régulière qui dénote l'ensemble L(a) = {a},
- si r est une expression régulière qui d’écrit le langage R, alors (𝑟)∗ et (𝑟)+ sont
des expressions régulières décrivant respectivement 𝐵 ∗ 𝑒𝑡 𝐵 + .
- si r et s sont des expression régulière qui d’écrivent les langages R et S, alors
(r)|(s) et (r).(s) sont des expressions régulières décrivant respectivement 𝑅 ∪ 𝑆
et 𝑅𝑆

Remarques :

- Afin de simplifier l’écriture d’expressions régulières, on conviendra des


priorités décroissante suivantes : "*", concaténation ".", ou |.par exemple :
a𝑏 ∗ |c=((a)((𝑏)∗))|(c).
- La concaténation est distributive par rapport à |. C-à-d, r(s|t)=rs|rt et (s|t)r=sr|tr (la
concaténation n’étant pas commutative). Par exemple, ab(𝑏 ∗ |𝑎+ 𝑏)= 𝑎𝑏 + | 𝑎𝑏𝑎 + 𝑏.

4 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024

- On peut trouver plusieurs expressions régulières (syntaxiquement différentes) qui


décrivent le même langage. Dans ce cas, on dit qu’elles sont équivalentes. Par
exemple : l’expression (𝑎|𝑏)∗ 𝑎(𝑎|𝑏)∗ (décrivent tous les mots sur {a,b}ayant au
moins un a) est équivalente à l’expression 𝑏 ∗ 𝑎(𝑎|𝑏)∗ (la première expression est
ambiguë alors que la deuxième ne l’est pas).
4. Automates à états finis

4.1 Définition : un automate à états finis (AEF) est défini par un quintuple (Q, Σ,
δ,𝑞0 , F), ou

- Q, est un ensemble fini des états de l’automate.


- Σ est l’alphabet des symboles d’entrée.
- δ est la fonction de transition qui a un couple formé d’un état et d’un
symbole de Σ fait correspondre un ensemble (éventuellement vide)
d’états : δ(𝑞𝑖 ,a)= {𝑞𝑖1 , 𝑞𝑖2 , … , 𝑞𝑖𝑛 }.
- 𝑞0 est l’état initial de l’automate.
- F ⊆ Q est l’ensemble des états finaux de l’automate.
Le langage reconnu par un automate est l'ensemble des chaines qui
permettant de passer de l’état initial à un état terminal (final).

4.2 Représentation graphique d’un automate à états finis

Un automate à états finis (AEF) peut être représenté graphiquement par un


graphe orienté étiqueté, appelé graphe de transition, dans lequel les nœuds
sont les états et les arcs étiquetés représentent la fonction de transition.

4.3 Représentation par une table de transition d’un automate à états finis

Un AEF peut être représenté par une table de transition, dans laquelle :
- Les Lignes représentent les états.
- Les colonnes représentent les symboles.
- Le contenu d’une case donne l’ensemble des états qui peut être atteint
par une transition depuis l’état i sur un des symboles de l’alphabet.

Exemple :
A={Q={𝑞0 , 𝑞1 , 𝑞2 , 𝑞3 }, Σ={a,b}, δ,𝑞0 , F={𝑞3 }}, ou δ={𝑞0 ,a}={𝑞0 , 𝑞1 }, δ={𝑞0 ,b}={𝑞0 },
δ={𝑞1 ,b}={𝑞2 }, δ={𝑞2 ,b}={𝑞3 } (automate non déterministe).

La représentation graphique de cet automate est :

5 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024

a/b

a b b
𝑞0 𝑞3 𝑞1 𝑞2 𝑞3

La représentation par une table de transition du même automate est F=𝑞3 :

a b
→ 𝑞0 {𝑞0 , 𝑞1 } 𝑞0
𝑞1 − 𝑞2
𝑞2 − 𝑞3
𝑞3 − −
Le langage régulier reconnu par cet automate est décrit par l’expression
régulière (a/b)*abb.
A noté que cet automate est non déterministe puisqu’à partir de l’état q 0 et à
la lecture d’un a, deux transitions sont possibles : vers q 0 ou q1 .

Remarque :

Il existe des algorithmes qui permettent de réaliser les passages suivants :


Expression régulière → AEF → AEF déterministe → AEF minimal

4.4 Construction d’un AFN à partir d’une expression régulière :

Il existe de nombreux algorithmes pour construire de façon automatique un


automate à états finis à partir d’une expression régulière. L’algorithmes la plus
simple et facile à implémenter est l’algorithme de construction de Thompson.
Entrée: Une expression régulière r sur un alphabet A
Sortie: Un AFN qui reconnait L(r)
Début
1. Décomposer d’abord r en ses sous-expressions;
2. Utiliser les règles (1) et (2) pour construire les AFN pour chacun des
symboles de base de r (c’est-à-dire soit ε ou les symboles de l’alphabet);
3. Combiner récursivement ces AFN en utilisant la règle (3) jusqu’à
l’obtention de l’AFN de l’expression complète;
Fin
Règle 1 :
Pour ε, construire l’AFN comme suit:

6 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024
ε
début i f

Cet automate reconnait le mot vide ε.


Règle 2 :
Pour chaque symbole a∈ A, construire l’AFN comme suit :
a
début i f

Cet automate reconnait le mot a.


Où: i est un état initial.
f est un état final.
Règle 3 :
Supposons que l’AFN (s) et l’AFN (r) sont les AFN des expressions régulières
de s et r respectivement :
a) Pour s|r, construire l’AFN comme suit :
1. Créer un nouvel état initial.
2. Mettre une ε-transition du nouvel état initial vers l’état initial de l’AFN(s)
et vers l’état initial de l’AFN(r).
3. L’état initial de l’AFN(s) n’est plus un état initial (même chose pour l’état
initial de l’AFN(r)).

4. Créer un nouvel état final f.

5. Mettre une ε-transition de l’état final de AFN(s) vers le nouvel état final
(même chose pour l’état final de l’AFN(r)).

6. L’état final de AFN(s) n’est plus un état final (même chose pour l’état final
de AFN(r)). AFN(s)

début 𝑖𝑠 --- 𝑓𝑠

AFN(r)

début 𝑖𝑟 --- 𝑓𝑟

7 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024

b) Pour sr, construire l’AFN comme suit :


1. L’état final de AFN(s) est fusionné avec l’état initial de AFN(r) en un seul état.

2. L’état final de l’AFN(s) n’est plus un état final.


3. L’état initial de l’AFN(r) n’est plus un état initial.

c) Pour s*, construire l’AFN comme suit :

1. Mettre une ε-transition de l’état final de l’AFN(s) vers son état initial.

2. Créer un nouvel état initial i et un nouvel état final f.

3. Mettre une ε-transition de i vers f.

4. Rajouter une ε-transition de l’état i vers l’état initial de AFN(s).

5. Rajouter une ε-transition de l’état final de l’AFN(s) vers l’état f.

8 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024

6. L’état initial de l’AFN(s) n’est plus un état initial.

7. L’état final de l’AFN(s) n’est plus un état final.

Exemple :

Utiliser les règles de constructions de Thompson pour obtenir l’AFN de


l’expression régulière (a|b)*abb :
- 𝑟1 = 𝑎

- 𝑟2 = 𝑏

- 𝑟3 = 𝑎|𝑏 = 𝑟1 |𝑟2

- 𝑟4 = (𝑎|𝑏) = (𝑟1|𝑟2 ) = (𝑟3 ) = 𝑟3


- 𝑟5 = (𝑎|𝑏) ∗=𝑟4 ∗

- 𝑟6 = 𝑎 = 𝑟1

- 𝑟7 = (𝑎|𝑏) ∗ 𝑎 = 𝑟4 ∗ 𝑟6 = 𝑟5 𝑟6

9 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024

- 𝑟8 = 𝑏 = 𝑟2
-

- 𝑟9 = (𝑎|𝑏) ∗ 𝑎𝑏 = 𝑟7 𝑟8

- 𝑟10 = 𝑏 = 𝑟2
-
-
- 𝑟11 = (𝑎|𝑏) ∗ 𝑎𝑏𝑏 = 𝑟9 𝑟10

- Renuméroter les états

Remarque
Les règles de construction de Thompson permettent d’avoir un automate à
états finis qui vérifie les propriétés suivantes :

10 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024

- L’état final est unique.


- L’état final n’a pas de transition sortante.
- L’état initial n’a pas de transition entrante.
- Chaque état de l’automate, mis à part l’état final, a soit une seule transition
sur un symbole de l’alphabet, soit deux transitions toutes deux sur ε.

4.5. Construction de l’automate union de tous les automates associés aux


expressions régulières

Après avoir converti chaque expression régulière en un automate, la phase


suivante consiste à regrouper les automates obtenus de l’étape précédente en un
seul automate selon le principe suivant :
1. Créer un nouvel état initial.
2. Mettre une ε-transition du nouvel état initial vers l’état initial de chaque
automate.
3. L’état initial de chaque automate n’est plus un état initial.

5. Mise en œuvre d’un analyseur lexicale

5.1 Spécification des unités lexicales


L’ensemble des unités lexicales, qu’un analyseur reconnait. Constitue un
langage régulier L qui peut être décrit par des expressions régulières et reconnu
par une automate d’états fini.
La spécification ou la description des unités lexicales peut être donc effectuée
en utilisant une notation appelée expression régulière. Par exemple : les
identificateurs en C peuvent être décrits par l’expression régulière suivante :
IDENT=(a|b|c|…|x|y|z|A|B|C|…|X|Y|Z|_)( a|b|c|…|x|y|z|A|B|C|…|X|Y|Z|0|1|2|…|7|8|9_)*

11 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024

La définition d’unités lexicales de la façon décrite ci-dessus n’est clairement


pas efficace. Afin de la rendre plus souple, on utilise souvent des définitions
régulières et le symbole "_" sur des types ordonnés (typiquement les lettres et les
chiffres), ou une définition régulière est une suite de définition de la forme :

𝑑1 = 𝑟1
𝑑2 = 𝑟2

𝑑𝑛 = 𝑟𝑛

⬚ 𝑟𝑖 est une expression régulière sur l’alphabet ∑∪ {𝑑1 , 𝑑2 , … , 𝑑𝑛−1 },
Ou chaque
et chaque 𝑑𝑖 est un nom différent. Par exemple : l’unité lexicale IDENT peut être
décrite à l’aide de la définition régulière suivante :
Lettre = A_Z|a_z

Chiffre = 0_9

IDENT = (lettre|_)((lettre|chiffre|_)*)

5.2 Attributs des unités lexicales


L’analyseur lexical réunit les informations sur les unités lexicales dans des
attributs qui leur sont associés. Ces information sont utiles non pas à l’analyseur
lexical mais aux phases qui la suivent.
Par exemple, pour ce qui est des symboles<, <=, >, >=, <>, = l’analyseur lexical
a juste besoin de savoir que cela correspond à l’unité lexicale OPREL. C’est
seulement lors de la génération de code qu’on aura besoin de distinguer <= et >=
(par exemple). De même, pour ce qui concerne les identificateurs, l’analyseur
lexical a juste besoin de savoir qu’il s’agit de l’unité lexicale IDENT, mais le
générateur de code a besoin de l’adresse de la variable correspondant, et
l’analyseur sémantique a besoin de son type.
En pratique, une unité lexicale a en général un seul attribut : un pointeur vers
l’entrée de la table des symboles dans laquelle l’information sur l’unité lexicale
est conservée.

5.3 Implémentation d’un analyseur lexicale

12 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024

Pour écrire un analyseur lexical de notre programme source, il suffit d’écrire


un programme simulant un automate. Lorsqu’une unité lexicale est reconnue, elle
est envoyée à l’analyseur syntaxique qui la traite, puis repasse la main à
l’analyseur lexical qui lit l’unité lexicale suivante. Et ainsi de suite, jusqu’à ce que
le programme source soit traité en entier ou une erreur soit détectée.
Exemple : un morceau d’analyseur lexical pour le langage Pascal. Le morceau de
code, écrit en C, reconnait les unités lexicales : AFFECT, DEUX_PT, OPREL.
c= getchar() ;
switch(c){
case ‘ :’ : c = getchar() ;
if (c == ‘=’)
{
Unite_lex =AFFECT; c = getchar();
}
Else
Unite_lex =DEUX_PT; break ;
case ‘ <’ : Unite_lex =OPREL; c = getchar() ;
if (c == ‘=’)
{
attribut =INFEG; c = getchar();
}
Else
attribut =INF; break ;
case …
}
On peut également copier le travail de l’automate comme suit :
Void Etat1 ( )
{
char c ; c = getchar( );
switch (c) {
case ‘:’ : Etat2( ); break;
case ‘<’ : Etat3( ); break;
………
Default : ERREUR( );
}
}
Void Etat2 ( ) ………….

Il est évident que cette façon de programmer un analyseur lexical pourrait


être fastidieuse. En particulier, si on veut modifier l’analyseur, le compléter etc.
pour remédier à ceci, de nombreux outils ont été bâtis pour construire les
analyseurs lexicaux.

13 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024

5.4 L’outil (f)Lex


(f)Lex est un outil qui a été intensivement utilisé pour spécifier des
analyseurs lexicaux pour une grande variété de langages. (f)Lex accepte en entrée
des spécifications d’unités lexicales sous forme de définition régulières et produit
un programme C qui, une fois compilé, reconnait ces unités lexicales. (f)Lex est
généralement utilisé de la manière décrite par la figure suivante :

5.4.1 Structure d’un fichier (f)Lex


Un programme Lex consiste en trois parties (principales) : déclaration, règles
de traduction, et procédures auxiliaires.
%{
Déclaration des variables et constantes, … en C
%}
Déclaration de définitions régulières
%%
Règles de traduction
%%
Bloc principale et fonctions auxiliaires

- Les définitions régulières permettent d’associer des noms à des


expressions régulières (f)Lex et de se référer par la suite (dans la partie
règles de traduction) à ces noms plutôt qu’aux expressions régulières.
Par exemple :
chiffre [0-9]
entier (+/-) ?{chiffre}+
- Les règles de traductions sont des instructions de la forme :
𝑚1 {𝑎𝑐𝑡𝑖𝑜𝑛1 }
𝑚2 {𝑎𝑐𝑡𝑖𝑜𝑛2 }

𝑚𝑛 {𝑎𝑐𝑡𝑖𝑜𝑛𝑛 }

14 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024

Où chaque 𝑚𝑖 est une expression régulière et chaque 𝑎𝑐𝑡𝑖𝑜𝑛𝑖 est un


fragment de programme (généralement en C) qui décrit quelle action
l’analyseur lexical devrait réaliser quand un lexème concorde avec le
modèle 𝑚𝑖 . Par exemple :
{entier} printf("un entier") ;
- La troisième partie (bloc principal et fonctions auxiliaires) est
facultative (y compris les derniers %%). Elle contient les routines C
définies par l’utilisateur et éventuellement la fonction main( ) si celle
par défaut ne convient pas.

Remarque : la première partie peut comporter la déclaration des constantes


littérales (exp : ID, NB, OPREL). Mais en pratique, elles sont généralement fournies
par l’analyseur syntaxique.

Quand l’analyseur lexical est activé par l’analyseur syntaxique, il commence à


lire le texte en entrée qui lui reste, caractère par caractère, jusqu’à ce qu’il trouve
le plus long préfixe du texte d’entrée qui corresponde à l’une des expressions
régulières mi . Alors il exécute l’𝑎𝑐𝑡𝑖𝑜𝑛𝑖 . Typiquement une action rend le contrôle
à l’analyseur syntaxique. Si ce n’est pas le cas, l’analyseur lexical continue à
chercher d’autre unités lexicales jusqu’à ce qu’une action rend enfin le contrôle à
l’analyseur syntaxique.
L’analyseur lexical retourne une seule information (l’unité lexicale) à
l’analyseur syntaxique. Pour passer une valeur d’attribut donnant des
informations sur le lexème, on peut l’affecter à une variable globale yylval.
5.4.2 Expressions régulières (f)Lex
Une expression régulière (f)Lex se compose de caractères normaux et de
méta-caractères qui ont une signification spéciale comme : $ \ ^ [ ] { } < > / | ? . *
+ -. Les expressions régulières reconnues par (f)Lex sont données par le tableau
suivant :
Expression Reconnait (accepte) exemple

Tout caractère c qui n’est pas un méta-caractère a


c
Si le caractère c n’est pas une lettre miniscule, le \+
\c
caractère c littéralement

15 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024

"s" La chaine de caractère s littéralement "abc*+"


𝑟1 𝑟2 𝑟1 suivie de 𝑟2 ab
. N’importe quel caractère, excepté le caractère "à la a.b
ligne"
^ Comme premier caractère de l’expression, signifie le ^ab
début de ligne
$ Comme dernier caractère de l’expression, signifie la ab$
fin de ligne
[s] N’importe lequel des caractères constituant la chaine s [abc][g-m]
[^s] N’importe lequel des caractères à l’exception de ceux [^abc]
constituant la chaine s
r* 0 ou plusieurs occurrences de r a*
r+ 1 ou plusieurs occurrences de r a+
r? 0 ou 1 occurrences de r a?
r{m} m occurrences de r a{3}
r{m,n} m à n occurrences de r a{5,8}
𝑟1 |𝑟2 𝑟1 𝑜𝑢 |𝑟2 a|b
𝑟1 /𝑟2 𝑟1si elle est suivie de 𝑟2 ab/cd
(r) r (a|b) ?c
\n caractère à la ligne
\t tabulation
{} pour faire référence à une définition régulière {nombre}
EOF fin de fichier (uniquement avec flex) EOF

5.4.3 Variables et fonctions prédéfinies


(f)Lex présente quelques variables et routines prédéfinies :
- char yytext : tableau de caractère qui contient la chaine d’entrée qui a
été acceptée.
- int yyleng : longueur de cette chaine.
- int yylex( ) : fonction qui lance l’analyseur (et appelle yywrap( ) ).
- int yywrap( ) : fonction toujours appelée en fin de flot d’entrée. Elle ne
fait rien par défaut, mais elle peut être définie par l’utilisateur.

16 Préparer par Dr. Merzoug Assia


Chapitre 2 : l’analyse lexicale 2023/2024

- int main( ) : la fonction main par défaut contient juste un appel à la


fonction yylex( ), mais elle peut être redéfinie par l’utilisateur.
- int yylineno : fonction (f)Lex qui retourne le numéro de la ligne
courante.
- yylex. Elle peut être redéfinie par l’utilisateur dans la section des
procédures auxiliaires.
- yyterminate( ) : fonction flex qui stoppe l’analyseur.

Exemple : comptage du nombre de voyelles, consonnes et caractères de


ponctuation.

%{

int nbVoyelles, nbConsonnes, nbPonctuation ;

%}

consonne [b-df-hj-np-xz]

ponctuation [, ; : ? ! \ .]

%%

[aeiouy] nbVoyelles++ ;

{consonne} nbConsonnes++ ;

{ponctuation}nbPonctuation++ ;

.|\n

%%

Int main ( ){

nbVoyelles = nbConsonnes = nbPonctuation =0 ;

yylex( ) ;

printf("il y a %d voyelles, %d consonne, et %d signes de ponctuation.\n", nbVoyelles,


nbConsonnes, nbPonctuation) ;

17 Préparer par Dr. Merzoug Assia

Vous aimerez peut-être aussi