mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-17 16:23:04 +00:00
c++: add parser::context for syntax error handling
* data/skeletons/lalr1.cc: here
This commit is contained in:
committed by
Akim Demaille
parent
72acecb30c
commit
879530cb95
@@ -235,7 +235,28 @@ m4_define([b4_shared_declarations],
|
|||||||
void error (const syntax_error& err);
|
void error (const syntax_error& err);
|
||||||
|
|
||||||
]b4_token_constructor_define[
|
]b4_token_constructor_define[
|
||||||
|
]b4_parse_error_bmatch([custom\|detailed\|verbose], [[
|
||||||
|
class context {
|
||||||
|
public:
|
||||||
|
context (const ]b4_parser_class[& yyparser, symbol_type yyla)
|
||||||
|
: yyparser (yyparser)
|
||||||
|
, yyla (yyla)
|
||||||
|
{}
|
||||||
|
]b4_locations_if([[
|
||||||
|
const location_type& get_location () const { 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 yyexpected_tokens (int yyarg[], int yyargn) const;
|
||||||
|
|
||||||
|
int yysyntax_error_arguments (int yyarg[], int yyargn) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const ]b4_parser_class[& yyparser;
|
||||||
|
symbol_type yyla;
|
||||||
|
};
|
||||||
|
]])[
|
||||||
private:
|
private:
|
||||||
/// This class is not copyable.
|
/// This class is not copyable.
|
||||||
]b4_parser_class[ (const ]b4_parser_class[&);
|
]b4_parser_class[ (const ]b4_parser_class[&);
|
||||||
@@ -254,13 +275,11 @@ m4_define([b4_shared_declarations],
|
|||||||
|
|
||||||
/// Stored state numbers (used for stacks).
|
/// Stored state numbers (used for stacks).
|
||||||
typedef ]b4_int_type(0, m4_eval(b4_states_number - 1))[ state_type;
|
typedef ]b4_int_type(0, m4_eval(b4_states_number - 1))[ state_type;
|
||||||
|
]b4_parse_error_bmatch([detailed\|verbose], [[
|
||||||
/// Generate an error message.
|
/// Generate an error message.
|
||||||
/// \param yystate the state where the error occurred.
|
/// \param yyctx the context in which the error occurred.
|
||||||
/// \param yyla the lookahead token.
|
virtual std::string yysyntax_error_ (const context& yyctx) const;
|
||||||
virtual std::string yysyntax_error_ (state_type yystate,
|
]])[
|
||||||
const symbol_type& yyla) const;
|
|
||||||
|
|
||||||
/// Compute post-reduction state.
|
/// Compute post-reduction state.
|
||||||
/// \param yystate the current state
|
/// \param yystate the current state
|
||||||
/// \param yysym the nonterminal to push on the stack
|
/// \param yysym the nonterminal to push on the stack
|
||||||
@@ -1050,9 +1069,13 @@ b4_dollar_popdef])[]dnl
|
|||||||
// If not already recovering from an error, report this error.
|
// If not already recovering from an error, report this error.
|
||||||
if (!yyerrstatus_)
|
if (!yyerrstatus_)
|
||||||
{
|
{
|
||||||
++yynerrs_;
|
++yynerrs_;]b4_parse_error_case(
|
||||||
error (]b4_join(b4_locations_if([yyla.location]),
|
[simple], [[
|
||||||
[[yysyntax_error_ (yystack_[0].state, yyla)]])[);
|
std::string msg = YY_("syntax error");]],
|
||||||
|
[[
|
||||||
|
context yyctx (*this, yyla);
|
||||||
|
std::string msg = yysyntax_error_ (yyctx);]])[
|
||||||
|
error (]b4_join(b4_locations_if([yyla.location]), [[YY_MOVE (msg)]])[);
|
||||||
}
|
}
|
||||||
|
|
||||||
]b4_locations_if([[
|
]b4_locations_if([[
|
||||||
@@ -1194,7 +1217,100 @@ b4_dollar_popdef])[]dnl
|
|||||||
{
|
{
|
||||||
error (]b4_join(b4_locations_if([yyexc.location]),
|
error (]b4_join(b4_locations_if([yyexc.location]),
|
||||||
[[yyexc.what ()]])[);
|
[[yyexc.what ()]])[);
|
||||||
}]b4_lac_if([[
|
}]b4_parse_error_bmatch([custom\|detailed\|verbose], [[
|
||||||
|
|
||||||
|
int
|
||||||
|
]b4_parser_class[::context::yyexpected_tokens (int yyarg[], int yyargn) const
|
||||||
|
{
|
||||||
|
// Actual number of expected tokens
|
||||||
|
int yycount = 0;
|
||||||
|
]b4_lac_if([[
|
||||||
|
#if ]b4_api_PREFIX[DEBUG
|
||||||
|
// Execute LAC once. We don't care if it is successful, we
|
||||||
|
// only do it for the sake of debugging output.
|
||||||
|
if (!yyparser.yy_lac_established_)
|
||||||
|
yyparser.yy_lac_check_ (yyla.type_get ());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (int yyx = 0; yyx < yyntokens_; ++yyx)
|
||||||
|
if (yyx != yy_error_token_ && yyx != yy_undef_token_ && yyparser.yy_lac_check_ (yyx))
|
||||||
|
{
|
||||||
|
if (!yyarg)
|
||||||
|
++yycount;
|
||||||
|
else if (yycount == yyargn)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
yyarg[yycount++] = yyx;
|
||||||
|
}
|
||||||
|
]], [[
|
||||||
|
int yyn = yypact_[yyparser.yystack_[0].state];
|
||||||
|
if (!yy_pact_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. */
|
||||||
|
int yyxbegin = yyn < 0 ? -yyn : 0;
|
||||||
|
// Stay within bounds of both yycheck and yytname.
|
||||||
|
int yychecklim = yylast_ - yyn + 1;
|
||||||
|
int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_;
|
||||||
|
for (int yyx = yyxbegin; yyx < yyxend; ++yyx)
|
||||||
|
if (yycheck_[yyx + yyn] == yyx && yyx != yy_error_token_
|
||||||
|
&& !yy_table_value_is_error_ (yytable_[yyx + yyn]))
|
||||||
|
{
|
||||||
|
if (!yyarg)
|
||||||
|
++yycount;
|
||||||
|
else if (yycount == yyargn)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
yyarg[yycount++] = yyx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]])[
|
||||||
|
return yycount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
]b4_parser_class[::context::yysyntax_error_arguments (int 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.)]b4_lac_if([[
|
||||||
|
In the first two cases, it might appear that the current syntax
|
||||||
|
error should have been detected in the previous state when
|
||||||
|
yy_lac_check was invoked. However, at that time, there might
|
||||||
|
have been a different syntax error that discarded a different
|
||||||
|
initial context during error recovery, leaving behind the
|
||||||
|
current lookahead.]], [[
|
||||||
|
- 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 ())
|
||||||
|
{
|
||||||
|
yyarg[0] = yyla.type_get ();
|
||||||
|
int yyn = yyexpected_tokens (yyarg ? yyarg + 1 : yyarg, yyargn - 1);
|
||||||
|
return yyn + 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}]])b4_lac_if([[
|
||||||
|
|
||||||
bool
|
bool
|
||||||
]b4_parser_class[::yy_lac_check_ (int yytoken) const
|
]b4_parser_class[::yy_lac_check_ (int yytoken) const
|
||||||
@@ -1333,99 +1449,17 @@ b4_dollar_popdef])[]dnl
|
|||||||
<< evt << '\n';
|
<< evt << '\n';
|
||||||
yy_lac_established_ = false;
|
yy_lac_established_ = false;
|
||||||
}
|
}
|
||||||
}]])[
|
}]])b4_parse_error_bmatch([detailed\|verbose], [[
|
||||||
|
|
||||||
// Generate an error message.
|
// Generate an error message.
|
||||||
std::string
|
std::string
|
||||||
]b4_parser_class[::yysyntax_error_ (]b4_parse_error_case([simple],
|
]b4_parser_class[::yysyntax_error_ (const context& yyctx) const
|
||||||
[state_type, const symbol_type&],
|
{
|
||||||
[state_type yystate, const symbol_type& yyla])[) const
|
|
||||||
{]b4_parse_error_case(
|
|
||||||
[simple], [[
|
|
||||||
return YY_("syntax error");]],
|
|
||||||
[[
|
|
||||||
// Number of reported tokens (one for the "unexpected", one per
|
|
||||||
// "expected").
|
|
||||||
std::ptrdiff_t yycount = 0;
|
|
||||||
// Its maximum.
|
// Its maximum.
|
||||||
enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
|
enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
|
||||||
// Arguments of yyformat.
|
// Arguments of yyformat.
|
||||||
char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
|
int yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
|
||||||
|
int yycount = yyctx.yysyntax_error_arguments (yyarg, YYERROR_VERBOSE_ARGS_MAXIMUM);
|
||||||
/* 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.)]b4_lac_if([[
|
|
||||||
In the first two cases, it might appear that the current syntax
|
|
||||||
error should have been detected in the previous state when
|
|
||||||
yy_lac_check was invoked. However, at that time, there might
|
|
||||||
have been a different syntax error that discarded a different
|
|
||||||
initial context during error recovery, leaving behind the
|
|
||||||
current lookahead.]], [[
|
|
||||||
- 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 ())
|
|
||||||
{
|
|
||||||
symbol_number_type yytoken = yyla.type_get ();
|
|
||||||
yyarg[yycount++] = ]b4_parse_error_case(
|
|
||||||
[verbose], [[yytname_[yytoken]]],
|
|
||||||
[[yysymbol_name (yytoken)]])[;]b4_lac_if([[
|
|
||||||
|
|
||||||
#if ]b4_api_PREFIX[DEBUG
|
|
||||||
// Execute LAC once. We don't care if it is successful, we
|
|
||||||
// only do it for the sake of debugging output.
|
|
||||||
if (!yy_lac_established_)
|
|
||||||
yy_lac_check_ (yytoken);
|
|
||||||
#endif]])[
|
|
||||||
|
|
||||||
int yyn = yypact_[+yystate];
|
|
||||||
if (!yy_pact_value_is_default_ (yyn))
|
|
||||||
{]b4_lac_if([[
|
|
||||||
for (int yyx = 0; yyx < yyntokens_; ++yyx)
|
|
||||||
if (yyx != yy_error_token_ && yyx != yy_undef_token_
|
|
||||||
&& yy_lac_check_ (yyx))
|
|
||||||
{]], [[
|
|
||||||
/* 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. */
|
|
||||||
int yyxbegin = yyn < 0 ? -yyn : 0;
|
|
||||||
// Stay within bounds of both yycheck and yytname.
|
|
||||||
int yychecklim = yylast_ - yyn + 1;
|
|
||||||
int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_;
|
|
||||||
for (int yyx = yyxbegin; yyx < yyxend; ++yyx)
|
|
||||||
if (yycheck_[yyx + yyn] == yyx && yyx != yy_error_token_
|
|
||||||
&& !yy_table_value_is_error_ (yytable_[yyx + yyn]))
|
|
||||||
{]])[
|
|
||||||
if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
|
|
||||||
{
|
|
||||||
yycount = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
yyarg[yycount++] = ]b4_parse_error_case(
|
|
||||||
[verbose], [[yytname_[yyx]]],
|
|
||||||
[[yysymbol_name (yyx)]])[;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char const* yyformat = YY_NULLPTR;
|
char const* yyformat = YY_NULLPTR;
|
||||||
switch (yycount)
|
switch (yycount)
|
||||||
@@ -1451,14 +1485,14 @@ b4_dollar_popdef])[]dnl
|
|||||||
if (yyp[0] == '%' && yyp[1] == 's' && yyi < yycount)
|
if (yyp[0] == '%' && yyp[1] == 's' && yyi < yycount)
|
||||||
{
|
{
|
||||||
yyres += ]b4_parse_error_case([verbose],
|
yyres += ]b4_parse_error_case([verbose],
|
||||||
[[yytnamerr_ (yyarg[yyi++])]],
|
[[yytnamerr_ (yytname_[yyarg[yyi++]])]],
|
||||||
[[yyarg[yyi++]]])[;
|
[[yysymbol_name (yyarg[yyi++])]])[;
|
||||||
++yyp;
|
++yyp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
yyres += *yyp;
|
yyres += *yyp;
|
||||||
return yyres;]])[
|
return yyres;
|
||||||
}
|
}]])[
|
||||||
|
|
||||||
|
|
||||||
const ]b4_int_type(b4_pact_ninf, b4_pact_ninf) b4_parser_class::yypact_ninf_ = b4_pact_ninf[;
|
const ]b4_int_type(b4_pact_ninf, b4_pact_ninf) b4_parser_class::yypact_ninf_ = b4_pact_ninf[;
|
||||||
|
|||||||
Reference in New Issue
Block a user