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");} %% |
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); } |
note : parfois il faut une ligne blanche ou un espace a la fin du fichier 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.
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.
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