[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH for Dlang support 2/2] d: add the custom error message feature
From: |
Adela Vais |
Subject: |
[PATCH for Dlang support 2/2] d: add the custom error message feature |
Date: |
Sun, 25 Oct 2020 16:19:56 +0200 |
* data/skeletons/lalr1.d: Add the custom error message feature.
* doc/bison.texi: Document it.
* tests/calc.at, tests/local.at: Test it.
---
data/skeletons/lalr1.d | 38 +++++++++++++++++++++++++-------------
doc/bison.texi | 37 +++++++++++++++++++++++++++++++++++++
tests/calc.at | 23 +++++++++++++++--------
tests/local.at | 41 ++++++++++++++++++++++++++++++++++++++++-
4 files changed, 117 insertions(+), 22 deletions(-)
diff --git a/data/skeletons/lalr1.d b/data/skeletons/lalr1.d
index 9b7c786c..a9e7e917 100644
--- a/data/skeletons/lalr1.d
+++ b/data/skeletons/lalr1.d
@@ -77,7 +77,15 @@ public interface Lexer
* @@param loc The location of the element to which the
* error message is related]])[
* @@param s The string for the error message. */
- void yyerror (]b4_locations_if([b4_location_type[ loc, ]])[string s);
+ void yyerror (]b4_locations_if([b4_location_type[ loc, ]])[string s);
+]b4_parse_error_bmatch([custom], [[
+ /**
+ * Build and emit a "syntax error" message in a user-defined way.
+ *
+ * @@param ctx The context of the error.
+ */
+ void syntax_error(]b4_parser_class[.Context ctx);
+]])[
}
]b4_locations_if([b4_position_type_if([[
@@ -276,7 +284,7 @@ b4_user_union_members
return yylexer.yylex ();
}
- protected final void yyerror (]b4_locations_if(ref [b4_location_type[ loc,
]])[string s) {
+ protected final void yyerror (]b4_locations_if([b4_location_type[ loc,
]])[string s) {
yylexer.yyerror (]b4_locations_if([loc, ])[s);
}
@@ -555,7 +563,7 @@ m4_popdef([b4_at_dollar])])dnl
++yynerrs_;
if (yychar == TokenKind.]b4_symbol(empty, id)[)
yytoken = ]b4_symbol(empty, kind)[;
- yyerror (]b4_locations_if([yylloc, ])[yysyntax_error(new
Context(yystack, yytoken]b4_locations_if([[, yylloc]])[)));
+ yysyntax_error(new Context(yystack, yytoken]b4_locations_if([[,
yylloc]])[));
}
]b4_locations_if([
yyerrloc = yylloc;])[
@@ -659,8 +667,11 @@ m4_popdef([b4_at_dollar])])dnl
}
// Generate an error message.
- private final string yysyntax_error(Context yyctx)
- {]b4_parse_error_case([verbose], [[
+ private final void yysyntax_error(Context yyctx)
+ {]b4_parse_error_bmatch(
+[custom], [[
+ yylexer.syntax_error(yyctx);]],
+[detailed\|verbose], [[
/* There are many possibilities here to consider:
- Assume YYFAIL is not used. It's too flawed to consider.
See
@@ -691,16 +702,16 @@ m4_popdef([b4_at_dollar])])dnl
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 (yyctx.getToken() != ]b4_symbol(empty, kind)[)
{
// FIXME: This method of building the message is not compatible
// with internationalization.
string res = "syntax error, unexpected ";
- res ~= format!"%s"(yyctx.getToken);
+ res ~= format!"%s"(yyctx.getToken());
immutable int argmax = 5;
- SymbolKind[] yyarg = new SymbolKind[argmax];
- int yycount = yyctx.getExpectedTokens(yyarg, argmax);
+ SymbolKind[] yyarg = new SymbolKind[yyntokens_];
+ int yycount = yyctx.getExpectedTokens(yyarg, yyntokens_);
if (yycount < argmax)
{
for (int yyi = 0; yyi < yycount; yyi++)
@@ -709,9 +720,10 @@ m4_popdef([b4_at_dollar])])dnl
res ~= format!"%s"(SymbolKind(yyarg[yyi]));
}
}
- return res;
- }]])[
- return "syntax error";
+ yyerror(]b4_locations_if([yyctx.getLocation(), ])[res);
+ }]],
+[[simple]], [[
+ yyerror(]b4_locations_if([yyctx.getLocation(), ])["syntax error");]])[
}
/**
@@ -770,7 +782,7 @@ m4_popdef([b4_at_dollar])])dnl
if (yycheck_[yyx + yyn] == yyx && yyx != ]b4_symbol(1, kind)[
&& !yyTableValueIsError(yytable_[yyx + yyn]))
yycount++;
- if (yycount < yyargn)
+ if (yycount < yyntokens_)
{
yycount = 0;
for (int x = yyxbegin; x < yyxend; ++x)
diff --git a/doc/bison.texi b/doc/bison.texi
index e49828c9..419173cc 100644
--- a/doc/bison.texi
+++ b/doc/bison.texi
@@ -14018,6 +14018,43 @@ They should return new objects for each call, to avoid
that all the symbol
share the same Position boundaries.
@end deftypemethod
+@deftypemethod {Lexer} {void} syntax_error(@code{YYParser.Context} @var{ctx})
+If you invoke @samp{%define parse.error custom} (@pxref{Bison
+Declarations}), then the parser no longer passes syntax error messages to
+@code{yyerror}, rather it delegates that task to the user by calling the
+@code{reportSyntaxError} function.
+
+Whether it uses @code{yyerror} is up to the user.
+
+Here is an example of a reporting function (@pxref{D Parser Context
+Interface}).
+
+@example
+public void syntax_error(YYParser.Context ctx)
+@{
+ stderr.write(ctx.getLocation(), ": syntax error");
+ // Report the expected tokens.
+ @{
+ immutable int TOKENMAX = 5;
+ YYParser.SymbolKind[] arg = new YYParser.SymbolKind[TOKENMAX];
+ int n = ctx.getExpectedTokens(arg, TOKENMAX);
+ if (n < TOKENMAX)
+ for (int i = 0; i < n; ++i)
+ stderr.write((i == 0 ? ": expected " : " or "), arg[i]);
+ @}
+ // Report the unexpected token which triggered the error.
+ @{
+ YYParser.SymbolKind lookahead = ctx.getToken();
+ stderr.writeln(" before ", lookahead);
+ @}
+@}
+@end example
+
+@noindent
+This implementation is inappropriate for internationalization, see
+the ???c/bistromathic??? example for a better alternative.
+@end deftypemethod
+
@node Java Parsers
@section Java Parsers
diff --git a/tests/calc.at b/tests/calc.at
index a96fc98a..cd7c8622 100644
--- a/tests/calc.at
+++ b/tests/calc.at
@@ -364,7 +364,7 @@ void location_print (FILE *o, Span s);
}]])[
/* Bison Declarations */
-%token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of input")], ["end of
input"])[
+%token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of file")], ["end of input"])[
%token <]AT_VALUE_UNION_IF([int], [ival])[> NUM "number"
%type <]AT_VALUE_UNION_IF([int], [ival])[> exp
@@ -666,20 +666,20 @@ m4_define([_AT_DATA_CALC_Y(d)],
%printer { fprintf (yyo, "%d", $$); } <ival>;
/* Bison Declarations */
-%token EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of input")], ["end of input"])[
+%token EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of file")], ["end of input"])[
%token <ival> NUM "number"
%type <ival> exp
-%token PLUS "+"
+%token EQUAL "="
MINUS "-"
+ PLUS "+"
STAR "*"
SLASH "/"
+ POW "^"
+ EOL "\n"
LPAR "("
RPAR ")"
- EQUAL "="
- POW "^"
NOT "!"
- EOL "\n"
%nonassoc "=" /* comparison */
%left "-" "+"
@@ -736,7 +736,6 @@ power (int base, int exponent)
return res;
}
-]AT_YYERROR_DEFINE[
]AT_CALC_YYLEX
AT_CALC_MAIN])
])# _AT_DATA_CALC_Y(d)
@@ -861,7 +860,7 @@ m4_define([_AT_DATA_CALC_Y(java)],
}
/* Bison Declarations */
-%token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of input")], ["end of
input"])[
+%token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of file")], ["end of input"])[
%token <Integer> NUM "number"
%type <Integer> exp
@@ -1448,6 +1447,14 @@ AT_CHECK_CALC_LALR1_D([%define parse.error verbose
%define api.prefix {calc} %ve
AT_CHECK_CALC_LALR1_D([%debug])
+AT_CHECK_CALC_LALR1_D([%define parse.error custom])
+AT_CHECK_CALC_LALR1_D([%define parse.error detailed])
+AT_CHECK_CALC_LALR1_D([%define parse.error simple])
+AT_CHECK_CALC_LALR1_D([%define parse.error verbose])
+AT_CHECK_CALC_LALR1_D([%locations %define parse.error custom])
+AT_CHECK_CALC_LALR1_D([%locations %define parse.error detailed])
+AT_CHECK_CALC_LALR1_D([%locations %define parse.error simple])
+AT_CHECK_CALC_LALR1_D([%locations %define parse.error verbose])
AT_CHECK_CALC_LALR1_D([%define parse.error verbose %debug %verbose])
AT_CHECK_CALC_LALR1_D([%define parse.error verbose %debug %define
api.token.prefix {TOK_} %verbose])
AT_CHECK_CALC_LALR1_D([%define parse.error verbose %debug %define
api.symbol.prefix {SYMB_} %verbose])
diff --git a/tests/local.at b/tests/local.at
index b18bdf3b..36019602 100644
--- a/tests/local.at
+++ b/tests/local.at
@@ -871,7 +871,46 @@ m4_define([AT_YYERROR_DEFINE(d)],
public void yyerror (]AT_LOCATION_IF([[YYLocation l, ]])[string m)
{
stderr.writeln (]AT_LOCATION_IF([[l, ": ", ]])[m);
-}]])
+}
+]AT_ERROR_CUSTOM_IF([[
+// In the case of D, there are no single quotes around the symbols
+// so they need to be added here
+public string transformToken(]AT_API_PREFIX[Parser.SymbolKind token)
+{
+ string tokenStr;
+ foreach (i; format("%s", token))
+ {
+ if (i == '\"')
+ tokenStr ~= '\'';
+ else
+ tokenStr ~= i;
+ }
+ if (tokenStr.length == 1)
+ return '\'' ~ tokenStr ~ '\'';
+ else
+ return tokenStr;
+}
+
+public void syntax_error(]AT_API_PREFIX[Parser.Context ctx)
+{
+ stderr.write(]AT_LOCATION_IF([[ctx.getLocation(), ": ",]])["syntax error");
+ {
+ ]AT_API_PREFIX[Parser.SymbolKind token = ctx.getToken();
+ stderr.write(" on token @<:@", transformToken(token), "@:>@");
+ }
+ {
+ immutable int argmax = 7;
+ ]AT_API_PREFIX[Parser.SymbolKind[] arg = new
]AT_API_PREFIX[Parser.SymbolKind[argmax];
+ int n = ctx.getExpectedTokens(arg, argmax);
+ if (0 < n) {
+ stderr.write(" (expected:");
+ for (int i = 0; i < n; ++i)
+ stderr.write(" @<:@", transformToken(arg[i]), "@:>@");
+ stderr.writeln(")");
+ }
+ }
+}
+]])[]])
m4_define([AT_MAIN_DEFINE(d)],
--
2.17.1