When parse.error is custom, let users define a yyreport_syntax_error function, and use it.
* data/skeletons/bison.m4 (b4_error_verbose_if): Accept 'custom'. * data/skeletons/yacc.c: Implement it. * examples/c/calc/calc.y: Experiment with it. --- data/skeletons/bison.m4 | 5 +++-- data/skeletons/yacc.c | 15 ++++++++++++++- examples/c/calc/calc.y | 23 +++++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/data/skeletons/bison.m4 b/data/skeletons/bison.m4 index c7be4037..946e7642 100644 --- a/data/skeletons/bison.m4 +++ b/data/skeletons/bison.m4 @@ -1018,13 +1018,14 @@ m4_define([b4_bison_locations_if], # b4_error_verbose_if([IF-ERRORS-ARE-VERBOSE], [IF-NOT]) # ------------------------------------------------------ -# Map %define parse.error "(simple|verbose)" to b4_error_verbose_if and +# Map %define parse.error "(custom|simple|verbose)" to b4_error_verbose_if and # b4_error_verbose_flag. b4_percent_define_default([[parse.error]], [[simple]]) b4_percent_define_check_values([[[[parse.error]], - [[simple]], [[verbose]]]]) + [[custom]], [[simple]], [[verbose]]]]) m4_define([b4_error_verbose_flag], [m4_case(b4_percent_define_get([[parse.error]]), + [custom], [[1]], [simple], [[0]], [verbose], [[1]])]) b4_define_flag_if([error_verbose]) diff --git a/data/skeletons/yacc.c b/data/skeletons/yacc.c index ff53b8d0..022b01de 100644 --- a/data/skeletons/yacc.c +++ b/data/skeletons/yacc.c @@ -1136,7 +1136,11 @@ yysyntax_error_arguments (const yyparse_context_t *yyctx, } ]])[ -]m4_case(b4_percent_define_get([[parse.error]]), [verbose], +]m4_case(b4_percent_define_get([[parse.error]]), + [custom], +[[static int +yyreport_syntax_error (const yyparse_context_t *yyctx);]], + [verbose], [[# ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S))) @@ -1786,6 +1790,15 @@ yyerrlab: { ++yynerrs; ]m4_case(b4_percent_define_get([[parse.error]]), + [custom], +[[ { + yyparse_context_t yyctx + = {yyssp, yytoken]b4_lac_if([[, yyesa, &yyes, &yyes_capacity]])[};]b4_lac_if([[ + if (yychar != YYEMPTY) + YY_LAC_ESTABLISH;]])[ + if (yyreport_syntax_error (]b4_yyerror_args[&yyctx) == 2) + goto yyexhaustedlab; + }]], [simple], [[ yyerror (]b4_yyerror_args[YY_("syntax error"));]], [verbose], diff --git a/examples/c/calc/calc.y b/examples/c/calc/calc.y index a9896e43..0ba74da6 100644 --- a/examples/c/calc/calc.y +++ b/examples/c/calc/calc.y @@ -9,6 +9,7 @@ %define api.header.include {"calc.h"} %define api.value.type union /* Generate YYSTYPE from these types: */ +%define parse.error custom %token <double> NUM "number" %type <double> expr term fact @@ -51,6 +52,28 @@ fact: %% +int +yyreport_syntax_error (const yyparse_context_t *ctx) +{ + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 10 }; + /* Arguments of yyformat: reported tokens (one for the "unexpected", + one per "expected"). */ + int arg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int n = yysyntax_error_arguments (ctx, arg, sizeof arg / sizeof *arg); + if (n == -2) + return 2; + fprintf (stderr, "SYNTAX ERROR on token [%s]", yysymbol_name (arg[0])); + if (1 < n) + { + fprintf (stderr, " (expected:"); + for (int i = 1; i < n; ++i) + fprintf (stderr, " [%s]", yysymbol_name (arg[i])); + fprintf (stderr, ")"); + } + fprintf (stderr, "\n"); + return 0; +} + int yylex (void) { -- 2.24.1