$ 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; } }