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 <akim@epita.fr>
+ * 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 <akim@epita.fr>
+
* tests/calc.at: Change all the AT_CHECK_CALC_LALR and
AT_CHECK_CALC_GLR invocations to use % directives, instead of
command line options.
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.
# 02111-1307 USA
-## ----------- ##
-## Copyright. ##
-## ----------- ##
+## ---------------- ##
+## Identification. ##
+## ---------------- ##
# b4_copyright(TITLE, YEARS)
# --------------------------
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. ##
## ------------ ##
# 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],
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. ##
[
/* This is the parser code for GLR (Generalized LR) parser. */
-/* FIXME: minimize these */
#include <assert.h>
-#include <setjmp.h>
-#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
+#include <setjmp.h>
-/* 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
\f
/* 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
};
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)
{
va_start (yyap, yyformat);
yystack->yyerrflag = 1;
vsprintf (yymsg, yyformat, yyap);
- yyerror (yymsg);
+ yyerror (yymsg]b4_pure_args[);
}
longjmp (yystack->yyexception_buffer, 1);
}
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;
# 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)
yyuserMerge (int yyn, YYSTYPE* yy0, YYSTYPE* yy1)
{
YYSTYPE yyval = *yy0;
- /* `Use' the arguments. */
+ /* `Use' the arguments. */
(void) yy0;
(void) 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
static void
yyaddDeferredAction (yyGLRStack* yystack, yyGLRState* yystate,
- yyGLRState* rhs, yyRuleNum yyrule)
+ yyGLRState* rhs, yyRuleNum yyrule]b4_pure_formals[)
{
yySemanticOption* yynewItem;
yynewItem = &yystack->yynextFree->yyoption;
yynewItem->yynext = yystate->yysemantics.yyfirstVal;
yystate->yysemantics.yyfirstVal = yynewItem;
if (yystack->yyspaceLeft < YYHEADROOM)
- yyexpandGLRStack (yystack);
+ yyexpandGLRStack (yystack]b4_pure_args[);
}
/* GLRStacks */
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;
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;
#else
- yyFail (yystack, "parsing stack overflow (%d items)", yysize);
-
+ yyFail (yystack][]b4_lpure_args[,
+ "parsing stack overflow (%d items)", yysize);
#endif
}
* 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;
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
* 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;
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
* 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);
*yylocp = rhs[1-yynrhs].yystate.yyloc;
}
return yyuserAction (yyrule, yynrhs, rhs,
- yyvalp, yylocp, yystack YY_USER_ARGS);
+ yyvalp, yylocp, yystack]b4_user_args[);
}
else
{
*yylocp = yyrhsVals[0].yystate.yyloc;
}
return yyuserAction (yyrule, yynrhs, yyrhsVals + (yynrhs-1),
- yyvalp, yylocp, yystack YY_USER_ARGS);
+ yyvalp, yylocp, yystack]b4_user_args[);
}
}
*/
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;
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));
}
{
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));
}
}
yystack->yytops.yystates[yyk] = yys;
- yyglrShiftDefer (yystack, yyk, yynewLRState, yyposn, yys0, yyrule);
+ yyglrShiftDefer (yystack, yyk, yynewLRState, yyposn, yys0, yyrule]b4_pure_args[);
}
return 0;
}
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;
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)
{
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
static void
yyreportAmbiguity (yySemanticOption* yyx0, yySemanticOption* yyx1,
- yyGLRStack* yystack)
+ yyGLRStack* yystack]b4_pure_formals[)
{
/* `Unused' warnings. */
(void) yyx0;
yyreportTree (yyx1, 2);
YYFPRINTF (stderr, "\n");
#endif
- yyFail (yystack, "ambiguity detected");
+ yyFail (yystack][]b4_pure_args[, "ambiguity detected");
}
* 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;
switch (yypreference (yybest, yyp))
{
case 0:
- yyreportAmbiguity (yybest, yyp, yystack);
+ yyreportAmbiguity (yybest, yyp, yystack]b4_pure_args[);
break;
case 1:
yymerge = 1;
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)
{
yys = yys->yypred, yyn += 1)
;
YYCHK (yyresolveStates (yystack->yytops.yystates[0], yyn, yystack
- YY_USER_ARGS));
+ ]b4_user_args[));
}
return yyok;
}
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;
yymarkStackDeleted (yystack, yyk);
return yyok;
}
- YYCHK (yyglrReduce (yystack, yyk, yyrule, yyfalse YY_USER_ARGS));
+ YYCHK (yyglrReduce (yystack, yyk, yyrule, yyfalse]b4_lpure_args[));
}
else
{
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;
}
{
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;
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;
yyprefix = " or ";
}
}
- yyerror (yymsg);
+ yyerror (yymsg]b4_lpure_args[);
free (yymsg);
}
else
#endif
- yyerror ("parse error");
+ yyerror ("parse error"]b4_lpure_args[);
yynerrs += 1;
}
}
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;
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)));
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)
{
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);
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;
yystack->yyspaceLeft += 1;
}
if (yystack->yytops.yystates[0] == NULL)
- yyFail (yystack, NULL);
+ yyFail (yystack][]b4_lpure_args[, NULL);
}
#define YYCHK1(YYE) \
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;
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
{
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",
}
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[));
}
}
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);
{
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;
}
continue;
yyuser_error:
- yyrecoverParseError (&yystack, yylvalp, yyllocp);
+ yyrecoverParseError (&yystack, yylvalp, yyllocp]b4_user_args[);
yyposn = yystack.yytops.yystates[0]->yyposn;
}
yyDone:
# 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)])
-
## ------------ ##
# ---------------------
# 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],
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. */
} \
else \
{ \
- yyerror ("syntax error: cannot back up"); \
+ yyerror ("syntax error: cannot back up"b4_pure_args); \
YYERROR; \
} \
while (0)
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;
| yyoverflowlab -- parser overflow comes here. |
`----------------------------------------------*/
yyoverflowlab:
- yyerror ("parser stack overflow");
+ yyerror ("parser stack overflow"]b4_pure_args[);
yyresult = 2;
/* Fall through. */
#endif
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
%@{
| decl %dprec 2
;
-expr : ID @{ printf ("%s ", $$); @}
+expr : ID @{ printf ("%s ", $$); @}
| TYPENAME '(' expr ')'
- @{ printf ("%s <cast> ", $1); @}
- | expr '+' expr @{ printf ("+ "); @}
- | expr '=' expr @{ printf ("= "); @}
+ @{ printf ("%s <cast> ", $1); @}
+ | expr '+' expr @{ printf ("+ "); @}
+ | expr '=' expr @{ printf ("= "); @}
;
decl : TYPENAME declarator ';'
- @{ printf ("%s <declare> ", $1); @}
+ @{ printf ("%s <declare> ", $1); @}
| TYPENAME declarator '=' expr ';'
- @{ printf ("%s <init-declare> ", $1); @}
+ @{ printf ("%s <init-declare> ", $1); @}
;
-declarator : ID @{ printf ("\"%s\" ", $1); @}
+declarator : ID @{ printf ("\"%s\" ", $1); @}
| '(' declarator ')'
;
@end example
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
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
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}
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}
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
(@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
$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
exp -> NUM . (rule 5)
- $default reduce using rule 5 (exp)
+ $default reduce using rule 5 (exp)
@end example
@noindent
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
$accept -> exp $ . (rule 0)
- $default accept
+ $default accept
@end example
@noindent
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
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{/}:
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
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
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
@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
@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
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}.
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
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}.
# ------------------------- #
-# _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
[m4_fatal([$0: Invalid arguments: $@])])dnl
AT_DATA([calc.y],
[[/* Infix notation calculator--calc */
-
+]$4[
%{
#include <config.h>
/* We don't need perfect functions for these tests. */
%}
-%parse-param "value_t *result", "result"
-%parse-param "int *count", "count"
-
/* Exercise %union. */
%union
{
# 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
#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);
%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; }
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')
{
}
else
LOC.last_column++;
-#endif
+])[
return res;
}
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);
}
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 */
#if YYDEBUG
yydebug = 1;
#endif
- yyparse (&result, &count);
+ yyparse (]AT_PARAM_IF([&result, &count])[);
assert (global_result == result);
assert (global_count == count);
# _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,
[$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.
])
+# 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
[# 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.
1.15-1.16: parse error, unexpected "number"
calc: error: 0 != 1])
+AT_CHECK_POPDEFS
+
AT_CLEANUP
])# AT_CHECK_CALC
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"])
# ----------------------- #
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"])
]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],
break;
default:
if (isalpha (c))
- {
+ {
i = 0;
do
}
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;
}