yacc
desarrollado
en las secciones anteriores ha sido escrito
usando la variante flex del lenguaje LEX. Un programa
flex
tiene una estructura similar a la
de un program yacc
con tres partes: cabeza, cuerpo
y cola separados por %%
. Veamos como ejemplo de manejo de
flex
, los contenidos
del fichero flex inherited1.l
utilizado en las secciones
anteriores:
1 %{ 2 #include <string.h> 3 #include "y.tab.h" 4 %} 5 id [A-Za-z_][A-Za-z_0-9]* 6 white [ \t\n]+ 7 %% 8 global { return GLOBAL; } 9 local { return LOCAL; } 10 float { return FLOAT; } 11 int { return INTEGER; } 12 {id} { yylval.s = strdup(yytext); return NAME; } 13 {white} { ; } 14 , { return yytext[0]; } 15 . { fprintf(stderr,"Error. carácter inesperado.\n"); } 16 %% 17 int yywrap() { return 1; }La cabeza contiene declaraciones
C
asi como definiciones
regulares. El fichero y.tab.h
que es incluído en la línea
3, fué generado
por yacc
y contiene, entre otras cosas,
la información recolectada
por yacc
sobre los tipos de los atributos
(declaración %union
) y la enumeración de los terminales.
Es, por tanto, necesario que la compilación con yacc
preceda a la compilación con flex
.
La información en y.tab.h
es usada por el analizador léxico
para ``sincronizarse'' con el analizador sintáctico.
Se definen en las líneas 5 y 6 las
macros para el reconocimiento de identificadores (id
)
y blancos (white
). Estas macros son llamadas en el cuerpo
en las líneas 12 y 13.
La estructura del cuerpo
consiste en parejas formadas por una definición
regular seguidas de una acción.
La variable yylval
contiene el atributo asociado
con el terminal actual. Puesto que el token NAME
fué declarado del tipo cadena (véase 7.19.2),
se usa el correspondiente
nombre de campo yylval.s
.
La cadena que acaba de casar queda guardada en la variable
yytext
, y su longitud queda en la
variable entera global yyleng
.
Una vez compilado con flex
el fuente,
obtenemos un fichero denominado lex.yy.c
.
Este fichero contiene la rutina yylex()
que realiza el análisis
léxico del lenguaje descrito.
La función yylex()
analiza las entradas, buscando la
secuencia mas larga que casa con alguna de las expresiones regulares
y ejecuta la correspondiente acción.
Si no se encuentra ningun emparejamiento se ejecuta la regla ``por defecto'', que es:
(.|\n) { printf("%s",yytext); }
Si encuentran dos expresiones regulares con las que la cadena mas larga
casa, elige la que figura primera en el programa flex
.
Una vez que se ha ejecutado la correspondiente acción, yylex()
continúa con el resto de la entrada, buscando por subsiguientes
emparejamientos. Asi continúa hasta encontrar un final de fichero
en cuyo caso termina, retornando un cero o bien hasta que una de las
acciones explicitamente ejecuta una sentencia return
.
Cuando el analizador léxico alcanza el final del fichero, el
comportamiento en las subsiguientes llamadas a yylex
resulta indefinido. En el momento en que yylex
alcanza el final del fichero llama a la función yywrap
, la cual retorna un
valor de 0 o 1 según haya mas entrada o no. Si el valor es 0,
la función yylex
asume que la propia yywrap
se ha encargado de abrir el nuevo fichero y asignarselo
a yyin
.