java: provide Context with a more OO interface

* data/skeletons/lalr1.java (yyexpectedTokens)
(yysyntaxErrorArguments): Make them methods of Context.
(Context.yysymbolName): New.
* tests/local.at: Adjust.
This commit is contained in:
Akim Demaille
2020-02-08 15:36:18 +01:00
parent ef097719ea
commit 80a4389377
4 changed files with 90 additions and 79 deletions

8
TODO
View File

@@ -18,6 +18,14 @@ We should be able to redefine EOF like we do in C.
** Java: calc.at ** Java: calc.at
Stop hard-coding "Calc". Adjust local.at (look for FIXME). Stop hard-coding "Calc". Adjust local.at (look for FIXME).
** Java: _
We must not use _ in Java, it is becoming a keyword in Java 9.
examples/java/calc/Calc.java:998: warning: '_' used as an identifier
"$end", "error", "$undefined", _("end of line"), _("number"), "'='",
^
(use of '_' as an identifier might not be supported in releases after Java SE 8)
** doc ** doc
I feel it's ugly to use the GNU style to declare functions in the doc. It I feel it's ugly to use the GNU style to declare functions in the doc. It
generates tons of white space in the page, and may contribute to bad page generates tons of white space in the page, and may contribute to bad page

View File

@@ -866,80 +866,83 @@ b4_dollar_popdef[]dnl
public int yytoken;]b4_locations_if([[ public int yytoken;]b4_locations_if([[
public ]b4_location_type[ yylocation;]])[ public ]b4_location_type[ yylocation;]])[
public static final int yyntokens = ]b4_parser_class[.yyntokens_; public static final int yyntokens = ]b4_parser_class[.yyntokens_;
};
/* Put in YYARG at most YYARGN of the expected tokens given the /* Put in YYARG at most YYARGN of the expected tokens given the
current YYCTX, and return the number of tokens stored in YYARG. If current YYCTX, and return the number of tokens stored in YYARG. If
YYARG is null, return the number of expected tokens (guaranteed to YYARG is null, return the number of expected tokens (guaranteed to
be less than YYNTOKENS_). */ be less than YYNTOKENS). */
static int int yyexpectedTokens (int yyarg[], int yyoffset, int yyargn)
yyexpectedTokens (Context yyctx, {
int yyarg[], int yyoffset, int yyargn) int yycount = yyoffset;
{ int yyn = yypact_[this.yystack.stateAt (0)];
int yycount = yyoffset; if (!yyPactValueIsDefault (yyn))
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
/* Start YYX at -YYN if negative to avoid negative -YYN actions for this state because they are default
indexes in YYCHECK. In other words, skip the first actions. */
-YYN actions for this state because they are default int yyxbegin = yyn < 0 ? -yyn : 0;
actions. */ /* Stay within bounds of both yycheck and yytname. */
int yyxbegin = yyn < 0 ? -yyn : 0; int yychecklim = yylast_ - yyn + 1;
/* Stay within bounds of both yycheck and yytname. */ int yyxend = yychecklim < yyntokens ? yychecklim : yyntokens;
int yychecklim = yylast_ - yyn + 1; for (int x = yyxbegin; x < yyxend; ++x)
int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_; if (yycheck_[x + yyn] == x && x != yy_error_token_
for (int x = yyxbegin; x < yyxend; ++x) && !yyTableValueIsError (yytable_[x + yyn]))
if (yycheck_[x + yyn] == x && x != yy_error_token_ {
&& !yyTableValueIsError (yytable_[x + yyn])) if (yyarg == null)
{ yycount += 1;
if (yyarg == null) else if (yycount == yyargn)
yycount += 1; return 0; // FIXME: this is incorrect.
else if (yycount == yyargn) else
return 0; // FIXME: this is incorrect. yyarg[yycount++] = x;
else }
yyarg[yycount++] = x; }
} return yycount - yyoffset;
} }
return yycount - yyoffset;
}
static int /* The user-facing name of the symbol whose (internal) number is
yysyntaxErrorArguments (Context yyctx, YYSYMBOL. No bounds checking. */
int[] yyarg, int yyargn) static String yysymbolName (int yysymbol)
{ {
/* There are many possibilities here to consider: return ]b4_parser_class[.yysymbolName (yysymbol);
- 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 int yysyntaxErrorArguments (int[] yyarg, int yyargn)
check for expected tokens because there are none. {
- The only way there can be no lookahead present (in tok) is /* 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,
Thus, detecting the absence of a lookahead is sufficient to then the only way this function was invoked is if the
determine that there is no unexpected or expected token to default action is an error action. In that case, don't
report. In that case, just report a simple "syntax error". check for expected tokens because there are none.
- Don't assume there isn't a lookahead just because this - The only way there can be no lookahead present (in tok) is
state is a consistent state with a default action. There if this state is a consistent state with a default action.
might have been a previous inconsistent state, consistent Thus, detecting the absence of a lookahead is sufficient to
state with a non-default action, or user semantic action determine that there is no unexpected or expected token to
that manipulated yychar. (However, yychar is currently out report. In that case, just report a simple "syntax error".
of scope during semantic actions.) - Don't assume there isn't a lookahead just because this
- Of course, the expected token list depends on states to state is a consistent state with a default action. There
have correct lookahead information, and it depends on the might have been a previous inconsistent state, consistent
parser not to perform extra reductions after fetching a state with a non-default action, or user semantic action
lookahead from the scanner and before detecting a syntax that manipulated yychar. (However, yychar is currently out
error. Thus, state merging (from LALR or IELR) and default of scope during semantic actions.)
reductions corrupt the expected token list. However, the - Of course, the expected token list depends on states to
list is correct for canonical LR with one exception: it have correct lookahead information, and it depends on the
will still contain any token that will not be accepted due parser not to perform extra reductions after fetching a
to an error action in a later state. lookahead from the scanner and before detecting a syntax
*/ error. Thus, state merging (from LALR or IELR) and default
int yycount = 0; reductions corrupt the expected token list. However, the
if (yyctx.yytoken != yyempty_) list is correct for canonical LR with one exception: it
{ will still contain any token that will not be accepted due
yyarg[yycount++] = yyctx.yytoken; to an error action in a later state.
yycount += yyexpectedTokens (yyctx, yyarg, 1, yyargn); */
} int yycount = 0;
return yycount; if (this.yytoken != yyempty_)
{
yyarg[yycount++] = this.yytoken;
yycount += this.yyexpectedTokens (yyarg, 1, yyargn);
}
return yycount;
}
} }
/** /**
@@ -954,7 +957,7 @@ b4_dollar_popdef[]dnl
{ {
final int argmax = 5; final int argmax = 5;
int[] yyarg = new int[argmax]; int[] yyarg = new int[argmax];
int yycount = yysyntaxErrorArguments (yyctx, yyarg, argmax); int yycount = yyctx.yysyntaxErrorArguments (yyarg, argmax);
String[] yystr = new String[yycount]; String[] yystr = new String[yycount];
for (int yyi = 0; yyi < yycount; ++yyi) for (int yyi = 0; yyi < yycount; ++yyi)
yystr[yyi] = yysymbolName (yyarg[yyi]); yystr[yyi] = yysymbolName (yyarg[yyi]);

View File

@@ -110,13 +110,13 @@ class CalcLexer implements Calc.Lexer {
{ {
final int ARGMAX = 10; final int ARGMAX = 10;
int[] arg = new int[ARGMAX]; int[] arg = new int[ARGMAX];
int n = Calc.yysyntaxErrorArguments (ctx, arg, ARGMAX); int n = ctx.yysyntaxErrorArguments (arg, ARGMAX);
System.err.print (ctx.yylocation + ": syntax error"); System.err.print (ctx.yylocation + ": syntax error");
for (int i = 1; i < n; ++i) for (int i = 1; i < n; ++i)
System.err.print ((i == 1 ? ": expected " : " or ") System.err.print ((i == 1 ? ": expected " : " or ")
+ Calc.yysymbolName (arg[i])); + ctx.yysymbolName (arg[i]));
if (n != 0) if (n != 0)
System.err.print (" before " + Calc.yysymbolName (arg[0])); System.err.print (" before " + ctx.yysymbolName (arg[0]));
System.err.println (""); System.err.println ("");
} }

View File

@@ -934,14 +934,14 @@ m4_define([AT_YYERROR_DEFINE(java)],
public void yyreportSyntaxError (Calc.Context ctx) public void yyreportSyntaxError (Calc.Context ctx)
{ {
int[] arg = new int[ctx.yyntokens]; int[] arg = new int[ctx.yyntokens];
int n = Calc.yysyntaxErrorArguments (ctx, arg, ctx.yyntokens); int n = ctx.yysyntaxErrorArguments (arg, ctx.yyntokens);
System.err.print (]AT_LOCATION_IF([[ctx.yylocation + ": "]] System.err.print (]AT_LOCATION_IF([[ctx.yylocation + ": "]]
+ )["syntax error on token @<:@" + Calc.yysymbolName(arg[0]) + "@:>@"); + )["syntax error on token @<:@" + ctx.yysymbolName (arg[0]) + "@:>@");
if (1 < n) if (1 < n)
{ {
System.err.print (" (expected:"); System.err.print (" (expected:");
for (int i = 1; i < n; ++i) for (int i = 1; i < n; ++i)
System.err.print (" @<:@" + Calc.yysymbolName (arg[i]) + "@:>@"); System.err.print (" @<:@" + ctx.yysymbolName (arg[i]) + "@:>@");
System.err.print (")"); System.err.print (")");
} }
System.err.println (""); System.err.println ("");