summaryrefslogtreecommitdiff
path: root/data
diff options
context:
space:
mode:
authorAkim Demaille <akim.demaille@gmail.com>2021-08-11 17:58:40 +0200
committerAkim Demaille <akim.demaille@gmail.com>2021-09-12 12:03:58 +0200
commita75072476e251db338f392bef4200d3a2fe2c17a (patch)
tree5e864e36f50755a7d9ecc2aff68333623e56ad28 /data
parent7c47598d4f7c290b7127e329c09750dab0975eab (diff)
downloadbison-a75072476e251db338f392bef4200d3a2fe2c17a.tar.gz
glr2.cc: custom error messages
Reported by Tom Shields <thomas.evans.shields@icloud.com>. <https://lists.gnu.org/r/bug-bison/2021-08/msg00003.html> * data/skeletons/glr2.cc (context): New. Use it to generate the error messages. Add support for custom error messages. * tests/calc.at: Check support for custom error messages.
Diffstat (limited to 'data')
-rw-r--r--data/skeletons/glr2.cc263
1 files changed, 167 insertions, 96 deletions
diff --git a/data/skeletons/glr2.cc b/data/skeletons/glr2.cc
index 55bf8648..d5f21645 100644
--- a/data/skeletons/glr2.cc
+++ b/data/skeletons/glr2.cc
@@ -283,6 +283,25 @@ class glr_state;
static std::string symbol_name (symbol_kind_type yysymbol);]])[
]b4_token_constructor_define[
+]b4_parse_error_bmatch([custom\|detailed\|verbose], [[
+ class context
+ {
+ public:
+ context (glr_stack& yystack, const symbol_type& yyla);
+ const symbol_type& lookahead () const YY_NOEXCEPT { return yyla_; }
+ symbol_kind_type token () const YY_NOEXCEPT { return yyla_.kind (); }]b4_locations_if([[
+ const location_type& location () const YY_NOEXCEPT { return yyla_.location; }
+]])[
+ /// Put in YYARG at most YYARGN of the expected tokens, and return the
+ /// number of tokens stored in YYARG. If YYARG is null, return the
+ /// number of expected tokens (guaranteed to be less than YYNTOKENS).
+ int expected_tokens (symbol_kind_type yyarg[], int yyargn) const;
+
+ private:
+ glr_stack& yystack_;
+ const symbol_type& yyla_;
+ };
+]])[
# if ]b4_api_PREFIX[DEBUG
public:
/// \brief Report a symbol value on the debug stream.
@@ -304,7 +323,22 @@ class glr_state;
std::ostream* yycdebug_;
#endif
- public: // FIXME: Private
+]b4_parse_error_bmatch(
+[custom], [[
+ private:
+ /// Report a syntax error
+ /// \param yyctx the context in which the error occurred.
+ void report_syntax_error (const context& yyctx) const;]],
+[detailed\|verbose], [[
+ private:
+ /// The arguments of the error message.
+ int yy_syntax_error_arguments_ (const context& yyctx,
+ symbol_kind_type yyarg[], int yyargn) const;
+
+ /// Generate an error message.
+ /// \param yyctx the context in which the error occurred.
+ virtual std::string yysyntax_error_ (const context& yyctx) const;]])[
+
/// Convert a scanner token kind \a t to a symbol kind.
/// In theory \a t should be a token_kind_type, but character literals
/// are valid, yet not members of the token_kind_type enum.
@@ -2020,6 +2054,12 @@ public:
typedef parser_type::value_type value_type;]b4_locations_if([[
typedef parser_type::location_type location_type;]])[
+]b4_parse_error_bmatch([custom\|detailed\|verbose], [[
+ typedef parser_type::context context;
+ // Needs access to yypact_value_is_default, etc.
+ friend context;
+]])[
+
glr_stack (size_t yysize, ]b4_namespace_ref[::]b4_parser_class[& yyparser_yyarg]m4_ifset([b4_parse_param], [, b4_parse_param_decl])[)
: yyerrState (0)
, yystateStack (yysize)
@@ -2293,109 +2333,26 @@ b4_dollar_popdef])[]dnl
yystateStack.dumpStack();
}
#endif
+
void
yyreportSyntaxError ()
{
if (yyerrState != 0)
return;
-]b4_parse_error_bmatch(
-[simple],
-[[ yyparser.error (]b4_locations_if([this->yyla.location, ])[YY_("syntax error"));]],
-[[ {
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- /* Arguments of yyformat. */
- yysymbol_kind_t yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]
- = { ]b4_symbol(empty, kind)[ };
- /* Number of reported tokens (one for the "unexpected", one per
- "expected"). */
- int yycount = 0;
-
- /* There are many possibilities here to consider:
- - If this state is a consistent state with a default action, then
- the only way this function was invoked is if the default action
- is an error action. In that case, don't check for expected
- tokens because there are none.
- - The only way there can be no lookahead present (in yytoken) is if
- this state is a consistent state with a default action. Thus,
- detecting the absence of a lookahead is sufficient to determine
- that there is no unexpected or expected token to report. In that
- case, just report a simple "syntax error".
- - Don't assume there isn't a lookahead just because this state is a
- consistent state with a default action. There might have been a
- previous inconsistent state, consistent state with a non-default
- action, or user semantic action that manipulated yytoken.
- - Of course, the expected token list depends on states to have
- correct lookahead information, and it depends on the parser not
- to perform extra reductions after fetching a lookahead from the
- scanner and before detecting a syntax error. Thus, state merging
- (from LALR or IELR) and default reductions corrupt the expected
- token list. However, the list is correct for canonical LR with
- one exception: it will still contain any token that will not be
- accepted due to an error action in a later state.
- */
- if (!yyla.empty ())
- {
- const int yyn = yypact[firstTopState()->yylrState];
- yyarg[yycount++] = yyla.kind ();
- if (!yypact_value_is_default (yyn))
- {
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. In other words, skip the first -YYN actions for this
- state because they are default actions. */
- const int yyxbegin = yyn < 0 ? -yyn : 0;
- /* Stay within bounds of both yycheck and yytname. */
- const int yychecklim = YYLAST - yyn + 1;
- const int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
- for (int yyx = yyxbegin; yyx < yyxend; ++yyx)
- if (yycheck[yyx + yyn] == yyx && yyx != ]b4_symbol(error, kind)[
- && !yytable_value_is_error (yytable[yyx + yyn]))
- {
- if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
- {
- yycount = 1;
- break;
- }
- yyarg[yycount++] = static_cast<yysymbol_kind_t>(yyx);
- }
- }
- }
-
- /* Internationalized format string. */
- const char *yyformat = YY_NULLPTR;
- switch (yycount)
- {
-#define YYCASE_(N, S) \
- case N: \
- yyformat = S; \
- break
- default: /* Avoid compiler warnings. */
- YYCASE_(0, YY_("syntax error"));
- YYCASE_(1, YY_("syntax error, unexpected %s"));
- YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
- YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
- YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
- YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-#undef YYCASE_
- }
-
- std::string yymsg;
- // Argument number.
- std::ptrdiff_t yyi = 0;
- for (char const* yyp = yyformat; *yyp; ++yyp)
- if (yyp[0] == '%' && yyp[1] == 's' && yyi < yycount)
- {
- yymsg += ]b4_namespace_ref[::]b4_parser_class[::symbol_name (yyarg[yyi++]);
- ++yyp;
- }
- else
- yymsg += *yyp;
- yyparser.error (]b4_locations_if([[yyla.location, ]])[yymsg);
- }
-]])[
+]b4_parse_error_case(
+[simple], [[
+ std::string msg = YY_("syntax error");
+ yyparser.error (]b4_join(b4_locations_if([yyla.location]), [[YY_MOVE (msg)]])[);]],
+[custom], [[
+ context yyctx (*this, yyla);
+ yyparser.report_syntax_error (yyctx);]],
+[[
+ context yyctx (*this, yyla);
+ std::string msg = yyparser.yysyntax_error_ (yyctx);
+ yyparser.error (]b4_join(b4_locations_if([yyla.location]), [[YY_MOVE (msg)]])[);]])[
yyerrcnt += 1;
}
-
/* Recover from a syntax error on this, assuming that yytoken,
yylval, and yylloc are the syntactic category, semantic value, and location
of the lookahead. */
@@ -3365,6 +3322,120 @@ static void yypdumpstack (const glr_stack& yystack)
#endif
]])[
+]b4_parse_error_bmatch([custom\|detailed\|verbose], [[
+ // ]b4_parser_class[::context.
+ ]b4_parser_class[::context::context (glr_stack& yystack, const symbol_type& yyla)
+ : yystack_ (yystack)
+ , yyla_ (yyla)
+ {}
+
+ int
+ ]b4_parser_class[::context::expected_tokens (symbol_kind_type yyarg[], int yyargn) const
+ {
+ // Actual number of expected tokens
+ int yycount = 0;
+ const int yyn = yypact[yystack_.firstTopState()->yylrState];
+ if (!yystack_.yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for this
+ state because they are default actions. */
+ const int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ const int yychecklim = YYLAST - yyn + 1;
+ const int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ for (int yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != ]b4_symbol(error, kind)[
+ && !yystack_.yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (!yyarg)
+ ++yycount;
+ else if (yycount == yyargn)
+ return 0;
+ else
+ yyarg[yycount++] = YY_CAST (symbol_kind_type, yyx);
+ }
+ }
+ if (yyarg && yycount == 0 && 0 < yyargn)
+ yyarg[0] = ]b4_symbol(empty, kind)[;
+ return yycount;
+ }
+
+]])[
+
+]b4_parse_error_bmatch([detailed\|verbose], [[
+ int
+ ]b4_parser_class[::yy_syntax_error_arguments_ (const context& yyctx,
+ symbol_kind_type yyarg[], int yyargn) const
+ {
+ /* There are many possibilities here to consider:
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yyla) is
+ if this state is a consistent state with a default action.
+ Thus, detecting the absence of a lookahead is sufficient to
+ determine that there is no unexpected or expected token to
+ report. In that case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is
+ a consistent state with a default action. There might have
+ been a previous inconsistent state, consistent state with a
+ non-default action, or user semantic action that manipulated
+ yyla. (However, yyla is currently not documented for users.)
+ */
+
+ if (!yyctx.lookahead ().empty ())
+ {
+ if (yyarg)
+ yyarg[0] = yyctx.token ();
+ int yyn = yyctx.expected_tokens (yyarg ? yyarg + 1 : yyarg, yyargn - 1);
+ return yyn + 1;
+ }
+ return 0;
+ }
+
+ // Generate an error message.
+ std::string
+ ]b4_parser_class[::yysyntax_error_ (const context& yyctx) const
+ {
+ // Its maximum.
+ enum { YYARGS_MAX = 5 };
+ // Arguments of yyformat.
+ symbol_kind_type yyarg[YYARGS_MAX];
+ int yycount = yy_syntax_error_arguments_ (yyctx, yyarg, YYARGS_MAX);
+
+ char const* yyformat = YY_NULLPTR;
+ switch (yycount)
+ {
+#define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ default: // Avoid compiler warnings.
+ YYCASE_ (0, YY_("syntax error"));
+ YYCASE_ (1, YY_("syntax error, unexpected %s"));
+ YYCASE_ (2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_ (3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_ (4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_ (5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+#undef YYCASE_
+ }
+
+ std::string yyres;
+ // Argument number.
+ std::ptrdiff_t yyi = 0;
+ for (char const* yyp = yyformat; *yyp; ++yyp)
+ if (yyp[0] == '%' && yyp[1] == 's' && yyi < yycount)
+ {
+ yyres += symbol_name (yyarg[yyi++]);
+ ++yyp;
+ }
+ else
+ yyres += *yyp;
+ return yyres;
+ }]])[
+
void
]b4_parser_class[::yy_destroy_ (const char* yymsg, symbol_kind_type yykind,
value_type& yyval]b4_locations_if([[,