bison-patches
[Top][All Lists]
Advanced

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

multistart: check duplicates


From: Akim Demaille
Subject: multistart: check duplicates
Date: Sun, 22 Nov 2020 16:03:13 +0100

commit a157644ebb735dc519e675f2baec08b0efcebce6
Author: Akim Demaille <akim.demaille@gmail.com>
Date:   Sun Nov 22 11:19:48 2020 +0100

    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.

diff --git a/src/reader.c b/src/reader.c
index 17038b42..b4b5527a 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -55,7 +55,34 @@ 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);
+          l = l->next;
+        }
+      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_append (symbol_list *list, symbol_list *node)
+symbol_list_last (symbol_list *list)
 {
   if (!list)
-    return node;
+    return NULL;
   symbol_list *next = list;
   while (next->next)
     next = next->next;
-  next->next = node;
+  return next;
+}
+
+symbol_list *
+symbol_list_append (symbol_list *list, symbol_list *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, <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.  */
 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(




reply via email to

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