

$ cat include.l
%x incl
%{
#define yywrap() 1
#define MAX_INCLUDE_DEPTH 10
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
int include_stack_ptr = 0;
%}
%%
include BEGIN(incl);
. ECHO;
<incl>[ \t]*
<incl>[^ \t\n]+ { /* got the file name */
if (include_stack_ptr >= MAX_INCLUDE_DEPTH) {
fprintf(stderr,"Includes nested too deeply\n");
exit(1);
}
include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
yyin = fopen(yytext,"r");
if (!yyin) {
fprintf(stderr,"File %s not found\n",yytext);
exit(1);
}
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
BEGIN(INITIAL);
}
<<EOF>> {
if ( --include_stack_ptr < 0) {
yyterminate();
} else {
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(include_stack[include_stack_ptr]);
}
}
%%
main(int argc, char ** argv) {
yyin = fopen(argv[1],"r");
yylex();
}
La función yy_create_buffer(yyin, YY_BUF_SIZE)); crea un buffer
lo suficientemente grande para mantener YY_BUF_SIZE caracteres. Devuelve un
YY_BUFFER_STATE, que puede ser pasado a otras rutinas. YY_BUFFER_STATE es un puntero a
una estructura de datos opaca (struct yy_buffer_state) que contiene la información para la manipulación
del buffer. Es posible por tanto inicializar un puntero YY_BUFFER_STATE
usando la expresión ((YY_BUFFER_STATE) 0).
La función yy_switch_to_buffer(YY_BUFFER_STATE new_buffer); conmuta la entrada
del analizador léxico. La función void yy_delete_buffer( YY_BUFFER_STATE buffer )
se usa para recuperar la memoria consumida por un buffer. También se pueden limpiar
los contenidos actuales de un buffer llamando a:
void yy_flush_buffer( YY_BUFFER_STATE buffer )
La regla especial <<EOF>> indica la acción a ejecutar cuando
se ha encontrado un final de fichero e yywrap() retorna un valor
distinto de cero. Cualquiera que sea la acción asociada, esta debe terminar
con uno de estos cuatro supuestos:
yyin a un nuevo fichero de entrada.
return.
yyterminate().
yy_switch_to_buffer().
La regla <<EOF>> no se puede mezclar con otros patrones.
Este es el resultado de una ejecución del programa:
$ cat hello.c
#include hello2.c
main() <%
int a<:1:>; /* a comment */
a<:0:> = 4; /* a comment in
two lines */
printf("\thell\157\nworld! a(0) is %d\n",a<:0:>);
%>
$ cat hello2.c
#include hello3.c
/* file hello2.c */
$ cat hello3.c
/*
third file
*/
$ flex include.l ; gcc lex.yy.c ; a.out hello.c
##/*
third file
*/
/* file hello2.c */
main() <%
int a<:1:>; /* a comment */
a<:0:> = 4; /* a comment in
two lines */
printf("\thell\157\nworld! a(0) is %d\n",a<:0:>);
%>
Una alternativa a usar el patrón <<EOF>>
es dejar la responsabilidad de recuperar el buffer anterior
a yywrap(). En tal caso suprimiríamos esta parajea patrón-acción
y reescribiríamos yywrap():
%x incl
%{
#define MAX_INCLUDE_DEPTH 10
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
int include_stack_ptr = 0;
%}
%%
include BEGIN(incl);
. ECHO;
<incl>[ \t]*
<incl>[^ \t\n]+ { /* got the file name */
if (include_stack_ptr >= MAX_INCLUDE_DEPTH) {
fprintf(stderr,"Includes nested too deeply\n");
exit(1);
}
include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
yyin = fopen(yytext,"r");
if (!yyin) {
fprintf(stderr,"File %s not found\n",yytext);
exit(1);
}
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
BEGIN(INITIAL);
}
%%
main(int argc, char ** argv) {
yyin = fopen(argv[1],"r");
yylex();
}
int yywrap() {
if ( --include_stack_ptr < 0) {
return 1;
} else {
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(include_stack[include_stack_ptr]);
return 0;
}
}

