static string ActionToString(ParserAction action) { string result = null; Shift shift = action as Shift; if (shift != null) { return("shift, and go to state " + StateRef(shift.next.num)); } Reduce reduce = action as Reduce; if (reduce != null) { return(String.Format(CultureInfo.InvariantCulture, "reduce using {0} ({1}{2})", ProductionRef(reduce.item.production.num), (reduce.item.production.rhs.Count == 0 ? "Erasing " : ""), reduce.item.production.lhs)); } return(result); }
internal void BuildParseTable() { foreach (AutomatonState state in states) { // // Add shift actions ... // This makes shift the default action for all // terminal transitions. This is modified as required, // later in this foreach state loop. // foreach (Terminal t in state.terminalTransitions) { state.parseTable[t] = new Shift(state.Goto[t]); } // Add reduce actions ... foreach (ProductionItem item in state.allItems) { if (item.isReduction()) { // Accept on everything if (item.production == grammar.rootProduction) { foreach (Terminal t in grammar.terminals.Values) { state.parseTable[t] = new Reduce(item); } } foreach (Terminal t in item.LA) { // possible conflict with existing action if (state.parseTable.ContainsKey(t)) { Reduce reduceAction; ParserAction other = state.parseTable[t]; Production iProd = item.production; if ((reduceAction = other as Reduce) != null) { Production oProd = reduceAction.item.production; // Choose in favour of production listed first in the grammar if (oProd.num > iProd.num) { state.parseTable[t] = new Reduce(item); } string p1 = String.Format(CultureInfo.InvariantCulture, " Reduce {0}:\t{1}", oProd.num, oProd.ToString()); string p2 = String.Format(CultureInfo.InvariantCulture, " Reduce {0}:\t{1}", iProd.num, iProd.ToString()); int chsn = (oProd.num > iProd.num ? iProd.num : oProd.num); grammar.conflicts.Add(new ReduceReduceConflict(t, p1, p2, chsn, state)); if (GPCG.Verbose) { Console.Error.WriteLine( "Reduce/Reduce conflict in state {0} on symbol {1}", state.num, t.ToString()); Console.Error.WriteLine(p1); Console.Error.WriteLine(p2); } else { Console.Error.WriteLine("Reduce/Reduce conflict, state {0}: {1} vs {2} on {3}", state.num, iProd.num, oProd.num, t); } } else { if (iProd.prec != null && t.prec != null) { if (iProd.prec.prec > t.prec.prec) { // // Production iProd has precedence over t, so Reduce. // state.parseTable[t] = new Reduce(item); // No shift/Reduce warning. } else if (iProd.prec.prec == t.prec.prec) { // // Precedence is equal, so use associativity to decide. // if (t.prec.type == PrecType.left) { // // For %left tokens reduce the left subexpression. // state.parseTable[t] = new Reduce(item); } else if (t.prec.type == PrecType.nonassoc) // && iProd.RightmostTerminal() == t) { // What is the correct semantics here? // If %nonassoc x y, is E x E y E an error? // The YACC spec seems to imply, but not explictly state, // that x,y are non-associative AS A GROUP // rather than just individually non-associative. // // For %nonassoc tokens disallow the shift action, and force // lookahead just in case this state has an LR0 Reduce action. // { state.parseTable.Remove(t); state.ForceLookahead = true; } // else t.prec.type == PrecType.right, so Shift. } // else iProd.prec.prec < t.proc.prec, so Shift anyway. } else // Need to issue a Shift/Reduce warning message. { AutomatonState next = ((Shift)other).next; string p1 = String.Format(CultureInfo.InvariantCulture, " Shift \"{0}\":\tState-{1} -> State-{2}", t, state.num, next.num); string p2 = String.Format(CultureInfo.InvariantCulture, " Reduce {0}:\t{1}", iProd.num, iProd.ToString()); grammar.conflicts.Add(new ShiftReduceConflict(t, p1, p2, state, next)); if (GPCG.Verbose) { Console.Error.WriteLine("Shift/Reduce conflict"); Console.Error.WriteLine(p1); Console.Error.WriteLine(p2); } else { Console.Error.WriteLine("Shift/Reduce conflict, state {0} on {1}", state.num, t); } } } } else { state.parseTable[t] = new Reduce(item); } } } } } }