java: add support for parse.error custom

* data/skeletons/lalr1.java: Add support for custom parse errors.
(yyntokens_): Make it public.  Under...
(yyntokens): this name.
(Context): Capture the location too.
* examples/c/bistromathic/parse.y,
* examples/c/bistromathic/bistromathic.test:
Improve error message.
* examples/java/calc/Calc.test, examples/java/calc/Calc.y: Use custom
error messages.
* tests/calc.at, tests/local.at: Check custom error messages.
This commit is contained in:
Akim Demaille
2020-02-08 14:19:03 +01:00
parent 0c90c59795
commit ef097719ea
8 changed files with 95 additions and 29 deletions

5
TODO
View File

@@ -12,6 +12,11 @@ The calc.at test should call yyerror with location:
yyerror (]AT_LOCATION_IF([[@$, ]])["calc: error: " + $1 + " != " + $3);
}
** Java: EOF
We should be able to redefine EOF like we do in C.
** Java: calc.at
Stop hard-coding "Calc". Adjust local.at (look for FIXME).
** doc
I feel it's ugly to use the GNU style to declare functions in the doc. It

View File

@@ -91,8 +91,10 @@ import java.text.MessageFormat;
*/
]b4_parser_class_declaration[
{
]b4_identification[
]b4_error_verbose_if([[
]b4_identification[
][
]m4_bmatch(b4_percent_define_get([[parse.error]]),
[detailed\|verbose], [[
/**
* True if verbose error messages are enabled.
*/
@@ -161,9 +163,6 @@ import java.text.MessageFormat;
}
}
]])[
]b4_locations_if([[
private ]b4_location_type[ yylloc (YYStack rhs, int n)
{
if (0 < n)
@@ -181,8 +180,8 @@ import java.text.MessageFormat;
public static final int EOF = 0;
]b4_token_enums[
]b4_locations_if([[/**
]b4_locations_if([[
/**
* Method to retrieve the beginning position of the last scanned token.
* @@return the position at which the last scanned token starts.
*/
@@ -217,7 +216,12 @@ import java.text.MessageFormat;
* @@param msg The string for the error message.
*/
void yyerror (]b4_locations_if([b4_location_type[ loc, ]])[String msg);
}
]m4_bmatch(b4_percent_define_get([[parse.error]]),
[custom], [[
void yyreportSyntaxError (][Context yyctx);
]])[
}
]b4_lexer_if([[
private class YYLexer implements Lexer {
@@ -676,8 +680,9 @@ b4_dollar_popdef[]dnl
yytoken = yyempty_;
Context yyctx = new Context ();
yyctx.yystack = yystack;
yyctx.yytoken = yytoken;
yyerror (]b4_locations_if([yylloc, ])[yysyntax_error (yyctx));
yyctx.yytoken = yytoken;]b4_locations_if([[
yyctx.yylocation = yylloc;]])[
yyreportSyntaxError (yyctx);
}
]b4_locations_if([[
@@ -858,13 +863,15 @@ b4_dollar_popdef[]dnl
public static final class Context
{
public YYStack yystack;
public int yytoken;
public int yytoken;]b4_locations_if([[
public ]b4_location_type[ yylocation;]])[
public static final int yyntokens = ]b4_parser_class[.yyntokens_;
};
/* Put in YYARG at most YYARGN of the expected tokens given the
current YYCTX, and return the number of tokens stored in YYARG. If
YYARG is null, return the number of expected tokens (guaranteed to
be less than YYNTOKENS). */
be less than YYNTOKENS_). */
static int
yyexpectedTokens (Context yyctx,
int yyarg[], int yyoffset, int yyargn)
@@ -935,13 +942,19 @@ b4_dollar_popdef[]dnl
return yycount;
}
// Generate an error message.
private String yysyntax_error (Context yyctx)
{]b4_error_verbose_if([[
/**
* Report a syntax error.
*/
private void yyreportSyntaxError (Context yyctx)
{]m4_bmatch(b4_percent_define_get([parse.error]),
[custom], [[
yylexer.yyreportSyntaxError (yyctx);]],
[detailed\|verbose], [[
if (yyErrorVerbose)
{
int[] yyarg = new int[5];
int yycount = yysyntaxErrorArguments (yyctx, yyarg, 5);
final int argmax = 5;
int[] yyarg = new int[argmax];
int yycount = yysyntaxErrorArguments (yyctx, yyarg, argmax);
String[] yystr = new String[yycount];
for (int yyi = 0; yyi < yycount; ++yyi)
yystr[yyi] = yysymbolName (yyarg[yyi]);
@@ -956,10 +969,12 @@ b4_dollar_popdef[]dnl
case 4: yyformat = ]b4_trans(["syntax error, unexpected {0}, expecting {1} or {2} or {3}"])[; break;
case 5: yyformat = ]b4_trans(["syntax error, unexpected {0}, expecting {1} or {2} or {3} or {4}"])[; break;
}
return new MessageFormat (yyformat).format (yystr);
yyerror (]b4_locations_if([[yyctx.yylocation, ]])[new MessageFormat (yyformat).format (yystr));
return;
}
]])[
return "syntax error";
yyerror (]b4_locations_if([[yyctx.yylocation, ]])["syntax error");]],
[simple], [[
yyerror (]b4_locations_if([[yyctx.yylocation, ]])["syntax error");]])[
}
/**

View File

@@ -45,9 +45,9 @@ run 0 '0.16
cat >input <<EOF
*
EOF
run 0 "err: 1.1: syntax error expected end of file or - or ( or end of line or double precision number or function or variable before *"
run 0 "err: 1.1: syntax error: expected end of file or - or ( or end of line or double precision number or function or variable before *"
cat >input <<EOF
1 + 2 * * 3
EOF
run 0 "err: 1.9: syntax error expected - or ( or double precision number or function or variable before *"
run 0 "err: 1.9: syntax error: expected - or ( or double precision number or function or variable before *"

View File

@@ -200,8 +200,8 @@ yyreport_syntax_error (const yyparse_context_t *ctx)
YY_LOCATION_PRINT (stderr, *yyparse_context_location (ctx));
fprintf (stderr, ": syntax error");
for (int i = 1; i < n; ++i)
fprintf (stderr, " %s %s",
i == 1 ? "expected" : "or", yysymbol_name (arg[i]));
fprintf (stderr, "%s %s",
i == 1 ? ": expected" : " or", yysymbol_name (arg[i]));
if (n)
fprintf (stderr, " before %s", yysymbol_name (arg[0]));
fprintf (stderr, "\n");

View File

@@ -30,9 +30,9 @@ run 0 '7
cat >input <<EOF
1 + 2 * * 3
EOF
run 0 "err: 1.9-1.10: syntax error, unexpected '*', expecting number or '-' or '(' or '!'"
run 0 "err: 1.9-1.10: syntax error: expected number or '-' or '(' or '!' before '*'"
cat >input <<EOF
12 222
EOF
run 0 "err: 1.6-1.9: syntax error, unexpected number"
run 0 "err: 1.6-1.9: syntax error: expected end of line or '=' or '-' or '+' or '*' or '/' or '^' before number"

View File

@@ -3,7 +3,7 @@
%define api.parser.class {Calc}
%define api.parser.public
%define parse.error detailed
%define parse.error custom
%define parse.trace
%locations
@@ -29,10 +29,17 @@
if (!p.parse ())
System.exit (1);
}
static String _ (String s)
{
return s;
}
}
/* Bison Declarations */
%token <Integer> NUM "number"
%token
'\n' _("end of line")
<Integer> NUM _("number")
%type <Integer> exp
%nonassoc '=' /* comparison */
@@ -73,7 +80,6 @@ exp:
| '-' error { $$ = 0; return YYERROR; }
;
%%
class CalcLexer implements Calc.Lexer {
@@ -100,6 +106,20 @@ class CalcLexer implements Calc.Lexer {
return end;
}
public void yyreportSyntaxError (Calc.Context ctx)
{
final int ARGMAX = 10;
int[] arg = new int[ARGMAX];
int n = Calc.yysyntaxErrorArguments (ctx, arg, ARGMAX);
System.err.print (ctx.yylocation + ": syntax error");
for (int i = 1; i < n; ++i)
System.err.print ((i == 1 ? ": expected " : " or ")
+ Calc.yysymbolName (arg[i]));
if (n != 0)
System.err.print (" before " + Calc.yysymbolName (arg[0]));
System.err.println ("");
}
public void yyerror (Calc.Location l, String s)
{
if (l == null)

View File

@@ -1185,8 +1185,11 @@ m4_define([AT_CHECK_CALC_LALR1_JAVA],
[AT_CHECK_CALC([%language "Java" $1], [$2])])
AT_CHECK_CALC_LALR1_JAVA
AT_CHECK_CALC_LALR1_JAVA([%define parse.error custom])
AT_CHECK_CALC_LALR1_JAVA([%define parse.error detailed])
AT_CHECK_CALC_LALR1_JAVA([%define parse.error verbose])
AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error custom])
AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error detailed])
AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error verbose])
AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose])
AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose %locations %lex-param {InputStream is}])

