diff --git a/gnulib b/gnulib index 9351b403..b141afaf 160000 --- a/gnulib +++ b/gnulib @@ -1 +1 @@ -Subproject commit 9351b4033bbf0bb1df3d3412376fefe785168c27 +Subproject commit b141afaf9ba197e361510da075556822ac453ff6 diff --git a/src/reader.c b/src/reader.c index 17038b42..11dc07bc 100644 --- a/src/reader.c +++ b/src/reader.c @@ -55,7 +55,37 @@ bool default_prec = true; void 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; + } + } } diff --git a/src/symlist.c b/src/symlist.c index f3bc12bc..1e899646 100644 --- a/src/symlist.c +++ b/src/symlist.c @@ -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. | `-----------------------------------------------------------------------*/ @@ -129,23 +139,29 @@ symbol_list_prepend (symbol_list *list, symbol_list *node) } -/*-------------------------. -| Append NODE to the LIST. | -`-------------------------*/ +symbol_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_append (symbol_list *list, symbol_list *node) { - if (!list) - return node; - symbol_list *next = list; - while (next->next) - next = next->next; - next->next = node; + if (list) + symbol_list_last (list)->next = node; + else + list = node; return list; } + /*-----------------------------------------------. | Free the LIST, but not the items it contains. | `-----------------------------------------------*/ diff --git a/src/symlist.h b/src/symlist.h index 39fdec40..6a3a4d53 100644 --- a/src/symlist.h +++ b/src/symlist.h @@ -112,6 +112,9 @@ symbol_list *symbol_list_type_new (uniqstr type_name, location loc); ** \returns \c syms */ 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. \pre For every node \c n in the list, n->content_type = @@ -121,6 +124,9 @@ void symbol_list_syms_print (const symbol_list *l, FILE *f); /** Prepend \c node to \c list. */ 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. */ 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); -/* Get the data type (alternative in the union) of the value for - symbol N in rule RULE. */ +/** Get the data type (alternative in the union) of the value for + symbol N in rule RULE. */ 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); /** Set the \c \%destructor or \c \%printer for \c node as \c cprops. */ diff --git a/tests/input.at b/tests/input.at index 8cf58914..26f52cf7 100644 --- a/tests/input.at +++ b/tests/input.at @@ -1814,6 +1814,75 @@ AT_BISON_CHECK([-o input.c input.y]) 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. ## ## --------------------- ## diff --git a/tests/reduce.at b/tests/reduce.at index f9d59a26..daaf3378 100644 --- a/tests/reduce.at +++ b/tests/reduce.at @@ -452,7 +452,7 @@ AT_CLEANUP AT_SETUP([Bad start symbols]) m4_pushdef([AT_TEST], -[ +[AT_BISON_OPTION_PUSHDEFS([$1]) AT_DATA([[input.y]], [%% $1 @@ -461,6 +461,7 @@ $1 AT_BISON_CHECK([[input.y]], 1, [], [$2 ]) +AT_BISON_OPTION_POPDEFS([$1]) ]) AT_TEST(