Analisis lexico.5.6
Aplicaciones analizadores Lexicos (Caso de estudio)
Adem´as de para construir compiladores e int´erpretes, los analizadores l´exicos se pueden emplear
para muchos programas “convencionales”. Los ejemplos m´as claros son aquellos programas
que tienen alg´un tipo de entrada de texto donde hay un formato razonablemente libre en cuanto
espacios y comentarios. En estos casos es bastante engorroso controlar d´onde empieza y termina
cada componente y es f´acil liarse con los punteros a char. Un analizador l´exico simplifica notablemente
la interfaz y si se dispone de un generador autom´atico, el problema se resuelve en pocas
l´ıneas de c´odigo.
8.1. Ficheros organizados por columnas
Un ejemplo sencillo de uso de analizadores l´exicos ser´ıa el trabajo con ficheros organizados en
forma de columnas separadas por tabuladores. Supongamos que tenemos un fichero de texto en
el que aparecen secuencias de d´ıgitos separadas por tabuladores que definen columnas. Queremos
sumar la columna n de la tabla.
Podemos emplear la siguiente especificaci´on l´exica:
categor´ıa expresi´on regular acciones atributos
numero [0–9]
+ calcular valor valor
emitir
separaci´on \t emitir
linea \n emitir
blanco
+ omitir
Pasar esto a flex es trivial:
%{
#include "columnas.h"
#include <stdio.h>
#include <string.h>
int nlinea;
int yyval;
%}
%%
" "+ ; /* Eliminamos los espacios. */
[0-9]+ { yyval= atoi(yytext); return NUMERO; }
\t { return SEPARACION; }
\n { nlinea++; return LINEA; }
. { fprintf(stderr, "Aviso: car´acter %c inesperado, l´ınea %d.\n", yytext[0], nlinea); }
Las definiciones auxiliares necesarias estar´ıan en el fichero columnas.h:
#define NUMERO 256
#define SEPARACION 257
#define LINEA 258
extern int yyval;
extern int nlinea;
int yylex();
c Universitat Jaume I 2008-2009
36 II26 Procesadores de lenguaje
int suma (int ncol) /* Suma los datos de la columna ncol. */
{
int token, col, res;
res= 0; /* resultado */
nlinea= 0;
while ( (token= yylex())!= 0)
{
col= 1; /* columna actual */
while (1)
{
if ( token!= NUMERO )
error("La l´ınea debe comenzar por un n´umero");
if ( col== ncol )
res+= yyval;
token= yylex();
if ( token!= SEPARACION && token!= LINEA )
error ("Detr´as de un n´umero debe haber un tabulador o un fin de l´ınea.");
if ( token== LINEA )
break;
token= yylex();
col++;
}
if ( col< ncol )
error ("No hay suficientes campos en la l´ınea.");
}
return res;
}
Figura 7: Funci´on para sumar los datos de una columna.
Algunos comentarios: hemos utilizado valores por encima de 255 para no mezclar categor´ıas
y caracteres (esto es un convenio debido al interfaz con bison y es bueno seguirlo); declaramos
nlinea e yyval para poder acceder a ellos en el programa principal. El m´etodo que tiene flex
para pasar atributos no es muy elegante (y tambi´en es debido a bison), por eso usamos yyval
para el valor del n´umero.
La funci´on que suma una columna determinada la puedes ver en la figura 7. La funci´on error
es simplemente:
void error (char *mensaje)
{
fprintf(stderr, "Error en l´ınea %d: %s\n", nlinea, mensaje);
exit(1);
} // error
8.2. Procesamiento de ficheros de configuraci´on
Otro ejemplo t´ıpico de uso de analizadores l´exicos ser´ıa la lectura de un fichero de configuraci´on.
Supongamos que en este fichero se tienen l´ıneas con el formato: variable = valor. Los nombres de
variable est´an son secuencias de letras y d´ıgitos que comienzan por una letra. Los valores pueden
ser cadenas entre comillas (sin comillas en su interior) o n´umeros enteros. Se permiten comentarios
que comienzan por el car´acter # y terminan al final de la l´ınea. Adem´as se permiten l´ıneas vac´ıas.
Analizador l´exico 37
Tambi´en ahora, la especificaci´on l´exica es sencilla:
categor´ıa expresi´on regular acciones atributos
variable [a–zA–Z][a–zA–Z0–9]
∗
copiar lexema lexema
emitir
igual = emitir
valor [0–9][0–9]
∗
|"[ˆ"\n]
∗" copiar lexema lexema
emitir
linea (#[ˆ\n]
∗
)?\n emitir
blanco [ \t]
+ omitir
Como antes, codificar el analizador con flex es f´acil:
%{
#include "config.h"
#include <stdio.h>
int nlinea;
%}
%%
[ \t]+ ;
[a-zA-Z][a-zA-Z0-9]* { return VARIABLE; }
= { return IGUAL; }
[0-9][0-9]*|\"[^"\n]*\" { return VALOR; }
(#.*)?\n { nlinea++; return LINEA; }
. { fprintf(stderr, "Aviso: car´acter %c inesperado, l´ınea %d.\n", yytext[0], nlinea); }
Los identificadores VARIABLE, IGUAL, VALOR y LINEA son constantes definidas en config.h:
#define VARIABLE 256
#define IGUAL 257
#define VALOR 258
#define LINEA 259
extern int nlinea;
extern char *yytext;
int yylex();
El procesamiento del fichero es ahora bastante sencillo, como puedes ver en la figura 8.

Comentarios
Publicar un comentario