yacc.c: add custom error message generation

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.
This commit is contained in:
Akim Demaille
2020-01-03 09:50:09 +01:00
parent 5b883180e6
commit cda1934606
3 changed files with 40 additions and 3 deletions

View File

@@ -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])

View File

@@ -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],

View File

@@ -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)
{