mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-18 00:33:03 +00:00
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:
@@ -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,74 +855,108 @@ b4_dollar_popdef[]dnl
|
|||||||
}
|
}
|
||||||
]])[
|
]])[
|
||||||
|
|
||||||
|
public final class Context
|
||||||
|
{
|
||||||
|
public YYStack yystack;
|
||||||
|
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:
|
||||||
|
- If this state is a consistent state with a default action,
|
||||||
|
then the only way this function was invoked is if the
|
||||||
|
default action is an error action. In that case, don't
|
||||||
|
check for expected tokens because there are none.
|
||||||
|
- The only way there can be no lookahead present (in tok) is
|
||||||
|
if this state is a consistent state with a default action.
|
||||||
|
Thus, detecting the absence of a lookahead is sufficient to
|
||||||
|
determine that there is no unexpected or expected token to
|
||||||
|
report. In that case, just report a simple "syntax error".
|
||||||
|
- Don't assume there isn't a lookahead just because this
|
||||||
|
state is a consistent state with a default action. There
|
||||||
|
might have been a previous inconsistent state, consistent
|
||||||
|
state with a non-default action, or user semantic action
|
||||||
|
that manipulated yychar. (However, yychar is currently out
|
||||||
|
of scope during semantic actions.)
|
||||||
|
- Of course, the expected token list depends on states to
|
||||||
|
have correct lookahead information, and it depends on the
|
||||||
|
parser not to perform extra reductions after fetching a
|
||||||
|
lookahead from the scanner and before detecting a syntax
|
||||||
|
error. Thus, state merging (from LALR or IELR) and default
|
||||||
|
reductions corrupt the expected token list. However, the
|
||||||
|
list is correct for canonical LR with one exception: it
|
||||||
|
will still contain any token that will not be accepted due
|
||||||
|
to an error action in a later state.
|
||||||
|
*/
|
||||||
|
int yycount = 0;
|
||||||
|
if (yyctx.yytoken != yyempty_)
|
||||||
|
{
|
||||||
|
yyarg[yycount++] = yyctx.yytoken;
|
||||||
|
yycount += yyexpectedTokens (yyctx, yyarg, 1, yyargn);
|
||||||
|
}
|
||||||
|
return yycount;
|
||||||
|
}
|
||||||
|
|
||||||
// Generate an error message.
|
// Generate an error message.
|
||||||
private String yysyntax_error (int yystate, int tok)
|
private String yysyntax_error (Context yyctx)
|
||||||
{]b4_error_verbose_if([[
|
{]b4_error_verbose_if([[
|
||||||
if (yyErrorVerbose)
|
if (yyErrorVerbose)
|
||||||
{
|
{
|
||||||
/* There are many possibilities here to consider:
|
int[] yyarg = new int[5];
|
||||||
- If this state is a consistent state with a default action,
|
int yycount = yysyntaxErrorArguments (yyctx, yyarg, 5);
|
||||||
then the only way this function was invoked is if the
|
String[] yystr = new String[yycount];
|
||||||
default action is an error action. In that case, don't
|
for (int yyi = 0; yyi < yycount; ++yyi)
|
||||||
check for expected tokens because there are none.
|
yystr[yyi] = yysymbolName (yyarg[yyi]);
|
||||||
- The only way there can be no lookahead present (in tok) is
|
MessageFormat yyformat;
|
||||||
if this state is a consistent state with a default action.
|
switch (yycount)
|
||||||
Thus, detecting the absence of a lookahead is sufficient to
|
|
||||||
determine that there is no unexpected or expected token to
|
|
||||||
report. In that case, just report a simple "syntax error".
|
|
||||||
- Don't assume there isn't a lookahead just because this
|
|
||||||
state is a consistent state with a default action. There
|
|
||||||
might have been a previous inconsistent state, consistent
|
|
||||||
state with a non-default action, or user semantic action
|
|
||||||
that manipulated yychar. (However, yychar is currently out
|
|
||||||
of scope during semantic actions.)
|
|
||||||
- Of course, the expected token list depends on states to
|
|
||||||
have correct lookahead information, and it depends on the
|
|
||||||
parser not to perform extra reductions after fetching a
|
|
||||||
lookahead from the scanner and before detecting a syntax
|
|
||||||
error. Thus, state merging (from LALR or IELR) and default
|
|
||||||
reductions corrupt the expected token list. However, the
|
|
||||||
list is correct for canonical LR with one exception: it
|
|
||||||
will still contain any token that will not be accepted due
|
|
||||||
to an error action in a later state.
|
|
||||||
*/
|
|
||||||
if (tok != yyempty_)
|
|
||||||
{
|
{
|
||||||
/* FIXME: This method of building the message is not compatible
|
default:
|
||||||
with internationalization. */
|
case 0: yyformat = new MessageFormat ("syntax error"); break;
|
||||||
StringBuffer res =
|
case 1: yyformat = new MessageFormat ("syntax error, unexpected {0}"); break;
|
||||||
new StringBuffer ("syntax error, unexpected ");
|
case 2: yyformat = new MessageFormat ("syntax error, unexpected {0}, expecting {1}"); break;
|
||||||
res.append (yysymbolName (tok));
|
case 3: yyformat = new MessageFormat ("syntax error, unexpected {0}, expecting {1} or {2}"); break;
|
||||||
int yyn = yypact_[yystate];
|
case 4: yyformat = new MessageFormat ("syntax error, unexpected {0}, expecting {1} or {2} or {3}"); break;
|
||||||
if (!yyPactValueIsDefault (yyn))
|
case 5: yyformat = new MessageFormat ("syntax error, unexpected {0}, expecting {1} or {2} or {3} or {4}"); break;
|
||||||
{
|
|
||||||
/* 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_;
|
|
||||||
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;
|
|
||||||
for (int x = yyxbegin; x < yyxend; ++x)
|
|
||||||
if (yycheck_[x + yyn] == x && x != yy_error_token_
|
|
||||||
&& !yyTableValueIsError (yytable_[x + yyn]))
|
|
||||||
{
|
|
||||||
res.append (count++ == 0 ? ", expecting " : " or ");
|
|
||||||
res.append (yysymbolName (x));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res.toString ();
|
|
||||||
}
|
}
|
||||||
|
return yyformat.format (yystr);
|
||||||
}
|
}
|
||||||
]])[
|
]])[
|
||||||
return "syntax error";
|
return "syntax error";
|
||||||
|
|||||||
Reference in New Issue
Block a user