Re: [PATCH 0/5] Conflict Counterexample Generation

Akim Demaille <[email protected]>
Newsgroups gmane.comp.parsers.bison.patches
Message-ID <[email protected]>
Hi Vincent,

I have addressed a number of minor issues in your code in your own commit.  Maybe at some point I should resend the current state of these commits.

But I have fixed a number of improper behavior in the commit below (mostly related to following our conventions, starting with: diagnostics are on stderr, not stdout).

Once I have fixed the test suite by providing it with the expected values, I can see that we have at least to SEGV: tests 247 and 253.  I will leave this to you, and will be back to work on this tomorrow in the morning (French time).

Please, *do start on my branch*.  My branch is the current state of work on your contribution.  Start from it, I won't rebase again to get something, I spent too much time already.

My branch is "cex", available currently on both GitHub and Savannah.

Cheers!




commit 0d72c68954d5575d2aa6d26b440558b53f901918
Author: Akim Demaille <[email protected]>
Date:   Wed May 13 18:38:09 2020 +0200

    cex: fixes
    
    * src/conflicts.c, src/counterexample.c, src/derivation.c:
    Do not output diagnostics on stdout, that's the job of stderr, and the
    testsuite heavily depend on this.
    Do not leave trailing spaces in the output.
    * tests/counterexample.at: Use AT_KEYWORDS.
    Specify the expected outputs.
    * tests/local.mk: Add counterexample.at.

diff --git a/src/conflicts.c b/src/conflicts.c
index 3cf21c47..b6cccd76 100644
--- a/src/conflicts.c
+++ b/src/conflicts.c
@@ -625,6 +625,15 @@ conflicts_total_count (void)
   return count_sr_conflicts () + count_rr_conflicts ();
 }
 
