mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 04:13:03 +00:00
yacc.c: isolate yyexpected_tokens
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.
This commit is contained in:
@@ -895,7 +895,7 @@ do { \
|
||||
{ \
|
||||
YYDPRINTF ((stderr, \
|
||||
"LAC: initial context established for %s\n", \
|
||||
yysymbol_name(yytoken))); \
|
||||
yysymbol_name (yytoken))); \
|
||||
yy_lac_established = 1; \
|
||||
{ \
|
||||
int yy_lac_status = \
|
||||
@@ -948,7 +948,7 @@ yy_lac (yy_state_t *yyesa, yy_state_t **yyes,
|
||||
yy_state_t *yyes_prev = yyssp;
|
||||
yy_state_t *yyesp = yyes_prev;
|
||||
/* Reduce until we encounter a shift and thereby accept the token. */
|
||||
YYDPRINTF ((stderr, "LAC: checking lookahead %s:", yysymbol_name(yytoken)));
|
||||
YYDPRINTF ((stderr, "LAC: checking lookahead %s:", yysymbol_name (yytoken)));
|
||||
if (yytoken == YYUNDEFTOK)
|
||||
{
|
||||
YYDPRINTF ((stderr, " Always Err\n"));
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user