On Fri, 15 Dec 2006, Joel E. Denny wrote:

> 3. Why don't we "Initialize the default location before parsing starts" 
> for push parsers?  Also, %initial-action does not play well with the 
> location passed to yypush_parse.  If @$ is set in %initial-action, @$ 
> overwrites the location of every token.  %initial-action ought to be 
> performed only the first time yypush_parse is called and each time the 
> parse starts over; that would be consistent with how it works for yyparse.  
> Moreover, the location passed to yypush_parse ought to be assigned to 
> yylloc only when it's time to read a token (where YYLEX is invoked).  
> Otherwise, @$ in %initial-action and it clobber each other.  I'm guessing 
> $$ has the same problem and solution.  I haven't fixed any of this.

Attached is a rather large patch that I believe fixes all the above... and 
does a lot more.  I have not yet committed it.

Here's a short description of this patch:

For push mode, I've defined a yyparse that effectively wraps yypush_parse.  
Push parsers can now be either pure (you must declare %pure-parser) or 
impure.  Now, if you trick the test suite into using push.c and 
effectively declaring %push-parser wherever it currently uses yacc.c, the 
entire test suite still passes make maintainer-check... except for some 
push-specific debugging output.

Here's a long description of this patch:

1. Don't read the push.c section of this patch.  It should be much more 
informative to apply the patch and then do: diff -u yacc.c push.c

2. yynerrs is back for push parsers.  Yes, I know we don't care, but the 
only effect I see in getting rid of it is more M4 differences between push 
and pull mode.

3. Impure push parsers are now possible, and you must declare %pure-parser 
with %push-parser to get pure push parsers instead.  Yes, I know we don't 
care about impure push parsers, but I have two reasons for supporting 
them:

a. Most importantly, it let's me run the impure pull tests from the test 
suite to make sure push-mode's yyparse works correctly.

b. It helps prove the point that push/pull is an almost completely 
orthogonal dimension from pure/impure.  As well as I can remember, there 
are only two places where these two dimensions actually interact 
noticeably: (1) yynerrs placement and (2) collisions between yylex and the 
first yypush_parse invocation since they both write to the global yychar, 
yylval, and yylloc.  Both places were easy to resolve.  Neither place 
would be relevant if neither yynerrs nor impurity were supported for push 
parsers.

4. Using M4 and #define's (maybe M4 would be better in both places... 
maybe later... maybe not), I've eliminated a lot of repeated code.

5. I've been careful to make repeated calls to yypush_parse ultimately 
behave like yyparse in pull mode.  This solves at least the 
%initial-action problem quoted at the top of this email.

6. Akim wanted there to be a yyparse in push mode.  Bob and Paul have 
noticed that this would create a dependence on yylex even when the user 
isn't interested in using yyparse.  I've defined yyparse as a macro to 
solve this:

  #define yyparse() yypull_parse (NULL, &yylex)

I've defined yypull_parse as the function wrapping yypush_parse.  This 
way, yylex is never referenced unless the user invokes yyparse.  However, 
the user must either define yyparse correctly himself or #include the 
Bison-generated header to get it.  For this reason, I had to make a couple 
of tweaks to a few test cases in the test suite to get them to pass under 
push mode.

The first argument to yypull_parse is a yypstate.  Thus, the user can now 
combine yypush_parse and yypull_parse.  For example, the user can 
yypush_parse a token to select a sub-grammar and then yypull_parse the 
input stream.

Passing NULL for the yypstate argument instructs yypull_parse to construct 
and destroy a yypstate internally.  This allows us to maintain the usual 
prototype of yyparse as Akim wanted... of course, it's actually a #define 
now instead of a function... oh well.

7. The test suite now passes in pull mode.  To see what I mean, do this:

a. Apply this patch and recompile Bison.

b. cp push.c yacc.c

c. In yacc.c, look for this line:

  m4_include(b4_pkgdatadir/[c.m4])

Add this line afterwards:

  m4_define([b4_push_if], [$1])

c. Now look for this line in yacc.c:

   YYDPRINTF ((stderr, "Return for a new token:\n"));

Delete it.

d. Run make maintainer-check.

8. Here are a few issues I have not yet explored:

a. Whether more members can be moved from yypstate to yyparse.

b. For yacc.c, you can invoke yyparse multiple times.  For push.c's push 
mode, I haven't thought this through.  yypush_parse should probably set 
yyps->yynew = 1 whenever it returns with a parse error or success.

c. I'm not sure why yypstate_new needs to set yyresult = -1.

