Copyright (C) 2000-2012 |
GNU Info (flex.info)Multiple buffersMultiple input buffers ********************** 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 (see below). The `YY_BUFFER_STATE' type is a pointer to an opaque `struct' `yy_buffer_state' structure, so you may safely initialize YY_BUFFER_STATE variables to `((YY_BUFFER_STATE) 0)' if you wish, and also refer to the opaque structure in order to correctly declare input buffers in source files other than that of your scanner. Note that the `FILE' pointer in the call to `yy_create_buffer' is only used as the value of `yyin' seen by `YY_INPUT'; if you redefine `YY_INPUT' so it no longer uses `yyin', then you can safely pass a nil `FILE' pointer to `yy_create_buffer'. You select a particular buffer to scan from using: 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 set things up for continued scanning, instead of opening a new file and pointing `yyin' at it. Note also that switching input sources via either `yy_switch_to_buffer()' or `yywrap()' does _not_ change the start condition. void yy_delete_buffer( YY_BUFFER_STATE buffer ) is used to reclaim the storage associated with a buffer. You can also clear the current contents of a buffer using: void yy_flush_buffer( YY_BUFFER_STATE buffer ) This function discards the buffer's contents, so the next time the scanner attempts to match a token from the buffer, it will first fill the buffer anew using `YY_INPUT'. `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_delete_buffer( YY_CURRENT_BUFFER ); yy_switch_to_buffer( include_stack[include_stack_ptr] ); } } Three routines are available for setting up input buffers for scanning in-memory strings instead of files. All of them create a new input buffer for scanning the string, and return a corresponding `YY_BUFFER_STATE' handle (which you should delete with `yy_delete_buffer()' when done with it). They also switch to the new buffer using `yy_switch_to_buffer()', so the next call to `yylex()' will start scanning the string. `yy_scan_string(const char *str)' scans a NUL-terminated string. `yy_scan_bytes(const char *bytes, int len)' scans `len' bytes (including possibly NUL's) starting at location BYTES. Note that both of these functions create and scan a _copy_ of the string or bytes. (This may be desirable, since `yylex()' modifies the contents of the buffer it is scanning.) You can avoid the copy by using: `yy_scan_buffer(char *base, yy_size_t size)' which scans in place the buffer starting at BASE, consisting of SIZE bytes, the last two bytes of which _must_ be `YY_END_OF_BUFFER_CHAR' (ASCII NUL). These last two bytes are not scanned; thus, scanning consists of `base[0]' through `base[size-2]', inclusive. If you fail to set up BASE in this manner (i.e., forget the final two `YY_END_OF_BUFFER_CHAR' bytes), then `yy_scan_buffer()' returns a nil pointer instead of creating a new input buffer. The type `yy_size_t' is an integral type to which you can cast an integer expression reflecting the size of the buffer. automatically generated by info2www version 1.2.2.9 |