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

Adela Vais <[email protected]>
Newsgroups gmane.comp.parsers.bison.patches
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.