Ok to commit this patch?
Index: ChangeLog
===================================================================
RCS file: /sources/bison/bison/ChangeLog,v
retrieving revision 1.1625
diff -p -u -r1.1625 ChangeLog
--- ChangeLog   17 Dec 2006 01:33:31 -0000      1.1625
+++ ChangeLog   18 Dec 2006 08:12:19 -0000
@@ -1,3 +1,32 @@
+2006-12-18  Joel E. Denny  <[EMAIL PROTECTED]>
+
+       Give push mode a yyparse wrapper, make push mode support impure mode,
+       and fix push mode well enough so that it passes the entire test suite
+       when it is substituted for yacc.c pull mode.  The following description
+       leaves out a lot of details that are explained at
+       <http://www.example.com/url/coming/soon>.
+       * data/push.c: Too much work to completely describe here.
+       (yypull_parse): New function wrapping yypush_parse.
+       (yyparse): New #define wrapping yypull_parse.
+       * src/parse-gram.y (prologue_declaration): Don't set pure_parser for
+       %push-parser since push mode now supports impure mode.
+       * tests/calc.at (_AT_DATA_CALC_Y): Call yyparse even when %push-parser
+       is declared.
+       (Simple LALR(1) Calculator): Always set %pure-parser along with
+       %push-parser since this test case was designed for pure push parsers.
+       * tests/headers.at (export YYLTYPE): Make yylex global.  For pull mode,
+       prototype yylex in the module that calls yyparse, and don't prototype
+       yyparse there.  Otherwise, the yyparse expansion in pull mode won't
+       compile.
+       * tests/input.at (Torturing the Scanner): Likewise.
+       * tests/local.at (AT_PURE_OR_PUSH_IF): Remove unused.
+       (AT_YACC_OR_PUSH_IF): New.
+       (AT_YYERROR_SEES_LOC_IF): Fix enough that the test suite passes, but
+       add a note that it's still wrong for some cases (as it has been for a
+       while).
+       (AT_PURE_LEX_IF): Use AT_PURE_IF instead of AT_PURE_OR_PUSH_IF since
+       %push-parser no longer implies %pure-parser.
+
 2006-12-16  Joel E. Denny  <[EMAIL PROTECTED]>
 
        Make %push-parser imply %pure-parser.  This fixes several bugs; see
