glr.cc: don't issue two error messages when syntax_error is thrown

Reported by Askar Safin.
https://lists.gnu.org/archive/html/bison-patches/2019-01/msg00000.html

* data/skeletons/glr.c (yygetToken): Return YYEMPTY when an exception
is thrown.
* data/skeletons/lalr1.cc: Log when an exception is caught.
* tests/c++.at (Syntax error as exception): Be sure to recover from
error before triggering another error.
This commit is contained in:
Akim Demaille
2019-01-02 11:43:08 +01:00
parent 5be47a73e8
commit 80ef7e7639
3 changed files with 19 additions and 7 deletions

View File

@@ -778,11 +778,12 @@ yygetToken (int *yycharp][]b4_pure_if([, yyGLRStack* yystackp])[]b4_user_formals
#if YY_EXCEPTIONS #if YY_EXCEPTIONS
} }
catch (const ]b4_namespace_ref[::]b4_parser_class[::syntax_error& yyexc) catch (const ]b4_namespace_ref[::]b4_parser_class[::syntax_error& yyexc)
{]b4_locations_if([ {
YYDPRINTF ((stderr, "Caught exception: %s\n", yyexc.what()));]b4_locations_if([
yylloc = yyexc.location;])[ yylloc = yyexc.location;])[
yyerror (]b4_lyyerror_args[yyexc.what ()); yyerror (]b4_lyyerror_args[yyexc.what ());
// Map to the undef token. // Leave yytoken/yychar to YYEMPTY.
*yycharp = YYMAXUTOK + 1; return YYEMPTY;
} }
#endif // YY_EXCEPTIONS]], [[ #endif // YY_EXCEPTIONS]], [[
*yycharp = ]b4_lex[;]])[ *yycharp = ]b4_lex[;]])[
@@ -871,7 +872,8 @@ yyuserAction (yyRuleNum yyn, int yyrhslen, yyGLRStackItem* yyvsp,
#if YY_EXCEPTIONS #if YY_EXCEPTIONS
} }
catch (const syntax_error& yyexc) catch (const syntax_error& yyexc)
{]b4_locations_if([ {
YYDPRINTF ((stderr, "Caught exception: %s\n", yyexc.what()));]b4_locations_if([
*yylocp = yyexc.location;])[ *yylocp = yyexc.location;])[
yyerror (]b4_yyerror_args[yyexc.what ()); yyerror (]b4_yyerror_args[yyexc.what ());
YYERROR; YYERROR;
@@ -2353,7 +2355,10 @@ b4_dollar_popdef])[]dnl
else if (yyisErrorAction (yyaction)) else if (yyisErrorAction (yyaction))
{]b4_locations_if([[ {]b4_locations_if([[
yystack.yyerror_range[1].yystate.yyloc = yylloc;]])[ yystack.yyerror_range[1].yystate.yyloc = yylloc;]])[
yyreportSyntaxError (&yystack]b4_user_args[); /* If yylex returned no token (YYEMPTY), it already
issued an error message. */
if (yytoken != YYEMPTY)
yyreportSyntaxError (&yystack]b4_user_args[);
goto yyuser_error; goto yyuser_error;
} }
else else

View File

@@ -827,6 +827,7 @@ b4_dollar_popdef])[]dnl
#if YY_EXCEPTIONS #if YY_EXCEPTIONS
catch (const syntax_error& yyexc) catch (const syntax_error& yyexc)
{ {
YYCDEBUG << "Caught exception: " << yyexc.what() << '\n';
error (yyexc); error (yyexc);
goto yyerrlab1; goto yyerrlab1;
} }
@@ -916,6 +917,7 @@ b4_dollar_popdef])[]dnl
#if YY_EXCEPTIONS #if YY_EXCEPTIONS
catch (const syntax_error& yyexc) catch (const syntax_error& yyexc)
{ {
YYCDEBUG << "Caught exception: " << yyexc.what() << '\n';
error (yyexc); error (yyexc);
YYERROR; YYERROR;
} }

View File

@@ -941,7 +941,7 @@ AT_CLEANUP
m4_pushdef([AT_TEST], m4_pushdef([AT_TEST],
[AT_SETUP([[Syntax error as exception: $1]]) [AT_SETUP([[Syntax error as exception: $1]])
AT_BISON_OPTION_PUSHDEFS([$1]) AT_BISON_OPTION_PUSHDEFS([$1 %debug])
AT_DATA_GRAMMAR([[input.yy]], AT_DATA_GRAMMAR([[input.yy]],
[[$1 [[$1
@@ -984,6 +984,7 @@ yy::parser::error (const std::string &m)
]AT_MAIN_DEFINE[ ]AT_MAIN_DEFINE[
]]) ]])
# Another file to check syntax_error's linkage.
AT_DATA_SOURCE([scan.cc], AT_DATA_SOURCE([scan.cc],
[[#include "input.hh" [[#include "input.hh"
@@ -991,7 +992,11 @@ int
yylex (yy::parser::semantic_type *) yylex (yy::parser::semantic_type *)
{ {
// 's': syntax error, 'l': lexical error. // 's': syntax error, 'l': lexical error.
static char const *input = "asal"; //
// Leave enough valid tokens to make sure we recovered from the
// previous error, otherwise we might hide some error messages
// (discarded during error recovery).
static char const *input = "asaaalaa";
switch (int res = *input++) switch (int res = *input++)
{ {
case 'l': case 'l':