]> granicus.if.org Git - flex/commitdiff
Removed yy_current_buffer from the planet.
authorJohn Millaway <john43@users.sourceforge.net>
Fri, 28 Feb 2003 11:27:10 +0000 (11:27 +0000)
committerJohn Millaway <john43@users.sourceforge.net>
Fri, 28 Feb 2003 11:27:10 +0000 (11:27 +0000)
Input buffer states are now in an internal unbounded stack.
Added new internal function, yyensure_buffer_stack.
Added new API function, yypush_buffer_state.
Added new API function, yypop_buffer_state.
Documented the new API calls in the manual.
Macro YY_BUFFER_STATE now refers to top of stack.
This revision breaks the C++ scanner (again.)

TODO
doc/flex.texi
flex.skl
gen.c
main.c

diff --git a/TODO b/TODO
index f4709990da7a1bfea97e8d47cb50dd7f4020e2e6..1fef06c1dc3950220863e906903eef34e73908a5 100644 (file)
--- a/TODO
+++ b/TODO
 
 ** make test suite more complete
 
+** add a test for yypush_buffer_state/yypop_buffer_state
+
 * generic coding
 
 ** move as much skeleton code as possible out of gen.c and into
   flex.skl
 
-** Automatic management of the input buffer stack. (currently does
-    this for the start condition stack, but not for the input
-    buffer stack.)
-
 ** figure out whether we want to add the capability to have
   auto-generated backout rules
 
index 9a0d0579f265c0edf12959f6a3c91bd1222baa78..cd3ecadbfc44933e9a00ba8bb85ae4c4400282d2 100644 (file)
@@ -1928,12 +1928,14 @@ using:
 @deftypefun void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer )
 @end deftypefun
 
-The above switches the scanner's input buffer so subsequent tokens will
-come from @code{new_buffer}.  Note that @code{yy_switch_to_buffer()} may
-be used by @code{yywrap()} to set things up for continued scanning,
-instead of opening a new file and pointing @file{yyin} at it.  Note also
-that switching input sources via either @code{yy_switch_to_buffer()} or
-@code{yywrap()} does @emph{not} change the start condition.
+The above function switches the scanner's input buffer so subsequent tokens
+will come from @code{new_buffer}.  Note that @code{yy_switch_to_buffer()} may
+be used by @code{yywrap()} to set things up for continued scanning, instead of
+opening a new file and pointing @file{yyin} at it. If you are looking for a
+stack of input buffers, then you want to use @code{yypush_buffer_state()}
+instead of this function. Note also that switching input sources via either
+@code{yy_switch_to_buffer()} or @code{yywrap()} does @emph{not} change the
+start condition.
 
 @cindex memory, deleting input buffers
 @deftypefun void yy_delete_buffer ( YY_BUFFER_STATE buffer )
@@ -1943,6 +1945,26 @@ is used to reclaim the storage associated with a buffer.  (@code{buffer}
 can be NULL, in which case the routine does nothing.)  You can also clear
 the current contents of a buffer using:
 
+@cindex pushing an input buffer
+@cindex stack, input buffer push
+@deftypefun void yypush_buffer_state ( YY_BUFFER_STATE buffer )
+@end deftypefun
+
+This function pushes the new buffer state onto an internal stack. The pushed
+state becomes the new current state. The stack is maintained by flex and will
+grow as required. This function is intended to be used instead of
+@code{yy_switch_to_buffer}, when you want to change states, but preserve the
+current state for later use. 
+
+@cindex popping an input buffer
+@cindex stack, input buffer pop
+@deftypefun void yypop_buffer_state ( )
+@end deftypefun
+
+This function removes the current state from the top of the stack, and deletes
+it by calling @code{yy_delete_buffer}.  The next state on the stack, if any,
+becomes the new current state.
+
 @cindex clearing an input buffer
 @cindex flushing an input buffer
 @deftypefun void yy_flush_buffer ( YY_BUFFER_STATE buffer )
@@ -1960,15 +1982,57 @@ is an alias for @code{yy_create_buffer()},
 provided for compatibility with the C++ use of @code{new} and
 @code{delete} for creating and destroying dynamic objects.
 
-@cindex YY_CURRENT_BUFFER, and multiple buffers
-Finally, the macro @code{YY_CURRENT_BUFFER} macro returns a
-@code{YY_BUFFER_STATE} handle to the current buffer.
+@cindex YY_CURRENT_BUFFER, and multiple buffers Finally, the macro
+@code{YY_CURRENT_BUFFER} macro returns a @code{YY_BUFFER_STATE} handle to the
+current buffer. It should not be used as an lvalue.
 
 @cindex EOF, example using multiple input buffers
