Cours lex analyseur lexical Théorie des langages-téléch...

Théorie des langages : Cours lex analyseur lexical

Télécharger PDF

Analyse Lexicale avec Lex

Introduction à Lex

Lex est un utilitaire sous Unix. Son équivalent GNU, fLex, est également disponible. Lex permet de définir des spécifications d'unités lexicales sous forme d'expressions régulières et génère un programme en langage C. Une fois compilé, ce programme reconnaît ces unités lexicales.

La commande Lex fichier.l produit le fichier Lex.yy.c, qui doit être compilé avec gcc Lex.yy.c -l l pour obtenir un exécutable.

Fonctionnement de Lex

Lex lit le texte d'entrée caractère par caractère. Il identifie le plus long préfixe correspondant à une expression régulière. En cas de conflit entre plusieurs règles, Lex privilégie la première règle rencontrée (de haut en bas). Si aucune règle ne correspond, il copie par défaut le caractère en sortie.

Expressions Régulières dans Lex

Lex utilise des expressions régulières composées de caractères normaux et de méta-caractères : $, ^, [ ], { }, < >, +, -, *, /, |, ?.

Voici les principales expressions régulières reconnues par Lex :

  • c : tout caractère c qui n'est pas un opérateur ou un méta-caractère.
  • \c : caractère littéral c (lorsque c est un méta-caractère).
  • . : n'importe quel caractère, sauf retour à la ligne (\n).
  • ^ : l'expression qui suit débute une ligne.
  • $ : l'expression qui précède termine une ligne.
  • [s] : n'importe quel caractère de l'ensemble s.
  • [abc] : n'importe quel caractère parmi a, b, c.
  • [^s] : n'importe quel caractère qui n'est pas dans s.
  • r* : 0 ou plusieurs occurrences de r.
  • r+ : 1 ou plusieurs occurrences de r.
  • r? : 0 ou 1 occurrence de r.
  • r{m} : m occurrences de r.
  • r{m,n} : entre m et n occurrences de r.
  • r1 r2 : r1 suivie de r2.
  • r1 | r2 : r1 ou r2.
  • r1 / r2 : r1 si elle est suivie de r2.
  • (r) : r entre parenthèses.
  • (a | b)?c : a ou b (optionnel) suivi de c.
  • <x>r : r si Lex se trouve dans l'état x.

Structure d'un Fichier Lex

Un fichier de description pour Lex est organisé en trois sections :

  1. Déclarations (optionnelle) :
    • Commence par %{ et se termine par %}, placés en début de ligne.
    • Contient des déclarations et définitions en C.
    • Est copiée telle quelle dans Lex.yy.c.
    • Les définitions et déclarations sont globales au programme produit.

    Exemple :

      %{ int nbVoyelles, nbConsonnes, nbPonct; %}
      
  2. Productions :
    • Contient des expressions régulières et leurs actions associées.
    • La partie gauche spécifie les expressions régulières reconnues.
    • La partie droite définit les actions exécutées (syntaxe C).
    • Si Lex est appelé par Yacc, les attributs doivent être déposés dans yylval et l'unité lexicale retournée.

    Exemple :

      {ident} { yylval = yytext; return(id); }
      {nbre} { yylval = yytext; return(nb); }
      
  3. Procédures auxiliaires (optionnelle) :
    • Permet de définir des fonctions utilisées dans les actions.
    • Peut redéfinir le programme principal (main()).

    Exemple :

      int main(int argc, char *argv[]) {
        yyin = fopen(argv[1], "r");
        yylex();
        fclose(yyin);
      }
      

Variables et Fonctions Prédéfinies

Lex fournit plusieurs variables et fonctions prédéfinies :

  • char yytext[] : tableau contenant la chaîne lexicale reconnue.
  • int yyleng : longueur de la chaîne yytext.
  • int yylex() : lance l'analyseur et appelle yywrap().
  • yylval : retourne la valeur associée à l'unité lexicale.
  • ECHO : affiche la chaîne lexicale reconnue.
  • FILE *yyout : fichier de sortie.
  • FILE *yyin : fichier d'entrée.
  • int yywrap() : appelée en fin de flux d'entrée, retourne 0 pour continuer ou 1 pour arrêter.
  • unput(char c) : remet le caractère dans le flux d'entrée.
  • int yylineno : numéro de la ligne courante.
  • yymore() : concatène yytext avec la chaîne précédente.
  • yyless(int k) : supprime les (yyleng - k) derniers caractères de yytext et recule le pointeur de lecture.
  • yyterminate() : stoppe l'analyseur.

Exemple Pratique : Insertion du Numéro de Ligne

Voici un exemple qui insère le numéro de ligne dans chaque ligne d'un fichier :

%{
  int yylineno;
%}

%%

^(.*)\n printf("%4d\t%s", ++yylineno, yytext);

%%
int main(int argc, char *argv[]) {
  yyin = fopen(argv[1], "r");
  yylex();
  fclose(yyin);
}

FAQ

1. Comment Lex gère-t-il les conflits entre règles ?

Lex privilégie la règle qui produit le plus long lexème. Si plusieurs règles donnent des lexèmes de même longueur, il choisit la première rencontrée.

2. Peut-on omettre les guillemets pour une chaîne de caractères dans les productions ?

Oui, pour une chaîne de lettres et de chiffres, les guillemets peuvent être omis. Par exemple, <= peut s'écrire <= sans guillemets.

3. Que se passe-t-il si aucune règle ne correspond au flux d'entrée ?

Lex utilise par défaut la règle implicite .\n {ECHO}, qui recopie le flux d'entrée sur le flux de sortie.

Cela peut vous intéresser :

Partagez vos remarques, questions , propositions d'amélioration ou d'autres cours à ajouter dans notre site

Enregistrer un commentaire (0)
Plus récente Plus ancienne