diff --git a/NEWS b/NEWS index 9b0ee9bb..92ffc91c 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,13 @@ GNU Bison NEWS * Noteworthy changes in release ?.? (????-??-??) [?] +** Changes + +*** Debugging glr.c and glr.cc + + The glr.c skeleton always had asserts to check its own behavior (not the + user's). These assertions are now under the control of the parse.assert + %define variable (disabled by default). * Noteworthy changes in release 3.4.91 (2019-11-20) [beta] diff --git a/TODO b/TODO index 5258b72d..ae3a6c96 100644 --- a/TODO +++ b/TODO @@ -2,11 +2,6 @@ ** Deprecate YYPRINT The doc shows it too much. -** glr.c: parse.assert -There are many assertions in glr.c that are there to check the skeleton -itself, not the user code. So it should be under the control of -parse.assert. - ** java, d: error.verbose The code checks dynamically for error.verbose. It should be controlled by M4. diff --git a/data/skeletons/glr.c b/data/skeletons/glr.c index 1f809bb6..467f7db9 100644 --- a/data/skeletons/glr.c +++ b/data/skeletons/glr.c @@ -311,15 +311,20 @@ static YYLTYPE yyloc_default][]b4_yyloc_default;])[ # define YYLONGJMP(Env, Val) \ do { \ longjmp (Env, Val); \ - YYASSERT (0); \ + YY_ASSERT (0); \ } while (yyfalse) #endif ]b4_attribute_define([noreturn])[ -#ifndef YYASSERT -# define YYASSERT(Condition) ((void) ((Condition) || (abort (), 0))) +]b4_parse_assert_if([[#ifdef NDEBUG +# define YY_ASSERT(E) ((void) (0 && (E))) +#else +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_ASSERT(E) assert (E) #endif +]], +[[#define YY_ASSERT(E) ((void) (0 && (E)))]])[ /* YYFINAL -- State number of the termination state. */ #define YYFINAL ]b4_final_state_number[ @@ -756,10 +761,7 @@ yyMemoryExhausted (yyGLRStack* yystackp) static inline const char* yytokenName (yySymbol yytoken) { - if (yytoken == YYEMPTY) - return ""; - - return yytname[yytoken]; + return yytoken == YYEMPTY ? "" : yytname[yytoken]; } #endif @@ -1090,7 +1092,7 @@ yyaddDeferredAction (yyGLRStack* yystackp, ptrdiff_t yyk, yyGLRState* yystate, { yySemanticOption* yynewOption = &yynewGLRStackItem (yystackp, yyfalse)->yyoption; - YYASSERT (!yynewOption->yyisState); + YY_ASSERT (!yynewOption->yyisState); yynewOption->yystate = yyrhs; yynewOption->yyrule = yyrule; if (yystackp->yytops.yylookaheadNeeds[yyk]) @@ -1336,7 +1338,7 @@ yyglrShiftDefer (yyGLRStack* yystackp, ptrdiff_t yyk, yyStateNum yylrState, ptrdiff_t yyposn, yyGLRState* yyrhs, yyRuleNum yyrule) { yyGLRState* yynewState = &yynewGLRStackItem (yystackp, yytrue)->yystate; - YYASSERT (yynewState->yyisState); + YY_ASSERT (yynewState->yyisState); yynewState->yylrState = yylrState; yynewState->yyposn = yyposn; @@ -1406,7 +1408,7 @@ yydoAction (yyGLRStack* yystackp, ptrdiff_t yyk, yyRuleNum yyrule, /* Standard special case: single stack. */ yyGLRStackItem* yyrhs = YY_REINTERPRET_CAST (yyGLRStackItem*, yystackp->yytops.yystates[yyk]); - YYASSERT (yyk == 0); + YY_ASSERT (yyk == 0); yystackp->yynextFree -= yynrhs; yystackp->yyspaceLeft += yynrhs; yystackp->yytops.yystates[0] = & yystackp->yynextFree[-1].yystate; @@ -1426,7 +1428,7 @@ yydoAction (yyGLRStack* yystackp, ptrdiff_t yyk, yyRuleNum yyrule, for (yyi = 0; yyi < yynrhs; yyi += 1) { yys = yys->yypred; - YYASSERT (yys); + YY_ASSERT (yys); } yyupdateSplit (yystackp, yys); yystackp->yytops.yystates[yyk] = yys; @@ -1482,7 +1484,7 @@ yyglrReduce (yyGLRStack* yystackp, ptrdiff_t yyk, yyRuleNum yyrule, 0 < yyn; yyn -= 1) { yys = yys->yypred; - YYASSERT (yys); + YY_ASSERT (yys); } yyupdateSplit (yystackp, yys); yynewLRState = yyLRgotoState (yys->yylrState, yylhsNonterm (yyrule)); @@ -1520,7 +1522,7 @@ yysplitStack (yyGLRStack* yystackp, ptrdiff_t yyk) { if (yystackp->yysplitPoint == YY_NULLPTR) { - YYASSERT (yyk == 0); + YY_ASSERT (yyk == 0); yystackp->yysplitPoint = yystackp->yytops.yystates[yyk]; } if (yystackp->yytops.yycapacity <= yystackp->yytops.yysize) @@ -1674,7 +1676,7 @@ yyresolveStates (yyGLRState* yys, int yyn, { if (0 < yyn) { - YYASSERT (yys->yypred); + YY_ASSERT (yys->yypred); YYCHK (yyresolveStates (yys->yypred, yyn-1, yystackp]b4_user_args[)); if (! yys->yyresolved) YYCHK (yyresolveValue (yys, yystackp]b4_user_args[)); @@ -1807,7 +1809,7 @@ yyresolveLocations (yyGLRState *yys1, int yyn1, yyGLRStackItem yyrhsloc[1 + YYMAXRHS]; int yynrhs; yySemanticOption *yyoption = yys1->yysemantics.yyfirstVal; - YYASSERT (yyoption); + YY_ASSERT (yyoption); yynrhs = yyrhsLength (yyoption->yyrule); if (0 < yynrhs) { @@ -1882,7 +1884,7 @@ yyresolveValue (yyGLRState* yys, yyGLRStack* yystackp]b4_user_formals[) yymerge = yyfalse; break; default: - /* This cannot happen so it is not worth a YYASSERT (yyfalse), + /* This cannot happen so it is not worth a YY_ASSERT (yyfalse), but some compilers complain if the default case is omitted. */ break; @@ -1985,7 +1987,7 @@ yyprocessOneStack (yyGLRStack* yystackp, ptrdiff_t yyk, yyStateNum yystate = yystackp->yytops.yystates[yyk]->yylrState; YY_DPRINTF ((stderr, "Stack %ld Entering state %d\n", yyk, yystate)); - YYASSERT (yystate != YYFINAL); + YY_ASSERT (yystate != YYFINAL); if (yyisDefaultedState (yystate)) { @@ -2492,7 +2494,7 @@ b4_dollar_popdef])[]dnl goto yyreturn; yybuglab: - YYASSERT (yyfalse); + YY_ASSERT (yyfalse); goto yyabortlab; yyabortlab: @@ -2586,8 +2588,8 @@ yypdumpstack (yyGLRStack* yystackp) YY_CAST (long, yyp - yystackp->yyitems))); if (*YY_REINTERPRET_CAST (yybool *, yyp)) { - YYASSERT (yyp->yystate.yyisState); - YYASSERT (yyp->yyoption.yyisState); + YY_ASSERT (yyp->yystate.yyisState); + YY_ASSERT (yyp->yyoption.yyisState); YY_FPRINTF ((stderr, "Res: %d, LR State: %d, posn: %ld, pred: %ld", yyp->yystate.yyresolved, yyp->yystate.yylrState, YY_CAST (long, yyp->yystate.yyposn), @@ -2598,8 +2600,8 @@ yypdumpstack (yyGLRStack* yystackp) } else { - YYASSERT (!yyp->yystate.yyisState); - YYASSERT (!yyp->yyoption.yyisState); + YY_ASSERT (!yyp->yystate.yyisState); + YY_ASSERT (!yyp->yyoption.yyisState); YY_FPRINTF ((stderr, "Option. rule: %d, state: %ld, next: %ld", yyp->yyoption.yyrule - 1, YYINDEX (yyp->yyoption.yystate), diff --git a/doc/bison.texi b/doc/bison.texi index 2cb6afc3..032c3ac8 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -6494,9 +6494,12 @@ Obsoleted by @code{api.namespace} @deffn Directive {%define parse.assert} @itemize -@item Languages(s): C++ +@item Languages(s): C, C++ @item Purpose: Issue runtime assertions to catch invalid uses. +In C, some important invariants in the implementation of the parser are +checked when this option is enabled. + In C++, when variants are used (@pxref{C++ Variants}), symbols must be constructed and destroyed properly. This option checks these constraints. diff --git a/tests/glr-regression.at b/tests/glr-regression.at index 67e3b3f8..8cf98467 100644 --- a/tests/glr-regression.at +++ b/tests/glr-regression.at @@ -41,9 +41,9 @@ static YYSTYPE exprMerge (YYSTYPE x0, YYSTYPE x1); %} +%define parse.assert %glr-parser - /* -------- productions ------ */ %% @@ -128,6 +128,7 @@ AT_DATA_GRAMMAR([glr-regr2a.y], ]AT_YYLEX_DECLARE[ %} +%define parse.assert %glr-parser %% @@ -265,6 +266,7 @@ static int MergeRule (int x0, int x1); %} +%define parse.assert %glr-parser %token BAD_CHAR @@ -370,6 +372,7 @@ AT_SETUP([Duplicate representation of merged trees]) AT_BISON_OPTION_PUSHDEFS AT_DATA_GRAMMAR([glr-regr4.y], [[ +%define parse.assert %union { char *ptr; } %type S A A1 A2 B %glr-parser @@ -469,6 +472,7 @@ AT_DATA_GRAMMAR([glr-regr5.y], enum { MAGIC_VALUE = -1057808125 }; /* originally chosen at random */ %} +%define parse.assert %glr-parser %union { int value; } %type start @@ -524,6 +528,7 @@ AT_DATA_GRAMMAR([glr-regr6.y], ]AT_YYLEX_DECLARE[ %} +%define parse.assert %glr-parser %union { int value; } %type 'a' @@ -580,6 +585,7 @@ AT_DATA_GRAMMAR([glr-regr7.y], static count_node *tail; %} +%define parse.assert %glr-parser %union { count_node *node; } %type 'a' @@ -667,6 +673,7 @@ AT_DATA_GRAMMAR([glr-regr8.y], %token T_PORT %token T_SIGNAL +%define parse.assert %glr-parser %% @@ -756,6 +763,7 @@ AT_DATA_GRAMMAR([glr-regr9.y], # define USE(Var) %} +%define parse.assert %glr-parser %union { int dummy; } %type 'a' @@ -831,6 +839,7 @@ AT_DATA_GRAMMAR([glr-regr10.y], static char garbage[GARBAGE_SIZE]; %} +%define parse.assert %glr-parser %union { char *ptr; } %type start @@ -884,6 +893,7 @@ AT_DATA_GRAMMAR([glr-regr11.y], # define USE(val) %} +%define parse.assert %glr-parser %union { int dummy; } %type 'a' @@ -934,6 +944,7 @@ AT_SETUP([Leaked semantic values if user action cuts parse]) AT_BISON_OPTION_PUSHDEFS AT_DATA_GRAMMAR([glr-regr12.y], [[ +%define parse.assert %glr-parser %union { int dummy; } %token PARENT_RHS_AFTER @@ -1073,6 +1084,7 @@ AT_DATA_GRAMMAR([glr-regr13.y], #define USE(value) %} +%define parse.assert %union { char value; } %type 'a' 'b' %glr-parser @@ -1213,6 +1225,7 @@ AT_DATA_GRAMMAR([glr-regr14.y], #define USE(value) %} +%define parse.assert %type 'a' 'b' 'c' 'd' stack_explosion %glr-parser %locations @@ -1397,6 +1410,7 @@ AT_SETUP([Leaked semantic values when reporting ambiguity]) AT_BISON_OPTION_PUSHDEFS AT_DATA_GRAMMAR([glr-regr15.y], [[ +%define parse.assert %glr-parser %destructor { parent_rhs_before_value = 0; } parent_rhs_before @@ -1479,6 +1493,7 @@ AT_SETUP([Leaked lookahead after nondeterministic parse syntax error]) AT_BISON_OPTION_PUSHDEFS AT_DATA_GRAMMAR([glr-regr16.y], [[ +%define parse.assert %glr-parser %destructor { lookahead_value = 0; } 'b' @@ -1540,6 +1555,7 @@ AT_BISON_OPTION_PUSHDEFS([%glr-parser %locations %define api.pure]) AT_DATA_GRAMMAR([glr-regr17.y], [[ +%define parse.assert %glr-parser %locations %define api.pure @@ -1612,7 +1628,8 @@ AT_SETUP([Missed %merge type warnings when LHS type is declared later]) AT_BISON_OPTION_PUSHDEFS AT_DATA_GRAMMAR([glr-regr18.y], -[[%glr-parser +[[%define parse.assert +%glr-parser %{ #include @@ -1625,7 +1642,6 @@ AT_DATA_GRAMMAR([glr-regr18.y], int type2; int type3; } - %% sym1: sym2 %merge { $$ = $1; } ; @@ -1661,14 +1677,14 @@ AT_SETUP([Ambiguity reports]) AT_BISON_OPTION_PUSHDEFS([%debug]) AT_DATA_GRAMMAR([input.y], -[[ -%{ +[[%{ #include #include ]AT_YYERROR_DECLARE[ ]AT_YYLEX_DECLARE[ %} +%define parse.assert %debug %glr-parser @@ -1762,7 +1778,8 @@ AT_CLEANUP AT_SETUP([Predicates]) AT_DATA_GRAMMAR([input.y], -[[%glr-parser +[[%define parse.assert +%glr-parser %define parse.error verbose %expect-rr 1 %code requires