Some scanners (such as those which support "include" files) require
reading from several input streams. As flex scanners do a large
amount of buffering, one cannot control where the next input will be
read from by simply writing a YY_INPUT which is sensitive to the
scanning context. YY_INPUT is only called when the scanner
reaches the end of its buffer, which may be a long time after scanning a
statement such as an "include" which requires switching the input
source.
To negotiate these sorts of problems, flex provides a mechanism
for creating and switching between multiple input buffers. An input
buffer is created by using:
YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
which takes a FILE pointer and a size and creates a buffer
associated with the given file and large enough to hold size
characters (when in doubt, use YY_BUF_SIZE for the size). It
returns a YY_BUFFER_STATE handle, which may then be passed to
other routines:
void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
switches the scanner's input buffer so subsequent tokens will come from
new_buffer. Note that yy_switch_to_buffer may be used by
yywrap to sets things up for continued scanning, instead of
opening a new file and pointing `yyin' at it.
void yy_delete_buffer( YY_BUFFER_STATE buffer )
is used to reclaim the storage associated with a buffer.
yy_new_buffer is an alias for yy_create_buffer, provided
for compatibility with the C++ use of new and delete for
creating and destroying dynamic objects.
Finally, the YY_CURRENT_BUFFER macro returns a
YY_BUFFER_STATE handle to the current buffer.
Here is an example of using these features for writing a scanner which expands include files (the `<<EOF>>' feature is discussed below):
/* the "incl" state is used for picking up the name
* of an include file
*/
%x incl
%{
#define MAX_INCLUDE_DEPTH 10
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
int include_stack_ptr = 0;
%}
%%
include BEGIN(incl);
[a-z]+ ECHO;
[^a-z\n]*\n? ECHO;
<incl>[ \t]* /* eat the whitespace */
<incl>[^ \t\n]+ { /* got the include file name */
if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
{
fprintf( stderr, "Includes nested too deeply" );
exit( 1 );
}
include_stack[include_stack_ptr++] =
YY_CURRENT_BUFFER;
yyin = fopen( yytext, "r" );
if ( ! yyin )
error( ... );
yy_switch_to_buffer(
yy_create_buffer( yyin, YY_BUF_SIZE ) );
BEGIN(INITIAL);
}
<<EOF>> {
if ( --include_stack_ptr < 0 )
{
yyterminate();
}
else
yy_switch_to_buffer(
include_stack[include_stack_ptr] );
}