From 2a8d363aabf1373d410deb96f5d030ccfed367a6 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Sun, 3 Nov 2002 16:41:57 +0000 Subject: [PATCH] * data/c.m4 (b4_identification, b4_user_args, b4_parse_param): New. * data/yacc.m4 (b4_pure_args, b4_Pure_args): New. (b4_parse_param): Remove. Use b4_identification. Propagate b4_pure_args where needed to pass them to yyerror. * data/glr.m4 (b4_parse_param): Remove. (b4_user_formals, b4_pure_args, b4_pure_formals, b4_lpure_args) (b4_lpure_formals): New. Use b4_identification. (YY_USER_FORMALS, YY_USER_ARGS): Remove, replaced by b4_user_formals and b4_user_args. (yyexpandGLRStack, yyFail, yyaddDeferredAction, yyglrShiftDefer) (yyreportAmbiguity): When using a pure parser, also need the location, and the parse-params. Adjust callers. (yyuserAction, yyglrShift, yyreportParseError, yyrecoverParseError): When using a pure parser, also need the parse-params. Adjust callers. * tests/calc.at: Test pure (%pure-parser) and absolutely pure (%pure-parser + %parse-param) LALR and GLR parsers. (AT_CHECK_PUSHDEFS, AT_CHECK_POPDEFS): New, define AT_PARAM_IF, AT_LOCATION_IF, AT_PURE_IF, AT_GLR_IF, AAT_PURE_AND_LOC_IF, AT_GLR_OR_PARAM_IF, AT_YYERROR_ARG_LOC_IF, AT_YYERROR_SEES_LOC_IF. (_AT_DATA_CALC_Y): Equip for purity of yyerror. (_AT_CHECK_CALC_ERROR): Use AT_YYERROR_SEES_LOC_IF. * tests/cxx-type.at (_AT_TEST_GLR_CALC): Equip for yyerror purity. * doc/bison.texinfo: Untabify the whole file. (Parser Function): Document %parse-param, deprecate YYPARSE_PARAM. (Pure Calling): Document %lex-param, deprecate YYLEX_PARAM. (Error Reporting): Adjust to these new directives. Document %error-verbose, deprecate YYERROR_VERBOSE. --- ChangeLog | 35 ++++++ NEWS | 8 ++ data/c.m4 | 45 +++++++- data/glr.c | 216 +++++++++++++++++++---------------- data/yacc.c | 54 +++++---- doc/bison.texinfo | 332 ++++++++++++++++++++++++++++++++---------------------- tests/calc.at | 145 ++++++++++++++++-------- tests/cxx-type.at | 17 ++- 8 files changed, 552 insertions(+), 300 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7c5dee4..4b0b8b7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,40 @@ 2002-11-03 Akim Demaille + * data/c.m4 (b4_identification, b4_user_args, b4_parse_param): + New. + * data/yacc.m4 (b4_pure_args, b4_Pure_args): New. + (b4_parse_param): Remove. + Use b4_identification. + Propagate b4_pure_args where needed to pass them to yyerror. + * data/glr.m4 (b4_parse_param): Remove. + (b4_user_formals, b4_pure_args, b4_pure_formals, b4_lpure_args) + (b4_lpure_formals): New. + Use b4_identification. + (YY_USER_FORMALS, YY_USER_ARGS): Remove, replaced by + b4_user_formals and b4_user_args. + (yyexpandGLRStack, yyFail, yyaddDeferredAction, yyglrShiftDefer) + (yyreportAmbiguity): When using a pure parser, also need + the location, and the parse-params. + Adjust callers. + (yyuserAction, yyglrShift, yyreportParseError, yyrecoverParseError): + When using a pure parser, also need the parse-params. + Adjust callers. + * tests/calc.at: Test pure (%pure-parser) and absolutely pure + (%pure-parser + %parse-param) LALR and GLR parsers. + (AT_CHECK_PUSHDEFS, AT_CHECK_POPDEFS): New, define AT_PARAM_IF, + AT_LOCATION_IF, AT_PURE_IF, AT_GLR_IF, AAT_PURE_AND_LOC_IF, + AT_GLR_OR_PARAM_IF, AT_YYERROR_ARG_LOC_IF, AT_YYERROR_SEES_LOC_IF. + (_AT_DATA_CALC_Y): Equip for purity of yyerror. + (_AT_CHECK_CALC_ERROR): Use AT_YYERROR_SEES_LOC_IF. + * tests/cxx-type.at (_AT_TEST_GLR_CALC): Equip for yyerror purity. + * doc/bison.texinfo: Untabify the whole file. + (Parser Function): Document %parse-param, deprecate YYPARSE_PARAM. + (Pure Calling): Document %lex-param, deprecate YYLEX_PARAM. + (Error Reporting): Adjust to these new directives. + Document %error-verbose, deprecate YYERROR_VERBOSE. + +2002-11-03 Akim Demaille + * tests/calc.at: Change all the AT_CHECK_CALC_LALR and AT_CHECK_CALC_GLR invocations to use % directives, instead of command line options. diff --git a/NEWS b/NEWS index 681a2bd..b6ab693 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,14 @@ Changes in version 1.75a, 2002-10-24: ago, but nobody noticed until we recently asked someone to try building Bison with a K&R C compiler. +* %error-verbose + This new directive is preferred over YYERROR_VERBOSE. + +* %lex-param, %parse-param + These new directives are preferred over PARSE_PARAM and LEX_PARAM. + In addition, they provide a means for yyerror to remain pure, and + to access to the current location. + Changes in version 1.75, 2002-10-14: * Bison should now work on 64-bit hosts. diff --git a/data/c.m4 b/data/c.m4 index 785f9e1..2617162 100644 --- a/data/c.m4 +++ b/data/c.m4 @@ -19,9 +19,9 @@ m4_divert(-1) -*- Autoconf -*- # 02111-1307 USA -## ----------- ## -## Copyright. ## -## ----------- ## +## ---------------- ## +## Identification. ## +## ---------------- ## # b4_copyright(TITLE, YEARS) # -------------------------- @@ -47,6 +47,45 @@ m4_define([b4_copyright], Boston, MA 02111-1307, USA. */]) +# b4_identification +# ----------------- +m4_define([b4_identification], +[/* Identify Bison output. */ +[#]define YYBISON 1 + +/* Skeleton name. */ +[#]define YYSKELETON_NAME "b4_skeleton" + +/* Pure parsers. */ +[#]define YYPURE b4_pure + +/* Using locations. */ +[#]define YYLSP_NEEDED b4_locations_flag +]) + + + +## ------------------------ ## +## Pure/impure interfaces. ## +## ------------------------ ## + + +# b4_user_args +# ------------ +m4_define([b4_user_args], +[m4_ifset([b4_parse_param], [, b4_c_args(b4_parse_param)])]) + + +# b4_parse_param +# -------------- +# If defined, b4_parse_param arrives double quoted, but below we prefer +# it to be single quoted. +m4_define_default([b4_parse_param]) +m4_define([b4_parse_param], +b4_parse_param)) + + + ## ------------ ## ## Data Types. ## ## ------------ ## diff --git a/data/glr.c b/data/glr.c index 14185cf..6a18bcb 100644 --- a/data/glr.c +++ b/data/glr.c @@ -31,6 +31,15 @@ m4_define_default([b4_stack_depth_init], [200]) # Location type. m4_define_default([b4_location_type], [yyltype]) + + +## ------------------------ ## +## Pure/impure interfaces. ## +## ------------------------ ## + + +# b4_lex_param +# ------------ # Accumule in b4_lex_param all the yylex arguments. # Yes, this is quite ugly... m4_define([b4_lex_param], @@ -38,13 +47,40 @@ m4_dquote(b4_pure_if([[[[YYSTYPE *]], [[yylvalp]]][]dnl b4_location_if([, [[YYLTYPE *], [yyllocp]]])])dnl m4_ifdef([b4_lex_param], [, ]b4_lex_param))) -# Yes, this is quite ugly... - m4_define_default([b4_parse_param]) -m4_ifdef([b4_parse_param], -[m4_define([b4_parse_param], - b4_parse_param)]) + +# b4_user_formals +# --------------- +m4_define([b4_user_formals], +[m4_ifset([b4_parse_param], [, b4_c_ansi_formals(b4_parse_param)])]) + + +# b4_pure_args +# ------------ +# Arguments passed to yyerror: user args plus yylloc. +m4_define([b4_pure_args], +[b4_pure_if([b4_location_if([, yylocp])])[]b4_user_args]) + + +# b4_pure_formals +# --------------- +# Arguments passed to yyerror: user formals plus yyllocp. +m4_define([b4_pure_formals], +[b4_pure_if([b4_location_if([, YYLTYPE *yylocp])])[]b4_user_formals]) + + +# b4_lpure_args +# ------------- +# Same as above, but on the lookahead, hence yyllocp instead of yylocp. +m4_define([b4_lpure_args], +[b4_pure_if([b4_location_if([, yyllocp])])[]b4_user_args]) +# b4_lpure_formals +# ---------------- +# Same as above, but on the lookahead, hence yyllocp instead of yylocp. +m4_define([b4_lpure_formals], +[b4_pure_if([b4_location_if([YYLTYPE *yyllocp])])[]b4_user_formals]) + ## ----------------- ## ## Semantic Values. ## @@ -119,24 +155,15 @@ b4_copyright([Skeleton parser for GLR parsing with Bison], [2002]) [ /* This is the parser code for GLR (Generalized LR) parser. */ -/* FIXME: minimize these */ #include -#include -#include #include #include #include +#include +#include -/* Identify Bison output. */ -#define YYBISON 1 - -/* Pure parsers. */ -#define YYPURE ]b4_pure[ - -/* Using locations. */ -#define YYLSP_NEEDED ]b4_locations_flag[ - -]m4_if(b4_prefix[], [yy], [], +]b4_identification +m4_if(b4_prefix[], [yy], [], [/* If NAME_PREFIX is specified substitute the variables and functions names. */ #define yyparse b4_prefix[]parse @@ -378,16 +405,9 @@ static const ]b4_int_type_for([b4_check])[ yycheck[] = /* Prevent warning if -Wmissing-prototypes. */ -]b4_c_ansi_function_decl([yyparse], [int], b4_parse_param) - -m4_ifset([b4_parse_param], -[#define YY_USER_FORMALS , b4_c_ansi_formals(b4_parse_param) -#define YY_USER_ARGS , b4_c_args(b4_parse_param)], -[#define YY_USER_FORMALS -#define YY_USER_ARGS]) +]b4_c_ansi_function_decl([yyparse], [int], b4_parse_param)[ - -[/* Error token number */ +/* Error token number */ #define YYTERROR 1 /* YYLLOC_DEFAULT -- Compute the default location (before the actions @@ -548,11 +568,11 @@ struct yyGLRStack { }; static void yyinitGLRStack (yyGLRStack* yystack, size_t yysize); -static void yyexpandGLRStack (yyGLRStack* yystack); +static void yyexpandGLRStack (yyGLRStack* yystack]b4_pure_formals[); static void yyfreeGLRStack (yyGLRStack* yystack); static void -yyFail (yyGLRStack* yystack, const char* yyformat, ...) +yyFail (yyGLRStack* yystack]b4_pure_formals[, const char* yyformat, ...) { if (yyformat != NULL) { @@ -561,7 +581,7 @@ yyFail (yyGLRStack* yystack, const char* yyformat, ...) va_start (yyap, yyformat); yystack->yyerrflag = 1; vsprintf (yymsg, yyformat, yyap); - yyerror (yymsg); + yyerror (yymsg]b4_pure_args[); } longjmp (yystack->yyexception_buffer, 1); } @@ -584,7 +604,7 @@ yytokenName (yySymbol yytoken) static YYRESULTTAG yyuserAction (yyRuleNum yyn, int yyrhslen, yyGLRStackItem* yyvsp, YYSTYPE* yyvalp, YYLTYPE* yylocp, yyGLRStack* yystack - YY_USER_FORMALS) + ]b4_user_formals[) { /* Avoid `unused' warnings in there are no $n. */ (void) yystack; @@ -616,7 +636,7 @@ yyuserAction (yyRuleNum yyn, int yyrhslen, yyGLRStackItem* yyvsp, # undef YYBACKUP # define YYBACKUP(Token, Value) \ do { \ - yyerror ("syntax error: cannot back up"); \ + yyerror ("syntax error: cannot back up"]b4_pure_args[); \ YYERROR; \ } while (0) @@ -644,7 +664,7 @@ static YYSTYPE yyuserMerge (int yyn, YYSTYPE* yy0, YYSTYPE* yy1) { YYSTYPE yyval = *yy0; - /* `Use' the arguments. */ + /* `Use' the arguments. */ (void) yy0; (void) yy1; @@ -655,7 +675,7 @@ yyuserMerge (int yyn, YYSTYPE* yy0, YYSTYPE* yy1) return yyval; } [ - /* Bison grammar-table manipulation */ + /* Bison grammar-table manipulation. */ /** Number of symbols composing the right hand side of rule #RULE. */ static inline int @@ -751,7 +771,7 @@ yyhasResolvedValue (yyGLRState* yystate) static void yyaddDeferredAction (yyGLRStack* yystack, yyGLRState* yystate, - yyGLRState* rhs, yyRuleNum yyrule) + yyGLRState* rhs, yyRuleNum yyrule]b4_pure_formals[) { yySemanticOption* yynewItem; yynewItem = &yystack->yynextFree->yyoption; @@ -763,7 +783,7 @@ yyaddDeferredAction (yyGLRStack* yystack, yyGLRState* yystate, yynewItem->yynext = yystate->yysemantics.yyfirstVal; yystate->yysemantics.yyfirstVal = yynewItem; if (yystack->yyspaceLeft < YYHEADROOM) - yyexpandGLRStack (yystack); + yyexpandGLRStack (yystack]b4_pure_args[); } /* GLRStacks */ @@ -808,7 +828,7 @@ yyinitGLRStack (yyGLRStack* yystack, size_t yysize) allocation, so that we can avoid having external pointers exist across an allocation. */ static void -yyexpandGLRStack (yyGLRStack* yystack) +yyexpandGLRStack (yyGLRStack* yystack]b4_pure_formals[) { #if YYSTACKEXPANDABLE yyGLRStack yynewStack; @@ -817,7 +837,8 @@ yyexpandGLRStack (yyGLRStack* yystack) size_t yyn; yysize = yystack->yynextFree - yystack->yyitems; if (YYMAXDEPTH <= yysize) - yyFail (yystack, "parsing stack overflow (%d items)", yysize); + yyFail (yystack][]b4_pure_args[, + "parsing stack overflow (%d items)", yysize); yynewSize = 2*yysize; if (YYMAXDEPTH < yynewSize) yynewSize = YYMAXDEPTH; @@ -864,8 +885,8 @@ yyexpandGLRStack (yyGLRStack* yystack) #else - yyFail (yystack, "parsing stack overflow (%d items)", yysize); - + yyFail (yystack][]b4_lpure_args[, + "parsing stack overflow (%d items)", yysize); #endif } @@ -937,7 +958,7 @@ yyremoveDeletes (yyGLRStack* yystack) * LRSTATE, at input position POSN, with (resolved) semantic value SVAL. */ static inline void yyglrShift (yyGLRStack* yystack, int yyk, yyStateNum yylrState, size_t yyposn, - YYSTYPE yysval, YYLTYPE* yylocp) + YYSTYPE yysval, YYLTYPE* yylocp]b4_user_formals[) { yyGLRStackItem* yynewItem; @@ -953,7 +974,7 @@ yyglrShift (yyGLRStack* yystack, int yyk, yyStateNum yylrState, size_t yyposn, yynewItem->yystate.yysemantics.yysval = yysval; yynewItem->yystate.yyloc = *yylocp; if (yystack->yyspaceLeft < YYHEADROOM) - yyexpandGLRStack (yystack); + yyexpandGLRStack (yystack]b4_pure_args[); } /** Shift to a new state on stack #K of STACK, to a new state @@ -961,7 +982,7 @@ yyglrShift (yyGLRStack* yystack, int yyk, yyStateNum yylrState, size_t yyposn, * the (unresolved) semantic value of RHS under the action for RULE. */ static inline void yyglrShiftDefer (yyGLRStack* yystack, int yyk, yyStateNum yylrState, - size_t yyposn, yyGLRState* rhs, yyRuleNum yyrule) + size_t yyposn, yyGLRState* rhs, yyRuleNum yyrule]b4_pure_formals[) { yyGLRStackItem* yynewItem; @@ -975,7 +996,7 @@ yyglrShiftDefer (yyGLRStack* yystack, int yyk, yyStateNum yylrState, yystack->yytops.yystates[yyk] = &yynewItem->yystate; yystack->yynextFree += 1; yystack->yyspaceLeft -= 1; - yyaddDeferredAction (yystack, &yynewItem->yystate, rhs, yyrule); + yyaddDeferredAction (yystack, &yynewItem->yystate, rhs, yyrule]b4_pure_args[); } /** Pop the symbols consumed by reduction #RULE from the top of stack @@ -986,7 +1007,7 @@ yyglrShiftDefer (yyGLRStack* yystack, int yyk, yyStateNum yylrState, * for userAction. */ static inline int yydoAction (yyGLRStack* yystack, int yyk, yyRuleNum yyrule, - YYSTYPE* yyvalp, YYLTYPE* yylocp YY_USER_FORMALS) + YYSTYPE* yyvalp, YYLTYPE* yylocp]b4_user_formals[) { int yynrhs = yyrhsLength (yyrule); @@ -1009,7 +1030,7 @@ yydoAction (yyGLRStack* yystack, int yyk, yyRuleNum yyrule, *yylocp = rhs[1-yynrhs].yystate.yyloc; } return yyuserAction (yyrule, yynrhs, rhs, - yyvalp, yylocp, yystack YY_USER_ARGS); + yyvalp, yylocp, yystack]b4_user_args[); } else { @@ -1037,7 +1058,7 @@ yydoAction (yyGLRStack* yystack, int yyk, yyRuleNum yyrule, *yylocp = yyrhsVals[0].yystate.yyloc; } return yyuserAction (yyrule, yynrhs, yyrhsVals + (yynrhs-1), - yyvalp, yylocp, yystack YY_USER_ARGS); + yyvalp, yylocp, yystack]b4_user_args[); } } @@ -1080,7 +1101,7 @@ yy_reduce_print (size_t yyk, yyRuleNum yyrule) */ static inline YYRESULTTAG yyglrReduce (yyGLRStack* yystack, size_t yyk, yyRuleNum yyrule, - bool yyforceEval YY_USER_FORMALS) + bool yyforceEval]b4_pure_formals[) { size_t yyposn = yystack->yytops.yystates[yyk]->yyposn; @@ -1090,11 +1111,11 @@ yyglrReduce (yyGLRStack* yystack, size_t yyk, yyRuleNum yyrule, YYLTYPE yyloc; YY_REDUCE_PRINT (yyk, yyrule); - YYCHK (yydoAction (yystack, yyk, yyrule, &yysval, &yyloc YY_USER_ARGS)); + YYCHK (yydoAction (yystack, yyk, yyrule, &yysval, &yyloc]b4_user_args[)); yyglrShift (yystack, yyk, yyLRgotoState (yystack->yytops.yystates[yyk]->yylrState, yylhsNonterm (yyrule)), - yyposn, yysval, &yyloc); + yyposn, yysval, &yyloc]b4_user_args[); YYDPRINTF ((stderr, "Stack %d entering state %d\n", yyk, yystack->yytops.yystates[yyk]->yylrState)); } @@ -1126,7 +1147,7 @@ yyglrReduce (yyGLRStack* yystack, size_t yyk, yyRuleNum yyrule, { if (yyp->yylrState == yynewLRState && yyp->yypred == yys) { - yyaddDeferredAction (yystack, yyp, yys0, yyrule); + yyaddDeferredAction (yystack, yyp, yys0, yyrule]b4_pure_args[); yymarkStackDeleted (yystack, yyk); YYDPRINTF ((stderr, "Merging stack %d into stack %d.\n", yyk, yyi)); @@ -1136,7 +1157,7 @@ yyglrReduce (yyGLRStack* yystack, size_t yyk, yyRuleNum yyrule, } } yystack->yytops.yystates[yyk] = yys; - yyglrShiftDefer (yystack, yyk, yynewLRState, yyposn, yys0, yyrule); + yyglrShiftDefer (yystack, yyk, yynewLRState, yyposn, yys0, yyrule]b4_pure_args[); } return 0; } @@ -1236,23 +1257,23 @@ yypreference (yySemanticOption* y0, yySemanticOption* y1) static YYRESULTTAG yyresolveValue (yySemanticOption* yyoptionList, yyGLRStack* yystack, YYSTYPE* yyvalp, - YYLTYPE* yylocp YY_USER_FORMALS); + YYLTYPE* yylocp]b4_user_formals[); static YYRESULTTAG -yyresolveStates (yyGLRState* yys, int yyn, yyGLRStack* yystack YY_USER_FORMALS) +yyresolveStates (yyGLRState* yys, int yyn, yyGLRStack* yystack]b4_user_formals[) { YYRESULTTAG yyflag; if (0 < yyn) { assert (yys->yypred != NULL); - yyflag = yyresolveStates (yys->yypred, yyn-1, yystack YY_USER_ARGS); + yyflag = yyresolveStates (yys->yypred, yyn-1, yystack]b4_user_args[); if (yyflag != yyok) return yyflag; if (! yys->yyresolved) { yyflag = yyresolveValue (yys->yysemantics.yyfirstVal, yystack, &yys->yysemantics.yysval, &yys->yyloc - YY_USER_ARGS); + ]b4_user_args[); if (yyflag != yyok) return yyflag; yys->yyresolved = yytrue; @@ -1263,14 +1284,14 @@ yyresolveStates (yyGLRState* yys, int yyn, yyGLRStack* yystack YY_USER_FORMALS) static YYRESULTTAG yyresolveAction (yySemanticOption* yyopt, yyGLRStack* yystack, - YYSTYPE* yyvalp, YYLTYPE* yylocp YY_USER_FORMALS) + YYSTYPE* yyvalp, YYLTYPE* yylocp]b4_user_formals[) { yyGLRStackItem yyrhsVals[YYMAXRHS]; int yynrhs, yyi; yyGLRState* yys; yynrhs = yyrhsLength (yyopt->yyrule); - YYCHK (yyresolveStates (yyopt->yystate, yynrhs, yystack YY_USER_ARGS)); + YYCHK (yyresolveStates (yyopt->yystate, yynrhs, yystack]b4_user_args[)); for (yyi = yynrhs-1, yys = yyopt->yystate; 0 <= yyi; yyi -= 1, yys = yys->yypred) { @@ -1280,7 +1301,7 @@ yyresolveAction (yySemanticOption* yyopt, yyGLRStack* yystack, yyrhsVals[yyi].yystate.yyloc = yys->yyloc; } return yyuserAction (yyopt->yyrule, yynrhs, yyrhsVals + (yynrhs-1), - yyvalp, yylocp, yystack YY_USER_ARGS); + yyvalp, yylocp, yystack]b4_user_args[); } #if YYDEBUG @@ -1331,7 +1352,7 @@ yyreportTree (yySemanticOption* yyx, int yyindent) static void yyreportAmbiguity (yySemanticOption* yyx0, yySemanticOption* yyx1, - yyGLRStack* yystack) + yyGLRStack* yystack]b4_pure_formals[) { /* `Unused' warnings. */ (void) yyx0; @@ -1345,7 +1366,7 @@ yyreportAmbiguity (yySemanticOption* yyx0, yySemanticOption* yyx1, yyreportTree (yyx1, 2); YYFPRINTF (stderr, "\n"); #endif - yyFail (yystack, "ambiguity detected"); + yyFail (yystack][]b4_pure_args[, "ambiguity detected"); } @@ -1353,7 +1374,7 @@ yyreportAmbiguity (yySemanticOption* yyx0, yySemanticOption* yyx1, * actions, and return the result. */ static YYRESULTTAG yyresolveValue (yySemanticOption* yyoptionList, yyGLRStack* yystack, - YYSTYPE* yyvalp, YYLTYPE* yylocp YY_USER_FORMALS) + YYSTYPE* yyvalp, YYLTYPE* yylocp]b4_user_formals[) { yySemanticOption* yybest; yySemanticOption* yyp; @@ -1369,7 +1390,7 @@ yyresolveValue (yySemanticOption* yyoptionList, yyGLRStack* yystack, switch (yypreference (yybest, yyp)) { case 0: - yyreportAmbiguity (yybest, yyp, yystack); + yyreportAmbiguity (yybest, yyp, yystack]b4_pure_args[); break; case 1: yymerge = 1; @@ -1386,25 +1407,25 @@ yyresolveValue (yySemanticOption* yyoptionList, yyGLRStack* yystack, if (yymerge) { int yyprec = yydprec[yybest->yyrule]; - YYCHK (yyresolveAction (yybest, yystack, yyvalp, yylocp YY_USER_ARGS)); + YYCHK (yyresolveAction (yybest, yystack, yyvalp, yylocp]b4_user_args[)); for (yyp = yybest->yynext; yyp != NULL; yyp = yyp->yynext) { if (yyprec == yydprec[yyp->yyrule]) { YYSTYPE yyval1; YYLTYPE yydummy; - YYCHK (yyresolveAction (yyp, yystack, &yyval1, &yydummy YY_USER_ARGS)); + YYCHK (yyresolveAction (yyp, yystack, &yyval1, &yydummy]b4_user_args[)); *yyvalp = yyuserMerge (yymerger[yyp->yyrule], yyvalp, &yyval1); } } return yyok; } else - return yyresolveAction (yybest, yystack, yyvalp, yylocp YY_USER_ARGS); + return yyresolveAction (yybest, yystack, yyvalp, yylocp]b4_user_args[); } static YYRESULTTAG -yyresolveStack (yyGLRStack* yystack YY_USER_FORMALS) +yyresolveStack (yyGLRStack* yystack]b4_user_formals[) { if (yystack->yysplitPoint != NULL) { @@ -1416,7 +1437,7 @@ yyresolveStack (yyGLRStack* yystack YY_USER_FORMALS) yys = yys->yypred, yyn += 1) ; YYCHK (yyresolveStates (yystack->yytops.yystates[0], yyn, yystack - YY_USER_ARGS)); + ]b4_user_args[)); } return yyok; } @@ -1454,7 +1475,7 @@ yycompressStack (yyGLRStack* yystack) static YYRESULTTAG yyprocessOneStack (yyGLRStack* yystack, int yyk, size_t yyposn, YYSTYPE* yylvalp, YYLTYPE* yyllocp - YY_USER_FORMALS) + ]b4_user_formals[) { int yyaction; const short* yyconflicts; @@ -1475,7 +1496,7 @@ yyprocessOneStack (yyGLRStack* yystack, int yyk, yymarkStackDeleted (yystack, yyk); return yyok; } - YYCHK (yyglrReduce (yystack, yyk, yyrule, yyfalse YY_USER_ARGS)); + YYCHK (yyglrReduce (yystack, yyk, yyrule, yyfalse]b4_lpure_args[)); } else { @@ -1495,9 +1516,9 @@ yyprocessOneStack (yyGLRStack* yystack, int yyk, YYDPRINTF ((stderr, "Splitting off stack %d from %d.\n", yynewStack, yyk)); YYCHK (yyglrReduce (yystack, yynewStack, - *yyconflicts, yyfalse YY_USER_ARGS)); + *yyconflicts, yyfalse]b4_lpure_args[)); YYCHK (yyprocessOneStack (yystack, yynewStack, yyposn, - yylvalp, yyllocp YY_USER_ARGS)); + yylvalp, yyllocp]b4_user_args[)); yyconflicts += 1; } @@ -1505,7 +1526,8 @@ yyprocessOneStack (yyGLRStack* yystack, int yyk, { YYDPRINTF ((stderr, "Shifting token %s on stack %d, ", yytokenName (*yytokenp), yyk)); - yyglrShift (yystack, yyk, yyaction, yyposn+1, *yylvalp, yyllocp); + yyglrShift (yystack, yyk, yyaction, yyposn+1, + *yylvalp, yyllocp]b4_user_args[); YYDPRINTF ((stderr, "which is now in state #%d\n", yystack->yytops.yystates[yyk]->yylrState)); break; @@ -1517,14 +1539,15 @@ yyprocessOneStack (yyGLRStack* yystack, int yyk, break; } else - YYCHK (yyglrReduce (yystack, yyk, -yyaction, yyfalse YY_USER_ARGS)); + YYCHK (yyglrReduce (yystack, yyk, -yyaction, yyfalse]b4_lpure_args[)); } } return yyok; } static void -yyreportParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) +yyreportParseError (yyGLRStack* yystack, + YYSTYPE* yylvalp, YYLTYPE* yyllocp]b4_user_formals[) { /* `Unused' warnings. */ (void) yylvalp; @@ -1568,12 +1591,12 @@ yyreportParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) yyprefix = " or "; } } - yyerror (yymsg); + yyerror (yymsg]b4_lpure_args[); free (yymsg); } else #endif - yyerror ("parse error"); + yyerror ("parse error"]b4_lpure_args[); yynerrs += 1; } } @@ -1582,7 +1605,8 @@ yyreportParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) YYLVALP, and YYLLOCP point to the syntactic category, semantic value, and location of the lookahead. */ static void -yyrecoverParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) +yyrecoverParseError (yyGLRStack* yystack, + YYSTYPE* yylvalp, YYLTYPE* yyllocp]b4_user_formals[) { yySymbol* const yytokenp = yystack->yytokenp; size_t yyk; @@ -1596,7 +1620,7 @@ yyrecoverParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) while (yytrue) { if (*yytokenp == YYEOF) - yyFail (yystack, NULL); + yyFail (yystack][]b4_lpure_args[, NULL); if (*yytokenp != YYEMPTY) YYDPRINTF ((stderr, "Discarding token %s\n", yytokenName (*yytokenp))); @@ -1607,7 +1631,7 @@ yyrecoverParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) yyj = yypact[yystack->yytops.yystates[0]->yylrState]; if (yyj == YYPACT_NINF) /* Something's not right; we shouldn't be here. */ - yyFail (yystack, NULL); + yyFail (yystack][]b4_lpure_args[, NULL); yyj += *yytokenp; if (yyj < 0 || YYLAST < yyj || yycheck[yyj] != *yytokenp) { @@ -1623,7 +1647,7 @@ yyrecoverParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) if (yystack->yytops.yystates[yyk] != NULL) break; if (yyk >= yystack->yytops.yysize) - yyFail (yystack, NULL); + yyFail (yystack][]b4_lpure_args[, NULL); for (yyk += 1; yyk < yystack->yytops.yysize; yyk += 1) yymarkStackDeleted (yystack, yyk); yyremoveDeletes (yystack); @@ -1637,7 +1661,8 @@ yyrecoverParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) yycheck[yyj] == YYTERROR && yyisShiftAction (yytable[yyj])) { yyglrShift (yystack, 0, yytable[yyj], - yystack->yytops.yystates[0]->yyposn, *yylvalp, yyllocp); + yystack->yytops.yystates[0]->yyposn, + *yylvalp, yyllocp]b4_user_args[); break; } yystack->yytops.yystates[0] = yystack->yytops.yystates[0]->yypred; @@ -1645,7 +1670,7 @@ yyrecoverParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) yystack->yyspaceLeft += 1; } if (yystack->yytops.yystates[0] == NULL) - yyFail (yystack, NULL); + yyFail (yystack][]b4_lpure_args[, NULL); } #define YYCHK1(YYE) \ @@ -1693,7 +1718,7 @@ yyrecoverParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) if (setjmp (yystack.yyexception_buffer) != 0) goto yyDone; - yyglrShift (&yystack, 0, 0, 0, yyval_default, &yyloc_default); + yyglrShift (&yystack, 0, 0, 0, yyval_default, &yyloc_default]b4_user_args[); yytoken = YYEMPTY; yyposn = 0; @@ -1718,10 +1743,10 @@ yyrecoverParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) yyrule = yydefaultAction (yystate); if (yyrule == 0) { - yyreportParseError (&yystack, yylvalp, yyllocp); + yyreportParseError (&yystack, yylvalp, yyllocp]b4_user_args[); goto yyuser_error; } - YYCHK1 (yyglrReduce (&yystack, 0, yyrule, yytrue YY_USER_ARGS)); + YYCHK1 (yyglrReduce (&yystack, 0, yyrule, yytrue]b4_lpure_args[)); } else { @@ -1743,7 +1768,8 @@ yyrecoverParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) if (yytoken != YYEOF) yytoken = YYEMPTY; yyposn += 1; - yyglrShift (&yystack, 0, yyaction, yyposn, yylval, yyllocp); + yyglrShift (&yystack, 0, yyaction, yyposn, + yylval, yyllocp]b4_user_args[); if (0 < yystack.yyerrState) yystack.yyerrState -= 1; YYDPRINTF ((stderr, "Entering state %d\n", @@ -1751,11 +1777,11 @@ yyrecoverParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) } else if (yyisErrorAction (yyaction)) { - yyreportParseError (&yystack, yylvalp, yyllocp); + yyreportParseError (&yystack, yylvalp, yyllocp]b4_user_args[); goto yyuser_error; } else - YYCHK1 (yyglrReduce (&yystack, 0, -yyaction, yytrue YY_USER_ARGS)); + YYCHK1 (yyglrReduce (&yystack, 0, -yyaction, yytrue]b4_lpure_args[)); } } @@ -1765,7 +1791,7 @@ yyrecoverParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) int yyn = yystack.yytops.yysize; for (yys = 0; yys < yyn; yys += 1) YYCHK1 (yyprocessOneStack (&yystack, yys, yyposn, - yylvalp, yyllocp YY_USER_ARGS)); + yylvalp, yyllocp]b4_user_args[)); yytoken = YYEMPTY; yyposn += 1; yyremoveDeletes (&yystack); @@ -1773,15 +1799,15 @@ yyrecoverParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) { yyundeleteLastStack (&yystack); if (yystack.yytops.yysize == 0) - yyFail (&yystack, "parse error"); - YYCHK1 (yyresolveStack (&yystack YY_USER_ARGS)); + yyFail (&yystack][]b4_lpure_args[, "parse error"); + YYCHK1 (yyresolveStack (&yystack]b4_user_args[)); YYDPRINTF ((stderr, "Returning to deterministic operation.\n")); - yyreportParseError (&yystack, yylvalp, yyllocp); + yyreportParseError (&yystack, yylvalp, yyllocp]b4_user_args[); goto yyuser_error; } else if (yystack.yytops.yysize == 1) { - YYCHK1 (yyresolveStack (&yystack YY_USER_ARGS)); + YYCHK1 (yyresolveStack (&yystack]b4_user_args[)); YYDPRINTF ((stderr, "Returning to deterministic operation.\n")); yycompressStack (&yystack); break; @@ -1789,7 +1815,7 @@ yyrecoverParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp) } continue; yyuser_error: - yyrecoverParseError (&yystack, yylvalp, yyllocp); + yyrecoverParseError (&yystack, yylvalp, yyllocp]b4_user_args[); yyposn = yystack.yytops.yystates[0]->yyposn; } yyDone: diff --git a/data/yacc.c b/data/yacc.c index 0bbd482..cd93373 100644 --- a/data/yacc.c +++ b/data/yacc.c @@ -33,19 +33,37 @@ m4_define_default([b4_stack_depth_init], [200]) # Location type. m4_define_default([b4_location_type], [yyltype]) + +## ------------------------ ## +## Pure/impure interfaces. ## +## ------------------------ ## + + +# b4_Pure_if(IF-TRUE, IF-FALSE) +# ----------------------------- +# Expand IF-TRUE, if %pure-parser and %parse-param, IF-FALSE otherwise. +m4_define([b4_Pure_if], +[b4_pure_if([m4_ifset([b4_parse_param], + [$1], [$2])], + [$2])]) + + +# b4_pure_args +# ------------ +# Arguments passed to yyerror: user args plus yylloc. +m4_define([b4_pure_args], +[b4_Pure_if([b4_location_if([, &yylloc])])[]b4_user_args]) + + +# b4_lex_param +# ------------ # Accumule in b4_lex_param all the yylex arguments. -# Yes, this is quite ugly... +# b4_lex_param arrives quoted twice, but we want to keep only one level. m4_define([b4_lex_param], m4_dquote(b4_pure_if([[[[YYSTYPE *]], [[&yylval]]][]dnl b4_location_if([, [[YYLTYPE *], [&yylloc]]])])dnl m4_ifdef([b4_lex_param], [, ]b4_lex_param))) -# Yes, this is quite ugly... -m4_define_default([b4_parse_param]) -m4_ifdef([b4_parse_param], -[m4_define([b4_parse_param], - b4_parse_param)]) - ## ------------ ## @@ -56,7 +74,7 @@ m4_ifdef([b4_parse_param], # --------------------- # Return the smallest int type able to handle numbers ranging from # MIN to MAX (included). We overwrite the version from c.m4 which relies -# on `signed char' which is not portable to old K&R compilers. +# on "signed char" which is not portable to old K&R compilers. m4_define([b4_int_type], [m4_if(b4_ints_in($@, [0], [255]), [1], [unsigned char], b4_ints_in($@, [-128], [127]), [1], [yysigned_char], @@ -178,15 +196,7 @@ b4_copyright([Skeleton parser for Yacc-like parsing with Bison], define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ -/* Identify Bison output. */ -#define YYBISON 1 - -/* Pure parsers. */ -#define YYPURE b4_pure - -/* Using locations. */ -#define YYLSP_NEEDED b4_locations_flag - +b4_identification m4_if(b4_prefix[], [yy], [], [/* If NAME_PREFIX is specified substitute the variables and functions names. */ @@ -519,7 +529,7 @@ do \ } \ else \ { \ - yyerror ("syntax error: cannot back up"); \ + yyerror ("syntax error: cannot back up"b4_pure_args); \ YYERROR; \ } \ while (0) @@ -1125,15 +1135,15 @@ yyerrlab: yycount++; } } - yyerror (yymsg); + yyerror (yymsg]b4_pure_args[); YYSTACK_FREE (yymsg); } else - yyerror ("parse error; also virtual memory exhausted"); + yyerror ("parse error; also virtual memory exhausted"]b4_pure_args[); } else #endif /* YYERROR_VERBOSE */ - yyerror ("parse error"); + yyerror ("parse error"]b4_pure_args[); } goto yyerrlab1; @@ -1248,7 +1258,7 @@ yyabortlab: | yyoverflowlab -- parser overflow comes here. | `----------------------------------------------*/ yyoverflowlab: - yyerror ("parser stack overflow"); + yyerror ("parser stack overflow"]b4_pure_args[); yyresult = 2; /* Fall through. */ #endif diff --git a/doc/bison.texinfo b/doc/bison.texinfo index 225bbaa..290cbab 100644 --- a/doc/bison.texinfo +++ b/doc/bison.texinfo @@ -682,7 +682,7 @@ involved, or by performing both actions, and then calling a designated user-defined function on the resulting values to produce an arbitrary merged result. -Let's consider an example, vastly simplified from C++. +Let's consider an example, vastly simplified from a C++ grammar. @example %@{ @@ -706,20 +706,20 @@ stmt : expr ';' %dprec 1 | decl %dprec 2 ; -expr : ID @{ printf ("%s ", $$); @} +expr : ID @{ printf ("%s ", $$); @} | TYPENAME '(' expr ')' - @{ printf ("%s ", $1); @} - | expr '+' expr @{ printf ("+ "); @} - | expr '=' expr @{ printf ("= "); @} + @{ printf ("%s ", $1); @} + | expr '+' expr @{ printf ("+ "); @} + | expr '=' expr @{ printf ("= "); @} ; decl : TYPENAME declarator ';' - @{ printf ("%s ", $1); @} + @{ printf ("%s ", $1); @} | TYPENAME declarator '=' expr ';' - @{ printf ("%s ", $1); @} + @{ printf ("%s ", $1); @} ; -declarator : ID @{ printf ("\"%s\" ", $1); @} +declarator : ID @{ printf ("\"%s\" ", $1); @} | '(' declarator ')' ; @end example @@ -3559,10 +3559,11 @@ accurate parse error messages. Rename the external symbols used in the parser so that they start with @var{prefix} instead of @samp{yy}. The precise list of symbols renamed is @code{yyparse}, @code{yylex}, @code{yyerror}, @code{yynerrs}, -@code{yylval}, @code{yychar}, @code{yydebug}, and possible -@code{yylloc}. For example, if you use @samp{%name-prefix="c_"}, the -names become @code{c_parse}, @code{c_lex}, and so on. @xref{Multiple -Parsers, ,Multiple Parsers in the Same Program}. +@code{yylval}, @code{yylloc}, @code{yychar}, @code{yydebug}, and +possible @code{yylloc}. For example, if you use +@samp{%name-prefix="c_"}, the names become @code{c_parse}, @code{c_lex}, +and so on. @xref{Multiple Parsers, ,Multiple Parsers in the Same +Program}. @item %no-parser Do not include any C code in the parser file; generate tables only. The @@ -3659,9 +3660,9 @@ instead of @samp{yy}. You can use this to give each parser distinct names that do not conflict. The precise list of symbols renamed is @code{yyparse}, @code{yylex}, -@code{yyerror}, @code{yynerrs}, @code{yylval}, @code{yychar} and -@code{yydebug}. For example, if you use @samp{-p c}, the names become -@code{cparse}, @code{clex}, and so on. +@code{yyerror}, @code{yynerrs}, @code{yylval}, @code{yylloc}, +@code{yychar} and @code{yydebug}. For example, if you use @samp{-p c}, +the names become @code{cparse}, @code{clex}, and so on. @strong{All the other variables and macros associated with Bison are not renamed.} These others are not global; there is no conflict if the same @@ -3706,23 +3707,65 @@ encounters end-of-input or an unrecoverable syntax error. You can also write an action which directs @code{yyparse} to return immediately without reading further. + +@deftypefun int yyparse (void) The value returned by @code{yyparse} is 0 if parsing was successful (return is due to end-of-input). The value is 1 if parsing failed (return is due to a syntax error). +@end deftypefun In an action, you can cause immediate return from @code{yyparse} by using these macros: -@table @code -@item YYACCEPT +@defmac YYACCEPT @findex YYACCEPT Return immediately with value 0 (to report success). +@end defmac -@item YYABORT +@defmac YYABORT @findex YYABORT Return immediately with value 1 (to report failure). -@end table +@end defmac + +If you use a reentrant parser, you can optionally pass additional +parameter information to it in a reentrant way. To do so, use the +declaration @code{%parse-param}: + +@deffn {Directive} %parse-param @var{argument-declaration} @var{argument-name} +@findex %parse-param +Declare that @code{argument-name} is an additional @code{yyparse} +argument. This argument is also passed to @code{yyerror}. The +@var{argument-declaration} is used when declaring functions or +prototypes. +@end deffn + +Here's an example. Write this in the parser: + +@example +%parse-param "int *nastiness" "nastiness" +%parse-param "int *randomness" "randomness" +@end example + +@noindent +Then call the parser like this: + +@example +@{ + int nastiness, randomness; + @dots{} /* @r{Store proper data in @code{nastiness} and @code{randomness}.} */ + value = yyparse (&nastiness, &randomness); + @dots{} +@} +@end example + +@noindent +In the grammar actions, use expressions like this to refer to the data: + +@example +exp: @dots{} @{ @dots{}; *randomness += 1; @dots{} @} +@end example + @node Lexical @section The Lexical Analyzer Function @code{yylex} @@ -3927,85 +3970,47 @@ textual positions, then the type @code{YYLTYPE} will not be defined. In this case, omit the second argument; @code{yylex} will be called with only one argument. -@vindex YYPARSE_PARAM -If you use a reentrant parser, you can optionally pass additional -parameter information to it in a reentrant way. To do so, define the -macro @code{YYPARSE_PARAM} as a variable name. This modifies the -@code{yyparse} function to accept one argument, of type @code{void *}, -with that name. - -When you call @code{yyparse}, pass the address of an object, casting the -address to @code{void *}. The grammar actions can refer to the contents -of the object by casting the pointer value back to its proper type and -then dereferencing it. Here's an example. Write this in the parser: -@example -%@{ -struct parser_control -@{ - int nastiness; - int randomness; -@}; +If you wish to pass the additional parameter data to @code{yylex}, use +@code{%lex-param} just like @code{%parse-param} (@pxref{Parser +Function}). -#define YYPARSE_PARAM parm -%@} -@end example +@deffn {Directive} lex-param @var{argument-declaration} @var{argument-name} +@findex %lex-param +Declare that @code{argument-name} is an additional @code{yylex} +argument. +@end deffn -@noindent -Then call the parser like this: +For instance: @example -struct parser_control -@{ - int nastiness; - int randomness; -@}; - -@dots{} - -@{ - struct parser_control foo; - @dots{} /* @r{Store proper data in @code{foo}.} */ - value = yyparse ((void *) &foo); - @dots{} -@} +%parse-param "int *nastiness" "nastiness" +%lex-param "int *nastiness" "nastiness" +%parse-param "int *randomness" "randomness" @end example @noindent -In the grammar actions, use expressions like this to refer to the data: +results in the following signature: @example -((struct parser_control *) parm)->randomness +int yylex (int *nastiness); +int yyparse (int *nastiness, int *randomness); @end example -@vindex YYLEX_PARAM -If you wish to pass the additional parameter data to @code{yylex}, -define the macro @code{YYLEX_PARAM} just like @code{YYPARSE_PARAM}, as -shown here: +If @code{%pure-parser} is added: @example -%@{ -struct parser_control -@{ - int nastiness; - int randomness; -@}; - -#define YYPARSE_PARAM parm -#define YYLEX_PARAM parm -%@} +int yylex (YYSTYPE *lvalp, int *nastiness); +int yyparse (int *nastiness, int *randomness); @end example -You should then define @code{yylex} to accept one additional -argument---the value of @code{parm}. (This makes either two or three -arguments in total, depending on whether an argument of type -@code{YYLTYPE} is passed.) You can declare the argument as a pointer to -the proper object type, or you can declare it as @code{void *} and -access the contents as shown above. +@noindent +and finally, if both @code{%pure-parser} and @code{%locations} are used: -You can use @samp{%pure-parser} to request a reentrant parser without -also using @code{YYPARSE_PARAM}. Then you should call @code{yyparse} -with no arguments, as usual. +@example +int yylex (YYSTYPE *lvalp, YYLTYPE *llocp, int *nastiness); +int yyparse (int *nastiness, int *randomness); +@end example @node Error Reporting @section The Error Reporting Function @code{yyerror} @@ -4026,13 +4031,11 @@ called by @code{yyparse} whenever a syntax error is found, and it receives one argument. For a parse error, the string is normally @w{@code{"parse error"}}. -@findex YYERROR_VERBOSE -If you define the macro @code{YYERROR_VERBOSE} in the Bison declarations -section (@pxref{Bison Declarations, ,The Bison Declarations Section}), -then Bison provides a more verbose and specific error message string -instead of just plain @w{@code{"parse error"}}. It doesn't matter what -definition you use for @code{YYERROR_VERBOSE}, just whether you define -it. +@findex %error-verbose +If you invoke the directive @code{%error-verbose} in the Bison +declarations section (@pxref{Bison Declarations, ,The Bison Declarations +Section}), then Bison provides a more verbose and specific error message +string instead of just plain @w{@code{"parse error"}}. The parser can detect one other kind of error: stack overflow. This happens when the input contains constructions that are very deeply @@ -4061,6 +4064,50 @@ error recovery if you have written suitable error recovery grammar rules (@pxref{Error Recovery}). If recovery is impossible, @code{yyparse} will immediately return 1. +Oviously, in location tracking pure parsers, @code{yyerror} should have +an access to the current location. This is indeed the case for the GLR +parsers, but not for the Yacc parser, for historical reasons. I.e., if +@samp{%locations %pure-parser} is passed then the prototypes for +@code{yyerror} are: + +@example +void yyerror (const char *msg); /* Yacc parsers. */ +void yyerror (const char *msg, YYLTYPE *locp); /* GLR parsers. */ +@end example + +If @samp{%parse-param "int *nastiness" "nastiness"} is used, then: + +@example +void yyerror (int *randomness); /* Yacc parsers. */ +void yyerror (int *randomness); /* GLR parsers. */ +@end example + +Finally, GLR and Yacc parsers share the same @code{yyerror} calling +convention for absolutely pure parsers, i.e., when the calling +convention of @code{yylex} @emph{and} the calling convention of +@code{%pure-parser} are pure. I.e.: + +@example +/* Location tracking. */ +%locations +/* Pure yylex. */ +%pure-parser +%lex-param "int *nastiness" "nastiness" +/* Pure yyparse. */ +%parse-param "int *nastiness" "nastiness" +%parse-param "int *randomness" "randomness" +@end example + +@noindent +results in the following signatures for all the parser kinds: + +@example +int yylex (YYSTYPE *lvalp, YYLTYPE *llocp, int *nastiness); +int yyparse (int *nastiness, int *randomness); +void yyerror (const char *msg, YYLTYPE *locp, + int *nastiness, int *randomness); +@end example + @vindex yynerrs The variable @code{yynerrs} contains the number of syntax errors encountered so far. Normally this variable is global; but if you @@ -5450,9 +5497,9 @@ state 0 $accept -> . exp $ (rule 0) - NUM shift, and go to state 1 + NUM shift, and go to state 1 - exp go to state 2 + exp go to state 2 @end example This reads as follows: ``state 0 corresponds to being at the very @@ -5499,7 +5546,7 @@ state 1 exp -> NUM . (rule 5) - $default reduce using rule 5 (exp) + $default reduce using rule 5 (exp) @end example @noindent @@ -5517,11 +5564,11 @@ state 2 exp -> exp . '*' exp (rule 3) exp -> exp . '/' exp (rule 4) - $ shift, and go to state 3 - '+' shift, and go to state 4 - '-' shift, and go to state 5 - '*' shift, and go to state 6 - '/' shift, and go to state 7 + $ shift, and go to state 3 + '+' shift, and go to state 4 + '-' shift, and go to state 5 + '*' shift, and go to state 6 + '/' shift, and go to state 7 @end example @noindent @@ -5540,7 +5587,7 @@ state 3 $accept -> exp $ . (rule 0) - $default accept + $default accept @end example @noindent @@ -5555,33 +5602,33 @@ state 4 exp -> exp '+' . exp (rule 1) - NUM shift, and go to state 1 + NUM shift, and go to state 1 - exp go to state 8 + exp go to state 8 state 5 exp -> exp '-' . exp (rule 2) - NUM shift, and go to state 1 + NUM shift, and go to state 1 - exp go to state 9 + exp go to state 9 state 6 exp -> exp '*' . exp (rule 3) - NUM shift, and go to state 1 + NUM shift, and go to state 1 - exp go to state 10 + exp go to state 10 state 7 exp -> exp '/' . exp (rule 4) - NUM shift, and go to state 1 + NUM shift, and go to state 1 - exp go to state 11 + exp go to state 11 @end example As was announced in beginning of the report, @samp{State 8 contains 1 @@ -5596,11 +5643,11 @@ state 8 exp -> exp . '*' exp (rule 3) exp -> exp . '/' exp (rule 4) - '*' shift, and go to state 6 - '/' shift, and go to state 7 + '*' shift, and go to state 6 + '/' shift, and go to state 7 - '/' [reduce using rule 1 (exp)] - $default reduce using rule 1 (exp) + '/' [reduce using rule 1 (exp)] + $default reduce using rule 1 (exp) @end example Indeed, there are two actions associated to the lookahead @samp{/}: @@ -5657,11 +5704,11 @@ state 9 exp -> exp . '*' exp (rule 3) exp -> exp . '/' exp (rule 4) - '*' shift, and go to state 6 - '/' shift, and go to state 7 + '*' shift, and go to state 6 + '/' shift, and go to state 7 - '/' [reduce using rule 2 (exp)] - $default reduce using rule 2 (exp) + '/' [reduce using rule 2 (exp)] + $default reduce using rule 2 (exp) state 10 @@ -5671,10 +5718,10 @@ state 10 exp -> exp '*' exp . (rule 3) exp -> exp . '/' exp (rule 4) - '/' shift, and go to state 7 + '/' shift, and go to state 7 - '/' [reduce using rule 3 (exp)] - $default reduce using rule 3 (exp) + '/' [reduce using rule 3 (exp)] + $default reduce using rule 3 (exp) state 11 @@ -5684,16 +5731,16 @@ state 11 exp -> exp . '/' exp (rule 4) exp -> exp '/' exp . (rule 4) - '+' shift, and go to state 4 - '-' shift, and go to state 5 - '*' shift, and go to state 6 - '/' shift, and go to state 7 + '+' shift, and go to state 4 + '-' shift, and go to state 5 + '*' shift, and go to state 6 + '/' shift, and go to state 7 - '+' [reduce using rule 4 (exp)] - '-' [reduce using rule 4 (exp)] - '*' [reduce using rule 4 (exp)] - '/' [reduce using rule 4 (exp)] - $default reduce using rule 4 (exp) + '+' [reduce using rule 4 (exp)] + '-' [reduce using rule 4 (exp)] + '*' [reduce using rule 4 (exp)] + '/' [reduce using rule 4 (exp)] + $default reduce using rule 4 (exp) @end example @noindent @@ -6171,18 +6218,21 @@ Macro to pretend that a syntax error has just been detected: call @code{yyparse} return 1. @xref{Error Recovery}. @item YYERROR_VERBOSE -Macro that you define with @code{#define} in the Bison declarations -section to request verbose, specific error message strings when -@code{yyerror} is called. +An obsolete macro that you define with @code{#define} in the Bison +declarations section to request verbose, specific error message strings +when @code{yyerror} is called. It doesn't matter what definition you +use for @code{YYERROR_VERBOSE}, just whether you define it. Using +@code{%error-verbose} is preferred. @item YYINITDEPTH Macro for specifying the initial size of the parser stack. @xref{Stack Overflow}. @item YYLEX_PARAM -Macro for specifying an extra argument (or list of extra arguments) for -@code{yyparse} to pass to @code{yylex}. @xref{Pure Calling,, Calling -Conventions for Pure Parsers}. +An obsolete macro for specifying an extra argument (or list of extra +arguments) for @code{yyparse} to pass to @code{yylex}. he use of this +macro is deprecated, and is supported only for Yacc like parsers. +@xref{Pure Calling,, Calling Conventions for Pure Parsers}. @item YYLTYPE Macro for the data type of @code{yylloc}; a structure with four @@ -6196,8 +6246,10 @@ Macro for specifying the maximum size of the parser stack. @xref{Stack Overflow}. @item YYPARSE_PARAM -Macro for specifying the name of a parameter that @code{yyparse} should -accept. @xref{Pure Calling,, Calling Conventions for Pure Parsers}. +An obsolete macro for specifying the name of a parameter that +@code{yyparse} should accept. The use of this macro is deprecated, and +is supported only for Yacc like parsers. @xref{Pure Calling,, Calling +Conventions for Pure Parsers}. @item YYRECOVERING Macro whose value indicates whether the parser is recovering from a @@ -6278,6 +6330,10 @@ Bison declaration to assign a precedence to a rule that is used at parse time to resolve reduce/reduce conflicts. @xref{GLR Parsers, ,Writing @acronym{GLR} Parsers}. +@item %error-verbose +Bison declaration to request verbose, specific error message strings +when @code{yyerror} is called. + @item %file-prefix="@var{prefix}" Bison declaration to set the prefix of the output files. @xref{Decl Summary}. @@ -6298,6 +6354,11 @@ Parsers, ,Writing @acronym{GLR} Parsers}. Bison declaration to assign left associativity to token(s). @xref{Precedence Decl, ,Operator Precedence}. +@item %lex-param "@var{argument-declaration}" "@var{argument-name}" +Bison declaration to specifying an additional parameter that +@code{yylex} should accept. @xref{Pure Calling,, Calling Conventions +for Pure Parsers}. + @item %merge Bison declaration to assign a merging function to a rule. If there is a reduce/reduce conflict with a rule having the same merging function, the @@ -6319,6 +6380,11 @@ Bison declaration to assign non-associativity to token(s). Bison declaration to set the name of the parser file. @xref{Decl Summary}. +@item %parse-param "@var{argument-declaration}" "@var{argument-name}" +Bison declaration to specifying an additional parameter that +@code{yyparse} should accept. @xref{Parser Function,, The Parser +Function @code{yyparse}}. + @item %prec Bison declaration to assign a precedence to a specific rule. @xref{Contextual Precedence, ,Context-Dependent Precedence}. diff --git a/tests/calc.at b/tests/calc.at index d239ddd..82674c1 100644 --- a/tests/calc.at +++ b/tests/calc.at @@ -26,8 +26,8 @@ # ------------------------- # -# _AT_DATA_CALC_Y($1, $2, $3, [CPP-DIRECTIVES]) -# --------------------------------------------- +# _AT_DATA_CALC_Y($1, $2, $3, [BISON-DIRECTIVES]) +# ----------------------------------------------- # Produce `calc.y'. Don't call this macro directly, because it contains # some occurrences of `$1' etc. which will be interpreted by m4. So # you should call it with $1, $2, and $3 as arguments, which is what @@ -37,7 +37,7 @@ m4_define([_AT_DATA_CALC_Y], [m4_fatal([$0: Invalid arguments: $@])])dnl AT_DATA([calc.y], [[/* Infix notation calculator--calc */ - +]$4[ %{ #include /* We don't need perfect functions for these tests. */ @@ -63,9 +63,6 @@ int global_count = 0; %} -%parse-param "value_t *result", "result" -%parse-param "int *count", "count" - /* Exercise %union. */ %union { @@ -81,16 +78,14 @@ int global_count = 0; # define VAL (yylval) #endif +#define YYLLOC_FORMAL ]AT_LOCATION_IF([, YYLTYPE *yylloc])[ +#define YYLLOC_ARG ]AT_LOCATION_IF([, yylloc])[ +#define USE_YYLLOC ]AT_LOCATION_IF([(void) yylloc;])[ + #if YYPURE -# if YYLSP_NEEDED -# define LEX_FORMALS YYSTYPE *yylval, YYLTYPE *yylloc -# define LEX_ARGS yylval, yylloc -# define USE_LEX_ARGS (void) yylval; (void) yylloc; -# else -# define LEX_FORMALS YYSTYPE *yylval -# define LEX_ARGS yylval -# define USE_LEX_ARGS (void) yylval -# endif +# define LEX_FORMALS YYSTYPE *yylval YYLLOC_FORMAL +# define LEX_ARGS yylval YYLLOC_ARG +# define USE_LEX_ARGS (void) yylval; USE_YYLLOC # define LEX_PRE_FORMALS LEX_FORMALS, # define LEX_PRE_ARGS LEX_ARGS, #else @@ -102,7 +97,13 @@ int global_count = 0; #endif static int power (int base, int exponent); -static void yyerror (const char *s); +/* yyerror receives the location if: + - %location & %pure & %glr + - %location & %pure & %yacc & %parse-param. */ +static void yyerror (const char *s + ]AT_YYERROR_ARG_LOC_IF([, YYLTYPE *yylloc])[ + ]AT_PARAM_IF([, value_t *result, int *count])[ + ); static int yylex (LEX_FORMALS); static int yygetc (LEX_FORMALS); static void yyungetc (LEX_PRE_FORMALS int c); @@ -119,27 +120,25 @@ static void yyungetc (LEX_PRE_FORMALS int c); %left NEG /* negation--unary minus */ %right '^' /* exponentiation */ -]$4[ - /* Grammar follows */ %% input: line -| input line { ++*count; ++global_count; } +| input line { ]AT_PARAM_IF([++*count; ++global_count;])[ } ; line: '\n' -| exp '\n' { *result = global_result = $1; } +| exp '\n' { ]AT_PARAM_IF([*result = global_result = $1;])[ } ; exp: NUM { $$ = $1; } | exp '=' exp { - if ($1 != $3) - fprintf (stderr, "calc: error: %d != %d\n", $1, $3); - $$ = $1; + if ($1 != $3) + fprintf (stderr, "calc: error: %d != %d\n", $1, $3); + $$ = $1; } | exp '+' exp { $$ = $1 + $3; } | exp '-' exp { $$ = $1 - $3; } @@ -155,26 +154,28 @@ exp: FILE *yyin; static void -yyerror (const char *s) +yyerror (const char *s + ]AT_YYERROR_ARG_LOC_IF([, YYLTYPE *yylloc])[ + ]AT_PARAM_IF([, value_t *result, int *count])[) { -#if YYLSP_NEEDED +]AT_YYERROR_SEES_LOC_IF([ fprintf (stderr, "%d.%d-%d.%d: ", LOC.first_line, LOC.first_column, LOC.last_line, LOC.last_column); -#endif +])[ fprintf (stderr, "%s\n", s); } -#if YYLSP_NEEDED +]AT_LOCATION_IF([ static YYLTYPE last_yylloc; -#endif +])[ static int yygetc (LEX_FORMALS) { int res = getc (yyin); USE_LEX_ARGS; -#if YYLSP_NEEDED +]AT_LOCATION_IF([ last_yylloc = LOC; if (res == '\n') { @@ -183,7 +184,7 @@ yygetc (LEX_FORMALS) } else LOC.last_column++; -#endif +])[ return res; } @@ -192,10 +193,10 @@ static void yyungetc (LEX_PRE_FORMALS int c) { USE_LEX_ARGS; -#if YYLSP_NEEDED +]AT_LOCATION_IF([ /* Wrong when C == `\n'. */ LOC = last_yylloc; -#endif +])[ ungetc (c, yyin); } @@ -241,24 +242,24 @@ yylex (LEX_FORMALS) if (init) { init = 0; -#if YYLSP_NEEDED +]AT_LOCATION_IF([ LOC.last_column = 1; LOC.last_line = 1; -#endif +])[ } -#if YYLSP_NEEDED +]AT_LOCATION_IF([ LOC.first_column = LOC.last_column; LOC.first_line = LOC.last_line; -#endif +])[ /* Skip white space. */ while ((c = yygetc (LEX_ARGS)) == ' ' || c == '\t') { -#if YYLSP_NEEDED +]AT_LOCATION_IF([ LOC.first_column = LOC.last_column; LOC.first_line = LOC.last_line; -#endif +])[ } /* process numbers */ @@ -309,7 +310,7 @@ main (int argc, const char **argv) #if YYDEBUG yydebug = 1; #endif - yyparse (&result, &count); + yyparse (]AT_PARAM_IF([&result, &count])[); assert (global_result == result); assert (global_count == count); @@ -352,8 +353,8 @@ m4_bmatch([$1], # _AT_CHECK_CALC_ERROR(BISON-OPTIONS, INPUT, [NUM-DEBUG-LINES], -# [ERROR-LOCATION], [IF-YYERROR-VERBOSE]) -# ------------------------------------------------------------ +# [VERBOSE-AND-LOCATED-ERROR-MESSAGE]) +# ------------------------------------------------------------- # Run `calc' on INPUT, and expect a `parse error' message. # # If INPUT starts with a slash, it is used as absolute input file name, @@ -402,7 +403,7 @@ AT_DATA([[expout]], [$4 ]) # 3. If locations are not used, remove them. -m4_bmatch([$1], [%locations], [], +AT_YYERROR_SEES_LOC_IF([], [[sed 's/^[-0-9.]*: //' expout >at-expout mv at-expout expout]]) # 4. If error-verbose is not used, strip the`, unexpected....' part. @@ -414,6 +415,54 @@ AT_CHECK([cat stderr], 0, [expout]) ]) +# AT_CALC_PUSHDEFS($1, $2, [BISON-OPTIONS]) +# ----------------------------------------- +# This macro works around the impossibility to define macros +# inside macros, because issuing `[$1]' is not possible in M4 :(. +# This sucks hard, GNU M4 should really provide M5 like $$1. +m4_define([AT_CHECK_PUSHDEFS], +[m4_if([$1$2], $[1]$[2], [], + [m4_fatal([$0: Invalid arguments: $@])])dnl +m4_pushdef([AT_PARAM_IF], +[m4_bmatch([$3], [%parse-param], [$1], [$2])]) +m4_pushdef([AT_LOCATION_IF], +[m4_bmatch([$3], [%locations], [$1], [$2])]) +m4_pushdef([AT_PURE_IF], +[m4_bmatch([$3], [%pure-parser], [$1], [$2])]) +m4_pushdef([AT_GLR_IF], +[m4_bmatch([$3], [%glr-parser], [$1], [$2])]) +m4_pushdef([AT_PURE_AND_LOC_IF], +[m4_bmatch([$3], [%locations.*%pure-parser\|%pure-parser.*%locations], + [$1], [$2])]) +m4_pushdef([AT_GLR_OR_PARAM_IF], +[m4_bmatch([$3], [%glr-parser\|%parse-param], [$1], [$2])]) + +# yyerror receives the location if %location & %pure & (%glr or %parse-param). +m4_pushdef([AT_YYERROR_ARG_LOC_IF], +[AT_GLR_OR_PARAM_IF([AT_PURE_AND_LOC_IF([$1], [$2])], + [$2])]) +# yyerror cannot see the locations if !glr & pure. +m4_pushdef([AT_YYERROR_SEES_LOC_IF], +[AT_LOCATION_IF([AT_GLR_IF([$1], + [AT_PURE_IF([$2], [$1])])], + [$2])]) +]) + + +# AT_CALC_POPDEFS +# --------------- +m4_define([AT_CHECK_POPDEFS], +[m4_popdef([AT_YYERROR_SEES_LOC_IF]) +m4_popdef([AT_YYERROR_ARG_LOC_IF]) +m4_popdef([AT_GLR_OR_PARAM_IF]) +m4_popdef([AT_PURE_AND_LOC_IF]) +m4_popdef([AT_GLR_IF]) +m4_popdef([AT_LOCATION_IF]) +m4_popdef([AT_PARAM_IF]) +]) + + + # AT_CHECK_CALC([BISON-OPTIONS]) # ------------------------------ # Start a testing chunk which compiles `calc' grammar with @@ -422,6 +471,8 @@ m4_define([AT_CHECK_CALC], [# We use integers to avoid dependencies upon the precision of doubles. AT_SETUP([Calculator $1]) +AT_CHECK_PUSHDEFS($[1], $[2], [$1]) + AT_DATA_CALC_Y([$1]) # Specify the output files to avoid problems on different file systems. @@ -473,6 +524,8 @@ _AT_CHECK_CALC_ERROR([$1], [(1 ++ 2) + (0 0) = 1], [82], 1.15-1.16: parse error, unexpected "number" calc: error: 0 != 1]) +AT_CHECK_POPDEFS + AT_CLEANUP ])# AT_CHECK_CALC @@ -508,7 +561,9 @@ AT_CHECK_CALC_LALR([%error-verbose %locations %defines %name-prefix="calc" %verb 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([%pure-parser %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 %parse-param "value_t *result", "result" %parse-param "int *count", "count"]) # ----------------------- # @@ -541,4 +596,6 @@ AT_CHECK_CALC_GLR([%error-verbose %locations %defines %name-prefix="calc" %verbo AT_CHECK_CALC_GLR([%debug]) AT_CHECK_CALC_GLR([%error-verbose %debug %locations %defines %name-prefix="calc" %verbose %yacc]) -# AT_CHECK_CALC_GLR([%pure-parser %error-verbose %debug %locations %defines %name-prefix="calc" %verbose %yacc]) +AT_CHECK_CALC_GLR([%pure-parser %error-verbose %debug %locations %defines %name-prefix="calc" %verbose %yacc]) + +AT_CHECK_CALC_GLR([%pure-parser %error-verbose %debug %locations %defines %name-prefix="calc" %verbose %yacc %parse-param "value_t *result", "result" %parse-param "int *count", "count"]) diff --git a/tests/cxx-type.at b/tests/cxx-type.at index 9562b13..61c7f50 100644 --- a/tests/cxx-type.at +++ b/tests/cxx-type.at @@ -36,7 +36,11 @@ $1 ]m4_bmatch([$2], [stmtMerge], [ static YYSTYPE stmtMerge (YYSTYPE x0, YYSTYPE x1);])[ #define YYINITDEPTH 10 - int yyerror (const char *s); + int yyerror (const char *s +#if YYPURE && YYLSP_NEEDED + , YYLTYPE *yylocation +#endif + ); #if YYPURE ]m4_bmatch([$1], [location], @@ -130,7 +134,7 @@ yylex () break; default: if (isalpha (c)) - { + { i = 0; do @@ -153,8 +157,15 @@ yylex () } int -yyerror (const char *s) +yyerror (const char *s +#if YYPURE && YYLSP_NEEDED + , YYLTYPE *yylocation +#endif + ) { +#if YYPURE && YYLSP_NEEDED + (void) *yylocation; +#endif fprintf (stderr, "%s\n", s); return 0; } -- 2.7.4