private void DoShift(TerminalToken token, ShiftAction action) { stateStack.Push(action.State); tokenStack.Push(token); lookahead = null; if (OnShift != null) { OnShift(this, new ShiftEventArgs(token, action.State)); } }
private void SetAction(ParserState state, ProductionEntry key, ParserAction newAction) { if (key is NonTerminal nt) { Console.WriteLine(); } if (state.Action.ContainsKey(key.ID)) { var oldAction = state.Action[key.ID]; if (oldAction.ToString() == newAction.ToString()) { return; } if (!(oldAction is AcceptAction) && !(newAction is AcceptAction)) { if (oldAction.Name != newAction.Name) { //Shift/Reduce Conflict ShiftAction shiftAction = (oldAction.Name == "shift" ? oldAction : newAction) as ShiftAction; ReduceAction reduceAction = (oldAction.Name == "shift" ? newAction : oldAction) as ReduceAction; var prod = reduceAction.Production; var term = key as Terminal; //Resolve based on precedence and associativity if (prod.Precendece > term.Precedence || (prod.Precendece == term.Precedence && prod.Associatvity == OperatorAssociativity.Left)) { state.Action[key.ID] = reduceAction; } else { state.Action[key.ID] = shiftAction; } return; } else if (newAction is ReduceAction) { //Reduce/Reduce conflict var newProd = (newAction as ReduceAction).Production; var oldProd = (oldAction as ReduceAction).Production; bool newFirst = false; if (newProd.Lhs != oldProd.Lhs) { //Find the NonTerminal to appear first newFirst = newProd.Lhs.ID < oldProd.Lhs.ID; } else { //Find the production to appear first foreach (var p in newProd.Lhs.Productions) { if (p != newProd && p != oldProd) { continue; } if (p == newProd) { newFirst = true; } break; } } //Resolve based on first appearance if (newFirst) { state.Action[key.ID] = newAction; } return; } else { throw new Exception($"Conflict in state {state} on entry {key}. Cannot resolve shift/shift conflict."); } } } state.Action[key.ID] = newAction; }