Ce mémento résume les fonctionnalités essentielles de FLEX et les illustre avec des exemples. Pour des informations plus complètes, plus techniques, ou plus à jour (dernière version), on se reportera au manuel officiel.
yytext
yytext
, yylen
, ...ECHO
, BEGIN
, ...yywrap()
, ...Caractère | Nom | Section | Remarque |
---|---|---|---|
Space | Tab | Newline | 2.2 | non concaténation (terminateur) | |
" | Double Quotes | 2.1 | |
\ | Back Slash | 2.1 | |
| | Vertical Bar | 2.2, 1.5 | |
* | Asterisk | star | 2.4, 2.2 | |
+ | Plus | 2.4 | |
? | Question mark | 2.4 | |
. | Period | 2.3 | |
^ | Carret | 2.3, 2.5 | deux interprétations différentes |
$ | Dollar sign | 2.5 | |
/ | Slash | 2.5 | |
‐ | Minus | Hyphen | 2.3 | uniquement entre [] |
, | Comma | 2.4 | uniquement entre {} |
( ) | Parenthesis | 2.2 | |
[ ] | Square Brackets | 2.3 | |
{ } | Curly Braces | 2.4, 4.1 | deux interprétations différentes |
< > | Less|Greater-than Signs | 3.1 |
Important : Une source d'erreur fréquente est le simple quote '
qui n'a aucune signification réservée dans Flex, contrairement à Bison. Exemple : '\n'
est une chaîne de trois caractères pour Flex alors qu'il sera le caractère de fin de ligne pour Bison.
---- Exemple 1.1 : fragments reconnus et actions %% x+ ECHO; y+ ; z+ %% -------------------------------------------------- ENTREE : xxxyyyzzzttt SORTIE : xxxttt
Si plusieurs expressions régulières peuvent s'appliquer :
----- Exemple 1.2 : ambiguïtés %% [0-9]+ printf("[1:%s]",yytext); [a-z0-9]+ printf("[2:%s]",yytext); %% -------------------------------------------------- ENTREE : 00000 X999 SORTIE : [1:00000] [2:X999]
N.B. : Si on permute les règles dans la spécification, on obtient un message "line 3: warning, rule cannot be matched"
yytext
Un fragment débute avec la reconnaissance d'une expression régulière
----- Exemple 1.3a : fragments %% truc printf("[%s]",yytext); machin printf("[%s]",yytext); %% -------------------------------------------------- ENTREE : truczzmachin SORTIE : [truc]zz[machin]
Un fragment se prolonge jusqu'à la reconnaissance d'un autre fragment ou jusqu'à la fin de l'entrée.
Le reconnaisseur est dit "glouton" (greedy) par opposition à d'autres implémentations d'analyseur
dites "récalcitrantes" (reluctant)
----- Exemple 1.3b : fragments étendus abusivement ! %% truc.* printf("[%s]",yytext); machin.* printf("[%s]",yytext); /* le point "." signifie tout caractère sauf \n */ %% ------------------------------------------------------ ENTREE : truczzmachin SORTIE : [truczzmachin]
A cause de l'expression ".*" attrappe-tout, la 1ère règle reconnaît toute l'entrée.
Il peut arriver qu'un fragment se prolonge au delà de ce que l'on veut reconnaître et utiliser. Souvent, il faut donc aussi des règles (avec éventuellement une action vide) pour reconnaître les fragments inutiles, non désirés ou sans intérêt applicatif.
Une réalisation simple consiste à ajouter en fin de spécification une
"regle-balai" ou "ramasse-miettes", reconnaissant tout caractère non reconnu par les expressions précédentes. C'est aussi très utile dans la phase de mise
au point pour vérifier le bon fonctionnement des autres règles.
------ Exemple 1.4 : visualiser ce qui est hors fragment utile %% [0-9]+ printf("[ENTIER=%s]",yytext); [0-9]+"."([0-9]+)? printf("[REEL=%s]",yytext); [A-Za-z0-9]+ printf("[SYMB=%s]",yytext); . { printf("[%c]",yytext[0]); %% ----------------------------------------------------------------- ENTREE : 123 Label1 0.999 XXX SORTIE : [ENTIER=123][ ][SYMB=Label1][ ][REEL=0.999][ ][SYMB=XXX]
L'action notée | indique qu'il faut faire l'action de la ligne suivante.
On peut aussi le voir comme l'écriture d'une expression régulière
sur plusieurs lignes séparées par l'opérateur "OU".
------ Exemple 1.5 : Action |, Expression multiligne %% ROUGE|VERT|BLEU printf("COULEUR=%s]",yytext); rouge | vert | bleu printf("couleur=%s]",yytext); %%
Pour supprimer l'interprétation par Flex de certains caractères spéciaux, on dispose de :
---- Exemple 2.1 : échappement %% \[\] ; // reconnaît et élimine la chaîne "[]" "(.)" ; // reconnaît et élimine la chaîne littérale "(.)" \.\.\. ; // reconnaît et élimine la chaîne littérale "..." "\r\n" printf("\n"); // remplacement de CR-LF par LF seul (Windows->Linux) %%
---- Exemple 2.2 : groupement/alternatives/* %% abc* ; /* ab abc abcc abccc abccc ... */ a(bc)* ; /* a abc abcbc abcbcbc ... */ a(b|c)* ; /* a ab ac abb acc abc acb abcbcbcbccc ...*/ veu(x|s|t|lent) | vou(dr|l)ai(s|t|ent) ; /* les conjugaisons de VOULOIR */ %%
L'alphabet de Flex est par défaut les caractères ASCII 8 bits.
L'option %option 7bits permet de réduire l'alphabet de moitié.
N.B. : les caractères accentués isolatin, utf8.. peuvent être sources de problèmes.
Un caractère C dans une expression régulière peut être obtenu par :
Une classe de caractère spécifie un seul caractère choisi parmi un ensemble. on a ainsi :
A l'intérieur d'une classe [...], les seuls caractères réservés sont -,^,\ et ].
Ces caractères peuvent être inclus dans la classe en utilisant l'échappement \ (ou éventuellement en ne mettant pas le '^' en tête, ou le '-' au milieu).
---- Exemple 2.3 : spécifications de caractères %% [aeiouy] printf("[V=%s]",yytext); // une voyelle [^aeiouy] printf("[C=%s]",yytext); // une consonne (~ hum!) [^A-Za-z] printf("[NA=%s]",yytext); // un car. non alphabétique [A-Fa-f0-9] printf("[H=%s]",yytext); // un chiffre hexadécimal [-^\\\]] printf("[SPE=%s]",yytext); // speciaux dans une classe flex [\^\-\\\]] printf("[SPE=%s]",yytext); // idwm %%
Pour une expression r, on a les "Répétitions" de r :
----- Exemple 2.4 : facteurs de répétitions %% (ab|cd)?(ef)* printf("[%s]",yytext); // ab, abef, abefef, cdef, ef ... [0-9]+\.([0-9]+)? | \.[0-9]+ printf("[NB.REEL]"); (AA){1,3} printf("[2,4,ou 6 As]"); (\n)+ printf("\n"); // élimination de lignes vides . printf("[%s!!!]",yytext); // bien voir le reste %%
dans les différents cas, le contexte (\n ou "suite") n'est pas consommé
----- Exemple 2.5a : supprimer les blancs/tabulations en fin de ligne %% [ \t]+$ ; %%
----- Exemple 2.5b : contexte à droite -- %% ^[ \t]+$ printf("[LIGNE APPAREMMENT VIDE]"); [sS]herlock[ ]+/[hH]olmes ; // supprimera le prénom %%
Nota Bene :
yywrap()
pour produire des actions sur une fin de fichier.
Flex permet de définir des sortes de "super-états" de l'automate permettant de faire jouer certaines expressions régulières selon certaines préconditions.
%s nom1 nom2 .. /* Définit des start-conditions inclusives */ %x nom4 nom5 .. /* Définit des start-conditions exclusives */
----- Exemple 3.1a : reconnaissance selon un contexte a gauche %s GOT_AUTHOR %% [Aa]uthor[ ]*:[ ]* BEGIN(GOT_AUTHOR); <GOT_AUTHOR>[A-Z][a-z]+ printf("[Author:%s]",yytext); . BEGIN(INITIAL); %% -------------------------------------------------------------- ENTREE : Dupond - Author: Miller - Duschmoll ; SORTIE : [Author:Miller]
----- Exemple 3.1b : suppression de commentaires en C %s IN_COMMENTS %% "/*" BEGIN(IN_COMMENTS); <IN_COMMENTS>"*/" BEGIN(INITIAL); <IN_COMMENTS>. ; %%
ECHO
, BEGIN
, ...void echo(char *Cat_lex) { fprintf(stderr,"[%s: %s]",Cat_lex, yytext); }
yywrap()
, ...Il s'agit de noms symboliques utilisables dans la définition des expressions régulières
NOM expr
{NOM}
----- Exemple 4.1a : macros-expressions d'exp. régulières ENTIER [0-9]+ SYMBOL [a-zA-Z][a-zA-Z0-9]+ ITYP (char|int|long) TYP {ITYP}|(float|double) %% {ENTIER} printf("[ENTIER:%s]",yytext); {SYMBOL} printf("[SYMBOL:%s]",yytext); {ENTIER}\.{ENTIER}? printf("[REEL:%s]",yytext); %%
a) Dans le prologue :
%{
... }%
----- Exemple 4.2a : enregistrement de symboles %{ #include <string.h> #define SYMB_NB 20 char *symbols[SYMB_NB]; int lineNbs[SYMB_NB], currLineNb = 0, symbolNb = 0; void storeSymbol( ) { if( symbolNb < SYMB_NB ) { symbols[symbolNb] = strdup(yytext); lineNbs[symbolNb++] = currLineNb; } } %} %% [a-zA-Z][a-zA-Z0-9]+ storeSymbol(); \n currLineNb++; . ; %%
b) Dans l'épilogue :
----- Exemple 4.2b : Une fonction pour rien %{ void doNothing(); } %} %% . doNothing(); %% void doNothing( ) { }
----- Exemple 4.2c : listage de symboles enregistres (suite de 4.2a) ... %% ... %% yywrap() { int i; printf("\nSYMBOLES:\n"); for( i=0; i<symbolNb; i++ ) printf("%s\t%d\n", symbols[i], lineNbs[i]); return 1; } int main() { while (yylex()!=0) ; return 0; }
On peut utiliser les commentaires dans le style C pour les spécifications. Toutefois sont interdits :
/*------- Definitions Section ------------*/ %{ /* C-code block */ %} %s STATE /* une start-condition, mais pas de commentaires sur la meme ligne */ DIGIT [0-9] /* une macro-expression, mais pas de commentaires sur la meme ligne */ %% /*------- Rules Section ------------*/ /* !!! des commentaires mais jamais en début de ligne !!! */ <STATE>rule { /* C-code block */ } /* after code block */ {DIGIT} /* before code block */ { /* C-code block */ } %% /*------- User Code Section ------------*/ /* C-code block */