Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
💥 Les 22 & 23 novembre : Accès 100% GRATUIT
à la Bibliothèque Numérique ENI. Je m'inscris !
  1. Livres et vidéos
  2. Expressions régulières
  3. lex, le générateur d'analyseurs lexicaux
Extrait - Expressions régulières Syntaxe et mise en œuvre (avec exercices et corrigés) (2e édition)
Extraits du livre
Expressions régulières Syntaxe et mise en œuvre (avec exercices et corrigés) (2e édition) Revenir à la page d'achat du livre

lex, le générateur d'analyseurs lexicaux

Description 

lex est un programme permettant de générer un analyseur lexical, c’est-à-dire un programme capable de lire un texte et d’exécuter des actions lorsqu’il reconnaît des mots ou des chaînes correspondant à des expressions régulières.

C’est un outil destiné à traduire un programme source, écrit selon les propres règles de lex, en un programme C capable de lire un texte, caractère par caractère, et d’effectuer le traitement pour lequel il a été conçu.

lex peut être utilisé pour l’écriture de programmes ayant besoin de traiter des syntaxes particulières, comme par exemple celles de fichiers de configuration ou de sources de programmes écrits dans un langage donné. Dans ce dernier cas, il est généralement associé à yacc (Yet Another Compiler Compiler : encore un autre compilateur de compilateur) qui va s’occuper de l’analyse grammaticale. Ces deux programmes facilitent considérablement l’analyse de texte et le développement d’interpréteurs et de compilateurs, en donnant aux développeurs les moyens de décrire le langage à reconnaître à l’aide d’un langage de plus haut niveau que le C.

Le rôle de lex dans le contexte de l’interprétation...

Principe de fonctionnement 

1. Généralités 

lex est un programme qui, grâce à son langage de haut niveau, facilite le travail des développeurs d’outils analysant des textes. Il leur permet d’écrire de façon relativement concise des programmes capables de reconnaître des expressions dans un texte, et d’appeler des fonctions de traitement associées aux expressions reconnues. Le langage que le programme doit reconnaître est décrit par le programmeur sous forme d’expressions régulières dans un langage qui est spécifique de lex, et intégrées à un analyseur lexical appelé programme lex.

Les analyseurs lexicaux utilisent généralement des mots-clés qui sont des éléments constants du langage, décrits sous forme de chaînes de caractères fixes (c’est-à-dire utilisant des caractères sans signification particulière), et des paramètres ou éléments variables, décrits sous forme d’expressions régulières.

2. Structure d’un programme lex 

Un programme lex est constitué de trois sections :

1.

Une section de définition des éléments du langage à reconnaître, pouvant utiliser des expressions régulières, qui permettront dans la section 2 de référencer les éléments de langage.

2.

Une section décrivant les traitements qui doivent être effectués lors de la reconnaissance des éléments de langage.

3.

Une section de programmes associés aux traitements de la section 2.

La commande lex fonctionne sur le même principe qu’un compilateur : elle lit un fichier, dont le nom se termine par l’extension .l, qui contient le programme lex, effectue elle-même une analyse de ce texte écrit par le programmeur, puis génère dans un fichier un programme C qui sera capable de faire les analyses et traitements prévus par le programmeur.

Pour analyser un texte, un programme lex doit le lire à partir d’un fichier ou de l’entrée standard. Le programmeur doit prendre en charge les opérations permettant...

Les expressions régulières 

1. Localisation des expressions régulières 

Les expressions régulières sont définies dans la première section, sous forme d’une suite de définitions au format :

nom     expression 

Ce sont des expressions régulières étendues.

2. Utilisation du caractère "

