bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: no users destructors if stack 0 deleted


From: Paul Eggert
Subject: Re: no users destructors if stack 0 deleted
Date: Tue, 06 Dec 2005 11:41:57 -0800
User-agent: Gnus/5.1007 (Gnus v5.10.7) Emacs/21.4 (gnu/linux)

"Joel E. Denny" <address@hidden> writes:

> The combined diff for the two patches appears below.

That patch was corrupted, unfortunately.  I guess your Pine client
munged it?  There were some leading spaces in it.

> There was also a new test case for the latter patch:
>
>    http://lists.gnu.org/archive/html/bison-patches/2005-09/msg00109.html

It's helpful to bundle all the related items in to the same patch,
along with a ChangeLog entry for it.  Something like the following,
which I just now installed.  (It reformats the comments a bit, to use
the usual GNU style.)

Thanks again for the fixes, and for persevering to get them installed.

2005-12-06  "Joel E. Denny" <address@hidden>

        * data/glr.c (yyprocessOneStack): Synchronize the shift for all
        stacks, and iterate another stack in order to call user
        destructors.
        * tests/glr-regression.at (No users destructors if stack 0 deleted):
        New test case.
        (Duplicated user destructor for lookahead): This test now is expected
        to succeed.

--- data/glr.c.~1.141~  2005-12-06 11:00:37.000000000 -0800
+++ data/glr.c  2005-12-06 11:15:55.000000000 -0800
@@ -1880,16 +1880,7 @@ yyprocessOneStack (yyGLRStack* yystack, 
            }
 
          if (yyisShiftAction (yyaction))
-           {
-             YYDPRINTF ((stderr, "On stack %lu, ", (unsigned long int) yyk));
-             YY_SYMBOL_PRINT ("shifting", *yytokenp, yylvalp, yyllocp);
-             yyglrShift (yystack, yyk, yyaction, yyposn+1,
-                         *yylvalp, yyllocp);
-             YYDPRINTF ((stderr, "Stack %lu now in state #%d\n",
-                         (unsigned long int) yyk,
-                         yystack->yytops.yystates[yyk]->yylrState));
-             break;
-           }
+           break;
          else if (yyisErrorAction (yyaction))
            {
              YYDPRINTF ((stderr, "Stack %lu dies.\n",
@@ -2236,14 +2227,59 @@ b4_syncline(address@hidden@], address@hidden@])])dnl
 
       while (yytrue)
        {
+         yySymbol yytoken_to_shift;
          size_t yys;
          size_t yyn = yystack.yytops.yysize;
+
+         /* yyprocessOneStack returns one of three things:
+
+             - An error flag.  If the caller is yyprocessOneStack, it
+               immediately returns as well.  When the caller is finally
+               yyparse, it jumps to an error label via YYCHK1.
+
+             - yyok, but yyprocessOneStack has invoked yymarkStackDeleted
+               (&yystack, yys), which sets the top state of yys to NULL.  Thus,
+               yyparse's following invocation of yyremoveDeletes will remove
+               the stack.
+
+             - yyok, when ready to shift a token.
+
+            Except in the first case, yyparse will invoke yyremoveDeletes and
+            then shift the next token onto all remaining stacks.  This
+            synchronization of the shift (that is, after all preceding
+            reductions on all stacks) helps prevents double destructor calls
+            on yylval in the event of memory exhaustion.  */
+
          for (yys = 0; yys < yyn; yys += 1)
            YYCHK1 (yyprocessOneStack (&yystack, yys, yyposn,
                                       yylvalp, yyllocp]b4_lpure_args[));
+         yyremoveDeletes (&yystack);
+         yyn = yystack.yytops.yysize;
+
+         /* If any yyglrShift call fails, it will fail after shifting.  Thus,
+            a copy of yylval will already be on stack 0 in the event of a
+            failure in the following loop.  Thus, yytoken is set to YYEMPTY
+            before the loop to make sure the user destructor for yylval isn't
+            called twice.  */
+         yytoken_to_shift = yytoken;
          yytoken = YYEMPTY;
          yyposn += 1;
-         yyremoveDeletes (&yystack);
+         for (yys = 0; yys < yyn; yys += 1)
+           {
+             int yyaction;
+             const short int* yyconflicts;
+             yyStateNum yystate = yystack.yytops.yystates[yys]->yylrState;
+             yygetLRActions (yystate, yytoken_to_shift, &yyaction,
+                             &yyconflicts);
+             /* Note that yyconflicts were handled by yyprocessOneStack.  */
+             YYDPRINTF ((stderr, "On stack %lu, ", (unsigned long int) yys));
+             YY_SYMBOL_PRINT ("shifting", yytoken_to_shift, yylvalp, yyllocp);
+             yyglrShift (&yystack, yys, yyaction, yyposn,
+                         *yylvalp, yyllocp);
+             YYDPRINTF ((stderr, "Stack %lu now in state #%d\n",
+                         (unsigned long int) yys,
+                         yystack.yytops.yystates[yys]->yylrState));
+           }
          if (yystack.yytops.yysize == 0)
            {
              yyundeleteLastStack (&yystack);
@@ -2298,15 +2334,24 @@ b4_syncline(address@hidden@], address@hidden@])])dnl
     {
       yyGLRState** yystates = yystack.yytops.yystates;
       if (yystates)
-       while (yystates[0])
-         {
-           yyGLRState *yys = yystates[0];
-]b4_location_if([[       yystack.yyerror_range[1].yystate.yyloc = yys->yyloc;]]
-)[         yydestroyGLRState ("Cleanup: popping", yys]b4_user_args[);
-           yystates[0] = yys->yypred;
-           yystack.yynextFree -= 1;
-           yystack.yyspaceLeft += 1;
-         }
+       {
+         size_t yysize = yystack.yytops.yysize;
+         size_t yyk;
+         for (yyk = 0; yyk < yysize; yyk += 1)
+           if (yystates[yyk])
+             {
+               while (yystates[yyk])
+                 {
+                   yyGLRState *yys = yystates[yyk];
+]b4_location_if([[                 yystack.yyerror_range[1].yystate.yyloc = 
yys->yyloc;]]
+)[                 yydestroyGLRState ("Cleanup: popping", yys]b4_user_args[);
+                   yystates[yyk] = yys->yypred;
+                   yystack.yynextFree -= 1;
+                   yystack.yyspaceLeft += 1;
+                 }
+               break;
+             }
+       }
       yyfreeGLRStack (&yystack);
     }
 