+static state_item_number
+find_state_item_number (const rule *r, state_number sn)
+{
+  for (int i = state_item_map[sn]; i < state_item_map[sn + 1]; ++i)
+    if (item_number_as_rule_number (*state_items[i].item) == r->number)
+      return i;
+  abort ();
+}
+
 static void
 report_state_counterexamples (const state *s)
 {
@@ -633,19 +642,8 @@ report_state_counterexamples (const state *s)
   for (int i = 0; i < reds->num; ++i)
     {
       rule *r1 = reds->rules[i];
-      state_item_number c1;
-      for (int j = state_item_map[sn];
-           j < state_item_map[sn + 1]; ++j)
-        {
-          if (item_number_as_rule_number (*state_items[j].item) == r1->number)
-            {
-              c1 = j;
-              break;
-            }
-        }
-
-      for (int j = state_item_map[sn];
-           j < state_item_map[sn + 1]; ++j)
+      const state_item_number c1 = find_state_item_number (r1, sn);
+      for (int j = state_item_map[sn]; j < state_item_map[sn + 1]; ++j)
         {
           if (SI_DISABLED (j))
             continue;
diff --git a/src/counterexample.c b/src/counterexample.c
index daf7f213..bdd54c79 100644
--- a/src/counterexample.c
+++ b/src/counterexample.c
@@ -18,22 +18,25 @@
  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
-#include <time.h>
-#include <hash.h>
-#include <stdlib.h>
+
+#include "counterexample.h"
+
 #include <gl_linked_list.h>
-#include <gl_xlist.h>
 #include <gl_rbtreehash_list.h>
-#include "counterexample.h"
-#include "derivation.h"
-#include "gram.h"
-#include "complain.h"
+#include <gl_xlist.h>
+#include <hash.h>
+#include <stdlib.h>
+#include <time.h>
+
 #include "closure.h"
-#include "nullable.h"
+#include "complain.h"
+#include "derivation.h"
 #include "getargs.h"
+#include "gram.h"
 #include "lalr.h"
-#include "parse-simulation.h"
 #include "lssi.h"
+#include "nullable.h"
+#include "parse-simulation.h"
 
 
 #define TIME_LIMIT_ENFORCED true
@@ -80,21 +83,22 @@ new_counterexample (const derivation *d1, const derivation *d2,
 void
 print_counterexample (counterexample *cex)
 {
+  FILE *out = stderr;
   if (cex->unifying)
-    printf ("Example ");
+    fprintf (out, "Example  ");
   else
-    printf ("First  Example");
-  derivation_print_leaves (cex->d1, stdout);
-  printf ("\nFirst  derivation ");
-  derivation_print (cex->d1, stdout);
+    fprintf (out, "First  Example ");
+  derivation_print_leaves (cex->d1, out);
+  fprintf (out, "\nFirst  derivation ");
+  derivation_print (cex->d1, out);
   if (!cex->unifying)
     {
-      printf ("\nSecond Example ");
-      derivation_print_leaves (cex->d2, stdout);
+      fprintf (out, "\nSecond Example ");
+      derivation_print_leaves (cex->d2, out);
     }
-  printf ("\nSecond derivation ");
-  derivation_print (cex->d2, stdout);
-  fputs ("\n\n", stdout);
+  fprintf (out, "\nSecond derivation ");
+  derivation_print (cex->d2, out);
+  fputs ("\n\n", out);
 }
 
 /*
@@ -461,11 +465,11 @@ nonunifying_shift_path (gl_list_t reduce_path, state_item *shift_conflict)
     }
   if (trace_flag & trace_cex)
     {
-      puts ("SHIFT ITEM PATH:");
+      fputs ("SHIFT ITEM PATH:\n", stderr);
       gl_list_iterator_t it = gl_list_iterator (result);
       state_item *sip;
       while (gl_list_iterator_next (&it, (const void **) &sip, NULL))
-        print_state_item (sip, stdout);
+        print_state_item (sip, stderr);
     }
   return result;
 }
@@ -560,11 +564,11 @@ search_state_free (search_state *ss)
 static void
 search_state_print (search_state *ss)
 {
-  fputs ("CONFLICT 1 ", stdout);
+  fputs ("CONFLICT 1 ", stderr);
   print_parse_state (ss->states[0]);
-  fputs ("CONFLICT 2 ", stdout);
+  fputs ("CONFLICT 2 ", stderr);
   print_parse_state (ss->states[1]);
-  putc ('\n', stdout);
+  putc ('\n', stderr);
 }
 
 /*
@@ -1069,13 +1073,14 @@ unifying_example (state_item_number itm1,
               if (!assurance_printed && time_passed > ASSURANCE_LIMIT
                   && stage3result)
                 {
-                  puts
-                    ("Productions leading up to the conflict state found.  Still finding a possible unifying counterexample...");
+                  fputs ("Productions leading up to the conflict state found.  "
+                         "Still finding a possible unifying counterexample...",
+                         stderr);
                   assurance_printed = true;
                 }
               if (time_passed > TIME_LIMIT)
                 {
-                  printf ("time limit exceeded: %f\n", time_passed);
+                  fprintf (stderr, "time limit exceeded: %f\n", time_passed);
                   goto cex_search_end;
                 }
             }
@@ -1153,12 +1158,10 @@ counterexample_report (state_item_number itm1, state_item_number itm2,
         bitset_set (rpp_set, si->state->number);
     }
   time_t t = time (NULL);
-  counterexample *cex = difftime (t,
-                                  cumulative_time) <
-    CUMULATIVE_TIME_LIMIT ? unifying_example (itm1, itm2, shift_reduce,
-                                              shortest_path,
-                                              next_sym) :
-    example_from_path (shift_reduce, itm2, shortest_path, next_sym);
+  counterexample *cex =
+    difftime (t, cumulative_time) < CUMULATIVE_TIME_LIMIT
+    ? unifying_example (itm1, itm2, shift_reduce, shortest_path, next_sym)
+    : example_from_path (shift_reduce, itm2, shortest_path, next_sym);
 
   gl_list_free (shortest_path);
   print_counterexample (cex);
@@ -1169,10 +1172,11 @@ void
 counterexample_report_shift_reduce (state_item_number itm1, state_item_number itm2,
                                     symbol_number next_sym)
 {
-  puts ("Shift-Reduce Conflict:");
-  print_state_item (&state_items[itm1], stdout);
-  print_state_item (&state_items[itm2], stdout);
-  printf ("On Symbol: %s\n", symbols[next_sym]->tag);
+  FILE *out = stderr;
+  fputs ("Shift-Reduce Conflict:\n", out);
+  print_state_item (&state_items[itm1], out);
+  print_state_item (&state_items[itm2], out);
+  fprintf (out, "On Symbol: %s\n", symbols[next_sym]->tag);
   counterexample_report (itm1, itm2, next_sym, true);
 }
 
@@ -1180,16 +1184,15 @@ void
 counterexample_report_reduce_reduce (state_item_number itm1, state_item_number itm2,
                                      bitset conflict_syms)
 {
-  puts ("Reduce-Reduce Conflict:");
-  print_state_item (&state_items[itm1], stdout);
-  print_state_item (&state_items[itm2], stdout);
-  fputs ("On Symbols: {", stdout);
+  FILE *out = stderr;
+  fputs ("Reduce-Reduce Conflict:\n", out);
+  print_state_item (&state_items[itm1], out);
+  print_state_item (&state_items[itm2], out);
+  fputs ("On Symbols: {", out);
   bitset_iterator biter;
   state_item_number sym;
   BITSET_FOR_EACH (biter, conflict_syms, sym, 0)
-    {
-      printf ("%s,", symbols[sym]->tag);
-    }
-  fputs ("}\n", stdout);
+    fprintf (out, "%s,", symbols[sym]->tag);
+  fputs ("}\n", out);
   counterexample_report (itm1, itm2, bitset_first (conflict_syms), false);
 }
diff --git a/src/derivation.c b/src/derivation.c
index b845ba89..a44627c5 100644
--- a/src/derivation.c
+++ b/src/derivation.c
@@ -68,21 +68,24 @@ derivation_print (const derivation *deriv, FILE *f)
 {
   if (deriv == &d_dot)
     {
-      fputs (" • ", f);
+      fputs (" •", f);
       return;
     }
   symbol *sym = symbols[deriv->sym];
   if (!deriv->children)
     {
-      fprintf (f, " %s ", sym->tag);
+      fprintf (f, " %s", sym->tag);
       return;
     }
   gl_list_iterator_t it = gl_list_iterator (deriv->children);
   derivation *child;
   fprintf (f, " %s ::=[", sym->tag);
   while (gl_list_iterator_next (&it, (const void **) &child, NULL))
-    derivation_print (child, f);
-  fputs ("] ", f);
+    {
+      derivation_print (child, f);
+      fputs (" ", f);
+    }
+  fputs ("]", f);
 }
 
 void
@@ -90,18 +93,23 @@ derivation_print_leaves (const derivation *deriv, FILE *f)
 {
   if (deriv == &d_dot)
     {
-      fputs (" • ", f);
+      fputs ("•", f);
       return;
     }
   if (!deriv->children)
     {
       symbol *sym = symbols[deriv->sym];
-      fprintf (f, " %s ", sym->tag);
+      fprintf (f, "%s", sym->tag);
       return;
     }
 
   gl_list_iterator_t it = gl_list_iterator (deriv->children);
+  const char *sep = "";
   derivation *child;
   while (gl_list_iterator_next (&it, (const void **) &child, NULL))
-    derivation_print_leaves (child, f);
+    {
+      fputs (sep, f);
+      sep = "  ";
+      derivation_print_leaves (child, f);
+    }
 }
diff --git a/tests/counterexample.at b/tests/counterexample.at
index a42ea013..65b1e361 100644
--- a/tests/counterexample.at
+++ b/tests/counterexample.at
@@ -23,6 +23,7 @@ AT_BANNER([[Counterexamples.]])
 ## --------------------- ##
 
 AT_SETUP([Unifying S/R])
+AT_KEYWORDS([cex])
 
 AT_DATA([[input.y]],
 [[%token A B C
@@ -34,8 +35,17 @@ x: B | B C;
 y: A | A B;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[Shift-Reduce Conflict:
+1:    3 a: A .
+1:    8 y: A . B
+On Symbol: B
+Example  A  •  B  C
+First  derivation  s ::=[ a ::=[ A  • ]  x ::=[ B  C ] ]
+Second derivation  s ::=[ y ::=[ A  •  B ]  c ::=[ C ] ]
+
+input.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
+input.y:4.4: warning: rule useless in parser due to conflicts [-Wother]
 ]])
 
 AT_CLEANUP
@@ -45,6 +55,7 @@ AT_CLEANUP
 ## ------------------- ##
 
 AT_SETUP([Deep Unifying S/R])
+AT_KEYWORDS([cex])
 
 AT_DATA([[input.y]],
 [[%token A B C
@@ -56,8 +67,17 @@ a: A | A a;
 bc: B bc C | B C;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[Shift-Reduce Conflict:
+1:    7 a: A .
+1:    5 b: . B
+On Symbol: B
+Example  A  •  B  C
+First  derivation  s ::=[ a ::=[ A  • ]  bc ::=[ B  C ] ]
+Second derivation  s ::=[ ac ::=[ A  ac ::=[ b ::=[ •  B ] ]  C ] ]
+
+input.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
+input.y:6.4: warning: rule useless in parser due to conflicts [-Wother]
 ]])
 
 AT_CLEANUP
@@ -67,6 +87,7 @@ AT_CLEANUP
 ## ------------------------------------ ##
 
 AT_SETUP([S/R Conflict with Nullable Symbols])
+AT_KEYWORDS([cex])
 
 AT_DATA([[input.y]],
 [[%token A B X Y
@@ -79,8 +100,26 @@ y: %empty | Y y;
 xby: B | X xby Y;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[Shift-Reduce Conflict:
+1:    4 x: . %empty
+1:    9 xby: . B
+On Symbol: B
+Example  A  •  B  y
+First  derivation  s ::=[ ax ::=[ A  x ::=[ • ] ]  by ::=[ B  y ] ]
+Second derivation  s ::=[ A  xby ::=[ •  B ] ]
+
+Shift-Reduce Conflict:
+5:    4 x: . %empty
+5:    9 xby: . B
+On Symbol: B
+First  Example A  X  •  B  y  $end
+First  derivation  $accept ::=[ s ::=[ ax ::=[ A  x ::=[ X  x ::=[ • ] ] ]  by ::=[ B  y ] ]  $end ]
+Second Example A  X  •  B  Y  $end
+Second derivation  $accept ::=[ s ::=[ A  xby ::=[ X  xby ::=[ •  B ]  Y ] ]  $end ]
+
+input.y: warning: 2 shift/reduce conflicts [-Wconflicts-sr]
+input.y:5.4-9: warning: rule useless in parser due to conflicts [-Wother]
 ]])
 
 AT_CLEANUP
@@ -90,6 +129,7 @@ AT_CLEANUP
 ## ---------------------------- ##
 
 AT_SETUP([Non-unifying Ambiguous S/R])
+AT_KEYWORDS([cex])
 
 AT_DATA([[input.y]],
 [[%token A B C D E
@@ -102,8 +142,18 @@ cd: C D;
 bc: B C;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[Shift-Reduce Conflict:
+2:    7 b: B .
+2:    9 bc: B . C
+On Symbol: C
+First  Example B  •  C  D  $end
+First  derivation  $accept ::=[ g ::=[ x ::=[ b ::=[ B  • ]  cd ::=[ C  D ] ] ]  $end ]
+Second Example B  •  C  $end
+Second derivation  $accept ::=[ g ::=[ x ::=[ bc ::=[ B  •  C ] ] ]  $end ]
+
+input.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
+input.y:6.4: warning: rule useless in parser due to conflicts [-Wother]
 ]])
 
 AT_CLEANUP
@@ -113,6 +163,7 @@ AT_CLEANUP
 ## ------------------------------ ##
 
 AT_SETUP([Non-unifying Unambiguous S/R])
+AT_KEYWORDS([cex])
 
 AT_DATA([[input.y]],
 [[%token A B
@@ -123,8 +174,17 @@ x: A;
 y: A A B;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[Shift-Reduce Conflict:
+1:    5 x: A .
+1:    6 y: A . A B
+On Symbol: A
+First  Example A  •  A  $end
+First  derivation  $accept ::=[ s ::=[ s ::=[ t ::=[ x ::=[ A  • ] ] ]  t ::=[ x ::=[ A ] ] ]  $end ]
+Second Example A  •  A  B  $end
+Second derivation  $accept ::=[ s ::=[ t ::=[ y ::=[ A  •  A  B ] ] ]  $end ]
+
+input.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
 ]])
 
 AT_CLEANUP
@@ -134,6 +194,7 @@ AT_CLEANUP
 ## ----------------------- ##
 
 AT_SETUP([S/R after first token])
+AT_KEYWORDS([cex])
 
 AT_DATA([[input.y]],
 [[%token A B X Y
@@ -149,8 +210,27 @@ xy: X Y;
 y: Y;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[Shift-Reduce Conflict:
+4:    3 r: b .
+4:    7 s: b . A xx y
+On Symbol: A
+Example  b  •  A  X  X  Y
+First  derivation  a ::=[ r ::=[ b  • ]  t ::=[ A  x ::=[ X ]  xy ::=[ X  Y ] ] ]
+Second derivation  a ::=[ s ::=[ b  •  xx ::=[ A  X  X ]  y ::=[ Y ] ] ]
+
+Shift-Reduce Conflict:
+10:    8 x: X .
+10:    9 xx: X . X
+On Symbol: X
+First  Example X  •  X
+First  derivation  t ::=[ x ::=[ X  • ]  X ]
+Second Example A  X  •  X
+Second derivation  a ::=[ t ::=[ A  xx ::=[ X  •  X ] ] ]
+
+input.y: warning: 2 shift/reduce conflicts [-Wconflicts-sr]
+input.y:4.4: warning: rule useless in parser due to conflicts [-Wother]
+input.y:8.4: warning: rule useless in parser due to conflicts [-Wother]
 ]])
 
 AT_CLEANUP
@@ -160,6 +240,7 @@ AT_CLEANUP
 ## ----------------------------- ##
 
 AT_SETUP([Unifying R/R counterexample])
+AT_KEYWORDS([cex])
 
 AT_DATA([[input.y]],
 [[%token A
@@ -168,8 +249,17 @@ a : A b ;
 b : A | b;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[Reduce-Reduce Conflict:
+4:    1 a: A b .
+4:    3 b: b .
+On Symbols: {$end,}
+Example  A  b  •
+First  derivation  a ::=[ A  b  • ]
+Second derivation  a ::=[ A  b ::=[ b  • ] ]
+
+input.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]
+input.y:4.9: warning: rule useless in parser due to conflicts [-Wother]
 ]])
 
 AT_CLEANUP
@@ -179,6 +269,7 @@ AT_CLEANUP
 ## ------------------------------- ##
 
 AT_SETUP([Non-unifying R/R lr1 conflict])
+AT_KEYWORDS([cex])
 
 AT_DATA([[input.y]],
 [[%token A B C D
@@ -188,8 +279,18 @@ a: D;
 b: D;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[Reduce-Reduce Conflict:
+2:    5 a: D .
+2:    6 b: D .
+On Symbols: {A,C,}
+First  Example D  •  A  $end
+First  derivation  $accept ::=[ s ::=[ a ::=[ D  • ]  A ]  $end ]
+Second Example B  D  •  A  $end
+Second derivation  $accept ::=[ s ::=[ B  b ::=[ D  • ]  A ]  $end ]
+
+input.y: warning: 2 reduce/reduce conflicts [-Wconflicts-rr]
+input.y:5.4: warning: rule useless in parser due to conflicts [-Wother]
 ]])
 
 AT_CLEANUP
@@ -199,6 +300,7 @@ AT_CLEANUP
 ## ------------------------------- ##
 
 AT_SETUP([Non-unifying R/R lr2 conflict])
+AT_KEYWORDS([cex])
 
 AT_DATA([[input.y]],
 [[%token H J K X
@@ -208,8 +310,19 @@ a: H i;
 i: X | i J K;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[Shift-Reduce Conflict:
+5:    2 a: H i .
+5:    4 i: i . J K
+On Symbol: J
+time limit exceeded: 6.000000
+First  Example H  i  •  J  $end
+First  derivation  $accept ::=[ s ::=[ a ::=[ H  i  • ]  J ]  $end ]
+Second Example H  i  •  J  K  $end
+Second derivation  $accept ::=[ a ::=[ H  i ::=[ i  •  J  K ] ]  $end ]
+
+input.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
+input.y:4.4-6: warning: rule useless in parser due to conflicts [-Wother]
 ]])
 
 AT_CLEANUP
@@ -222,6 +335,7 @@ AT_CLEANUP
 # graph search
 
 AT_SETUP([Cex Search Prepend])
+AT_KEYWORDS([cex])
 
 AT_DATA([[input.y]],
 [[%token N A B C D
@@ -232,8 +346,17 @@ a: A;
 b: A B C | A B D;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[Shift-Reduce Conflict:
+4:    7 a: A .
+4:    8 b: A . B C
+On Symbol: B
+Example  N  A  •  B  C
+First  derivation  s ::=[ n ::=[ N  a ::=[ A  • ]  B ]  C ]
+Second derivation  s ::=[ n ::=[ N  b ::=[ A  •  B  C ] ] ]
+
+input.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
+input.y:5.4: warning: rule useless in parser due to conflicts [-Wother]
 ]])
 
 AT_CLEANUP
@@ -246,6 +369,7 @@ AT_CLEANUP
 # precedence/associativity directives work.
 
 AT_SETUP([R/R cex with prec])
+AT_KEYWORDS([cex])
 
 AT_DATA([[input.y]],
 [[%left b
@@ -257,8 +381,24 @@ B : A b A;
 C : A c A;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[Reduce-Reduce Conflict:
+3:    3 A: B .
+3:    5 A: . %empty
+On Symbols: {b,c,}
+Example  B  •  b  A  A  c  A
+First  derivation  S ::=[ B ::=[ A ::=[ B  • ]  b  A ]  C ::=[ A  c  A ] ]
+Second derivation  S ::=[ B  C ::=[ A ::=[ B ::=[ A ::=[ • ]  b  A ] ]  c  A ] ]
+
+Reduce-Reduce Conflict:
+4:    4 A: C .
+4:    5 A: . %empty
+On Symbols: {b,c,}
+Example  C  •  c  A  A  b  A
+First  derivation  S ::=[ C ::=[ A ::=[ C  • ]  c  A ]  B ::=[ A  b  A ] ]
+Second derivation  S ::=[ C  B ::=[ A ::=[ C ::=[ A ::=[ • ]  c  A ] ]  b  A ] ]
+
+input.y: warning: 4 reduce/reduce conflicts [-Wconflicts-rr]
 ]])
 
 AT_CLEANUP
@@ -268,6 +408,7 @@ AT_CLEANUP
 ## ------------------- ##
 
 AT_SETUP([Null nonterminals])
+AT_KEYWORDS([cex])
 
 AT_DATA([[input.y]],
 [[%token A
@@ -278,9 +419,8 @@ c : ;
 d : a | c A | d;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
-]])
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[]])
 
 AT_CLEANUP
 
@@ -289,6 +429,7 @@ AT_CLEANUP
 ## --------------------------- ##
 
 AT_SETUP([Non-unifying Prefix Share])
+AT_KEYWORDS([cex])
 
 # Tests for a counterexample which should start its derivation
 # at a shared symbol rather than the start symbol.
@@ -301,8 +442,17 @@ a: H i J J
 i: %empty | i J;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[Shift-Reduce Conflict:
+7:    5 i: i J .
+7:    3 a: H i J . J
+On Symbol: J
+Example  H  i  J  •  J  J
+First  derivation  s ::=[ a ::=[ H  i ::=[ i  J  • ]  J  J ] ]
+Second derivation  s ::=[ a ::=[ H  i  J  •  J ]  J ]
+
+input.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
+input.y:5.13-15: warning: rule useless in parser due to conflicts [-Wother]
 ]])
 
 AT_CLEANUP
@@ -315,6 +465,7 @@ AT_CLEANUP
 # are derived correctly.
 
 AT_SETUP([Deep Null Unifying])
+AT_KEYWORDS([cex])
 
 AT_DATA([[input.y]],
 [[%token a d
@@ -326,8 +477,16 @@ C: %empty
 D: d;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[Shift-Reduce Conflict:
+3:    5 C: . %empty
+3:    6 D: . d
+On Symbol: d
+Example  a  A  •  d
+First  derivation  S ::=[ a  A  A ::=[ B ::=[ C ::=[ • ] ] ]  D ::=[ d ] ]
+Second derivation  S ::=[ a  A  D ::=[ •  d ] ]
+
+input.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
 ]])
 
 AT_CLEANUP
@@ -339,6 +498,7 @@ AT_CLEANUP
 # Tests that expand_to_conflict works with nullable sybols
 
 AT_SETUP([Deep Null Non-unifying])
+AT_KEYWORDS([cex])
 
 AT_DATA([[input.y]],
 [[%token a d e
@@ -350,8 +510,17 @@ C: %empty
 D: d;
 ]])
 
-AT_BISON_CHECK([-Wcounterexample input.y], 0, [],
-[[
+AT_BISON_CHECK([-Wcounterexample input.y], [], [],
+[[Shift-Reduce Conflict:
+3:    5 C: . %empty
+3:    6 D: . d
+On Symbol: d
+First  Example a  A  •  d  e  $end
+First  derivation  $accept ::=[ S ::=[ a  A  A ::=[ B ::=[ C ::=[ • ] ] ]  D ::=[ d ]  e ]  $end ]
+Second Example a  A  •  d  $end
+Second derivation  $accept ::=[ S ::=[ a  A  D ::=[ •  d ] ]  $end ]
+
+input.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
 ]])
 
-AT_CLEANUP
\ No newline at end of file
+AT_CLEANUP
diff --git a/tests/local.mk b/tests/local.mk
index fac8426f..098b1ddb 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -47,6 +47,7 @@ TESTSUITE_AT =                                \
   %D%/c++.at                                  \
   %D%/calc.at                                 \
   %D%/conflicts.at                            \
+  %D%/counterexample.at                       \
   %D%/cxx-type.at                             \
   %D%/diagnostics.at                          \
   %D%/existing.at                             \
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.