diff options
author | Akim Demaille <akim.demaille@gmail.com> | 2020-02-07 06:09:10 +0100 |
---|---|---|
committer | Akim Demaille <akim.demaille@gmail.com> | 2020-02-08 11:24:53 +0100 |
commit | 088356cb2f57216cd2026fa4145ece14f3c0ab16 (patch) | |
tree | ebf57a105f72481b72a533288f9d4b765a056ad0 /data/skeletons | |
parent | 52db24b2bc46ca1cc9af2ce1cb15b00bdab99d90 (diff) | |
download | bison-088356cb2f57216cd2026fa4145ece14f3c0ab16.tar.gz |
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.
Diffstat (limited to 'data/skeletons')
-rw-r--r-- | data/skeletons/lalr1.java | 164 |
1 files changed, 101 insertions, 63 deletions
diff --git a/data/skeletons/lalr1.java b/data/skeletons/lalr1.java index 1005fafb..f74ac646 100644 --- a/data/skeletons/lalr1.java +++ b/data/skeletons/lalr1.java @@ -82,6 +82,7 @@ m4_define([b4_define_state],[[ ]])[ ]b4_user_pre_prologue[ ]b4_user_post_prologue[ +import java.text.MessageFormat; ]b4_percent_code_get([[imports]])[ /** * A Bison parser, automatically generated from <tt>]m4_bpatsubst(b4_file_name, [^"\(.*\)"$], [\1])[</tt>. @@ -673,7 +674,10 @@ b4_dollar_popdef[]dnl ++yynerrs; if (yychar == 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([[ @@ -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. - private String yysyntax_error (int yystate, int tok) + private String yysyntax_error (Context yyctx) {]b4_error_verbose_if([[ if (yyErrorVerbose) { - /* 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. - */ - if (tok != yyempty_) + int[] yyarg = new int[5]; + int yycount = yysyntaxErrorArguments (yyctx, yyarg, 5); + String[] yystr = new String[yycount]; + for (int yyi = 0; yyi < yycount; ++yyi) + yystr[yyi] = yysymbolName (yyarg[yyi]); + MessageFormat yyformat; + switch (yycount) { - /* FIXME: This method of building the message is not compatible - with internationalization. */ - StringBuffer res = - new StringBuffer ("syntax error, unexpected "); - res.append (yysymbolName (tok)); - int yyn = yypact_[yystate]; - 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_; - 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 (); + default: + case 0: yyformat = new MessageFormat ("syntax error"); break; + case 1: yyformat = new MessageFormat ("syntax error, unexpected {0}"); break; + 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; + case 4: yyformat = new MessageFormat ("syntax error, unexpected {0}, expecting {1} or {2} or {3}"); break; + case 5: yyformat = new MessageFormat ("syntax error, unexpected {0}, expecting {1} or {2} or {3} or {4}"); break; } + return yyformat.format (yystr); } ]])[ return "syntax error"; |