From 80ef7e7639f99618bee490b2dea02b5fd9ab28e5 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Wed, 2 Jan 2019 11:43:08 +0100 Subject: [PATCH] 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. --- data/skeletons/glr.c | 15 ++++++++++----- data/skeletons/lalr1.cc | 2 ++ tests/c++.at | 9 +++++++-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/data/skeletons/glr.c b/data/skeletons/glr.c index 20add6f7..779c1c91 100644 --- a/data/skeletons/glr.c +++ b/data/skeletons/glr.c @@ -778,11 +778,12 @@ yygetToken (int *yycharp][]b4_pure_if([, yyGLRStack* yystackp])[]b4_user_formals #if YY_EXCEPTIONS } 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;])[ yyerror (]b4_lyyerror_args[yyexc.what ()); - // Map to the undef token. - *yycharp = YYMAXUTOK + 1; + // Leave yytoken/yychar to YYEMPTY. + return YYEMPTY; } #endif // YY_EXCEPTIONS]], [[ *yycharp = ]b4_lex[;]])[ @@ -871,7 +872,8 @@ yyuserAction (yyRuleNum yyn, int yyrhslen, yyGLRStackItem* yyvsp, #if YY_EXCEPTIONS } catch (const syntax_error& yyexc) - {]b4_locations_if([ + { + YYDPRINTF ((stderr, "Caught exception: %s\n", yyexc.what()));]b4_locations_if([ *yylocp = yyexc.location;])[ yyerror (]b4_yyerror_args[yyexc.what ()); YYERROR; @@ -2353,7 +2355,10 @@ b4_dollar_popdef])[]dnl else if (yyisErrorAction (yyaction)) {]b4_locations_if([[ 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; } else diff --git a/data/skeletons/lalr1.cc b/data/skeletons/lalr1.cc index 58e8f897..aa777ec1 100644 --- a/data/skeletons/lalr1.cc +++ b/data/skeletons/lalr1.cc @@ -827,6 +827,7 @@ b4_dollar_popdef])[]dnl #if YY_EXCEPTIONS catch (const syntax_error& yyexc) { + YYCDEBUG << "Caught exception: " << yyexc.what() << '\n'; error (yyexc); goto yyerrlab1; } @@ -916,6 +917,7 @@ b4_dollar_popdef])[]dnl #if YY_EXCEPTIONS catch (const syntax_error& yyexc) { + YYCDEBUG << "Caught exception: " << yyexc.what() << '\n'; error (yyexc); YYERROR; } diff --git a/tests/c++.at b/tests/c++.at index c2b892bc..6b6d2e41 100644 --- a/tests/c++.at +++ b/tests/c++.at @@ -941,7 +941,7 @@ AT_CLEANUP m4_pushdef([AT_TEST], [AT_SETUP([[Syntax error as exception: $1]]) -AT_BISON_OPTION_PUSHDEFS([$1]) +AT_BISON_OPTION_PUSHDEFS([$1 %debug]) AT_DATA_GRAMMAR([[input.yy]], [[$1 @@ -984,6 +984,7 @@ yy::parser::error (const std::string &m) ]AT_MAIN_DEFINE[ ]]) +# Another file to check syntax_error's linkage. AT_DATA_SOURCE([scan.cc], [[#include "input.hh" @@ -991,7 +992,11 @@ int yylex (yy::parser::semantic_type *) { // '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++) { case 'l':