--- tests/glr-regression.at.~1.19.~     2005-10-30 17:16:32.000000000 -0800
+++ tests/glr-regression.at     2005-12-06 11:31:32.000000000 -0800
@@ -633,8 +633,6 @@ AT_CHECK([[./glr-regr7]], 2, [],
 [memory exhausted
 ])
 
-AT_XFAIL_IF(:)
-
 AT_CLEANUP
 
 
@@ -667,9 +665,9 @@ AT_DATA_GRAMMAR([glr-regr8.y],
 
 
 PortClause     : T_PORT InterfaceDeclaration T_PORT
-               { printf("%d/%d - %d/%d - %d/%d\n", 
-                        @1.first_column, @1.last_column, 
-                        @2.first_column, @2.last_column, 
+               { printf("%d/%d - %d/%d - %d/%d\n",
+                        @1.first_column, @1.last_column,
+                        @2.first_column, @2.last_column,
                         @3.first_column, @3.last_column); }
        ;
 
@@ -695,7 +693,7 @@ void yyerror(const char *msg)
 
 static int lexIndex;
 
-int yylex() 
+int yylex (void)
 {
   lexIndex += 1;
   switch (lexIndex)
@@ -714,7 +712,7 @@ int yylex() 
 }
 
 int
-main (void) 
+main (void)
 {
   yyparse();
   return 0;
@@ -726,10 +724,91 @@ AT_CHECK([[bison -o glr-regr8.c glr-regr
 ])
 AT_COMPILE([glr-regr8])
 
-AT_CHECK([[./glr-regr8]], 0, 
+AT_CHECK([[./glr-regr8]], 0,
 [empty: 9/9
 1/9 - 9/9 - 13/17
 ],
 [])
 
 AT_CLEANUP
+
+
+## ------------------------------------------------------------------------- ##
+## No users destructors if stack 0 deleted                                   ##
+## Thanks to Joel E. Denny for this test; see                                ##
+## <http://lists.gnu.org/archive/html/bison-patches/2005-09/msg00109.html>.  ##
+## ------------------------------------------------------------------------- ##
+
+AT_SETUP([No users destructors if stack 0 deleted])
+
+AT_DATA_GRAMMAR([glr-regr9.y],
+[[
+%{
+  #include <stdio.h>
+  #include <stdlib.h>
+  static void yyerror (char const *);
+  static int yylex (void);
+  #define YYSTACKEXPANDABLE 0
+  static int tokens = 0;
+  static int destructors = 0;
+%}
+
+%glr-parser
+%union { int dummy; }
+%type <dummy> 'a'
+
+%destructor {
+  destructors += 1;
+} 'a'
+
+%%
+
+start:
+  ambig0 'a' { destructors += 2; }
+  | ambig1 start { destructors += 1; }
+  | ambig2 start { destructors += 1; }
+  ;
+
+ambig0: 'a' ;
+ambig1: 'a' ;
+ambig2: 'a' ;
+
+%%
+
+static int
+yylex (void)
+{
+  tokens += 1;
+  return 'a';
+}
+
+static void
+yyerror (char const *msg)
+{
+  fprintf (stderr, "%s\n", msg);
+}
+
+int
+main (void)
+{
+  int exit_status;
+  exit_status = yyparse ();
+  if (tokens != destructors)
+    {
+      fprintf (stderr, "Tokens = %d, Destructors = %d\n", tokens, destructors);
+      return 1;
+    }
+  return !exit_status;
+}
+]])
+
+AT_CHECK([[bison -o glr-regr9.c glr-regr9.y]], 0, [],
+[glr-regr9.y: conflicts: 1 reduce/reduce
+])
+AT_COMPILE([glr-regr9])
+
+AT_CHECK([[./glr-regr9]], 0, [],
+[memory exhausted
+])
+
+AT_CLEANUP




reply via email to

[Prev in Thread] Current Thread [Next in Thread]