-Here is an example of using these features for writing a scanner
+Here are two examples of using these features for writing a scanner
 which expands include files (the
 @code{<<EOF>>}
-feature is discussed below):
+feature is discussed below).
+
+This first example uses yypush_buffer_state and yypop_buffer_state. Flex
+maintains the stack internally.
+
+@cindex handling include files with multiple input buffers
+@example
+@verbatim
+    /* the "incl" state is used for picking up the name
+     * of an include file
+     */
+    %x incl
+    %%
+    include             BEGIN(incl);
+
+    [a-z]+              ECHO;
+    [^a-z\n]*\n?        ECHO;
+
+    <incl>[ \t]*      /* eat the whitespace */
+    <incl>[^ \t\n]+   { /* got the include file name */
+            yyin = fopen( yytext, "r" );
+
+            if ( ! yyin )
+                error( ... );
+
+                       yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
+
+            BEGIN(INITIAL);
+            }
+
+    <<EOF>> {
+                       yypop_buffer_state();
+
+            if ( !YY_CURRENT_BUFFER )
+                {
+                yyterminate();
+                }
+            }
+@end verbatim
+@end example
+
+The second example, below, does the same thing as the previous example did, but
+manages its own input buffer stack manually (instead of letting flex do it).
 
 @cindex handling include files with multiple input buffers
 @example
@@ -5882,7 +5946,7 @@ you might try this:
 @example
 @verbatim
 /* For non-reentrant C scanner only. */
-yy_delete_buffer(yy_current_buffer);
+yy_delete_buffer(YY_CURRENT_BUFFER);
 yy_init = 1;
 @end verbatim
 @end example
@@ -5898,7 +5962,7 @@ situation. It is possible that some other globals may need resetting as well.
 >   We thought that it would be possible to have this number through the
 >   evaluation of the following expression:
 >
->   seek_position = (no_buffers)*YY_READ_BUF_SIZE + yy_c_buf_p - yy_current_buffer->yy_ch_buf
+>   seek_position = (no_buffers)*YY_READ_BUF_SIZE + yy_c_buf_p - YY_CURRENT_BUFFER->yy_ch_buf
 @end verbatim
 @end example
 
@@ -5909,7 +5973,7 @@ even though @code{YY_READ_BUF_SIZE} bytes were requested).  The second problem
 is that when refilling its internal buffer, @code{flex} keeps some characters
 from the previous buffer (because usually it's in the middle of a match,
 and needs those characters to construct @code{yytext} for the match once it's
-done).  Because of this, @code{yy_c_buf_p - yy_current_buffer->yy_ch_buf} won't
+done).  Because of this, @code{yy_c_buf_p - YY_CURRENT_BUFFER->yy_ch_buf} won't
 be exactly the number of characters already read from the current buffer.
 
 An alternative solution is to count the number of characters you've matched
@@ -6267,7 +6331,7 @@ Date: Wed, 13 Nov 1996 19:51:54 PST
 From: Vern Paxson <vern>
 
 > "unput()" them to input flow, question occurs. If I do this after I scan
-> a carriage, the variable "yy_current_buffer->yy_at_bol" is changed. That
+> a carriage, the variable "YY_CURRENT_BUFFER->yy_at_bol" is changed. That
 > means the carriage flag has gone.
 
 You can control this by calling yy_set_bol().  It's described in the manual.
index c3c1fc9868aabb49bcc0bb8fa0419f373e5f7792..c4d70d10fd3d32478924df3acfc46825307640aa 100644 (file)
--- a/flex.skl
+++ b/flex.skl
@@ -393,16 +393,28 @@ struct yy_buffer_state
 %c-only Standard (non-C++) definition
 %not-for-header
 %if-not-reentrant
-static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /*<< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /*<< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /*<< Stack as an array. */
 %endif
 %ok-for-header
 %pop
-
 /* We provide macros for accessing buffer states in case in the
  * future we want to put the buffer states in a more general
  * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( YY_G(yy_buffer_stack) \
+                          ? YY_G(yy_buffer_stack)[YY_G(yy_buffer_stack_top)] \
+                          : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
  */
-#define YY_CURRENT_BUFFER yy_current_buffer
+#define YY_CURRENT_BUFFER_FAST YY_G(yy_buffer_stack)[YY_G(yy_buffer_stack_top)]
 
 %push
 %c-only Standard (non-C++) definition
