1 /* Find and resolve or report look-ahead conflicts for bison, 
   2    Copyright (C) 1984, 1989, 1992, 2000, 2001, 2002 
   3    Free Software Foundation, Inc. 
   5    This file is part of Bison, the GNU Compiler Compiler. 
   7    Bison is free software; you can redistribute it and/or modify it 
   8    under the terms of the GNU General Public License as published by 
   9    the Free Software Foundation; either version 2, or (at your option) 
  12    Bison is distributed in the hope that it will be useful, but 
  13    WITHOUT ANY WARRANTY; without even the implied warranty of 
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
  15    General Public License for more details. 
  17    You should have received a copy of the GNU General Public License 
  18    along with Bison; see the file COPYING.  If not, write to the Free 
  19    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 
  31 #include "conflicts.h" 
  35 /* -1 stands for not specified. */ 
  36 int expected_conflicts 
= -1; 
  37 static char *conflicts 
= NULL
; 
  38 struct obstack solved_conflicts_obstack
; 
  40 static bitset shiftset
; 
  41 static bitset lookaheadset
; 
  45 enum conflict_resolution_e
 
  55 /*----------------------------------------------------------------. 
  56 | Explain how an SR conflict between TOKEN and RULE was resolved: | 
  58 `----------------------------------------------------------------*/ 
  61 log_resolution (rule_t 
*rule
, int token
, 
  62                 enum conflict_resolution_e resolution
) 
  64   if (report_flag 
& report_solved_conflicts
) 
  66       /* The description of the resolution. */ 
  69         case shift_resolution