La double quote (") sert à priver les caractères spéciaux de leur signification. Tous les caractères encadrés par des doubles quotes seront donc interprétés comme de simples caractères sans signification, à l’exception de l’antislash (\).

Syntaxe

"expression" 

Exemple 1

"ab+cd*e?" 

La chaîne ab+cd*e?, une fois encadrée par des doubles quotes, ne contient aucun métacaractère, et ne désigne que la chaîne ab+cd*e?.

Exemple 2

ab"+"cd"*"e"?" 

La chaîne ab"+"cd"*"e"?" désigne exactement la même chaîne que dans l’exemple précédent, à savoir la chaîne ab+cd*e?. Les quotes ne font pas partie intégrante de la chaîne, et servent uniquement à indiquer que les caractères encadrés sont sans signification particulière.

Exemple 3

"\"" 

La chaîne \", encadrée ou non par des doubles quotes, sert à désigner le caractère " (double quote).

3. Utilisation du caractère \ 

Le caractère antislash sert à supprimer sa signification particulière à un métacaractère, ou à définir un caractère particulier, tel que ceux qui sont définis par le langage C : \t (tabulation), \n (saut de ligne, ou newline), \r (retour en début de ligne, ou carriage return), \b (caractère d’effacement, ou backspace)...

Si un antislash doit être traité sans signification particulière, il doit être lui-même précédé d’un antislash pour lui faire perdre sa signification particulière.

Syntaxe

\c 

Exemple 1

a\* 

Cette chaîne désigne la chaîne a*, et non une répétition du caractère a.

Exemple 2

\n 

Cette chaîne désigne le caractère newline...

Les règles 

1. Localisation des règles de traitement 

Les règles de traitement sont définies dans la deuxième section, sous forme d’une suite de définitions au format :

{nom}  traitement 

Les noms cités dans les règles doivent correspondre aux noms définis dans la première section du programme lex.

Le traitement est une instruction en C, ou un bloc d’instructions en C. Les blocs d’instructions en C sont délimités par des accolades ({ et }).

2. Utilisation du caractère ^ 

Le caractère ^ placé en tête d’une expression dans une règle de traitement spécifie un début de ligne.

Syntaxe

^{nom} traitement 

ou

^expression traitement 

Exemple

^abcd  printf("CHAINE TROUVEE : %s\n", yytext); 

Lorsque l’analyseur lexical trouve la chaîne abcd en début de ligne, il exécute le traitement associé qui affiche sur la sortie standard le message suivant :

CHAINE TROUVEE : abcd 

3. Utilisation du caractère $ 

Le caractère $ en fin d’une expression dans une règle de traitement spécifie une fin de ligne.

Syntaxe

expression$ traitement 

ou

{nom}$ traitement 

Exemple

cdef$ { cpt_cdef++; fct_cdef(yytext); } 

Lorsque l’analyseur lexical trouve la chaîne cdef en fin de ligne, il exécute...

Exercices 

1. Exercice 1 

Comment reconnaître un entier positif ou nul, ne commençant pas par le chiffre 0 ?

Solution

L’expression régulière à utiliser est la suivante :

[1-9][0-9]* 

qui signifie : un caractère numérique compris entre 1 et 9 ([1-9]), éventuellement suivi d’une suite de chiffres de 0 à 9 ([0-9]*).

Le programme lex sera le suivant :

entier    ([1-9][0-9]*)  
 
%%  
 
{entier}       {  
                   printf("[%s]\n", yytext);  
              }  
 
.|\n           ;  
 
%%  
 
int main()  
{  
    yylex();  
    return 0;  
}  
 
int yywrap()  
{  
    return 1;  
} 

La règle :

.|\n   ; 

signifie :

si l’on rencontre un caractère quelconque, ou un caractère newline, on exécutera l’instruction vide (;), ce qui, dit de façon différente, signifie que l’analyseur lexical va ignorer tous les caractères non traités par les règles précédentes.

2. Exercice 2 

Comment reconnaître un entier relatif (négatif, nul, ou positif) ne commençant pas par 0, et avec un signe + optionnel ?

Solution

L’expression régulière à utiliser sera la suivante :

[-+]?[1-9][0-9]* 

qui signifie : une chaîne commençant éventuellement par un signe + ou - ([-+]?), suivi d’un chiffre non nul ([1-9]), éventuellement suivi d’une suite de chiffres de 0 à 9 ([0-9]*).

Le programme lex sera le suivant :

entier    ([-+]?[1-9][0-9]*) 
 
%%  
 
{entier}       {  
                   printf("[%s]\n", yytext); 
              }  
 
.|\n           ;  
 
%%  
 
int main()   
{  
    yylex();  
    return 0;  
}  
 
int yywrap()  
{  
    return 1;  
} 

3. Exercice 3 

Comment reconnaître...