bison-patches
[Top][All Lists]
Advanced

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

[PATCH 07/12] yacc.c: isolate yyexpected_tokens


From: Akim Demaille
Subject: [PATCH 07/12] yacc.c: isolate yyexpected_tokens
Date: Thu, 16 Jan 2020 07:58:18 +0100

Provide users with a means to query for the currently allowed tokens.
Could be used for autocompletion for instance.

* data/skeletons/yacc.c (yyexpected_tokens): New, extracted from
yysyntax_error_arguments.
* examples/c/calc/calc.y (PRINT_EXPECTED_TOKENS): New.
Use it.
---
 data/skeletons/yacc.c  | 99 +++++++++++++++++++++++++++---------------
 examples/c/calc/calc.y | 32 +++++++++++---
 2 files changed, 90 insertions(+), 41 deletions(-)

diff --git a/data/skeletons/yacc.c b/data/skeletons/yacc.c
index 022b01de..5c7a938d 100644
--- a/data/skeletons/yacc.c
+++ b/data/skeletons/yacc.c
@@ -1056,6 +1056,62 @@ yy_lac (yy_state_t *yyesa, yy_state_t **yyes,
   YYPTRDIFF_T *yyes_capacity_p;]])[
 } yyparse_context_t;
 
+/* 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.  */
+static int
+yyexpected_tokens (const yyparse_context_t *yyctx,
+                   int yyarg[], int yyargn)
+{
+  /* Actual size of YYARG. */
+  int yycount = 0;
+]b4_lac_if([[
+  int yyx;
+  for (yyx = 0; yyx < YYNTOKENS; ++yyx)
+    if (yyx != YYTERROR && yyx != YYUNDEFTOK)
+      {
+        {
+          int yy_lac_status = yy_lac (yyctx->yyesa, yyctx->yyes_p, 
yyctx->yyes_capacity_p,
+                                      yyctx->yyssp, yyx);
+          if (yy_lac_status == 2)
+            return -2;
+          if (yy_lac_status == 1)
+            continue;
+        }
+        if (!yyarg)
+          ++yycount;
+        else if (yycount == yyargn)
+          return 0;
+        else
+          yyarg[yycount++] = yyx;
+      }]],
+[[  int yyn = yypact[+*yyctx->yyssp];
+  if (!yypact_value_is_default (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 yyx;
+      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+        if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+            && !yytable_value_is_error (yytable[yyx + yyn]))
+          {
+            if (!yyarg)
+              ++yycount;
+            else if (yycount == yyargn)
+              return 0;
+            else
+              yyarg[yycount++] = yyx;
+          }
+    }]])[
+  return yycount;
+}
+
 static int
 yysyntax_error_arguments (const yyparse_context_t *yyctx,
                           int yyarg[], int yyargn)
@@ -1092,45 +1148,16 @@ yysyntax_error_arguments (const yyparse_context_t 
*yyctx,
   */
   if (yyctx->yytoken != YYEMPTY)
     {
-      int yyn = yypact[+*yyctx->yyssp];]b4_lac_if([[
+      int yyn;]b4_lac_if([[
       YYDPRINTF ((stderr, "Constructing syntax error message\n"));]])[
       yyarg[yycount++] = yyctx->yytoken;
-      if (!yypact_value_is_default (yyn))
-        {]b4_lac_if([[
-          int yyx;
-          for (yyx = 0; yyx < YYNTOKENS; ++yyx)
-            if (yyx != YYTERROR && yyx != YYUNDEFTOK)
-              {
-                {
-                  int yy_lac_status = yy_lac (yyctx->yyesa, yyctx->yyes_p, 
yyctx->yyes_capacity_p,
-                                              yyctx->yyssp, yyx);
-                  if (yy_lac_status == 2)
-                    return -2;
-                  if (yy_lac_status == 1)
-                    continue;
-                }]], [[
-          /* 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 yyx;
-          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
-                && !yytable_value_is_error (yytable[yyx + yyn]))
-              {]])[
-                if (yycount == yyargn)
-                  {
-                    yycount = 1;
-                    break;
-                  }
-                yyarg[yycount++] = yyx;
-              }
-        }]b4_lac_if([[
-      else
+      yyn = yyexpected_tokens (yyctx, yyarg ? yyarg + 1 : yyarg, yyargn - 1);
+      if (yyn == -2)
+        return -2;]b4_lac_if([[
+      else if (yyn == 0)
         YYDPRINTF ((stderr, "No expected tokens.\n"));]])[
+      else
+        yycount += yyn;
     }
   return yycount;
 }
diff --git a/examples/c/calc/calc.y b/examples/c/calc/calc.y
index 0ba74da6..20f000a2 100644
--- a/examples/c/calc/calc.y
+++ b/examples/c/calc/calc.y
@@ -1,15 +1,35 @@
 %code top {
   #include <ctype.h>  /* isdigit. */
+  #include <stdbool.h>
   #include <stdio.h>  /* For printf, etc. */
   #include <string.h> /* strcmp. */
 
   int yylex (void);
   void yyerror (char const *);
+
+  bool show_expected = false;
+
+#define PRINT_EXPECTED_TOKENS()                                         \
+  do {                                                                  \
+    if (show_expected)                                                  \
+      {                                                                 \
+        yyparse_context_t ctx                                           \
+          = {yyssp, yytoken, yyesa, &yyes, &yyes_capacity};             \
+        int tokens[YYNTOKENS];                                          \
+        int cnt = yyexpected_tokens (&ctx, tokens, YYNTOKENS);          \
+        fprintf (stderr, "expected tokens in state %d rule %d (%d):",   \
+                 *yyssp, yyn - 1, cnt);                                 \
+        for (int i = 0; i < cnt; ++i)                                   \
+          fprintf (stderr, " %s", yysymbol_name(tokens[i]));            \
+        fprintf (stderr, "\n");                                         \
+      }                                                                 \
+  } while (0)
 }
 
 %define api.header.include {"calc.h"}
 %define api.value.type union /* Generate YYSTYPE from these types:  */
 %define parse.error custom
+%define parse.lac full
 %token <double> NUM "number"
 %type  <double> expr term fact
 
@@ -23,8 +43,8 @@
 
 %% /* The grammar follows.  */
 input:
-  %empty
-| input line
+  %empty       { PRINT_EXPECTED_TOKENS (); }
+| input line   { PRINT_EXPECTED_TOKENS (); }
 ;
 
 line:
@@ -46,8 +66,8 @@ term:
 ;
 
 fact:
-  "number"
-| '(' expr ')' { $$ = $2; }
+  "number"                                   { PRINT_EXPECTED_TOKENS (); }
+| '(' expr { PRINT_EXPECTED_TOKENS (); } ')' { $$ = $expr; }
 ;
 
 %%
@@ -110,7 +130,9 @@ main (int argc, char const* argv[])
 {
   /* Enable parse traces on option -p.  */
   for (int i = 1; i < argc; ++i)
-    if (!strcmp (argv[i], "-p"))
+    if (!strcmp (argv[i], "-e"))
+      show_expected = 1;
+    else if (!strcmp (argv[i], "-p"))
       yydebug = 1;
   return yyparse ();
 }
-- 
2.24.1




reply via email to

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