B.A. BA de Lex (ou Flex).

Introduction

Lex est un utilitaire Unix produisant des analyseurs lexicaux reconnaissant des expressions régulières décrites dans un fichier. Lex, comme Unix, est basé sur le langage de programmation C. Il permet de décomposer une chaîne en lexèmes (unités lexicales).

Il est souvent associé à Yacc, un autre utilitaire Unix, basé aussi sur le langage C, pour produire des compilateurs. Lex sert à effectuer la phase d'analyse lexicale de la compilation, Yacc permet de réaliser la phase d'analyse syntaxique. Les autres phases de compilations sont définies en C.

L'analyseur lexical produit par Lex est décrit dans un fichier texte composé de trois parties séparés par "%%" un double signe pourcent.

Voici un schéma de code en LEX :

%{
/* Déclaration des variables */
/* et des symboles appelés constantes littérales */
/* #include... */
%}
/* Déclarations des classes et des expressions régulières */
...
%%
/* Règles de traduction */
m1 {actions1}
m2 {actions2}
...
mn {actionn}
/* mi est une expression régulière */
/* actioni est une action lorsque le lexème correspond à mi*/
%%
/* Procédures auxiliaires en C utiles dans les actions
et/ou permettant de faire un programme indépendant */

Pour en savoir plus, il faut lire attentivement le man Unix de lex ( > man lex ). Vous pouvez également consulter différentes sources sur Lex et Yacc dont : http://members.xoom.com/thomasn/y_man.htm, ou le livre de Levine, Mason et Brown "Lex & Yacc" Ed. O'Reilly Int. Thomson, ou encore le Livre de Aho, Sethi et Ullman Chez InterEdition.

Remarque : vous pouvez aussi consulter le manuel Flex.

Exemples de fichier de description compris par Lex :

    %%
    .|\n   {printf(".\n");}
    %%
Petit fichier Lex

et un fichier un peu plus long :
 

    %{
      int noms,mots,lignes;
    %}
    mot [a-z]+
    maj [A-Z]
    %%
    {maj}{mot}   {noms++; printf("Bonjour %s. \n",yytext);}
    {mot}        {mots++;}
    \n           {lignes++;printf("   Encore !\n");}
    .            ;
    %%
    main()
    {
    noms=mots=lignes=0;
    yylex();
    printf("nb de noms :%d, mots: %d, lignes: %d.\n",noms,mots,lignes);
    }
Exemple de fichier de description Lex.

note : parfois il faut une ligne blanche ou un espace a la fin du fichier lex.

B.A. BA technique de Lex

Pour voir comment Lex s'utilise, c'est-à-dire, comment à partir d'une description on obtient l'analyseur lexical, écrire dans un fichier exemple1.l une description minimale pour Lex (le tout petit exemple précédent, le premier exemple de fichier lex.)

Il est généralement utilisé de la manière suivante :

Programme source LEX : expressions régulières et actions (lex.l)

Compilateur LEX

Table de transition, fonctions de reconnaissance des lexèmes, actions en C... (lex.yy.c)

Compilateur C

Analyseur Lexical (a.out)

Le programme obtenu permet alors de décomposer une chaîne en lexèmes selon le principe suivant :

flot d'entrée → a.out → Suite d'unités lexicales

Autrement dit, utiliser Lex est simple, car il suffit de compiler sous Unix une première fois avec Lex pour obtenir un fichier intermédiaire C (lex.yy.c) puis de compiler ce fichier C avec la bonne bibliothèque. L'analyseur se trouve alors dans l'executable a.out. Il suffit donc de faire :

Par curiosité, observez le fichier construit par Lex (lex.yy.c).

Enfin, executez l'analyseur a.out. Taper quelques mots, puis pour finir ^D.

Utilisation de Lex

Pour travailler de manière un peu plus conséquente avec Lex, recopier le second exemple fourni dans un fichier, le compiler, et l'exécuter. En le recopiant, lire le descriptif qui suit :

Comme vous pouvez le constater en tapant "vive TeX et LaTeX ^D", l'analyseur ne compte pas exactement comme nous !

Corriger si possible l'analyseur pour avoir un comportement plus conforme à ce que l'on attend de lui.

Exemple

Analyse lexicale d'un flottant saisi au clavier. Un flottant est ici composé de la manière suivante :

%{
%}
Sig [+\-]
Ent [1-9][0-9]*
Dec [0-9]*\.[0-9]+
Exp [eE]{Sig}?([0-9]{1,2})
Delim [\n\t ]
%%
Delim {}
{Sig}?({Ent}|{Dec})({Exp})? {printf("flottant:%s\n", yytext);}
. ECHO ;

%%
int main(void)
{
yylex();
return 0;
}

Un jeu d'essai sur ce programme :

valeur
résultat
fg
fg
12
flottant : 12
+12
flottant : +12
-12.
flottant : -12 .
-12.32
flottant : -12.32
12.2e1
flottant : 12.2e1
12e123
flottant : 12e12 flottant : 3
e23
eflottant : 23
1e-2365
flottant : 1e-23 flottant : 65
12E-12.1e2
flottant : 12E-12 flottant : .1e2

jeudi, 27/05/04 15:10