multistart: check duplicates

* src/symlist.h, src/symlist.c (symbol_list_find_symbol)
(symbol_list_last): New.
(symbol_list_append): Use symbol_list_last.
* src/reader.c (grammar_start_symbols_add): Check and discard duplicates.
* tests/input.at (Duplicate %start symbol): New.
* tests/reduce.at (Bad start symbols): Add the multistart keyword.
This commit is contained in:
Akim Demaille
2020-11-22 11:19:48 +01:00
parent 7fe9205b9f
commit 5b19f91ccf
6 changed files with 137 additions and 15 deletions

2
gnulib

Submodule gnulib updated: 9351b4033b...b141afaf9b

View File

@@ -55,7 +55,37 @@ bool default_prec = true;
void void
grammar_start_symbols_add (symbol_list *syms) grammar_start_symbols_add (symbol_list *syms)
{ {
start_symbols = symbol_list_append (start_symbols, syms); /* Report and ignore duplicates. Append the others to START_SYMBOLS. */
symbol_list *last = symbol_list_last (start_symbols);
for (symbol_list *l = syms; l && l->content.sym; /* nothing */)
{
/* Is there a previous definition? */
symbol_list *first = symbol_list_find_symbol (start_symbols, l->content.sym);
if (first)
{
duplicate_directive ("%start", first->sym_loc, l->sym_loc);
symbol_list *dup = l;
l = l->next;
dup->next = NULL;
symbol_list_free (dup);
}
else
{
if (last)
{
last->next = l;
last = l;
}
else
{
last = l;
start_symbols = last;
}
symbol_list *next = l->next;
l->next = NULL;
l = next;
}
}
} }

View File

