bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH for Dlang support 1/2] d: create the Parser.Context class


From: Adela Vais
Subject: [PATCH for Dlang support 1/2] d: create the Parser.Context class
Date: Sun, 25 Oct 2020 16:19:55 +0200

This will provide the user an interface for creating custom error messages.

* data/skeletons/lalr1.d: Add the Context class.
* doc/bison.texi: Document it.
---
 data/skeletons/lalr1.d | 112 ++++++++++++++++++++++++++++++-----------
 doc/bison.texi         |  21 +++++++-
 2 files changed, 102 insertions(+), 31 deletions(-)

diff --git a/data/skeletons/lalr1.d b/data/skeletons/lalr1.d
index 9e0095f3..9b7c786c 100644
--- a/data/skeletons/lalr1.d
+++ b/data/skeletons/lalr1.d
@@ -452,7 +452,7 @@ m4_popdef([b4_at_dollar])])dnl
 
         /* Take a decision.  First try without lookahead.  */
         yyn = yypact_[yystate];
-        if (yy_pact_value_is_default_ (yyn))
+        if (yyPactValueIsDefault(yyn))
         {
           label = YYDEFAULT;
           break;
@@ -497,7 +497,7 @@ m4_popdef([b4_at_dollar])])dnl
           /* <= 0 means reduce or error.  */
           else if ((yyn = yytable_[yyn]) <= 0)
           {
-            if (yy_table_value_is_error_ (yyn))
+            if (yyTableValueIsError(yyn))
               label = YYERRLAB;
             else
             {
@@ -555,7 +555,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 (yystate, 
yytoken));
+          yyerror (]b4_locations_if([yylloc, ])[yysyntax_error(new 
Context(yystack, yytoken]b4_locations_if([[, yylloc]])[)));
         }
 ]b4_locations_if([
         yyerrloc = yylloc;])[
@@ -602,7 +602,7 @@ m4_popdef([b4_at_dollar])])dnl
         for (;;)
         {
           yyn = yypact_[yystate];
-          if (!yy_pact_value_is_default_ (yyn))
+          if (!yyPactValueIsDefault(yyn))
           {
             yyn += ]b4_symbol(1, kind)[;
             if (0 <= yyn && yyn <= yylast_ && yycheck_[yyn] == ]b4_symbol(1, 
kind)[)
@@ -659,7 +659,7 @@ m4_popdef([b4_at_dollar])])dnl
   }
 
   // Generate an error message.
