2. Utilisation de Lex dans l'analyse lexicale

Le but de l'analyse lexicale est de transformer une suite de symboles en terminaux (un terminal peut être par exemple un nombre, un signe "+", un identificateur, etc...). Une fois cette transformation effectuée, la main est repassée à l'analyseur syntaxique (voir ci-dessous). Le but de l'analyseur lexical est donc de "consommer" des symboles et de les fournir à l'analyseur syntaxique.

Un fichier de description pour Lex est formé de trois parties, selon le schéma suivant ;

déclarations
%%
productions
%%
code additionnel

dans lequel aucune partie n'est obligatoire. Cependant, le premier %% l'est, afin d'indiquer la séparation entre les déclarations et les productions.

2.1. La première partie d'un fichier Lex

Cette partie d'un fichier Lex peut contenir :

Exemple :

%{

#include "calc.h"

#include <stdio.h>
#include <stdlib.h>

%}

/* Expressions régulières */
/* ---------------------- */

blancs          [\t\n ]+
lettre          [A-Za-z]
chiffre10       [0-9]                   /* base 10 */
chiffre16       [0-9A-Fa-f]             /* base 16 */

identificateur  {lettre}(_|{lettre}|{chiffre10})*
entier10        {chiffre10}+

L'exemple en lui-même est clair, mais regardons d'un peu plus près comment sont formées les expressions régulières.

2.2. Les expressions régulières

Symbole Signification
x le caractère "x"
. n'importe quel caractère sauf \n
[xyz] soit x, soit y, soit z
[^bz] tous les caractères, sauf b et z
[a-z] n'importe quel caractère entre a et z
[^a-z] tous les caractères, sauf ceux compris entre a et z
R* zéro R ou plus, où R est n'importe quelle expression régulière
R+ un R ou plus
R? zéro ou un R (c'est-à-dire un R optionnel)
R{2,5} entre 2 et 5 R
R{2,} 2 R ou plus
R{2} exactement 2 R
"[xyz\"foo" la chaîne "[xyz"foo"
{NOTION} l'expansion de la notion NOTION définie plus haut
\X si X est un "a", "b", "f", "n", "r", "t", ou "v", représente l'interprétation ANSI-C de \X.
\0 le caractère ASCII 0
\123 le caractère dont le code ASCII est 123, en octal
\x2A le caractère dont le code ASCII est 2A, en hexadécimal
RS R suivi de S
R|S R ou S
R/S R, seulement s'il est suivi par S
^R R, mais seulement en début de ligne
R$ R, mais seulement en fin de ligne
<<EOF>> fin de fichier

Ainsi, la définition :

identificateur  {lettre}(_|{lettre}|{chiffre10})*

reconnaitra comme identificateur les mots "integer", "une_variable", "a1", mais pas "_ident" ni "1variable". Facile, non ?

Enfin, comme dernier exemple, voici la définition d'un réel :

chiffre         [0-9]
entier          {chiffre}+
exposant        [eE][+-]?{entier}
reel            {entier}("."{entier})?{exposant}?

2.3. La deuxième partie d'un fichier Lex : les productions

Cette partie sert à indiquer à Lex ce qu'il devra faire lorsqu'il rencontrera telle ou telle notion. Celle-ci peut contenir :

Il faut de plus savoir que les commentaires tels que /* ... */ ne peuvent être présents dans la deuxième partie d'un fichier Lex que s'il sont placés dans les actions parenthésées. Dans le cas contraire, ceux-ci seraient considérés par Lex comme des expressions régulières ou des actions, ce qui donnerait lieu à des messages d'erreur, ou, au mieux, à un comportement inattendu.

Enfin, la variable yytext désigne dans les actions les caractères acceptés par expression_régulière. Il s'agit d'un tableau de caractère de longueur yyleng (donc défini comme char yytext[yyleng]).

Exemple :

%%
[ \t]+$         ;
[ \t]+          printf(" ");

Ce programme supprime tous les espaces inutiles dans un fichier. Tu auras d'ailleurs noté que Lex permet de faire énormément de choses, et pas seulement des interpréteurs et des compilateurs (Il peut par exemple servir à la recherche/remplacement dans un texte, etc...).

2.4. Troisième partie d'un fichier Lex : le code additionnel

Tu peux mettre dans cette partie facultative tous le code que tu veux. Si tu ne mets rien, Lex considère que c'est juste :

main() {
  yylex();
}

2.5. Conclusion sur Lex

Comme tu as pu le voir, Lex est très simple d'emploi (en tout cas dans les cas simples tels que ceux présentés). Pourtant, nous n'avons pas fait le tour de toutes les fonctionnalités de Lex, et je t'invite donc à consulter la page de manuel pour une information plus détaillée.