@@ -91,6 +91,16 @@ symbol_list_type_set (symbol_list *syms, uniqstr type_name)
} }
symbol_list *
symbol_list_find_symbol (symbol_list *l, const symbol *sym)
{
for (/* Nothing. */; l && l->content.sym; l = l->next)
if (l->content.sym == sym)
return l;
return NULL;
}
/*-----------------------------------------------------------------------. /*-----------------------------------------------------------------------.
| Print this list, for which every content_type must be SYMLIST_SYMBOL. | | Print this list, for which every content_type must be SYMLIST_SYMBOL. |
`-----------------------------------------------------------------------*/ `-----------------------------------------------------------------------*/
@@ -129,23 +139,29 @@ symbol_list_prepend (symbol_list *list, symbol_list *node)
} }
/*-------------------------. symbol_list *
| Append NODE to the LIST. | symbol_list_last (symbol_list *list)
`-------------------------*/ {
if (!list)
return NULL;
symbol_list *next = list;
while (next->next)
next = next->next;
return next;
}
symbol_list * symbol_list *
symbol_list_append (symbol_list *list, symbol_list *node) symbol_list_append (symbol_list *list, symbol_list *node)
{ {
if (!list) if (list)
return node; symbol_list_last (list)->next = node;
symbol_list *next = list; else
while (next->next) list = node;
next = next->next;
next->next = node;
return list; return list;
} }
/*-----------------------------------------------. /*-----------------------------------------------.
| Free the LIST, but not the items it contains. | | Free the LIST, but not the items it contains. |
`-----------------------------------------------*/ `-----------------------------------------------*/

View File

@@ -112,6 +112,9 @@ symbol_list *symbol_list_type_new (uniqstr type_name, location loc);
** \returns \c syms */ ** \returns \c syms */
symbol_list *symbol_list_type_set (symbol_list *syms, uniqstr type_name); symbol_list *symbol_list_type_set (symbol_list *syms, uniqstr type_name);
/** Find a symbol with the same content as \c sym within \c syms. */
symbol_list *symbol_list_find_symbol (symbol_list *syms, const symbol *sym);
/** Print this list. /** Print this list.
\pre For every node \c n in the list, <tt>n->content_type = \pre For every node \c n in the list, <tt>n->content_type =
@@ -121,6 +124,9 @@ void symbol_list_syms_print (const symbol_list *l, FILE *f);
/** Prepend \c node to \c list. */ /** Prepend \c node to \c list. */
symbol_list *symbol_list_prepend (symbol_list *list, symbol_list *node); symbol_list *symbol_list_prepend (symbol_list *list, symbol_list *node);
/** The last node of this list. */
symbol_list *symbol_list_last (symbol_list *list);
/** Append \c node to \c list. */ /** Append \c node to \c list. */
symbol_list *symbol_list_append (symbol_list *list, symbol_list *node); symbol_list *symbol_list_append (symbol_list *list, symbol_list *node);
@@ -136,11 +142,11 @@ int symbol_list_length (symbol_list const *l);
**/ **/
symbol_list *symbol_list_n_get (symbol_list *l, int n); symbol_list *symbol_list_n_get (symbol_list *l, int n);
/* Get the data type (alternative in the union) of the value for /** Get the data type (alternative in the union) of the value for
symbol N in rule RULE. */ symbol N in rule RULE. */
uniqstr symbol_list_n_type_name_get (symbol_list *l, int n); uniqstr symbol_list_n_type_name_get (symbol_list *l, int n);
/* Check whether the node is a border element of a rule. */ /** Check whether the node is a border element of a rule. */
bool symbol_list_null (symbol_list *node); bool symbol_list_null (symbol_list *node);
/** Set the \c \%destructor or \c \%printer for \c node as \c cprops. */ /** Set the \c \%destructor or \c \%printer for \c node as \c cprops. */

View File

@@ -1814,6 +1814,75 @@ AT_BISON_CHECK([-o input.c input.y])
AT_CLEANUP AT_CLEANUP
## ------------------------- ##
## Duplicate %start symbol. ##
## ------------------------- ##
AT_SETUP([Duplicate %start symbol])
AT_KEYWORDS([multistart])
AT_DATA([input.y],
[[%start exp exp exp
%%
exp: %empty;
]])
AT_BISON_CHECK([-fcaret input.y], [0], [],
[[input.y:1.12-14: warning: duplicate directive [-Wother]
1 | %start exp exp exp
| ^~~
input.y:1.8-10: note: previous declaration
1 | %start exp exp exp
| ^~~
input.y:1.16-18: warning: duplicate directive [-Wother]
1 | %start exp exp exp
| ^~~
input.y:1.8-10: note: previous declaration
1 | %start exp exp exp
| ^~~
input.y: warning: fix-its can be applied. Rerun with option '--update'. [-Wother]
]])
AT_DATA([input.y],
[[%start exp foo exp
%%
exp: foo;
foo: %empty;
]])
AT_BISON_CHECK([-fcaret input.y], [0], [],
[[input.y:1.16-18: warning: duplicate directive [-Wother]
1 | %start exp foo exp
| ^~~
input.y:1.8-10: note: previous declaration
1 | %start exp foo exp
| ^~~
input.y: warning: fix-its can be applied. Rerun with option '--update'. [-Wother]
]])
AT_DATA([input.y],
[[%start exp foo
%start exp
%%
exp: foo;
foo: %empty;
]])
AT_BISON_CHECK([-fcaret input.y], [0], [],
[[input.y:2.8-10: warning: duplicate directive [-Wother]
2 | %start exp
| ^~~
input.y:1.8-10: note: previous declaration
1 | %start exp foo
| ^~~
input.y: warning: fix-its can be applied. Rerun with option '--update'. [-Wother]
]])
AT_CLEANUP
## --------------------- ## ## --------------------- ##
## %prec takes a token. ## ## %prec takes a token. ##
## --------------------- ## ## --------------------- ##

View File

@@ -452,7 +452,7 @@ AT_CLEANUP
AT_SETUP([Bad start symbols]) AT_SETUP([Bad start symbols])
m4_pushdef([AT_TEST], m4_pushdef([AT_TEST],
[ [AT_BISON_OPTION_PUSHDEFS([$1])
AT_DATA([[input.y]], AT_DATA([[input.y]],
[%% [%%
$1 $1
@@ -461,6 +461,7 @@ $1
AT_BISON_CHECK([[input.y]], 1, [], AT_BISON_CHECK([[input.y]], 1, [],
[$2 [$2
]) ])
AT_BISON_OPTION_POPDEFS([$1])
]) ])
AT_TEST( AT_TEST(