TP de compilation : une solution de l'exercice 3 du TP 1

3.1.
On doit rechercher le motif [ \t]+ dans divers situations :
  – en fin de ligne pour éliminer les espaces et tabulations superflues,
  – en début de ligne pour conserver une unique tabulation,
  – dans les autres circonstances pour ne conserver qu'un espace séparateur.

La difficulté de l'exercice est de faire distinguer à Lex ces différentes situations. Il faut pour cela ordonner les motifs des plus spécifiques aux plus généraux.
Une solution peut être :
SP [ \t]+
%%
^\n      {return 0;}
^{SP}$   ;
{SP}$    ;
^{SP}    {printf("\t");}
{SP}     {printf(" ");}

N.B. Il n'est pas toujours facile de tester ce programme avec des espacements, on pourrait remplacer par exemple le motif [ \t]+ par [et]+ le temps de tester le comportement de l'analyseur.
On peut aussi remarquer que la première ligne d'analyse est redondante :
^{SP}$
semble subsumée par
{SP}$   ;
peut-on retirer sans soucis cette ligne ? (le comportement peut être différent avec Flex d'avec Lex)
L'espace étant un méta-caractère de Lex, son utilisation comme caractère à reconnaître peut se faire entre crochets [ ], entre guillements " ", ou entre apostrophes ' '.

On peut maintenant réaliser le décompte des mots du texte. Plusieurs solutions existent.
Proposons deux solutions (quels sont les avantages et inconvénients de chacune ?).
%{
// Solution 1
int c=1;
%}
SP [ \t]+
%%
^\n       {return 0;}
^{SP}$    {c=0;}
{SP}$     ;
^{SP}     {printf("\t");}
{SP}      {printf(" ");c++;}
\n       {printf(" : %d mot(s) sur la ligne\n",c); c=1;}

%{
// Solution 2
int c=0;
%}
SP [ \t]+
%%
^\n       {return 0;}
^{SP}$    ;
{SP}$     ;
^{SP}     {printf("\t");}
{SP}      {printf(" ");}
[a-zA-Z]+  {ECHO; c++;}
\n        {printf(": %d mot(s) sur la ligne\n",c); c=0;}

3.2.
Un seule règle devrait suffire :
^[a-z]     {printf("%c",yytext[0]-32);}

3.3.
On peut, par exemple, ajouter en premier motif dans le premier analyseur la règle du second analyseur.
Mais pourquoi ne pas tout simplement mettre les deux analyseurs en série ? Si analyseur1 et analyseur2 sont les exécutables de ces deux analyseurs, essayer la commande shell : analyseur1|analyseur2.

© 2000, 2017 – A. Sigayret