]> git.saurik.com Git - bison.git/blame - src/conflicts.c
Copy BYacc's nice way to report the grammar.
[bison.git] / src / conflicts.c
CommitLineData
08089d5d 1/* Find and resolve or report look-ahead conflicts for bison,
03b31c0c
AD
2 Copyright (C) 1984, 1989, 1992, 2000, 2001, 2002
3 Free Software Foundation, Inc.
08089d5d 4
ceed8467 5 This file is part of Bison, the GNU Compiler Compiler.
08089d5d 6
ceed8467
AD
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)
10 any later version.
08089d5d 11
ceed8467
AD
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.
08089d5d 16
ceed8467
AD
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
20 02111-1307, USA. */
08089d5d 21
08089d5d 22#include "system.h"
602bbf31 23#include "bitset.h"
7da99ede 24#include "complain.h"
ceed8467 25#include "getargs.h"
0e78e603 26#include "symtab.h"
08089d5d
DM
27#include "files.h"
28#include "gram.h"
29#include "state.h"
720d742f 30#include "lalr.h"
0619caf0 31#include "conflicts.h"
b2ca4022
AD
32#include "reader.h"
33#include "LR0.h"
d2729d44 34
7da99ede
AD
35/* -1 stands for not specified. */
36int expected_conflicts = -1;
342b8b6e 37static char *conflicts = NULL;
b408954b 38struct obstack solved_conflicts_obstack;
08089d5d 39
b86796bf
AD
40static bitset shiftset;
41static bitset lookaheadset;
b408954b 42
c29240e7 43\f
08089d5d 44
b408954b
AD
45enum conflict_resolution_e
46 {
47 shift_resolution,
48 reduce_resolution,
49 left_resolution,
50 right_resolution,
86eff183 51 nonassoc_resolution
b408954b
AD
52 };
53
54
c29240e7 55static inline void
b408954b
AD
56log_resolution (int lookahead, int token,
57 enum conflict_resolution_e resolution)
08089d5d 58{
b408954b
AD
59 if (report_flag & report_solved_conflicts)
60 {
61 /* The description of the resolution. */
62 switch (resolution)
63 {
64 case shift_resolution:
65 case left_resolution:
66 obstack_fgrow2 (&solved_conflicts_obstack,
67 _("\
68 Conflict between rule %d and token %s resolved as shift"),
69 LArule[lookahead]->number,
70 symbols[token]->tag);
71 break;
72 case reduce_resolution:
73 case right_resolution:
74 obstack_fgrow2 (&solved_conflicts_obstack,
75 _("\
76 Conflict between rule %d and token %s resolved as reduce"),
77 LArule[lookahead]->number,
78 symbols[token]->tag);
79 break;
80 case nonassoc_resolution:
81 obstack_fgrow2 (&solved_conflicts_obstack,
82 _("\
83 Conflict between rule %d and token %s resolved as an error"),
84 LArule[lookahead]->number,
85 symbols[token]->tag);
86 break;
87 }
88
89 /* The reason. */
90 switch (resolution)
91 {
92 case shift_resolution:
93 obstack_fgrow2 (&solved_conflicts_obstack,
94 " (%s < %s)",
95 LArule[lookahead]->prec->tag,
96 symbols[token]->tag);
97 break;
98
99 case reduce_resolution:
100 obstack_fgrow2 (&solved_conflicts_obstack,
101 " (%s < %s)",
102 symbols[token]->tag,
103 LArule[lookahead]->prec->tag);
104 break;
105
106 case left_resolution:
4a713ec2 107 obstack_fgrow1 (&solved_conflicts_obstack,
b408954b
AD
108 " (%%left %s)",
109 symbols[token]->tag);
110 break;
111
112 case right_resolution:
113 obstack_fgrow1 (&solved_conflicts_obstack,
114 " (%%right %s)",
115 symbols[token]->tag);
116 break;
117 case nonassoc_resolution:
118 obstack_fgrow1 (&solved_conflicts_obstack,
119 " (%%nonassoc %s)",
120 symbols[token]->tag);
121 break;
122 }
123 obstack_sgrow (&solved_conflicts_obstack, ".\n");
124 }
08089d5d
DM
125}
126
127
c29240e7
AD
128/*------------------------------------------------------------------.
129| Turn off the shift recorded for the specified token in the |
130| specified state. Used when we resolve a shift-reduce conflict in |
131| favor of the reduction. |
132`------------------------------------------------------------------*/
133
4a120d45 134static void
065fbd27 135flush_shift (state_t *state, int token)
08089d5d 136{
065fbd27 137 shifts *shiftp = state->shifts;
9f136c07 138 int i;
c29240e7 139
b86796bf 140 bitset_reset (lookaheadset, token);
d954473d
AD
141 for (i = 0; i < shiftp->nshifts; i++)
142 if (!SHIFT_IS_DISABLED (shiftp, i) && SHIFT_SYMBOL (shiftp, i) == token)
143 SHIFT_DISABLE (shiftp, i);
08089d5d
DM
144}
145
146
709ae8c6
AD
147/*-------------------------------------------------------------------.
148| Turn off the reduce recorded for the specified token for the |
149| specified lookahead. Used when we resolve a shift-reduce conflict |
150| in favor of the shift. |
151`-------------------------------------------------------------------*/
152
153static void
154flush_reduce (int lookahead, int token)
155{
602bbf31 156 bitset_reset (LA[lookahead], token);
709ae8c6
AD
157}
158
159
c29240e7
AD
160/*------------------------------------------------------------------.
161| Attempt to resolve shift-reduce conflict for one rule by means of |
162| precedence declarations. It has already been checked that the |
163| rule has a precedence. A conflict is resolved by modifying the |
164| shift or reduce tables so that there is no longer a conflict. |
165`------------------------------------------------------------------*/
08089d5d 166
4a120d45 167static void
065fbd27 168resolve_sr_conflict (state_t *state, int lookahead)
08089d5d 169{
c29240e7 170 int i;
9f136c07 171 /* find the rule to reduce by to get precedence of reduction */
03b31c0c 172 int redprec = LArule[lookahead]->prec->prec;
2cec70b9
AD
173 errs *errp = errs_new (ntokens + 1);
174 errp->nerrs = 0;
08089d5d 175
08089d5d 176 for (i = 0; i < ntokens; i++)
602bbf31 177 if (bitset_test (LA[lookahead], i)
b86796bf 178 && bitset_test (lookaheadset, i)
0e78e603 179 && symbols[i]->prec)
92b16366 180 {
709ae8c6
AD
181 /* Shift-reduce conflict occurs for token number i
182 and it has a precedence.
183 The precedence of shifting is that of token i. */
0e78e603 184 if (symbols[i]->prec < redprec)
92b16366 185 {
b408954b 186 log_resolution (lookahead, i, reduce_resolution);
92b16366
AD
187 flush_shift (state, i);
188 }
0e78e603 189 else if (symbols[i]->prec > redprec)
92b16366 190 {
b408954b 191 log_resolution (lookahead, i, shift_resolution);
709ae8c6 192 flush_reduce (lookahead, i);
92b16366
AD
193 }
194 else
709ae8c6
AD
195 /* Matching precedence levels.
196 For left association, keep only the reduction.
197 For right association, keep only the shift.
198 For nonassociation, keep neither. */
199
5a670b1e 200 switch (symbols[i]->assoc)
709ae8c6
AD
201 {
202 case right_assoc:
b408954b 203 log_resolution (lookahead, i, right_resolution);
709ae8c6
AD
204 flush_reduce (lookahead, i);
205 break;
206
207 case left_assoc:
b408954b 208 log_resolution (lookahead, i, left_resolution);
709ae8c6
AD
209 flush_shift (state, i);
210 break;
211
212 case non_assoc:
b408954b 213 log_resolution (lookahead, i, nonassoc_resolution);
709ae8c6
AD
214 flush_shift (state, i);
215 flush_reduce (lookahead, i);
216 /* Record an explicit error for this token. */
2cec70b9 217 errp->errs[errp->nerrs++] = i;
709ae8c6 218 break;
e9955c83
AD
219
220 case undef_assoc:
221 assert (symbols[i]->assoc != undef_assoc);
222 break;
709ae8c6 223 }
92b16366
AD
224 }
225
92b16366
AD
226 /* Some tokens have been explicitly made errors. Allocate a
227 permanent errs structure for this state, to record them. */
2cec70b9 228 state->errs = errs_dup (errp);
c29240e7 229 free (errp);
b408954b
AD
230
231 if (obstack_object_size (&solved_conflicts_obstack))
232 {
233 obstack_1grow (&solved_conflicts_obstack, '\0');
234 state->solved_conflicts = obstack_finish (&solved_conflicts_obstack);
235 }
08089d5d
DM
236}
237
238
4a120d45 239static void
065fbd27 240set_conflicts (state_t *state)
08089d5d 241{
914feea9 242 int i;
c29240e7 243 shifts *shiftp;
c29240e7 244
065fbd27 245 if (state->consistent)
c29240e7 246 return;
08089d5d 247
b86796bf 248 bitset_zero (lookaheadset);
08089d5d 249
065fbd27 250 shiftp = state->shifts;
d954473d
AD
251 for (i = 0; i < shiftp->nshifts && SHIFT_IS_SHIFT (shiftp, i); i++)
252 if (!SHIFT_IS_DISABLED (shiftp, i))
b86796bf 253 bitset_set (lookaheadset, SHIFT_SYMBOL (shiftp, i));
08089d5d 254
c29240e7
AD
255 /* Loop over all rules which require lookahead in this state. First
256 check for shift-reduce conflict, and try to resolve using
257 precedence */
065fbd27 258 for (i = 0; i < state->nlookaheads; ++i)
b0299a2e 259 if (LArule[state->lookaheadsp + i]->prec
03b31c0c 260 && LArule[state->lookaheadsp + i]->prec->prec
914feea9
AD
261 && !bitset_disjoint_p (LA[state->lookaheadsp + i], lookaheadset))
262 {
263 resolve_sr_conflict (state, state->lookaheadsp + i);
264 break;
265 }
08089d5d 266
c29240e7
AD
267 /* Loop over all rules which require lookahead in this state. Check
268 for conflicts not resolved above. */
065fbd27 269 for (i = 0; i < state->nlookaheads; ++i)
08089d5d 270 {
914feea9
AD
271 if (!bitset_disjoint_p (LA[state->lookaheadsp + i], lookaheadset))
272 conflicts[state->number] = 1;
08089d5d 273
f9abaa2c 274 bitset_or (lookaheadset, lookaheadset, LA[state->lookaheadsp + i]);
c29240e7
AD
275 }
276}
08089d5d
DM
277
278void
b408954b 279conflicts_solve (void)
08089d5d 280{
602bbf31 281 size_t i;
08089d5d 282
d7913476 283 conflicts = XCALLOC (char, nstates);
b86796bf 284 shiftset = bitset_create (ntokens, BITSET_FIXED);
b86796bf 285 lookaheadset = bitset_create (ntokens, BITSET_FIXED);
b408954b 286 obstack_init (&solved_conflicts_obstack);
08089d5d 287
c29240e7 288 for (i = 0; i < nstates; i++)
29e88316 289 set_conflicts (states[i]);
08089d5d
DM
290}
291
292
c29240e7
AD
293/*---------------------------------------------.
294| Count the number of shift/reduce conflicts. |
295`---------------------------------------------*/
296
0df87bb6 297static int
065fbd27 298count_sr_conflicts (state_t *state)
08089d5d 299{
f9abaa2c 300 int i;
0df87bb6 301 int src_count = 0;
065fbd27 302 shifts *shiftp = state->shifts;
08089d5d 303
c29240e7 304 if (!shiftp)
0df87bb6 305 return 0;
08089d5d 306
b86796bf
AD
307 bitset_zero (lookaheadset);
308 bitset_zero (shiftset);
08089d5d 309
52afa962 310 for (i = 0; i < shiftp->nshifts && SHIFT_IS_SHIFT (shiftp, i); i++)
9839bbe5 311 if (!SHIFT_IS_DISABLED (shiftp, i))
b86796bf 312 bitset_set (shiftset, SHIFT_SYMBOL (shiftp, i));
08089d5d 313
065fbd27 314 for (i = 0; i < state->nlookaheads; ++i)
f9abaa2c 315 bitset_or (lookaheadset, lookaheadset, LA[state->lookaheadsp + i]);
08089d5d 316
b86796bf 317 bitset_and (lookaheadset, lookaheadset, shiftset);
08089d5d 318
914feea9 319 src_count = bitset_count (lookaheadset);
0df87bb6
AD
320
321 return src_count;
08089d5d
DM
322}
323
324
c29240e7
AD
325/*----------------------------------------------.
326| Count the number of reduce/reduce conflicts. |
327`----------------------------------------------*/
328
0df87bb6 329static int
065fbd27 330count_rr_conflicts (state_t *state)
08089d5d 331{
c29240e7 332 int i;
0df87bb6 333 int rrc_count = 0;
08089d5d 334
065fbd27 335 if (state->nlookaheads < 2)
0df87bb6 336 return 0;
08089d5d 337
08089d5d
DM
338 for (i = 0; i < ntokens; i++)
339 {
0df87bb6
AD
340 int count = 0;
341 int j;
065fbd27 342 for (j = 0; j < state->nlookaheads; ++j)
602bbf31 343 if (bitset_test (LA[state->lookaheadsp + j], i))
52afa962 344 count++;
08089d5d 345
c29240e7
AD
346 if (count >= 2)
347 rrc_count++;
08089d5d 348 }
0df87bb6
AD
349
350 return rrc_count;
08089d5d
DM
351}
352
ff4423cc
AD
353/*--------------------------------------------------------------.
354| Return a human readable string which reports shift/reduce and |
355| reduce/reduce conflict numbers (SRC_NUM, RRC_NUM). |
356`--------------------------------------------------------------*/
c29240e7 357
ff4423cc
AD
358static const char *
359conflict_report (int src_num, int rrc_num)
c29240e7 360{
ff4423cc
AD
361 static char res[4096];
362 char *cp = res;
363
7da99ede 364 if (src_num >= 1)
22c821f3 365 {
7da99ede
AD
366 sprintf (cp, ngettext ("%d shift/reduce conflict",
367 "%d shift/reduce conflicts", src_num), src_num);
22c821f3
AD
368 cp += strlen (cp);
369 }
c29240e7 370
0619caf0 371 if (src_num > 0 && rrc_num > 0)
22c821f3 372 {
7da99ede 373 sprintf (cp, " %s ", _("and"));
22c821f3
AD
374 cp += strlen (cp);
375 }
c29240e7 376
7da99ede 377 if (rrc_num >= 1)
22c821f3 378 {
7da99ede
AD
379 sprintf (cp, ngettext ("%d reduce/reduce conflict",
380 "%d reduce/reduce conflicts", rrc_num), rrc_num);
22c821f3
AD
381 cp += strlen (cp);
382 }
ff4423cc
AD
383
384 *cp++ = '.';
385 *cp++ = '\n';
386 *cp++ = '\0';
c29240e7 387
ff4423cc 388 return res;
c29240e7
AD
389}
390
391
0df87bb6
AD
392/*-----------------------------------------------------------.
393| Output the detailed description of states with conflicts. |
394`-----------------------------------------------------------*/
c29240e7
AD
395
396void
0df87bb6 397conflicts_output (FILE *out)
c29240e7 398{
d2d1b42b 399 bool printed_sth = FALSE;
602bbf31 400 size_t i;
0df87bb6
AD
401 for (i = 0; i < nstates; i++)
402 if (conflicts[i])
403 {
7da99ede 404 fprintf (out, _("State %d contains "), i);
29e88316
AD
405 fputs (conflict_report (count_sr_conflicts (states[i]),
406 count_rr_conflicts (states[i])), out);
d2d1b42b 407 printed_sth = TRUE;
0df87bb6 408 }
d2d1b42b
AD
409 if (printed_sth)
410 fputs ("\n\n", out);
0df87bb6 411}
c29240e7 412
c29240e7 413
0df87bb6
AD
414/*------------------------------------------.
415| Reporting the total number of conflicts. |
416`------------------------------------------*/
0619caf0 417
0df87bb6
AD
418void
419conflicts_print (void)
420{
602bbf31 421 size_t i;
0df87bb6 422
a034c8b8
AD
423 /* Is the number of SR conflicts OK? Either EXPECTED_CONFLICTS is
424 not set, and then we want 0 SR, or else it is specified, in which
425 case we want equality. */
426 int src_ok = 0;
427
0df87bb6
AD
428 int src_total = 0;
429 int rrc_total = 0;
430
431 /* Conflicts by state. */
432 for (i = 0; i < nstates; i++)
433 if (conflicts[i])
434 {
29e88316
AD
435 src_total += count_sr_conflicts (states[i]);
436 rrc_total += count_rr_conflicts (states[i]);
0df87bb6 437 }
c29240e7 438
a034c8b8
AD
439 src_ok = src_total == (expected_conflicts == -1 ? 0 : expected_conflicts);
440
441 /* If there are no RR conflicts, and as many SR conflicts as
442 expected, then there is nothing to report. */
443 if (!rrc_total && src_ok)
444 return;
445
0619caf0 446 /* Report the total number of conflicts on STDERR. */
a034c8b8 447 if (yacc_flag)
09b503c8 448 {
a034c8b8
AD
449 /* If invoked with `--yacc', use the output format specified by
450 POSIX. */
451 fprintf (stderr, _("conflicts: "));
452 if (src_total > 0)
453 fprintf (stderr, _(" %d shift/reduce"), src_total);
454 if (src_total > 0 && rrc_total > 0)
455 fprintf (stderr, ",");
456 if (rrc_total > 0)
457 fprintf (stderr, _(" %d reduce/reduce"), rrc_total);
458 putc ('\n', stderr);
459 }
460 else
461 {
462 fprintf (stderr, _("%s contains "), infile);
463 fputs (conflict_report (src_total, rrc_total), stderr);
09b503c8 464 }
7da99ede 465
a034c8b8 466 if (expected_conflicts != -1 && !src_ok)
7da99ede
AD
467 {
468 complain_message_count++;
81e895c0
AD
469 fprintf (stderr, ngettext ("expected %d shift/reduce conflict\n",
470 "expected %d shift/reduce conflicts\n",
7da99ede
AD
471 expected_conflicts),
472 expected_conflicts);
473 }
c29240e7
AD
474}
475
476
08089d5d 477void
b408954b 478conflicts_free (void)
08089d5d 479{
d7913476 480 XFREE (conflicts);
b86796bf
AD
481 bitset_free (shiftset);
482 bitset_free (lookaheadset);
b408954b 483 obstack_free (&solved_conflicts_obstack, NULL);
08089d5d 484}