@@ -438,8 +450,11 @@ YY_BUFFER_STATE yy_create_buffer YY_PARAMS(( FILE *file, int size YY_PROTO_LAST_
 void yy_delete_buffer YY_PARAMS(( YY_BUFFER_STATE b YY_PROTO_LAST_ARG ));
 void yy_init_buffer YY_PARAMS(( YY_BUFFER_STATE b, FILE *file YY_PROTO_LAST_ARG ));
 void yy_flush_buffer YY_PARAMS(( YY_BUFFER_STATE b YY_PROTO_LAST_ARG ));
+void yypush_buffer_state YY_PARAMS(( YY_BUFFER_STATE new_buffer YY_PROTO_LAST_ARG ));
+void yypop_buffer_state YY_PARAMS(( YY_PROTO_ONLY_ARG ));
+void yyensure_buffer_stack YY_PARAMS(( YY_PROTO_ONLY_ARG ));
 
-#define YY_FLUSH_BUFFER yy_flush_buffer( YY_G(yy_current_buffer) YY_CALL_LAST_ARG)
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER YY_CALL_LAST_ARG)
 
 YY_BUFFER_STATE yy_scan_buffer YY_PARAMS(( char *base, yy_size_t size YY_PROTO_LAST_ARG ));
 YY_BUFFER_STATE yy_scan_string YY_PARAMS(( yyconst char *yy_str YY_PROTO_LAST_ARG ));
@@ -455,21 +470,25 @@ void yyfree YY_PARAMS(( void * YY_PROTO_LAST_ARG ));
 
 #define yy_set_interactive(is_interactive) \
        { \
-       if ( ! YY_G(yy_current_buffer) ) \
-               YY_G(yy_current_buffer) =    \
+       if ( ! YY_CURRENT_BUFFER ){ \
+        yyensure_buffer_stack (YY_CALL_ONLY_ARG); \
+               YY_CURRENT_BUFFER_FAST =    \
             yy_create_buffer( yyin, YY_BUF_SIZE YY_CALL_LAST_ARG); \
-       YY_G(yy_current_buffer)->yy_is_interactive = is_interactive; \
+       } \
+       YY_CURRENT_BUFFER_FAST->yy_is_interactive = is_interactive; \
        }
 
 #define yy_set_bol(at_bol) \
        { \
-       if ( ! YY_G(yy_current_buffer) ) \
-               YY_G(yy_current_buffer) =    \
+       if ( ! YY_CURRENT_BUFFER ){\
+        yyensure_buffer_stack (YY_CALL_ONLY_ARG); \
+               YY_CURRENT_BUFFER_FAST =    \
             yy_create_buffer( yyin, YY_BUF_SIZE YY_CALL_LAST_ARG); \
-       YY_G(yy_current_buffer)->yy_at_bol = at_bol; \
+       } \
+       YY_CURRENT_BUFFER_FAST->yy_at_bol = at_bol; \
        }
 
-#define YY_AT_BOL() (YY_G(yy_current_buffer)->yy_at_bol)
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_FAST->yy_at_bol)
 
 %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here
 
@@ -531,7 +550,9 @@ struct yyguts_t
 
     /* The rest are the same as the globals declared in the non-reentrant scanner. */
     FILE *yyin_r, *yyout_r;
-    YY_BUFFER_STATE yy_current_buffer;
+    size_t yy_buffer_stack_top; /*<< index of top of stack. */
+    size_t yy_buffer_stack_max; /*<< capacity of stack. */
+    YY_BUFFER_STATE * yy_buffer_stack; /*<< Stack as an array. */
     char yy_hold_char;
     int yy_n_chars;
     int yyleng_r;
@@ -934,9 +955,11 @@ YY_DECL
                        yyout = & std::cout;
 %pop
 
-               if ( ! YY_G(yy_current_buffer) )
-                       YY_G(yy_current_buffer) =
+               if ( ! YY_CURRENT_BUFFER ) {
+                       yyensure_buffer_stack (YY_CALL_ONLY_ARG);
+                       YY_CURRENT_BUFFER_FAST =
                                yy_create_buffer( yyin, YY_BUF_SIZE YY_CALL_LAST_ARG);
+               }
 
                yy_load_buffer_state( YY_CALL_ONLY_ARG );
                }
@@ -980,20 +1003,20 @@ do_action:       /* This label is used only to access EOF actions. */
                *yy_cp = YY_G(yy_hold_char);
                YY_RESTORE_YY_MORE_OFFSET
 
