private List <GrammarItem> Closure(List <GrammarItem> items) { List <GrammarItem> I = new List <GrammarItem>(); I.AddRange(items); for (int i = 0; i < I.Count; i++) { var item = I[i]; if (item.IsHightlightAfterFinalEntry) { continue; } if (item.HighlightedEntry.IsTerminal) { continue; } var nt = item.HighlightedEntry as NonTerminal; var afterHighlight = item.EntriesAfterHighlight; foreach (var l in item.Lookaheads) { ProductionEntry[] afterPlusLookahead = new ProductionEntry[afterHighlight.Length + 1]; Array.Copy(afterHighlight, afterPlusLookahead, afterHighlight.Length); afterPlusLookahead[^ 1] = l;
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; }