java: introduce yyexpectedTokens

And allow syntax error messages for 'detailed' and 'verbose' to be
translated.

* data/skeletons/lalr1.java (Context, yyexpectedTokens)
(yysyntaxErrorArguments): New.
(yysyntax_error): Use it.
This commit is contained in:
Akim Demaille
2020-02-07 06:09:10 +01:00
parent 52db24b2bc
commit 088356cb2f

View File

@@ -82,6 +82,7 @@ m4_define([b4_define_state],[[
]])[ ]])[
]b4_user_pre_prologue[ ]b4_user_pre_prologue[
]b4_user_post_prologue[ ]b4_user_post_prologue[
import java.text.MessageFormat;
]b4_percent_code_get([[imports]])[ ]b4_percent_code_get([[imports]])[
/** /**
* A Bison parser, automatically generated from <tt>]m4_bpatsubst(b4_file_name, [^"\(.*\)"$], [\1])[</tt>. * A Bison parser, automatically generated from <tt>]m4_bpatsubst(b4_file_name, [^"\(.*\)"$], [\1])[</tt>.
@@ -673,7 +674,10 @@ b4_dollar_popdef[]dnl
++yynerrs; ++yynerrs;
if (yychar == yyempty_) if (yychar == yyempty_)
yytoken = yyempty_; yytoken = yyempty_;
yyerror (]b4_locations_if([yylloc, ])[yysyntax_error (yystate, yytoken)); Context yyctx = new Context ();
yyctx.yystack = yystack;
yyctx.yytoken = yytoken;
yyerror (]b4_locations_if([yylloc, ])[yysyntax_error (yyctx));
} }
]b4_locations_if([[ ]b4_locations_if([[
@@ -851,10 +855,50 @@ b4_dollar_popdef[]dnl
} }
]])[ ]])[
// Generate an error message. public final class Context
private String yysyntax_error (int yystate, int tok) {
{]b4_error_verbose_if([[ public YYStack yystack;
if (yyErrorVerbose) public int yytoken;
};
/* 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). */
static int
yyexpectedTokens (Context yyctx,
int yyarg[], int yyoffset, int yyargn)
{
int yycount = yyoffset;
int yyn = yypact_[yyctx.yystack.stateAt (0)];
if (!yyPactValueIsDefault (yyn))
{
/* Start YYX at -YYN if negative to avoid negative
indexes in YYCHECK. In other words, skip the first
-YYN actions for this state because they are default
actions. */
int yyxbegin = yyn < 0 ? -yyn : 0;
/* Stay within bounds of both yycheck and yytname. */
int yychecklim = yylast_ - yyn + 1;
int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_;
for (int x = yyxbegin; x < yyxend; ++x)
if (yycheck_[x + yyn] == x && x != yy_error_token_
&& !yyTableValueIsError (yytable_[x + yyn]))
{
if (yyarg == null)
yycount += 1;
else if (yycount == yyargn)
return 0; // FIXME: this is incorrect.
else
yyarg[yycount++] = x;
}
}
return yycount - yyoffset;
}
static int
yysyntaxErrorArguments (Context yyctx,
int[] yyarg, int yyargn)
{ {
/* There are many possibilities here to consider: /* There are many possibilities here to consider:
- If this state is a consistent state with a default action, - If this state is a consistent state with a default action,
@@ -882,43 +926,37 @@ b4_dollar_popdef[]dnl
will still contain any token that will not be accepted due will still contain any token that will not be accepted due
to an error action in a later state. to an error action in a later state.
*/ */
if (tok != yyempty_) int yycount = 0;
if (yyctx.yytoken != yyempty_)
{ {
/* FIXME: This method of building the message is not compatible yyarg[yycount++] = yyctx.yytoken;
with internationalization. */ yycount += yyexpectedTokens (yyctx, yyarg, 1, yyargn);
StringBuffer res = }
new StringBuffer ("syntax error, unexpected "); return yycount;
res.append (yysymbolName (tok)); }
int yyn = yypact_[yystate];
if (!yyPactValueIsDefault (yyn)) // Generate an error message.
private String yysyntax_error (Context yyctx)
{]b4_error_verbose_if([[
if (yyErrorVerbose)
{ {
/* Start YYX at -YYN if negative to avoid negative int[] yyarg = new int[5];
indexes in YYCHECK. In other words, skip the first int yycount = yysyntaxErrorArguments (yyctx, yyarg, 5);
-YYN actions for this state because they are default String[] yystr = new String[yycount];
actions. */ for (int yyi = 0; yyi < yycount; ++yyi)
int yyxbegin = yyn < 0 ? -yyn : 0; yystr[yyi] = yysymbolName (yyarg[yyi]);
/* Stay within bounds of both yycheck and yytname. */ MessageFormat yyformat;
int yychecklim = yylast_ - yyn + 1; switch (yycount)
int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_;
int count = 0;
for (int x = yyxbegin; x < yyxend; ++x)
if (yycheck_[x + yyn] == x && x != yy_error_token_
&& !yyTableValueIsError (yytable_[x + yyn]))
++count;
if (count < 5)
{ {
count = 0; default:
for (int x = yyxbegin; x < yyxend; ++x) case 0: yyformat = new MessageFormat ("syntax error"); break;
if (yycheck_[x + yyn] == x && x != yy_error_token_ case 1: yyformat = new MessageFormat ("syntax error, unexpected {0}"); break;
&& !yyTableValueIsError (yytable_[x + yyn])) case 2: yyformat = new MessageFormat ("syntax error, unexpected {0}, expecting {1}"); break;
{ case 3: yyformat = new MessageFormat ("syntax error, unexpected {0}, expecting {1} or {2}"); break;
res.append (count++ == 0 ? ", expecting " : " or "); case 4: yyformat = new MessageFormat ("syntax error, unexpected {0}, expecting {1} or {2} or {3}"); break;
res.append (yysymbolName (x)); case 5: yyformat = new MessageFormat ("syntax error, unexpected {0}, expecting {1} or {2} or {3} or {4}"); break;
}
}
}
return res.toString ();
} }
return yyformat.format (yystr);
} }
]])[ ]])[
return "syntax error"; return "syntax error";