-               if ( YY_G(yy_current_buffer)->yy_buffer_status == YY_BUFFER_NEW )
+               if ( YY_CURRENT_BUFFER_FAST->yy_buffer_status == YY_BUFFER_NEW )
                        {
                        /* We're scanning a new file or input source.  It's
                         * possible that this happened because the user
                         * just pointed yyin at a new source and called
                         * yylex().  If so, then we have to assure
-                        * consistency between yy_current_buffer and our
+                        * consistency between YY_CURRENT_BUFFER and our
                         * globals.  Here is the right place to do so, because
                         * this is the first action (other than possibly a
                         * back-up) that will match for the new input source.
                         */
-                       YY_G(yy_n_chars) = YY_G(yy_current_buffer)->yy_n_chars;
-                       YY_G(yy_current_buffer)->yy_input_file = yyin;
-                       YY_G(yy_current_buffer)->yy_buffer_status = YY_BUFFER_NORMAL;
+                       YY_G(yy_n_chars) = YY_CURRENT_BUFFER_FAST->yy_n_chars;
+                       YY_CURRENT_BUFFER_FAST->yy_input_file = yyin;
+                       YY_CURRENT_BUFFER_FAST->yy_buffer_status = YY_BUFFER_NORMAL;
                        }
 
                /* Note that here we test for yy_c_buf_p "<=" to the position
@@ -1003,7 +1026,7 @@ do_action:        /* This label is used only to access EOF actions. */
                 * end-of-buffer state).  Contrast this with the test
                 * in input().
                 */