Index: data/push.c
===================================================================
RCS file: /sources/bison/bison/data/push.c,v
retrieving revision 1.17
diff -p -u -r1.17 push.c
--- data/push.c 17 Dec 2006 01:33:31 -0000      1.17
+++ data/push.c 18 Dec 2006 08:12:19 -0000
@@ -63,6 +63,31 @@ b4_locations_if([, [[YYLTYPE *], [&yyllo
 m4_ifdef([b4_lex_param], b4_lex_param)))
 
 
+# b4_generate_macro_args([A], [B], [C], ...)
+# ---------------------------------------------------
+# Generate a comma-delimited list whose size is equal to the number of input
+# arguments and whose form is:
+#
+#   YYARG1, YYARG2, YYARG3, ...
+#
+# No argument should be the empty string except A in the special invocation
+# b4_generate_macro_args(), which generates an empty string.
+m4_define([b4_generate_macro_args],
+[m4_if([$1], [], [], [$#], [1], [[YYARG1]],
+       [b4_generate_macro_args(m4_shift($@)), [YYARG$#]])])
+
+
+# b4_parenthesize([A], [B], [C], ...)
+# ---------------------------------------------------
+# Convert arguments to the form:
+#
+#   (A), (B), (C), ...
+#
+# No argument should be the empty string except A in the special invocation
+# b4_parenthesize(), which generates an empty string.
+m4_define([b4_parenthesize],
+[m4_if([$1], [], [], [$#], [1], [[($1)]],
+       [($1), b4_parenthesize(m4_shift($@))])])
 
 ## ------------ ##
 ## Data Types.  ##
@@ -152,6 +177,7 @@ b4_copyright([Skeleton implementation fo
 m4_if(b4_prefix, [yy], [],
 [/* Substitute the variable and function names.  */
 ]b4_push_if([#define yypush_parse b4_prefix[]push_parse
+#define yypull_parse b4_prefix[]pull_parse
 #define yypstate_new b4_prefix[]pstate_new
 #define yypstate_delete b4_prefix[]pstate_delete
 #define yypstate b4_prefix[]pstate],
@@ -217,6 +243,27 @@ typedef struct YYLTYPE
 # define YYLTYPE_IS_TRIVIAL 1
 #endif])
 
+b4_push_if([[
+struct yypstate;
+#ifndef YYPSTATE_DECLS
+# define YYPSTATE_DECLS
+typedef struct yypstate yypstate;
+enum { YYPUSH_MORE = 4 };
+# define yyparse(]b4_generate_macro_args(b4_parse_param))[ yypull_parse (0, 
&yylex]m4_ifset([b4_parse_param], [, 
b4_parenthesize(b4_generate_macro_args(b4_parse_param))])[)
+#endif
+]b4_c_function_decl([yypstate_new], [yypstate *], [[void], []])
+b4_c_function_decl([yypstate_delete], [void], [[yypstate *yyps], [yyps]])
+b4_c_function_decl([yypush_parse], [int],
+   [[yypstate *yyps], [yyps]]b4_pure_if([,
+   [[int yypushed_char], [yypushed_char]],
+   [[YYSTYPE const *yypushed_val], [yypushed_val]]b4_locations_if([,
+   [[YYLTYPE const *yypushed_loc], 
[yypushed_loc]]])])m4_ifset([b4_parse_param],
+   [, b4_parse_param]))
+b4_c_function_decl([yypull_parse], [int],
+   [[yypstate *yyps], [yyps]],
+   [[int (*yylexp)(b4_c_ansi_formals(b4_lex_param))], 
[yylexp]]m4_ifset([b4_parse_param], [,
+   b4_parse_param]))
+])
 m4_ifdef([b4_provides],
 [[/* Copy the %provides blocks.  */
 ]b4_user_provides])[]dnl
@@ -373,9 +420,9 @@ void free (void *); /* INFRINGES ON USER
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
 {
-  yytype_int16 yyss;
-  YYSTYPE yyvs;
-  ]b4_locations_if([  YYLTYPE yyls;
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+  ]b4_locations_if([  YYLTYPE yyls_alloc;
 ])dnl
 [};
 
@@ -419,8 +466,8 @@ union yyalloc
     do                                                                 \
       {                                                                        
\
        YYSIZE_T yynewbytes;                                            \
-       YYCOPY (&yyptr->Stack, Stack, yysize);                          \
-       Stack = &yyptr->Stack;                                          \
+       YYCOPY (&yyptr->Stack##_alloc, Stack, yysize);                  \
+       Stack = &yyptr->Stack##_alloc;                                  \
        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
        yyptr += yynewbytes / sizeof (*yyptr);                          \
       }                                                                        
\
@@ -961,53 +1008,37 @@ yysyntax_error (char *yyresult, int yyst
 
 /* Prevent warnings from -Wmissing-prototypes.  */
 
-]b4_push_if([
-struct yypstate;
-typedef struct yypstate yypstate;
-enum { YYPUSH_MORE = 4 };
-]b4_c_function_decl([yypstate_new], [yypstate *], [[void], []])[
-]b4_c_function_decl([yypstate_delete], [void], [[yypstate *yyps], [yyps]])[
-]b4_c_function_decl([yypush_parse], [int],
-   [[yypstate *yyps], [yyps]],
-   [[int yynchar], [yynchar]],
-   [[YYSTYPE const *yynlval], [yynlval]]
-   b4_locations_if([,[[YYLTYPE const *yynlloc], [yynlloc]]])
-   m4_ifset([b4_parse_param], [, b4_parse_param]))[
-],[#ifdef YYPARSE_PARAM
+]b4_push_if([],
+[[#ifdef YYPARSE_PARAM
 ]b4_c_function_decl([yyparse], [int],
    [[void *YYPARSE_PARAM], [YYPARSE_PARAM]])[
 #else /* ! YYPARSE_PARAM */
 ]b4_c_function_decl([yyparse], [int], b4_parse_param)[
-#endif /* ! YYPARSE_PARAM */])[
+#endif /* ! YYPARSE_PARAM */]])
 
-]m4_divert_push([KILL])# ======================== M4 code.
-# b4_declare_parser_variables
-# ---------------------------
+m4_divert_push([KILL])# ======================== M4 code.
+# b4_declare_parser_interface_variables
+# -------------------------------------
 # Declare the variables that are global, or local to YYPARSE if
 # pure-parser.
-m4_define([b4_declare_parser_variables],
-[/* The lookahead symbol.  */
+m4_define([b4_declare_parser_interface_variables],
+[[/* The lookahead symbol.  */
 int yychar;
 
 /* The semantic value of the lookahead symbol.  */
 YYSTYPE yylval;
-
-/* Number of syntax errors so far.  */
-]b4_push_if([],[
-int yynerrs;])[b4_locations_if([
+]b4_locations_if([[
 /* Location data for the lookahead symbol.  */
-YYLTYPE yylloc;])
-])
-
-m4_define([b4_yyssa],b4_push_if([yyps->yyssa],[yyssa]))
-m4_define([b4_yyerror_range],b4_push_if([yyps->yyerror_range],[yyerror_range]))
+YYLTYPE yylloc;
+]])b4_pure_if([], [[
+/* Number of syntax errors so far.  */
+int yynerrs;
+]])])
 
-# b4_declare_yyparse_variables
-# ----------------------------
-# Declare all the variables that are needed local to YYPARSE
-m4_define([b4_declare_yyparse_variables],
-[[struct yypstate
-  {
+m4_define([b4_declare_parser_state_variables],
+[b4_pure_if([[    /* Number of syntax errors so far.  */
+    int yynerrs;
+]])[
     int yystate;
     int yyn;
     int yyresult;
@@ -1032,45 +1063,89 @@ m4_define([b4_declare_yyparse_variables]
     /* The semantic value stack.  */
     YYSTYPE yyvsa[YYINITDEPTH];
     YYSTYPE *yyvs;
-    YYSTYPE *yyvsp;]]b4_locations_if([[[
-    /* The location stack.  */
+    YYSTYPE *yyvsp;
+
+]b4_locations_if(
+[[    /* The location stack.  */
     YYLTYPE yylsa[YYINITDEPTH];
     YYLTYPE *yyls;
     YYLTYPE *yylsp;
     /* The locations where the error started and ended.  */
-    YYLTYPE yyerror_range[2];]]])[
+    YYLTYPE yyerror_range[2];]])[
+
     YYSIZE_T yystacksize;
+
     /* The variables used to return semantic value and location from the
        action routines.  */
     YYSTYPE yyval;
+]b4_locations_if([[    YYLTYPE yyloc;
+]])])
+
+m4_divert_pop([KILL])dnl# ====================== End of M4 code.
+
+b4_pure_if([], [b4_declare_parser_interface_variables])
+
+b4_push_if(
+[[struct yypstate
+  {
+    ]b4_declare_parser_state_variables[
     /* Used to determine if this is the first time this instance has
        been used.  */
-    int yynew;]b4_locations_if([YYLTYPE yyloc;])[
+    int yynew;
   };
 
+]b4_c_function_def([yypull_parse], [int],
+   [[yypstate *yyps], [yyps]],
+   [[int (*yylexp)(b4_c_ansi_formals(b4_lex_param))], 
[yylexp]]m4_ifset([b4_parse_param],
+   [, b4_parse_param]))[
+{
+  int yystatus;
+  yypstate *yyps_local;
+]b4_pure_if([[  int yychar;
+  YYSTYPE yylval;
+]b4_locations_if([[  YYLTYPE yylloc;
+]])])[
+  if (yyps == 0)
+     yyps_local = yypstate_new ();
+   else
+     yyps_local = yyps;
+   do {
+     yychar = ]b4_c_function_call([yylexp], [int], b4_lex_param)[;
+     yystatus =
+       yypush_parse (yyps_local]b4_pure_if([[, yychar, 
&yylval]b4_locations_if([[, &yylloc]])])m4_ifset([b4_parse_param], [, 
b4_c_args(b4_parse_param)])[);
+  } while (yystatus == YYPUSH_MORE);
+  if (yyps == 0)
+    yypstate_delete (yyps_local);
+  return yystatus;
+}
+
+]b4_pure_if([[#define ]b4_prefix[nerrs yyps->]b4_prefix[nerrs]])[
+#define yystate yyps->yystate
+#define yyn yyps->yyn
+#define yyresult yyps->yyresult
+#define yyerrstatus yyps->yyerrstatus
+#define yytoken yyps->yytoken
+#define yyssa yyps->yyssa
+#define yyss yyps->yyss
+#define yyssp yyps->yyssp
+#define yyvsa yyps->yyvsa
+#define yyvs yyps->yyvs
+#define yyvsp yyps->yyvsp
+]b4_locations_if([[#define yylsa yyps->yylsa
+#define yyls yyps->yyls
+#define yylsp yyps->yylsp
+#define yyerror_range yyps->yyerror_range
+]])[#define yystacksize yyps->yystacksize
+#define yyval yyps->yyval
+]b4_locations_if([[#define yyloc yyps->yyloc
+]])[
+
 /* Initialize the parser data structure.  */
 ]b4_c_function_def([yypstate_new], [yypstate *])[
 {
   yypstate *yyps = (yypstate *) malloc (sizeof *yyps);
-  yyps->yystate = 0;
-  yyps->yyresult = -1;
-  yyps->yyerrstatus = 0;
-  yyps->yytoken = 0;
-
-  yyps->yyss = yyps->yyssa;
-  yyps->yyvs = yyps->yyvsa;
-
-  ]b4_locations_if([
-    yyps->yyls = yyps->yylsa;])[
-  yyps->yystacksize = YYINITDEPTH;
-
-  yyps->yyssp = yyps->yyss;
-  yyps->yyvsp = yyps->yyvs;
-
+  yyresult = -1;
   yyps->yynew = 1;
-
-]b4_locations_if([  yyps->yylsp = yyps->yyls;])[
-
   return yyps;
 }
 
@@ -1079,37 +1154,34 @@ m4_define([b4_declare_yyparse_variables]
 {
   free (yyps);
 }
-])
-m4_divert_pop([KILL])dnl# ====================== End of M4 code.
-
-b4_pure_if([], [b4_declare_parser_variables])
-
-b4_push_if([b4_declare_yyparse_variables])
+]])
 
 /*-------------------------.
 | yyparse or yypush_parse.  |
 `-------------------------*/
 
 b4_push_if([
-b4_c_function_def([yypush_parse], [int], [[yypstate *yyps], [yyps]], 
-                  [[int yynchar], [yynchar]],
-                  [[YYSTYPE const *yynlval], [yynlval]]
-                 b4_locations_if([,[[YYLTYPE const *yynlloc], [yynlloc]]])
-                  m4_ifset([b4_parse_param], [, b4_parse_param]))],[
+b4_c_function_def([yypush_parse], [int],
+                  [[yypstate *yyps], [yyps]]b4_pure_if([,
+                  [[int yypushed_char], [yypushed_char]],
+                  [[YYSTYPE const *yypushed_val], 
[yypushed_val]]b4_locations_if([,
+                  [[YYLTYPE const *yypushed_loc], 
[yypushed_loc]]])])m4_ifset([b4_parse_param],
+                  [, b4_parse_param]))],[
 #ifdef YYPARSE_PARAM
 b4_c_function_def([yyparse], [int], [[void *YYPARSE_PARAM], [YYPARSE_PARAM]])
 #else /* ! YYPARSE_PARAM */
 b4_c_function_def([yyparse], [int], b4_parse_param)
-#endif])
-{[
-  ]b4_pure_if([b4_declare_parser_variables])[
-  int yystate;
-  int yyn;
-  int yyresult;
-  /* Number of tokens to shift before error messages enabled.  */
-  int yyerrstatus;
-  /* Lookahead token as an internal (translated) token number.  */
-  int yytoken = 0;
+#endif])[
+{
+  ]b4_pure_if([b4_declare_parser_interface_variables])
+  b4_push_if([b4_pure_if([], [[  int yypushed_char = yychar;
+  YYSTYPE yypushed_val_local = yylval;
+  YYSTYPE *yypushed_val = &yylval;
+  ]b4_locations_if([[YYLTYPE yypushed_loc_local = yylloc;
+  YYLTYPE *yypushed_loc = &yylloc;
+]])])],
+  [b4_declare_parser_state_variables])[
+
 #if YYERROR_VERBOSE
   /* Buffer for error messages, and its allocated size.  */
   char yymsgbuf[128];
@@ -1117,110 +1189,54 @@ b4_c_function_def([yyparse], [int], b4_p
   YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
 #endif
 
-  /* Three stacks and their tools:
-     `yyss': related to states,
-     `yyvs': related to semantic values,
-     `yyls': related to locations.
-
-     Refer to the stacks thru separate pointers, to allow yyoverflow
-     to reallocate them elsewhere.  */
-
-  /* The state stack.  */
-  yytype_int16 yyssa[YYINITDEPTH];
-  yytype_int16 *yyss = yyssa;
-  yytype_int16 *yyssp;
-
-  /* The semantic value stack.  */
-  YYSTYPE yyvsa[YYINITDEPTH];
-  YYSTYPE *yyvs = yyvsa;
-  YYSTYPE *yyvsp;
-
-]b4_locations_if(
-[[  /* The location stack.  */
-  YYLTYPE yylsa[YYINITDEPTH];
-  YYLTYPE *yyls = yylsa;
-  YYLTYPE *yylsp;
-  /* The locations where the error started and ended.  */
-  ]b4_push_if([],[YYLTYPE yyerror_range[[2]]])[;
-  ]])[
-
 #define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N)]b4_locations_if([, yylsp 
-= (N)])[)
 
-  YYSIZE_T yystacksize = YYINITDEPTH;
-
-  /* The variables used to return semantic value and location from the
-     action routines.  */
-  YYSTYPE yyval;
-]b4_locations_if([  YYLTYPE yyloc;])[
-
   /* The number of symbols on the RHS of the reduced rule.
      Keep to zero when no symbol should be popped.  */
   int yylen = 0;
+]b4_push_if([[
+  if (!yyps->yynew)
+    goto yyread_pushed_token;
+]])[
+  yytoken = 0;
+  yyss = yyssa;
+  yyvs = yyvsa;
+]b4_locations_if([[  yyls = yylsa;
+]])[
+  yystacksize = YYINITDEPTH;
 
   YYDPRINTF ((stderr, "Starting parse\n"));
 
   yystate = 0;
   yyerrstatus = 0;
-]b4_push_if([  yychar = yynchar;
-  if (yynlval)
-    yylval = *yynlval;
-]b4_locations_if([  if (yynlloc)
-     yylloc = *yynlloc;])[],[yynerrs = 0;
-  yychar = YYEMPTY; /* Cause a token to be read.  */])[
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
 
   /* Initialize stack pointers.
      Waste one element of value and location stack
      so that they stay on the same level as the state stack.
      The wasted elements are never initialized.  */
-
   yyssp = yyss;
   yyvsp = yyvs;
 ]b4_locations_if([[  yylsp = yyls;
-]b4_push_if([],[
 #if YYLTYPE_IS_TRIVIAL
   /* Initialize the default location before parsing starts.  */
   yylloc.first_line   = yylloc.last_line   = ]b4_location_initial_line[;
   yylloc.first_column = yylloc.last_column = ]b4_location_initial_column[;
-#endif])[
+#endif
 ]])
 m4_ifdef([b4_initial_action], [
 m4_pushdef([b4_at_dollar],     [m4_define([b4_at_dollar_used])yylloc])dnl
 m4_pushdef([b4_dollar_dollar], [m4_define([b4_dollar_dollar_used])yylval])dnl
   /* User initialization code.  */
-b4_user_initial_action
+  b4_user_initial_action
 m4_popdef([b4_dollar_dollar])dnl
 m4_popdef([b4_at_dollar])])dnl
 m4_ifdef([b4_dollar_dollar_used],[[  yyvsp[0] = yylval;
 ]])dnl
 m4_ifdef([b4_at_dollar_used], [[  yylsp[0] = yylloc;
 ]])dnl
-[  ]b4_push_if([
-       /* Initialize the locals to the current context. */
-       yystate = yyps->yystate;
-       yyn = yyps->yyn;
-       yyresult = yyps->yyresult;
-       yyerrstatus = yyps->yyerrstatus;
-       yytoken = yyps->yytoken;
-
-       yyss = yyps->yyss;
-       yyssp = yyps->yyssp;
-
-       yyvs = yyps->yyvs;
-       yyvsp = yyps->yyvsp;
-
-       ]b4_locations_if([[  /* The location stack.  */
-       yyls = yyps->yyls;
-       yylsp = yyps->yylsp;]])[
-
-       yystacksize = yyps->yystacksize;
-       yyval = yyps->yyval;
-       ]b4_locations_if([yyloc = yyps->yyloc;])[
-      if (yyps->yynew == 0)
-      {
-       goto gottoken;
-      }
-      yyps->yynew= 0;])[
-  goto yysetstate;
+[  goto yysetstate;
 
 /*------------------------------------------------------------.
 | yynewstate -- Push a new state, which is found in yystate.  |
@@ -1281,7 +1297,7 @@ m4_ifdef([b4_at_dollar_used], [[  yylsp[
        YYSTACK_RELOCATE (yyvs);
 ]b4_locations_if([     YYSTACK_RELOCATE (yyls);])[
 #  undef YYSTACK_RELOCATE
-       if (yyss1 != ]b4_yyssa[)
+       if (yyss1 != yyssa)
          YYSTACK_FREE (yyss1);
       }
 # endif
@@ -1323,32 +1339,29 @@ yybackup:
   /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
   if (yychar == YYEMPTY)
     {
-      ]b4_push_if([
-       YYDPRINTF ((stderr, "Return for a new token:\n"));
-       yyresult = YYPUSH_MORE;
-       /* Initialize the locals to the current context. */
-       yyps->yystate = yystate;
-       yyps->yyn = yyn;
-       yyps->yyerrstatus = yyerrstatus;
-       yyps->yytoken = yytoken;
-
-       yyps->yyss = yyss;
-       yyps->yyssp = yyssp;
-
-       yyps->yyvs = yyvs;
-       yyps->yyvsp = yyvsp;
-
-       ]b4_locations_if([[  /* The location stack.  */
-       yyps->yyls = yyls;
-       yyps->yylsp = yylsp;]])[
-
-       yyps->yystacksize = yystacksize;
-       yyps->yyval = yyval;
-       ]b4_locations_if([yyps->yyloc = yyloc;])[
-       goto yypushreturn;
-gottoken:])[
-      YYDPRINTF ((stderr, "Reading a token: "));
-      ]b4_push_if([], [yychar = YYLEX;])[
+]b4_push_if([[      if (!yyps->yynew)
+        {
+          YYDPRINTF ((stderr, "Return for a new token:\n"));
+          yyresult = YYPUSH_MORE;
+          goto yypushreturn;
+        }
+      yyps->yynew = 0;
+      ]b4_pure_if([], [[
+      /* Restoring the pushed token is only necessary for the first
+         yypush_parse invocation since subsequent invocations don't overwrite
+         it before jumping to yyread_pushed_token.  */
+      yychar = yypushed_char;
+      yylval = yypushed_val_local;
+      ]b4_locations_if([[yylloc = yypushed_loc_local;
+]])])[
+yyread_pushed_token:
+]])[      YYDPRINTF ((stderr, "Reading a token: "));
+]b4_push_if([[      yychar = yypushed_char;
+      if (yypushed_val)
+        yylval = *yypushed_val;
+]b4_locations_if([[      if (yypushed_loc)
+        yylloc = *yypushed_loc;]])],
+[[      yychar = YYLEX;]])[
     }
 
   if (yychar <= YYEOF)
@@ -1460,7 +1473,7 @@ yyerrlab:
   /* If not already recovering from an error, report this error.  */
   if (!yyerrstatus)
     {
-]b4_push_if([],[ ++yynerrs;])[
+      ++yynerrs;
 #if ! YYERROR_VERBOSE
       yyerror (]b4_yyerror_args[YY_("syntax error"));
 #else
@@ -1498,7 +1511,7 @@ yyerrlab:
 #endif
     }
 
-]b4_locations_if([[  ]b4_yyerror_range[[0] = yylloc;]])[
+]b4_locations_if([[  yyerror_range[0] = yylloc;]])[
 
   if (yyerrstatus == 3)
     {
@@ -1535,7 +1548,7 @@ yyerrorlab:
   if (/*CONSTCOND*/ 0)
      goto yyerrorlab;
 
-]b4_locations_if([[  ]b4_yyerror_range[[0] = yylsp[1-yylen];
+]b4_locations_if([[  yyerror_range[0] = yylsp[1-yylen];
 ]])[  /* Do not reclaim the symbols of the rule which action triggered
      this YYERROR.  */
   YYPOPSTACK (yylen);
@@ -1569,7 +1582,7 @@ yyerrlab1:
       if (yyssp == yyss)
        YYABORT;
 
-]b4_locations_if([[      ]b4_yyerror_range[[0] = *yylsp;]])[
+]b4_locations_if([[      yyerror_range[0] = *yylsp;]])[
       yydestruct ("Error: popping",
                  yystos[yystate], yyvsp]b4_locations_if([, 
yylsp])[]b4_user_args[);
       YYPOPSTACK (1);
@@ -1579,10 +1592,10 @@ yyerrlab1:
 
   *++yyvsp = yylval;
 ]b4_locations_if([[
-  ]b4_yyerror_range[[1] = yylloc;
+  yyerror_range[1] = yylloc;
   /* Using YYLLOC is tempting, but would change the location of
      the lookahead.  YYLOC is available though.  */
-  YYLLOC_DEFAULT (yyloc, (]b4_yyerror_range[- 1), 2);
+  YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2);
   *++yylsp = yyloc;]])[
 
   /* Shift the error token.  */
@@ -1631,7 +1644,7 @@ yyreturn:
       YYPOPSTACK (1);
     }
 #ifndef yyoverflow
-  if (yyss != ]b4_yyssa[)
+  if (yyss != yyssa)
     YYSTACK_FREE (yyss);
 #endif
 ]b4_push_if([yypushreturn:])[
@@ -1639,7 +1652,7 @@ yyreturn:
   if (yymsg != yymsgbuf)
     YYSTACK_FREE (yymsg);
 #endif
-  ]b4_push_if([yyps->yyresult = YYID (yyresult);])[
+  ]b4_push_if([yyresult = YYID (yyresult);])[
   /* Make sure YYID is used.  */
   return YYID (yyresult);
 ]}
@@ -1687,23 +1700,31 @@ typedef struct YYLTYPE
 #endif
 
 ]b4_pure_if([],
-          [extern YYLTYPE b4_prefix[]lloc;])
+          [[extern YYLTYPE b4_prefix[]lloc;]])
 )dnl b4_locations_if
 
-]b4_push_if([struct ]b4_prefix[pstate;
+b4_push_if([[struct ]b4_prefix[pstate;
+#ifndef YYPSTATE_DECLS
+# define YYPSTATE_DECLS
 typedef struct ]b4_prefix[pstate ]b4_prefix[pstate;
-]b4_c_function_decl([]b4_prefix[pstate_new], []b4_prefix[pstate *],
-                    [[void], []])[
-]b4_c_function_decl([]b4_prefix[pstate_delete], [void],
-                    [[]b4_prefix[pstate *yyps],[yyps]])[
-]b4_c_function_decl([]b4_prefix[push_parse], [int],
-   [[]b4_prefix[pstate *]b4_prefix[pstate], []b4_prefix[pstate]],
-   [[int yynchar], [yynchar]],
-   [[YYSTYPE const *yynlval], [yynlval]]
-   b4_locations_if([,[[YYLTYPE const *yynlloc], [yynlloc]]])
-   m4_ifset([b4_parse_param], [, b4_parse_param]))[
-enum { YYPUSH_MORE = 4 };])[
-
+enum { YYPUSH_MORE = 4 };
+# define ]b4_prefix[parse(]b4_generate_macro_args(b4_parse_param)) 
b4_prefix[pull_parse (0, &]b4_prefix[lex]m4_ifset([b4_parse_param], [, 
b4_parenthesize(b4_generate_macro_args(b4_parse_param))])[)
+#endif
+]b4_c_function_decl([b4_prefix[pstate_new]], [b4_prefix[pstate *]],
+                    [[void], []])
+b4_c_function_decl([b4_prefix[pstate_delete]], [[void]],
+                    [[b4_prefix[pstate *yyps]],[[yyps]]])
+b4_c_function_decl([b4_prefix[push_parse]], [[int]],
+   [[b4_prefix[pstate *yyps]], [[yyps]]]b4_pure_if([,
+   [[[int yypushed_char]], [[yypushed_char]]],
+   [[[YYSTYPE const *yypushed_val]], [[yypushed_val]]]b4_locations_if([,
+   [[[YYLTYPE const *yypushed_loc]], 
[[yypushed_loc]]]])])m4_ifset([b4_parse_param],
+   [, b4_parse_param]))
+b4_c_function_decl([b4_prefix[pull_parse]], [[int]],
+   [[b4_prefix[pstate *yyps]], [[yyps]]],
+   [[[int (*yylexp)(]b4_c_ansi_formals(b4_lex_param)[)]], 
[[yylexp]]]m4_ifset([b4_parse_param], [,
+   b4_parse_param]))
+])
 m4_ifdef([b4_provides],
 [[/* Copy the %provides blocks.  */
 ]b4_user_provides])[]
Index: src/parse-gram.y
===================================================================
RCS file: /sources/bison/bison/src/parse-gram.y,v
retrieving revision 1.101
diff -p -u -r1.101 parse-gram.y
--- src/parse-gram.y    17 Dec 2006 01:33:31 -0000      1.101
+++ src/parse-gram.y    18 Dec 2006 08:12:21 -0000
@@ -255,7 +255,7 @@ prologue_declaration:
 | "%output" "=" STRING          { spec_outfile = $3; }  /* deprecated */
 | "%parse-param" "{...}"       { add_param ("parse_param", $2, @2); }
 | "%pure-parser"                { pure_parser = true; }
-| "%push-parser"                { push_parser = true; pure_parser = true; }
+| "%push-parser"                { push_parser = true; }
 | "%require" STRING             { version_check (&@2, $2); }
 | "%skeleton" STRING            { skeleton = $2; }
 | "%token-table"                { token_table_flag = true; }
Index: tests/calc.at
===================================================================
RCS file: /sources/bison/bison/tests/calc.at,v
retrieving revision 1.98
diff -p -u -r1.98 calc.at
--- tests/calc.at       15 Dec 2006 05:31:26 -0000      1.98
+++ tests/calc.at       18 Dec 2006 08:12:21 -0000
@@ -336,17 +336,7 @@ main (int argc, const char **argv)
 
 ]AT_SKEL_CC_IF([], [m4_bmatch([$4], [%debug],
 [  yydebug = 1;])])[
-]AT_PUSH_IF([
-  {
-    yypstate *pstate = yypstate_new ();
-    YYSTYPE my_lval;
-    ]AT_LOCATION_IF([YYLTYPE my_lloc;])[
-    do {
-      status = yypush_parse (pstate, yylex (&my_lval]AT_LOCATION_IF([[, 
&my_lloc]])[), &my_lval]AT_LOCATION_IF([[, &my_lloc]])[);
-    } while (status == YYPUSH_MORE);
-    yypstate_delete (pstate);
-  }],[
-  status = yyparse (]AT_PARAM_IF([[&result, &count]])[);])[
+  status = yyparse (]AT_PARAM_IF([[&result, &count]])[);
   fclose (input);
   if (global_result != result)
     abort ();
@@ -572,7 +562,7 @@ AT_CHECK_CALC_LALR([%yacc])
 AT_CHECK_CALC_LALR([%error-verbose])
 
 AT_CHECK_CALC_LALR([%pure-parser %locations])
-AT_CHECK_CALC_LALR([%push-parser %locations %skeleton "push.c"])
+AT_CHECK_CALC_LALR([%push-parser %pure-parser %locations %skeleton "push.c"])
 AT_CHECK_CALC_LALR([%error-verbose %locations])
 
 AT_CHECK_CALC_LALR([%error-verbose %locations %defines %name-prefix "calc" 
%verbose %yacc])
@@ -581,7 +571,7 @@ AT_CHECK_CALC_LALR([%debug])
 AT_CHECK_CALC_LALR([%error-verbose %debug %locations %defines %name-prefix 
"calc" %verbose %yacc])
 
 AT_CHECK_CALC_LALR([%pure-parser %error-verbose %debug %locations %defines 
%name-prefix "calc" %verbose %yacc])
-AT_CHECK_CALC_LALR([%push-parser %error-verbose %debug %locations %defines 
%name-prefix "calc" %verbose %yacc %skeleton "push.c"])
+AT_CHECK_CALC_LALR([%push-parser %pure-parser %error-verbose %debug %locations 
%defines %name-prefix "calc" %verbose %yacc %skeleton "push.c"])
 
 AT_CHECK_CALC_LALR([%pure-parser %error-verbose %debug %locations %defines 
%name-prefix "calc" %verbose %yacc %parse-param {semantic_value *result} 
%parse-param {int *count}])
 
Index: tests/headers.at
===================================================================
RCS file: /sources/bison/bison/tests/headers.at,v
retrieving revision 1.15
diff -p -u -r1.15 headers.at
--- tests/headers.at    2 Dec 2006 01:52:16 -0000       1.15
+++ tests/headers.at    18 Dec 2006 08:12:21 -0000
@@ -94,7 +94,9 @@ AT_DATA_GRAMMAR([input.y],
 #include <stdio.h>
 #include <stdlib.h>
 
-static int
+int my_lex (void);
+
+int
 my_lex (void)
 {
   return EOF;
@@ -118,7 +120,11 @@ AT_DATA([caller.c],
 [[#include "input.h"
 YYLTYPE *my_llocp = &my_lloc;
 
+#ifndef YYPSTATE_DECLS
 int my_parse (void);
+#else
+int my_lex (void);
+#endif
 
 int
 main (void)
Index: tests/input.at
===================================================================
RCS file: /sources/bison/bison/tests/input.at,v
retrieving revision 1.64
diff -p -u -r1.64 input.at
--- tests/input.at      21 Nov 2006 07:07:35 -0000      1.64
+++ tests/input.at      18 Dec 2006 08:12:21 -0000
@@ -470,7 +470,7 @@ char quote[] = "@:>@@:>@,";
 
 %{
 static void yyerror (const char *s);
-static int yylex (void);
+int yylex (void);
 %}
 
 %type <ival> '@<:@'
@@ -503,7 +503,7 @@ value_as_yystype (value val)
   return res;
 }
 
-static int
+int
 yylex (void)
 {
   static char const input[] = "@<:@[EMAIL PROTECTED]@[EMAIL PROTECTED]@&[EMAIL 
PROTECTED]
@@ -529,7 +529,11 @@ AT_DATA([main.c],
 [[typedef int value;
 #include "input.h"
 
+#ifndef YYPSTATE_DECLS
 int yyparse (void);
+#else
+int yylex (void);
+#endif
 
 int
 main (void)
Index: tests/local.at
===================================================================
RCS file: /sources/bison/bison/tests/local.at,v
retrieving revision 1.19
diff -p -u -r1.19 local.at
--- tests/local.at      7 Dec 2006 02:21:13 -0000       1.19
+++ tests/local.at      18 Dec 2006 08:12:21 -0000
@@ -60,8 +60,8 @@ m4_pushdef([AT_PURE_IF],
 [m4_bmatch([$3], [%pure-parser], [$1], [$2])])
 m4_pushdef([AT_PUSH_IF],
 [m4_bmatch([$3], [%push-parser], [$1], [$2])])
-m4_pushdef([AT_PURE_OR_PUSH_IF],
-[m4_bmatch([$3], [%pure-parser\|%push-parser], [$1], [$2])])
+m4_pushdef([AT_YACC_OR_PUSH_IF],
+[AT_YACC_IF([$1], [AT_PUSH_IF([$1], [$2])])])
 m4_pushdef([AT_PURE_AND_LOC_IF],
 [m4_bmatch([$3], [%locations.*%pure-parser\|%pure-parser.*%locations],
           [$1], [$2])])
@@ -76,17 +76,17 @@ m4_pushdef([AT_YYERROR_ARG_LOC_IF],
 [AT_GLR_OR_PARAM_IF([AT_PURE_AND_LOC_IF([$1], [$2])],
                    [$2])])
 # yyerror always sees the locations (when activated), except if
-# push or (yacc & pure & !param).
+# (yacc & pure & !param).  FIXME: This is wrong.  See the manual.
 m4_pushdef([AT_YYERROR_SEES_LOC_IF],
-[AT_PUSH_IF([$2],[AT_LOCATION_IF([AT_YACC_IF([AT_PURE_IF([AT_PARAM_IF([$1], 
[$2])],
-                                       [$1])],
-                           [$1])],
-               [$2])])])
+[AT_LOCATION_IF([AT_YACC_OR_PUSH_IF([AT_PURE_IF([AT_PARAM_IF([$1], [$2])],
+                                               [$1])],
+                                   [$1])],
+               [$2])])
 
 # The interface is pure: either because %pure-parser, or because we
 # are using the C++ parsers.
 m4_pushdef([AT_PURE_LEX_IF],
-[AT_PURE_OR_PUSH_IF([$1],
+[AT_PURE_IF([$1],
            [AT_SKEL_CC_IF([$1], [$2])])])
 
 AT_PURE_LEX_IF(

Reply via email to