View File

@@ -908,6 +908,9 @@ class PositionReader extends BufferedReader {
}]])
# AT_YYERROR_DEFINE(java)
# -----------------------
# FIXME: We should not hard-code "Calc".
m4_define([AT_YYERROR_DEFINE(java)],
[AT_LOCATION_IF([[public void yyerror (Calc.Location l, String m)
{]m4_bmatch(m4_defn([AT_PARSE_PARAMS]), [nerrs],[[
@@ -925,6 +928,24 @@ m4_define([AT_YYERROR_DEFINE(java)],
++*nerrs;]])[
System.err.println (m);
}
]])[
]AT_ERROR_CUSTOM_IF([[
public void yyreportSyntaxError (Calc.Context ctx)
{
int[] arg = new int[ctx.yyntokens];
int n = Calc.yysyntaxErrorArguments (ctx, arg, ctx.yyntokens);
System.err.print (]AT_LOCATION_IF([[ctx.yylocation + ": "]]
+ )["syntax error on token @<:@" + Calc.yysymbolName(arg[0]) + "@:>@");
if (1 < n)
{
System.err.print (" (expected:");
for (int i = 1; i < n; ++i)
System.err.print (" @<:@" + Calc.yysymbolName (arg[i]) + "@:>@");
System.err.print (")");
}
System.err.println ("");
}
]])
])
@@ -962,6 +983,8 @@ m4_define([AT_MAIN_DEFINE(java)],
m4_define([AT_LANG_FOR_EACH_STD(java)],
[$1])
## --------------- ##
## Running Bison. ##
## --------------- ##