📄 conflicts.c
字号:
/* Find and resolve or report look-ahead conflicts for bison, Copyright (C) 1984, 1989, 1992 Free Software Foundation, Inc.This file is part of Bison, the GNU Compiler Compiler.Bison is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.Bison is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with Bison; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include <stdio.h>#include "system.h"#include "machine.h"#include "new.h"#include "files.h"#include "gram.h"#include "state.h"extern char **tags;extern int tokensetsize;extern char *consistent;extern short *accessing_symbol;extern shifts **shift_table;extern unsigned *LA;extern short *LAruleno;extern short *lookaheads;extern int verboseflag;void set_conflicts();void resolve_sr_conflict();void flush_shift();void log_resolution();void total_conflicts();void count_sr_conflicts();void count_rr_conflicts();char any_conflicts;char *conflicts;errs **err_table;int expected_conflicts;static unsigned *shiftset;static unsigned *lookaheadset;static int src_total;static int rrc_total;static int src_count;static int rrc_count;voidinitialize_conflicts(){ register int i;/* register errs *sp; JF unused */ conflicts = NEW2(nstates, char); shiftset = NEW2(tokensetsize, unsigned); lookaheadset = NEW2(tokensetsize, unsigned); err_table = NEW2(nstates, errs *); any_conflicts = 0; for (i = 0; i < nstates; i++) set_conflicts(i);}voidset_conflicts(state)int state;{ register int i; register int k; register shifts *shiftp; register unsigned *fp2; register unsigned *fp3; register unsigned *fp4; register unsigned *fp1; register int symbol; if (consistent[state]) return; for (i = 0; i < tokensetsize; i++) lookaheadset[i] = 0; shiftp = shift_table[state]; if (shiftp) { k = shiftp->nshifts; for (i = 0; i < k; i++) { symbol = accessing_symbol[shiftp->shifts[i]]; if (ISVAR(symbol)) break; SETBIT(lookaheadset, symbol); } } k = lookaheads[state + 1]; fp4 = lookaheadset + tokensetsize; /* loop over all rules which require lookahead in this state */ /* first check for shift-reduce conflict, and try to resolve using precedence */ for (i = lookaheads[state]; i < k; i++) if (rprec[LAruleno[i]]) { fp1 = LA + i * tokensetsize; fp2 = fp1; fp3 = lookaheadset; while (fp3 < fp4) { if (*fp2++ & *fp3++) { resolve_sr_conflict(state, i); break; } } } /* loop over all rules which require lookahead in this state */ /* Check for conflicts not resolved above. */ for (i = lookaheads[state]; i < k; i++) { fp1 = LA + i * tokensetsize; fp2 = fp1; fp3 = lookaheadset; while (fp3 < fp4) { if (*fp2++ & *fp3++) { conflicts[state] = 1; any_conflicts = 1; } } fp2 = fp1; fp3 = lookaheadset; while (fp3 < fp4) *fp3++ |= *fp2++; }}/* Attempt to resolve shift-reduce conflict for one ruleby means of precedence declarations.It has already been checked that the rule has a precedence.A conflict is resolved by modifying the shift or reduce tablesso that there is no longer a conflict. */voidresolve_sr_conflict(state, lookaheadnum)int state;int lookaheadnum;{ register int i; register int mask; register unsigned *fp1; register unsigned *fp2; register int redprec; errs *errp = (errs *) xmalloc (sizeof(errs) + ntokens * sizeof(short)); short *errtokens = errp->errs; /* find the rule to reduce by to get precedence of reduction */ redprec = rprec[LAruleno[lookaheadnum]]; mask = 1; fp1 = LA + lookaheadnum * tokensetsize; fp2 = lookaheadset; for (i = 0; i < ntokens; i++) { if ((mask & *fp2 & *fp1) && sprec[i]) /* Shift-reduce conflict occurs for token number i and it has a precedence. The precedence of shifting is that of token i. */ { if (sprec[i] < redprec) { if (verboseflag) log_resolution(state, lookaheadnum, i, "reduce"); *fp2 &= ~mask; /* flush the shift for this token */ flush_shift(state, i); } else if (sprec[i] > redprec) { if (verboseflag) log_resolution(state, lookaheadnum, i, "shift"); *fp1 &= ~mask; /* flush the reduce for this token */ } else { /* Matching precedence levels. For left association, keep only the reduction. For right association, keep only the shift. For nonassociation, keep neither. */ switch (sassoc[i]) { case RIGHT_ASSOC: if (verboseflag) log_resolution(state, lookaheadnum, i, "shift"); break; case LEFT_ASSOC: if (verboseflag) log_resolution(state, lookaheadnum, i, "reduce"); break; case NON_ASSOC: if (verboseflag) log_resolution(state, lookaheadnum, i, "an error"); break; } if (sassoc[i] != RIGHT_ASSOC) { *fp2 &= ~mask; /* flush the shift for this token */ flush_shift(state, i); } if (sassoc[i] != LEFT_ASSOC) { *fp1 &= ~mask; /* flush the reduce for this token */ } if (sassoc[i] == NON_ASSOC) { /* Record an explicit error for this token. */ *errtokens++ = i; } } } mask <<= 1; if (mask == 0) { mask = 1; fp2++; fp1++; } } errp->nerrs = errtokens - errp->errs; if (errp->nerrs) { /* Some tokens have been explicitly made errors. Allocate a permanent errs structure for this state, to record them. */ i = (char *) errtokens - (char *) errp; err_table[state] = (errs *) xmalloc ((unsigned int)i); bcopy (errp, err_table[state], i); } else err_table[state] = 0; free(errp);}/* turn off the shift recorded for the specified token in the specified state.Used when we resolve a shift-reduce conflict in favor of the reduction. */voidflush_shift(state, token)int state;int token;{ register shifts *shiftp; register int k, i;/* register unsigned symbol; JF unused */ shiftp = shift_table[state]; if (shiftp) { k = shiftp->nshifts; for (i = 0; i < k; i++) { if (shiftp->shifts[i] && token == accessing_symbol[shiftp->shifts[i]]) (shiftp->shifts[i]) = 0; } }}voidlog_resolution(state, LAno, token, resolution)int state, LAno, token;char *resolution;{ fprintf(foutput, "Conflict in state %d between rule %d and token %s resolved as %s.\n", state, LAruleno[LAno], tags[token], resolution);}voidconflict_log(){ register int i; src_total = 0; rrc_total = 0; for (i = 0; i < nstates; i++) { if (conflicts[i]) { count_sr_conflicts(i); count_rr_conflicts(i); src_total += src_count; rrc_total += rrc_count; } } total_conflicts();} voidverbose_conflict_log(){ register int i; src_total = 0; rrc_total = 0; for (i = 0; i < nstates; i++) { if (conflicts[i]) { count_sr_conflicts(i); count_rr_conflicts(i); src_total += src_count; rrc_total += rrc_count; fprintf(foutput, "State %d contains", i); if (src_count == 1) fprintf(foutput, " 1 shift/reduce conflict"); else if (src_count > 1) fprintf(foutput, " %d shift/reduce conflicts", src_count); if (src_count > 0 && rrc_count > 0) fprintf(foutput, " and"); if (rrc_count == 1) fprintf(foutput, " 1 reduce/reduce conflict"); else if (rrc_count > 1) fprintf(foutput, " %d reduce/reduce conflicts", rrc_count); putc('.', foutput); putc('\n', foutput); } } total_conflicts();}voidtotal_conflicts(){ extern int fixed_outfiles; if (src_total == expected_conflicts && rrc_total == 0) return; if (fixed_outfiles) { /* If invoked under the name `yacc', use the output format specified by POSIX. */ fprintf(stderr, "conflicts: "); if (src_total > 0) fprintf(stderr, " %d shift/reduce", src_total); if (src_total > 0 && rrc_total > 0) fprintf(stderr, ","); if (rrc_total > 0) fprintf(stderr, " %d reduce/reduce", rrc_total); putc('\n', stderr); } else { fprintf(stderr, "%s contains", infile); if (src_total == 1) fprintf(stderr, " 1 shift/reduce conflict"); else if (src_total > 1) fprintf(stderr, " %d shift/reduce conflicts", src_total); if (src_total > 0 && rrc_total > 0) fprintf(stderr, " and"); if (rrc_total == 1) fprintf(stderr, " 1 reduce/reduce conflict"); else if (rrc_total > 1) fprintf(stderr, " %d reduce/reduce conflicts", rrc_total); putc('.', stderr); putc('\n', stderr); }}voidcount_sr_conflicts(state)int state;{ register int i; register int k; register int mask; register shifts *shiftp; register unsigned *fp1; register unsigned *fp2; register unsigned *fp3; register int symbol; src_count = 0; shiftp = shift_table[state]; if (!shiftp) return; for (i = 0; i < tokensetsize; i++) { shiftset[i] = 0; lookaheadset[i] = 0; } k = shiftp->nshifts; for (i = 0; i < k; i++) { if (! shiftp->shifts[i]) continue; symbol = accessing_symbol[shiftp->shifts[i]]; if (ISVAR(symbol)) break; SETBIT(shiftset, symbol); } k = lookaheads[state + 1]; fp3 = lookaheadset + tokensetsize; for (i = lookaheads[state]; i < k; i++) { fp1 = LA + i * tokensetsize; fp2 = lookaheadset; while (fp2 < fp3) *fp2++ |= *fp1++; } fp1 = shiftset; fp2 = lookaheadset; while (fp2 < fp3) *fp2++ &= *fp1++; mask = 1; fp2 = lookaheadset; for (i = 0; i < ntokens; i++) { if (mask & *fp2) src_count++; mask <<= 1; if (mask == 0) { mask = 1; fp2++; } }}voidcount_rr_conflicts(state)int state;{ register int i; register int j; register int count; register unsigned mask; register unsigned *baseword; register unsigned *wordp; register int m; register int n; rrc_count = 0; m = lookaheads[state]; n = lookaheads[state + 1]; if (n - m < 2) return; mask = 1; baseword = LA + m * tokensetsize; for (i = 0; i < ntokens; i++) { wordp = baseword; count = 0; for (j = m; j < n; j++) { if (mask & *wordp) count++; wordp += tokensetsize; } if (count >= 2) rrc_count++; mask <<= 1; if (mask == 0) { mask = 1; baseword++; } }}voidprint_reductions(state)int state;{ register int i; register int j; register int k; register unsigned *fp1; register unsigned *fp2; register unsigned *fp3; register unsigned *fp4; register int rule; register int symbol; register unsigned mask; register int m; register int n; register int default_LA; register int default_rule; register int cmax; register int count; register shifts *shiftp; register errs *errp; int nodefault = 0; for (i = 0; i < tokensetsize; i++) shiftset[i] = 0; shiftp = shift_table[state]; if (shiftp) { k = shiftp->nshifts; for (i = 0; i < k; i++) { if (! shiftp->shifts[i]) continue; symbol = accessing_symbol[shiftp->shifts[i]]; if (ISVAR(symbol)) break; /* if this state has a shift for the error token, don't use a default rule. */ if (symbol == error_token_number) nodefault = 1; SETBIT(shiftset, symbol); } } errp = err_table[state]; if (errp) { k = errp->nerrs; for (i = 0; i < k; i++) { if (! errp->errs[i]) continue; symbol = errp->errs[i]; SETBIT(shiftset, symbol); } } m = lookaheads[state]; n = lookaheads[state + 1]; if (n - m == 1 && ! nodefault) { default_rule = LAruleno[m]; fp1 = LA + m * tokensetsize; fp2 = shiftset; fp3 = lookaheadset; fp4 = lookaheadset + tokensetsize; while (fp3 < fp4) *fp3++ = *fp1++ & *fp2++; mask = 1; fp3 = lookaheadset; for (i = 0; i < ntokens; i++) { if (mask & *fp3) fprintf(foutput, " %-4s\t[reduce using rule %d (%s)]\n", tags[i], default_rule, tags[rlhs[default_rule]]); mask <<= 1; if (mask == 0) { mask = 1; fp3++; } } fprintf(foutput, " $default\treduce using rule %d (%s)\n\n", default_rule, tags[rlhs[default_rule]]); } else if (n - m >= 1) { cmax = 0; default_LA = -1; fp4 = lookaheadset + tokensetsize; if (! nodefault) for (i = m; i < n; i++) { fp1 = LA + i * tokensetsize; fp2 = shiftset; fp3 = lookaheadset; while (fp3 < fp4) *fp3++ = *fp1++ & (~(*fp2++)); count = 0; mask = 1; fp3 = lookaheadset; for (j = 0; j < ntokens; j++) { if (mask & *fp3) count++; mask <<= 1; if (mask == 0) { mask = 1; fp3++; } } if (count > cmax) { cmax = count; default_LA = i; default_rule = LAruleno[i]; } fp2 = shiftset; fp3 = lookaheadset; while (fp3 < fp4) *fp2++ |= *fp3++; } for (i = 0; i < tokensetsize; i++) shiftset[i] = 0; if (shiftp) { k = shiftp->nshifts; for (i = 0; i < k; i++) { if (! shiftp->shifts[i]) continue; symbol = accessing_symbol[shiftp->shifts[i]]; if (ISVAR(symbol)) break; SETBIT(shiftset, symbol); } } mask = 1; fp1 = LA + m * tokensetsize; fp2 = shiftset; for (i = 0; i < ntokens; i++) { int defaulted = 0; if (mask & *fp2) count = 1; else count = 0; fp3 = fp1; for (j = m; j < n; j++) { if (mask & *fp3) { if (count == 0) { if (j != default_LA) { rule = LAruleno[j]; fprintf(foutput, " %-4s\treduce using rule %d (%s)\n", tags[i], rule, tags[rlhs[rule]]); } else defaulted = 1; count++; } else { if (defaulted) { rule = LAruleno[default_LA]; fprintf(foutput, " %-4s\treduce using rule %d (%s)\n", tags[i], rule, tags[rlhs[rule]]); defaulted = 0; } rule = LAruleno[j]; fprintf(foutput, " %-4s\t[reduce using rule %d (%s)]\n", tags[i], rule, tags[rlhs[rule]]); } } fp3 += tokensetsize; } mask <<= 1; if (mask == 0) { mask = 1; /* We tried incrementing just fp1, and just fp2; both seem wrong. It seems necessary to increment both in sync. */ fp1++; fp2++; } } if (default_LA >= 0) { fprintf(foutput, " $default\treduce using rule %d (%s)\n", default_rule, tags[rlhs[default_rule]]); } putc('\n', foutput); }}voidfinalize_conflicts(){ FREE(conflicts); FREE(shiftset); FREE(lookaheadset);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -