Hi Askar! > Le 2 janv. 2019 à 01:41, Askar Safin <[email protected]> a écrit : > > Hi. > >> I'll push these commits to master once the CI validates them >> ( https://travis-ci.com/akimd/bison/builds/95974577 ). > Thanks a lot for this fix. Unfortunately, it seems it is buggy. > > I tested it on that code from paste.gg (I attached the code here in case that > paste.gg paste disappears). Command line is same: > > flex -o lex.yy.cpp scanner.lpp && bison -do parser.tab.cpp parser.ypp && > g++ lex.yy.cpp parser.tab.cpp && echo 2 + 2 | ./a.out # Should print 4 > > And your patches work. But when I type this: > > echo 2 + % | ./a.out > > I see this: > > Invalid character: % > syntax error: unexpected $undefined, expecting NUMBER or '(' > > But if I replace %skeleton "glr.cc" with %skeleton "lalr1.cc", I see this: > > Invalid character: % > > So, it seems that now syntax_error support in glr.cc is inconsistent with > lalr1.cc .
Indeed, it is. I'll install this when it passes on the CI. commit 80ef7e7639f99618bee490b2dea02b5fd9ab28e5 Author: Akim Demaille <[email protected]> Date: Wed Jan 2 11:43:08 2019 +0100 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. 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': #