: 
  71           obstack_fgrow2 (&solved_conflicts_obstack
, 
  73     Conflict between rule %d and token %s resolved as shift"), 
  77         case reduce_resolution
: 
  78         case right_resolution
: 
  79           obstack_fgrow2 (&solved_conflicts_obstack
, 
  81     Conflict between rule %d and token %s resolved as reduce"), 
  85         case nonassoc_resolution
: 
  86           obstack_fgrow2 (&solved_conflicts_obstack
, 
  88     Conflict between rule %d and token %s resolved as an error"), 
  97         case shift_resolution
: 
  98           obstack_fgrow2 (&solved_conflicts_obstack
, 
 101                           symbols
[token
]->tag
); 
 104         case reduce_resolution
: 
 105           obstack_fgrow2 (&solved_conflicts_obstack
, 
 111         case left_resolution
: 
 112           obstack_fgrow1 (&solved_conflicts_obstack
, 
 114                           symbols
[token
]->tag
); 
 117         case right_resolution
: 
 118           obstack_fgrow1 (&solved_conflicts_obstack
, 
 120                           symbols
[token
]->tag
); 
 122         case nonassoc_resolution
: 
 123           obstack_fgrow1 (&solved_conflicts_obstack
, 
 125                           symbols
[token
]->tag
); 
 128       obstack_sgrow (&solved_conflicts_obstack
, ".\n"); 
 133 /*------------------------------------------------------------------. 
 134 | Turn off the shift recorded for the specified token in the        | 
 135 | specified state.  Used when we resolve a shift-reduce conflict in | 
 136 | favor of the reduction.                                           | 
 137 `------------------------------------------------------------------*/ 
 140 flush_shift (state_t 
*state
, int token
) 
 142   shifts 
*shiftp 
= state
->shifts
; 
 145   bitset_reset (lookaheadset
, token
); 
 146   for (i 
= 0; i 
< shiftp
->nshifts
; i
++) 
 147     if (!SHIFT_IS_DISABLED (shiftp
, i
) && SHIFT_SYMBOL (shiftp
, i
) == token
) 
 148       SHIFT_DISABLE (shiftp
, i
); 
 152 /*-------------------------------------------------------------------. 
 153 | Turn off the reduce recorded for the specified token for the       | 
 154 | specified lookahead.  Used when we resolve a shift-reduce conflict | 
 155 | in favor of the shift.                                             | 
 156 `-------------------------------------------------------------------*/ 
 159 flush_reduce (bitset lookaheads
, int token
) 
 161   bitset_reset (lookaheads
, token
); 
 165 /*------------------------------------------------------------------. 
 166 | Attempt to resolve shift-reduce conflict for one rule by means of | 
 167 | precedence declarations.  It has already been checked that the    | 
 168 | rule has a precedence.  A conflict is resolved by modifying the   | 
 169 | shift or reduce tables so that there is no longer a conflict.     | 
 171 | LOOKAHEAD is the number of the lookahead bitset to consider.      | 
 172 `------------------------------------------------------------------*/ 
 175 resolve_sr_conflict (state_t 
*state
, int lookahead
) 
 178   /* Find the rule to reduce by to get precedence of reduction.  */ 
 179   rule_t 
*redrule 
= state
->lookaheads_rule
[lookahead
]; 
 180   int redprec 
= redrule
->prec
->prec
; 
 181   bitset lookaheads 
= state
->lookaheads
[lookahead
]; 
 182   errs 
*errp 
= errs_new (ntokens 
+ 1); 
 185   for (i 
= 0; i 
< ntokens
; i
++) 
 186     if (bitset_test (lookaheads
, i
) 
 187         && bitset_test (lookaheadset
, i
) 
 190         /* Shift-reduce conflict occurs for token number i 
 191            and it has a precedence. 
 192            The precedence of shifting is that of token i.  */ 
 193         if (symbols
[i
]->prec 
< redprec
) 
 195             log_resolution (redrule
, i
, reduce_resolution
); 
 196             flush_shift (state
, i
); 
 198         else if (symbols
[i
]->prec 
> redprec
) 
 200             log_resolution (redrule
, i
, shift_resolution
); 
 201             flush_reduce (lookaheads
, i
); 
 204           /* Matching precedence levels. 
 205              For left association, keep only the reduction. 
 206              For right association, keep only the shift. 
 207              For nonassociation, keep neither.  */ 
 209           switch (symbols
[i
]->assoc
) 
 212               log_resolution (redrule
, i
, right_resolution
); 
 213               flush_reduce (lookaheads
, i
); 
 217               log_resolution (redrule
, i
, left_resolution
); 
 218               flush_shift (state
, i
); 
 222               log_resolution (redrule
, i
, nonassoc_resolution
); 
 223               flush_shift (state
, i
); 
 224               flush_reduce (lookaheads
, i
); 
 225               /* Record an explicit error for this token.  */ 
 226               errp
->errs
[errp
->nerrs
++] = i
; 
 230               assert (symbols
[i
]->assoc 
!= undef_assoc
); 
 235   /* Some tokens have been explicitly made errors.  Allocate a 
 236      permanent errs structure for this state, to record them.  */ 
 237   state
->errs 
= errs_dup (errp
); 
 240   if (obstack_object_size (&solved_conflicts_obstack
)) 
 242       obstack_1grow (&solved_conflicts_obstack
, '\0'); 
 243       state
->solved_conflicts 
= obstack_finish (&solved_conflicts_obstack
); 
 249 set_conflicts (state_t 
*state
) 
 254   if (state
->consistent
) 
 257   bitset_zero (lookaheadset
); 
 259   shiftp 
= state
->shifts
; 
 260   for (i 
= 0; i 
< shiftp
->nshifts 
&& SHIFT_IS_SHIFT (shiftp
, i
); i
++) 
 261     if (!SHIFT_IS_DISABLED (shiftp
, i
)) 
 262       bitset_set (lookaheadset
, SHIFT_SYMBOL (shiftp
, i
)); 
 264   /* Loop over all rules which require lookahead in this state.  First 
 265      check for shift-reduce conflict, and try to resolve using 
 267   for (i 
= 0; i 
< state
->nlookaheads
; ++i
) 
 268     if (state
->lookaheads_rule
[i
]->prec
 
 269         && state
->lookaheads_rule
[i
]->prec
->prec
 
 270         && !bitset_disjoint_p (state
->lookaheads
[i
], lookaheadset
)) 
 272         resolve_sr_conflict (state
, i
); 
 276   /* Loop over all rules which require lookahead in this state.  Check 
 277      for conflicts not resolved above.  */ 
 278   for (i 
= 0; i 
< state
->nlookaheads
; ++i
) 
 280       if (!bitset_disjoint_p (state
->lookaheads
[i
], lookaheadset
)) 
 281         conflicts
[state
->number
] = 1; 
 283       bitset_or (lookaheadset
, lookaheadset
, state
->lookaheads
[i
]); 
 288 conflicts_solve (void) 
 292   conflicts 
= XCALLOC (char, nstates
); 
 293   shiftset 
= bitset_create (ntokens
, BITSET_FIXED
); 
 294   lookaheadset 
= bitset_create (ntokens
, BITSET_FIXED
); 
 295   obstack_init (&solved_conflicts_obstack
); 
 297   for (i 
= 0; i 
< nstates
; i
++) 
 298     set_conflicts (states
[i
]); 
 302 /*---------------------------------------------. 
 303 | Count the number of shift/reduce conflicts.  | 
 304 `---------------------------------------------*/ 
 307 count_sr_conflicts (state_t 
*state
) 
 311   shifts 
*shiftp 
= state
->shifts
; 
 316   bitset_zero (lookaheadset
); 
 317   bitset_zero (shiftset
); 
 319   for (i 
= 0; i 
< shiftp
->nshifts 
&& SHIFT_IS_SHIFT (shiftp
, i
); i
++) 
 320     if (!SHIFT_IS_DISABLED (shiftp
, i
)) 
 321       bitset_set (shiftset
, SHIFT_SYMBOL (shiftp
, i
)); 
 323   for (i 
= 0; i 
< state
->nlookaheads
; ++i
) 
 324     bitset_or (lookaheadset
, lookaheadset
, state
->lookaheads
[i
]); 
 326   bitset_and (lookaheadset
, lookaheadset
, shiftset
); 
 328   src_count 
= bitset_count (lookaheadset
); 
 334 /*----------------------------------------------. 
 335 | Count the number of reduce/reduce conflicts.  | 
 336 `----------------------------------------------*/ 
 339 count_rr_conflicts (state_t 
*state
) 
 344   if (state
->nlookaheads 
< 2) 
 347   for (i 
= 0; i 
< ntokens
; i
++) 
 351       for (j 
= 0; j 
< state
->nlookaheads
; ++j
) 
 352         if (bitset_test (state
->lookaheads
[j
], i
)) 
 362 /*--------------------------------------------------------------. 
 363 | Return a human readable string which reports shift/reduce and | 
 364 | reduce/reduce conflict numbers (SRC_NUM, RRC_NUM).            | 
 365 `--------------------------------------------------------------*/ 
 368 conflict_report (int src_num
, int rrc_num
) 
 370   static char res
[4096]; 
 375       sprintf (cp
, ngettext ("%d shift/reduce conflict", 
 376                              "%d shift/reduce conflicts", src_num
), src_num
); 
 380   if (src_num 
> 0 && rrc_num 
> 0) 
 382       sprintf (cp
, " %s ", _("and")); 
 388       sprintf (cp
, ngettext ("%d reduce/reduce conflict", 
 389                              "%d reduce/reduce conflicts", rrc_num
), rrc_num
); 
 401 /*-----------------------------------------------------------. 
 402 | Output the detailed description of states with conflicts.  | 
 403 `-----------------------------------------------------------*/ 
 406 conflicts_output (FILE *out
) 
 408   bool printed_sth 
= FALSE
; 
 410   for (i 
= 0; i 
< nstates
; i
++) 
 413         fprintf (out
, _("State %d contains "), i
); 
 414         fputs (conflict_report (count_sr_conflicts (states
[i
]), 
 415                                 count_rr_conflicts (states
[i
])), out
); 
 423 /*------------------------------------------. 
 424 | Reporting the total number of conflicts.  | 
 425 `------------------------------------------*/ 
 428 conflicts_print (void) 
 432   /* Is the number of SR conflicts OK?  Either EXPECTED_CONFLICTS is 
 433      not set, and then we want 0 SR, or else it is specified, in which 
 434      case we want equality.  */ 
 440   /* Conflicts by state.  */ 
 441   for (i 
= 0; i 
< nstates
; i
++) 
 444         src_total 
+= count_sr_conflicts (states
[i
]); 
 445         rrc_total 
+= count_rr_conflicts (states
[i
]); 
 448   src_ok 
= src_total 
== (expected_conflicts 
== -1 ? 0 : expected_conflicts
); 
 450   /* If there are no RR conflicts, and as many SR conflicts as 
 451      expected, then there is nothing to report.  */ 
 452   if (!rrc_total 
&& src_ok
) 
 455   /* Report the total number of conflicts on STDERR.  */ 
 458       /* If invoked with `--yacc', use the output format specified by 
 460       fprintf (stderr
, _("conflicts: ")); 
 462         fprintf (stderr
, _(" %d shift/reduce"), src_total
); 
 463       if (src_total 
> 0 && rrc_total 
> 0) 
 464         fprintf (stderr
, ","); 
 466         fprintf (stderr
, _(" %d reduce/reduce"), rrc_total
); 
 471       fprintf (stderr
, _("%s contains "), infile
); 
 472       fputs (conflict_report (src_total
, rrc_total
), stderr
); 
 475   if (expected_conflicts 
!= -1 && !src_ok
) 
 477       complain_message_count
++; 
 478       fprintf (stderr
, ngettext ("expected %d shift/reduce conflict\n", 
 479                                  "expected %d shift/reduce conflicts\n", 
 487 conflicts_free (void) 
 490   bitset_free (shiftset
); 
 491   bitset_free (lookaheadset
); 
 492   obstack_free (&solved_conflicts_obstack
, NULL
);