[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
- Re: RFC: custom error messages, (continued)
- [PATCH 02/12] yacc.c: store token numbers, not token strings, Akim Demaille, 2020/01/16
- [PATCH 03/12] yacc.c: style: avoid macros, Akim Demaille, 2020/01/16
- [PATCH 01/12] yacc.c: extract yyerror_message_arguments, Akim Demaille, 2020/01/16
- [PATCH 04/12] yacc.c: add custom error message generation, Akim Demaille, 2020/01/16
- [PATCH 06/12] tests: compute verbose error messages from the custom ones, Akim Demaille, 2020/01/16
- [PATCH 05/12] yacc.c: check custom error messages, Akim Demaille, 2020/01/16
- [PATCH 07/12] yacc.c: isolate yyexpected_tokens,
Akim Demaille <=
- [PATCH 08/12] yacc.c: let custom error messages see the location, Akim Demaille, 2020/01/16
- [PATCH 09/12] yacc.c: check custom error messages with parse-params, Akim Demaille, 2020/01/16
- [PATCH 10/12] tests: a clearer test for parse-params, Akim Demaille, 2020/01/16
- [PATCH 12/12] yacc.c: portability to G++ 4.8, Akim Demaille, 2020/01/16
- [PATCH 11/12] yacc.c: pass the parse-params to yyreport_syntax_error, Akim Demaille, 2020/01/16
- Re: RFC: custom error messages, Christian Schoenebeck, 2020/01/16
- Re: RFC: custom error messages, Akim Demaille, 2020/01/17
- Re: RFC: custom error messages, Christian Schoenebeck, 2020/01/18
Re: RFC: custom error messages, Rici Lake, 2020/01/06