bison-patches
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]