-               if ( YY_G(yy_c_buf_p) <= &YY_G(yy_current_buffer)->yy_ch_buf[YY_G(yy_n_chars)] )
+               if ( YY_G(yy_c_buf_p) <= &YY_CURRENT_BUFFER_FAST->yy_ch_buf[YY_G(yy_n_chars)] )
                        { /* This was really a NUL. */
                        yy_state_type yy_next_state;
 
@@ -1082,7 +1105,7 @@ do_action:        /* This label is used only to access EOF actions. */
 
                        case EOB_ACT_LAST_MATCH:
                                YY_G(yy_c_buf_p) =
-                               &YY_G(yy_current_buffer)->yy_ch_buf[YY_G(yy_n_chars)];
+                               &YY_CURRENT_BUFFER_FAST->yy_ch_buf[YY_G(yy_n_chars)];
 
                                yy_current_state = yy_get_previous_state( YY_CALL_ONLY_ARG );
 
@@ -1205,16 +1228,16 @@ static int yy_get_next_buffer YYFARGS0(void)
 int yyFlexLexer::yy_get_next_buffer()
 %pop
        {
-       register char *dest = YY_G(yy_current_buffer)->yy_ch_buf;
+       register char *dest = YY_CURRENT_BUFFER_FAST->yy_ch_buf;
        register char *source = YY_G(yytext_ptr);
        register int number_to_move, i;
        int ret_val;
 
-       if ( YY_G(yy_c_buf_p) > &YY_G(yy_current_buffer)->yy_ch_buf[YY_G(yy_n_chars) + 1] )
+       if ( YY_G(yy_c_buf_p) > &YY_CURRENT_BUFFER_FAST->yy_ch_buf[YY_G(yy_n_chars) + 1] )
                YY_FATAL_ERROR(
                "fatal flex scanner internal error--end of buffer missed" );
 
-       if ( YY_G(yy_current_buffer)->yy_fill_buffer == 0 )
+       if ( YY_CURRENT_BUFFER_FAST->yy_fill_buffer == 0 )
                { /* Don't try to fill the buffer, so this is an EOF. */
                if ( YY_G(yy_c_buf_p) - YY_G(yytext_ptr) - YY_MORE_ADJ == 1 )
                        {
@@ -1241,16 +1264,16 @@ int yyFlexLexer::yy_get_next_buffer()
        for ( i = 0; i < number_to_move; ++i )
                *(dest++) = *(source++);
 
-       if ( YY_G(yy_current_buffer)->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+       if ( YY_CURRENT_BUFFER_FAST->yy_buffer_status == YY_BUFFER_EOF_PENDING )
                /* don't do the read, it's not guaranteed to return an EOF,
                 * just force an EOF
                 */
-               YY_G(yy_current_buffer)->yy_n_chars = YY_G(yy_n_chars) = 0;
+               YY_CURRENT_BUFFER_FAST->yy_n_chars = YY_G(yy_n_chars) = 0;
 
        else
                {
                        size_t num_to_read =
-                       YY_G(yy_current_buffer)->yy_buf_size - number_to_move - 1;
+                       YY_CURRENT_BUFFER_FAST->yy_buf_size - number_to_move - 1;
 
                while ( num_to_read <= 0 )
                        { /* Not enough room in the buffer - grow it. */
@@ -1260,7 +1283,7 @@ int yyFlexLexer::yy_get_next_buffer()
 #else
 
                        /* just a shorter name for the current buffer */
-                       YY_BUFFER_STATE b = YY_G(yy_current_buffer);
+                       YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
 
                        int yy_c_buf_p_offset =
                                (int) (YY_G(yy_c_buf_p) - b->yy_ch_buf);
@@ -1289,7 +1312,7 @@ int yyFlexLexer::yy_get_next_buffer()
 
                        YY_G(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
 
-                       num_to_read = YY_G(yy_current_buffer)->yy_buf_size -
+                       num_to_read = YY_CURRENT_BUFFER_FAST->yy_buf_size -
                                                number_to_move - 1;
 #endif
                        }
@@ -1298,10 +1321,10 @@ int yyFlexLexer::yy_get_next_buffer()
                        num_to_read = YY_READ_BUF_SIZE;
 
                /* Read in more data. */
-               YY_INPUT( (&YY_G(yy_current_buffer)->yy_ch_buf[number_to_move]),
+               YY_INPUT( (&YY_CURRENT_BUFFER_FAST->yy_ch_buf[number_to_move]),
                        YY_G(yy_n_chars), num_to_read );
 
-               YY_G(yy_current_buffer)->yy_n_chars = YY_G(yy_n_chars);
+               YY_CURRENT_BUFFER_FAST->yy_n_chars = YY_G(yy_n_chars);
                }
 
        if ( YY_G(yy_n_chars) == 0 )
@@ -1315,7 +1338,7 @@ int yyFlexLexer::yy_get_next_buffer()
                else
                        {
                        ret_val = EOB_ACT_LAST_MATCH;
-                       YY_G(yy_current_buffer)->yy_buffer_status =
+                       YY_CURRENT_BUFFER_FAST->yy_buffer_status =
                                YY_BUFFER_EOF_PENDING;
                        }
                }
@@ -1324,10 +1347,10 @@ int yyFlexLexer::yy_get_next_buffer()
                ret_val = EOB_ACT_CONTINUE_SCAN;
 
        YY_G(yy_n_chars) += number_to_move;
-       YY_G(yy_current_buffer)->yy_ch_buf[YY_G(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
-       YY_G(yy_current_buffer)->yy_ch_buf[YY_G(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+       YY_CURRENT_BUFFER_FAST->yy_ch_buf[YY_G(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+       YY_CURRENT_BUFFER_FAST->yy_ch_buf[YY_G(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
 
-       YY_G(yytext_ptr) = &YY_G(yy_current_buffer)->yy_ch_buf[0];
+       YY_G(yytext_ptr) = &YY_CURRENT_BUFFER_FAST->yy_ch_buf[0];
 
        return ret_val;
        }
@@ -1389,24 +1412,24 @@ int yyFlexLexer::yy_get_next_buffer()
        /* undo effects of setting up yytext */
        *yy_cp = YY_G(yy_hold_char);
 
-       if ( yy_cp < YY_G(yy_current_buffer)->yy_ch_buf + 2 )
+       if ( yy_cp < YY_CURRENT_BUFFER_FAST->yy_ch_buf + 2 )
                { /* need to shift things up to make room */
                /* +2 for EOB chars. */
                register int number_to_move = YY_G(yy_n_chars) + 2;
-               register char *dest = &YY_G(yy_current_buffer)->yy_ch_buf[
-                                       YY_G(yy_current_buffer)->yy_buf_size + 2];
+               register char *dest = &YY_CURRENT_BUFFER_FAST->yy_ch_buf[
+                                       YY_CURRENT_BUFFER_FAST->yy_buf_size + 2];
                register char *source =
-                               &YY_G(yy_current_buffer)->yy_ch_buf[number_to_move];
+                               &YY_CURRENT_BUFFER_FAST->yy_ch_buf[number_to_move];
 
-               while ( source > YY_G(yy_current_buffer)->yy_ch_buf )
+               while ( source > YY_CURRENT_BUFFER_FAST->yy_ch_buf )
                        *--dest = *--source;
 
                yy_cp += (int) (dest - source);
                yy_bp += (int) (dest - source);
-               YY_G(yy_current_buffer)->yy_n_chars =
-                       YY_G(yy_n_chars) = YY_G(yy_current_buffer)->yy_buf_size;
+               YY_CURRENT_BUFFER_FAST->yy_n_chars =
+                       YY_G(yy_n_chars) = YY_CURRENT_BUFFER_FAST->yy_buf_size;
 
-               if ( yy_cp < YY_G(yy_current_buffer)->yy_ch_buf + 2 )
+               if ( yy_cp < YY_CURRENT_BUFFER_FAST->yy_ch_buf + 2 )
                        YY_FATAL_ERROR( "flex scanner push-back overflow" );
                }
 
@@ -1450,7 +1473,7 @@ int yyFlexLexer::yy_get_next_buffer()
                 * If this occurs *before* the EOB characters, then it's a
                 * valid NUL; if not, then we've hit the end of the buffer.
                 */
-               if ( YY_G(yy_c_buf_p) < &YY_G(yy_current_buffer)->yy_ch_buf[YY_G(yy_n_chars)] )
+               if ( YY_G(yy_c_buf_p) < &YY_CURRENT_BUFFER_FAST->yy_ch_buf[YY_G(yy_n_chars)] )
                        /* This was really a NUL. */
                        *YY_G(yy_c_buf_p) = '\0';
 
@@ -1518,11 +1541,13 @@ int yyFlexLexer::yy_get_next_buffer()
     void yyFlexLexer::yyrestart( std::istream* input_file )
 %pop
        {
-       if ( ! YY_G(yy_current_buffer) )
-               YY_G(yy_current_buffer) =
+       if ( ! YY_CURRENT_BUFFER ){
+        yyensure_buffer_stack (YY_CALL_ONLY_ARG);
+               YY_CURRENT_BUFFER_FAST =
             yy_create_buffer( yyin, YY_BUF_SIZE YY_CALL_LAST_ARG);
+       }
 
-       yy_init_buffer( YY_G(yy_current_buffer), input_file YY_CALL_LAST_ARG);
+       yy_init_buffer( YY_CURRENT_BUFFER, input_file YY_CALL_LAST_ARG);
        yy_load_buffer_state( YY_CALL_ONLY_ARG );
        }
 
@@ -1533,18 +1558,24 @@ int yyFlexLexer::yy_get_next_buffer()
     void yyFlexLexer::yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
 %pop
        {
-       if ( YY_G(yy_current_buffer) == new_buffer )
+       /* TODO. We should be able to replace this entire function body
+        * with
+        *              yypop_buffer_state();
+        *              yypush_buffer_state(new_buffer);
+     */
+       yyensure_buffer_stack (YY_CALL_ONLY_ARG);
+       if ( YY_CURRENT_BUFFER == new_buffer )
                return;
 
-       if ( YY_G(yy_current_buffer) )
+       if ( YY_CURRENT_BUFFER )
                {
                /* Flush out information for old buffer. */
                *YY_G(yy_c_buf_p) = YY_G(yy_hold_char);
-               YY_G(yy_current_buffer)->yy_buf_pos = YY_G(yy_c_buf_p);
-               YY_G(yy_current_buffer)->yy_n_chars = YY_G(yy_n_chars);
+               YY_CURRENT_BUFFER_FAST->yy_buf_pos = YY_G(yy_c_buf_p);
+               YY_CURRENT_BUFFER_FAST->yy_n_chars = YY_G(yy_n_chars);
                }
 
-       YY_G(yy_current_buffer) = new_buffer;
+       YY_CURRENT_BUFFER_FAST = new_buffer;
        yy_load_buffer_state( YY_CALL_ONLY_ARG );
 
        /* We don't actually know whether we did this switch during
@@ -1563,9 +1594,9 @@ int yyFlexLexer::yy_get_next_buffer()
     void yyFlexLexer::yy_load_buffer_state()
 %pop
        {
-       YY_G(yy_n_chars) = YY_G(yy_current_buffer)->yy_n_chars;
-       YY_G(yytext_ptr) = YY_G(yy_c_buf_p) = YY_G(yy_current_buffer)->yy_buf_pos;
-       yyin = YY_G(yy_current_buffer)->yy_input_file;
+       YY_G(yy_n_chars) = YY_CURRENT_BUFFER_FAST->yy_n_chars;
+       YY_G(yytext_ptr) = YY_G(yy_c_buf_p) = YY_CURRENT_BUFFER_FAST->yy_buf_pos;
+       yyin = YY_CURRENT_BUFFER_FAST->yy_input_file;
        YY_G(yy_hold_char) = *YY_G(yy_c_buf_p);
        }
 
@@ -1608,8 +1639,8 @@ int yyFlexLexer::yy_get_next_buffer()
        if ( ! b )
                return;
 
-       if ( b == YY_G(yy_current_buffer) )
-               YY_G(yy_current_buffer) = (YY_BUFFER_STATE) 0;
+       if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+               YY_CURRENT_BUFFER_FAST = (YY_BUFFER_STATE) 0;
 
        if ( b->yy_is_our_buffer )
                yyfree( (void *) b->yy_ch_buf YY_CALL_LAST_ARG );
@@ -1688,10 +1719,111 @@ void yyFlexLexer::yy_init_buffer( YY_BUFFER_STATE b, std::istream* file )
        b->yy_at_bol = 1;
        b->yy_buffer_status = YY_BUFFER_NEW;
 
-       if ( b == YY_G(yy_current_buffer) )
+       if ( b == YY_CURRENT_BUFFER )
                yy_load_buffer_state( YY_CALL_ONLY_ARG );
        }
 
+%push
+%c-only
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ */
+void yypush_buffer_state YYFARGS1(YY_BUFFER_STATE,new_buffer)
+{
+       if (new_buffer == NULL)
+               return;
+
+       yyensure_buffer_stack(YY_CALL_ONLY_ARG);
+
+       /* This block is copied from yy_switch_to_buffer. */
+       if ( YY_CURRENT_BUFFER )
+               {
+               /* Flush out information for old buffer. */
+               *YY_G(yy_c_buf_p) = YY_G(yy_hold_char);
+               YY_CURRENT_BUFFER_FAST->yy_buf_pos = YY_G(yy_c_buf_p);
+               YY_CURRENT_BUFFER_FAST->yy_n_chars = YY_G(yy_n_chars);
+               }
+
+       /* Only push if top exists. Otherwise, replace top. */
+       if (YY_CURRENT_BUFFER)
+               YY_G(yy_buffer_stack_top)++;
+       YY_CURRENT_BUFFER_FAST = new_buffer;
+
+       /* copied from yy_switch_to_buffer. */
+       yy_load_buffer_state( YY_CALL_ONLY_ARG );
+       YY_G(yy_did_buffer_switch_on_eof) = 1;
+}
+%pop
+
+%push
+%c-only
+/** Removes and DELETES the top of the stack, if present.
+ *  The next element becomes the new top, if present.
+ */
+void yypop_buffer_state YYFARGS0(void)
+{
+       if (!YY_CURRENT_BUFFER)
+               return;
+
+       yy_delete_buffer(YY_CURRENT_BUFFER YY_CALL_LAST_ARG);
+       YY_CURRENT_BUFFER_FAST = NULL;
+       if (YY_G(yy_buffer_stack_top) > 0)
+               --YY_G(yy_buffer_stack_top);
+
+       if (YY_CURRENT_BUFFER) {
+               yy_load_buffer_state( YY_CALL_ONLY_ARG );
+               YY_G(yy_did_buffer_switch_on_eof) = 1;
+       }
+}
+%pop
+
+%push
+%c-only
+/** Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+void yyensure_buffer_stack YYFARGS0(void)
+{
+       int num_to_alloc;
+
+       if (!YY_G(yy_buffer_stack)) {
+
+               /* First allocation is just for 2 elements, since we don't know if this
+                * scanner will even need a stack. We use 2 instead of 1 to avoid an
+                * immediate realloc on the next call.
+         */
+               num_to_alloc = 1;
+               YY_G(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+                                                               (num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               YY_CALL_LAST_ARG);
+               
+               memset(YY_G(yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+                               
+               YY_G(yy_buffer_stack_max) = num_to_alloc;
+               YY_G(yy_buffer_stack_top) = 0;
+               return;
+       }
+
+       if (YY_G(yy_buffer_stack_top) >= (YY_G(yy_buffer_stack_max)) - 1){
+
+               /* Increase the buffer to prepare for a possible push. */
+               int grow_size = 8 /* arbitrary grow size */;
+
+               num_to_alloc = YY_G(yy_buffer_stack_max) + grow_size;
+               YY_G(yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+                                                               (YY_G(yy_buffer_stack),
+                                                               num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               YY_CALL_LAST_ARG);
+
+               /* zero only the new slots.*/
+               memset(YY_G(yy_buffer_stack) + YY_G(yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+               YY_G(yy_buffer_stack_max) = num_to_alloc;
+       }
+}
+%pop
+
+
 
 #ifndef YY_NO_SCAN_BUFFER
 %push
@@ -2020,7 +2152,9 @@ static int yy_init_globals YYFARGS0(void)
 #ifdef YY_USE_LINENO
     yylineno =  1;
 #endif
-    YY_G(yy_current_buffer) = 0;
+    YY_G(yy_buffer_stack) = 0;
+    YY_G(yy_buffer_stack_top) = 0;
+    YY_G(yy_buffer_stack_max) = 0;
     YY_G(yy_c_buf_p) = (char *) 0;
     YY_G(yy_init) = 1;
     YY_G(yy_start) = 0;
@@ -2093,16 +2227,23 @@ int yylex_init( ptr_yy_globals )
 /* yylex_destroy is for both reentrant and non-reentrant scanners. */
 int yylex_destroy  YYFARGS0(void)
 {
-    /* Destroy the current (main) buffer. */
-    yy_delete_buffer( YY_G(yy_current_buffer) YY_CALL_LAST_ARG );
-    YY_G(yy_current_buffer) = NULL;
+       int i;
+
+    /* Pop the buffer stack, destroying each element. */
+       while(YY_CURRENT_BUFFER){
+               yy_delete_buffer( YY_CURRENT_BUFFER YY_CALL_LAST_ARG );
+               YY_CURRENT_BUFFER_FAST = NULL;
+               yypop_buffer_state(YY_CALL_ONLY_ARG);
+       }
+
+       /* Destroy the stack itself. */
+       yyfree(YY_G(yy_buffer_stack) YY_CALL_LAST_ARG);
+       YY_G(yy_buffer_stack) = NULL;
 
 #if defined(YY_STACK_USED) || defined(YY_REENTRANT)
     /* Destroy the start condition stack. */
-    if (YY_G(yy_start_stack) ){
         yyfree( YY_G(yy_start_stack) YY_CALL_LAST_ARG );
         YY_G(yy_start_stack) = NULL;
-    }
 #endif
 
 #ifdef YY_USES_REJECT
diff --git a/gen.c b/gen.c
index 3532af2dc6670483596870763f9f1eef812bbdec..eb9acd80951dd6b527f55bda70704973b5512f61 100644 (file)
--- a/gen.c
+++ b/gen.c
@@ -1898,7 +1898,7 @@ void make_tables ()
                }
 
                else {
-                       outn ("\tif ( YY_G(yy_current_buffer)->yy_is_interactive ) \\");
+                       outn ("\tif ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \\");
                        outn ("\t\t{ \\");
                        outn ("\t\tint c = '*'; \\");
                        outn ("\t\tsize_t n; \\");
@@ -1935,7 +1935,7 @@ void make_tables ()
        if (bol_needed) {
                indent_puts ("if ( yyleng > 0 ) \\");
                indent_up ();
-               indent_puts ("YY_G(yy_current_buffer)->yy_at_bol = \\");
+               indent_puts ("YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \\");
                indent_puts ("\t\t(yytext[yyleng - 1] == '\\n'); \\");
                indent_down ();
        }
@@ -2149,10 +2149,10 @@ void make_tables ()
        /* Update BOL and yylineno inside of input(). */
        if (bol_needed) {
                indent_puts
-                       ("YY_G(yy_current_buffer)->yy_at_bol = (c == '\\n');");
+                       ("YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\\n');");
                if (do_yylineno) {
                        indent_puts
-                               ("if ( YY_G(yy_current_buffer)->yy_at_bol )");
+                               ("if ( YY_CURRENT_BUFFER_LVALUE->yy_at_bol )");
                        indent_up ();
                        indent_puts ("++yylineno;");
                        indent_down ();
diff --git a/main.c b/main.c
index 8ae5b83a9ecdaa6ac3a9daebc90909a9850ca21f..9df72696b8d9af146d5f51e80fb921653d4f53a7 100644 (file)
--- a/main.c
+++ b/main.c
@@ -405,6 +405,9 @@ void check_options ()
                        GEN_PREFIX ("_flush_buffer");
                        GEN_PREFIX ("_load_buffer_state");
                        GEN_PREFIX ("_switch_to_buffer");
+                       GEN_PREFIX ("push_buffer_state");
+                       GEN_PREFIX ("pop_buffer_state");
+                       GEN_PREFIX ("ensure_buffer_stack");
                        GEN_PREFIX ("lex");
                        GEN_PREFIX ("restart");
                        GEN_PREFIX ("lex_init");
@@ -753,6 +756,9 @@ void flexend (exit_status)
                 "yy_set_bol",
                 "yy_set_interactive",
                 "yy_switch_to_buffer",
+                               "yypush_buffer_state",
+                               "yypop_buffer_state",
+                               "yyensure_buffer_stack",
                 "yyalloc",
                 "yyconst",
                 "yyextra",