Analyse lexicale, examen de compilation, janvier 1997

Sujet

On considère un texte (probablement produit par un tableur), dont chaque ligne représente un enregistrement. Un enregistrement est constitué d'un nombre variable de champs, et le séparateur de champs est le caractère de tabulation ; un champ peut être vide. On distingue trois types de champs : entier, positif ou négatif ; réel, positif ou négatif (on ne se préoccupera pas des cas particuliers tels que .5 ou 3.) ; tout autre champ est traité comme une chaîne de caractères.

On suppose disponibles :

Ecrire un analyseur lexical, dans le format reconnu par lex, qui lit un texte du type décrit ci-dessus, et remplit un tableau d'au plus EMAX enregistrements. La fonction produite retourne le nombre d'enregistrements lus, et a pour prototype :
   int tableur (Enregistrement *t);
Commenter les (quelques) points délicats de programmation lex.

Corrigé

%{
#define ENTIER 1
#define REEL 2
#define CHAINE 3
#define TAB 10
#define NL 11

/* et toutes les déclarations de l'énoncé */
%}

signe		[\+\-]?
point		[\.]
chiffre		[0-9]
entier		{signe}{chiffre}+
reel		{entier}{point}{chiffre}+([eE]{entier})?

%%
{entier}	return ENTIER;
{reel}		return REEL;
[^\t\n]+	return CHAINE;
\t		return TAB;
\n		return NL;
%%

int tableur (Enregistrement *t) {
  int i, j, token;
  
  /* initialisation : toutes les cases sont vides */
  for (i = 0; i < EMAX; i++)
    for (j = 0; j < CMAX; j++)
      t[i][j] = 0;

  i = j = 0;
  while (token = yylex ())	/* c'est bien '=' */
    switch (token) {
      case ENTIER:
        t[i][j] = allouer_entier (atoi (yytext));
        break;
        
      case REEL:
        t[i][j] = allouer_reel (atof (yytext));
        break;
        
      case CHAINE:
        t[i][j] = allouer_chaine (yytext);
        break;
        
      case TAB:
        if (j < CMAX - 1) j++;
        break;
        
      case NL:
        if (i < EMAX - 1) {i++; j = 0;}
        break;    
    }
  return i;
}
Commentaires :