-  private final string yysyntax_error (int yystate, SymbolKind tok)
+  private final string yysyntax_error(Context yyctx)
   {]b4_parse_error_case([verbose], [[
     /* There are many possibilities here to consider:
        - Assume YYFAIL is not used.  It's too flawed to consider.
@@ -692,14 +692,71 @@ m4_popdef([b4_at_dollar])])dnl
          will still contain any token that will not be accepted due
          to an error action in a later state.
       */
-    if (tok != ]b4_symbol(empty, kind)[)
+    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"(tok);
-      int yyn = yypact_[yystate];
-      if (!yy_pact_value_is_default_ (yyn))
+      res ~= format!"%s"(yyctx.getToken);
+      immutable int argmax = 5;
+      SymbolKind[] yyarg = new SymbolKind[argmax];
+      int yycount = yyctx.getExpectedTokens(yyarg, argmax);
+      if (yycount < argmax)
+      {
+        for (int yyi = 0; yyi < yycount; yyi++)
+        {
+          res ~= yyi == 0 ? ", expecting " : " or ";
+          res ~= format!"%s"(SymbolKind(yyarg[yyi]));
+        }
+      }
+      return res;
+    }]])[
+    return "syntax error";
+  }
+
+  /**
+   * Information needed to get the list of expected tokens and to forge
+   * a syntax error diagnostic.
+   */
+  public static final class Context
+  {
+
+    private YYStack yystack;
+    private SymbolKind yytoken;]b4_locations_if([[
+    private ]b4_location_type[ yylocation;]])[
+
+    this(YYStack stack, SymbolKind kind]b4_locations_if([[, ]b4_location_type[ 
loc]])[)
+    {
+      yystack = stack;
+      yytoken = kind;]b4_locations_if([[
+      yylocation = loc;]])[
+    }
+
+    final SymbolKind getToken() const
+    {
+      return yytoken;
+    }]b4_locations_if([[
+
+    final ]b4_location_type[ getLocation()
+    {
+      return yylocation;
+    }]])[
+    /**
+     * 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).
+     */
+    int getExpectedTokens(SymbolKind[] yyarg, int yyargn)
+    {
+      return getExpectedTokens(yyarg, 0, yyargn);
+    }
+
+    int getExpectedTokens(SymbolKind[] yyarg, int yyoffset, int yyargn)
+    {
+      int yycount = yyoffset;
+      int yyn = yypact_[this.yystack.stateAt(0)];
+      if (!yyPactValueIsDefault(yyn))
       {
         /* Start YYX at -YYN if negative to avoid negative
            indexes in YYCHECK.  In other words, skip the first
@@ -709,33 +766,28 @@ m4_popdef([b4_at_dollar])])dnl
         /* 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 != ]b4_symbol(1, kind)[
-              && !yy_table_value_is_error_ (yytable_[x + yyn]))
-             ++count;
-          if (count < 5)
-          {
-             count = 0;
-             for (int x = yyxbegin; x < yyxend; ++x)
-               if (yycheck_[x + yyn] == x && x != ]b4_symbol(1, kind)[
-                   && !yy_table_value_is_error_ (yytable_[x + yyn]))
-               {
-                  res ~= count++ == 0 ? ", expecting " : " or ";
-                  res ~= format!"%s"(SymbolKind(x));
-               }
-          }
+        for (int yyx = yyxbegin; yyx < yyxend; ++yyx)
+          if (yycheck_[yyx + yyn] == yyx && yyx != ]b4_symbol(1, kind)[
+              && !yyTableValueIsError(yytable_[yyx + yyn]))
+            yycount++;
+        if (yycount < yyargn)
+        {
+          yycount = 0;
+          for (int x = yyxbegin; x < yyxend; ++x)
+            if (yycheck_[x + yyn] == x && x != ]b4_symbol(1, kind)[
+                && !yyTableValueIsError(yytable_[x + yyn]))
+              yyarg[yycount++] = SymbolKind(x);
+        }
       }
-      return res;
-    }]])[
-    return "syntax error";
+      return yycount - yyoffset;
+    }
   }
 
   /**
    * Whether the given <code>yypact_</code> value indicates a defaulted state.
    * @@param yyvalue   the value to check
    */
-  private static bool yy_pact_value_is_default_ (int yyvalue)
+  private static bool yyPactValueIsDefault(int yyvalue)
   {
     return yyvalue == yypact_ninf_;
   }
@@ -744,7 +796,7 @@ m4_popdef([b4_at_dollar])])dnl
    * Whether the given <code>yytable_</code> value indicates a syntax error.
    * @@param yyvalue   the value to check
    */
-  private static bool yy_table_value_is_error_ (int yyvalue)
+  private static bool yyTableValueIsError(int yyvalue)
   {
     return yyvalue == yytable_ninf_;
   }
diff --git a/doc/bison.texi b/doc/bison.texi
index 67494d35..e49828c9 100644
--- a/doc/bison.texi
+++ b/doc/bison.texi
@@ -13948,10 +13948,29 @@ enumerators are forged from the symbol names.  Use 
void toString(W)(W sink) to g
 the symbol names.
 @end defcv
 
-@deftypemethod {YYParser.Context} {YYParser.Location} yylloc_from_stack()
+@deftypemethod {YYParser.Context} {YYParser.SymbolKind} getToken()
+The kind of the lookahead.  Return ???null??? iff there is no lookahead.
+@end deftypemethod
+
+@deftypemethod {YYParser.Context} {YYParser.Location} getLocation()
 The location of the lookahead.
 @end deftypemethod
 
+@deftypemethod {YYParser.Context} {int} 
getExpectedTokens(@code{YYParser.SymbolKind[]} @var{argv}, @code{int} 
@var{argc})
+Fill @var{argv} with the expected tokens, which never includes
+@code{SymbolKind.YYERROR}, or @code{SymbolKind.YYUNDEF}.
+
+Never put more than @var{argc} elements into @var{argv}, and on success
+return the number of tokens stored in @var{argv}.  If there are more
+expected tokens than @var{argc}, fill @var{argv} up to @var{argc} and return
+0.  If there are no expected tokens, also return 0, but set @code{argv[0]}
+to @code{null}.
+
+If @var{argv} is null, return the size needed to store all the possible
+values, which is always less than @code{YYNTOKENS}.
+@end deftypemethod
+
+
 @node D Scanner Interface
 @subsection D Scanner Interface
 @c - %code lexer
-- 
2.17.1




reply via email to

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