private LRItem TryFindItem(ParserState state, LR0Item core) { foreach (LRItem item in state.Items) { if (item.Core == core) { return(item); } } return(null); }//method
private static int ById(LR0Item x, LR0Item y) { if (x.ID < y.ID) { return(-1); } if (x.ID == y.ID) { return(0); } return(1); }
//Creates closure items with "spontaneously generated" lookaheads private bool AddClosureItems(ParserState state) { bool result = false; //note that we change collection while we iterate thru it, so we have to use "for i" loop for (int i = 0; i < state.Items.Count; i++) { LRItem item = state.Items[i]; NonTerminal nextNT = item.Core.NextElement as NonTerminal; if (nextNT == null) { continue; } //1. Add normal closure items foreach (Production prod in nextNT.Productions) { LR0Item core = prod.LR0Items[0]; //item at zero index is the one that starts with dot LRItem newItem = TryFindItem(state, core); if (newItem == null) { newItem = new LRItem(state, core); state.Items.Add(newItem); result = true; } #region Comments on lookaheads processing // The general idea of generating ("spontaneously") the lookaheads is the following: // Let's the original item be in the form // [A -> alpha . B beta , lset] // where <B> is a non-terminal and <lset> is a set of lookaheads, // <beta> is some string (B's tail in our terminology) // Then the closure item on non-teminal B is an item // [B -> x, firsts(beta + lset)] // (the lookahead set is expression after the comma). // To generate lookaheads on a closure item, we simply take "firsts" // from the tail <beta> of the NonTerminal <B>. // Normally if tail <beta> is nullable we would add ("propagate") // the <lset> lookaheads from <A> to <B>. // We dont' do it right here - we simply add a propagation link. // We propagate all lookaheads later in a separate process. #endregion newItem.NewLookaheads.AddRange(item.Core.TailFirsts); if (item.Core.TailIsNullable && !item.PropagateTargets.Contains(newItem)) { item.PropagateTargets.Add(newItem); } } //foreach prod } //for i (LRItem) return(result); }
} //method #endregion #region Calculating Tail Firsts private void CalculateTailFirsts() { foreach (Production prod in Data.Productions) { StringSet accumulatedFirsts = new StringSet(); bool allNullable = true; //We are going backwards in LR0Items list for (int i = prod.LR0Items.Count - 1; i >= 0; i--) { LR0Item item = prod.LR0Items[i]; if (i >= prod.LR0Items.Count - 2) { //Last and before last items have empty tails item.TailIsNullable = true; item.TailFirsts.Clear(); continue; } BnfTerm term = prod.RValues[item.Position + 1]; //Element after-after-dot NonTerminal ntElem = term as NonTerminal; if (ntElem == null || !ntElem.Nullable) //term is a terminal or non-nullable NonTerminal //term is not nullable, so we clear all old firsts and add this term { accumulatedFirsts.Clear(); allNullable = false; item.TailIsNullable = false; if (ntElem == null) { item.TailFirsts.Add(term.Key);//term is terminal so add its key accumulatedFirsts.Add(term.Key); } else { item.TailFirsts.AddRange(ntElem.Firsts); //nonterminal accumulatedFirsts.AddRange(ntElem.Firsts); } continue; } //if we are here, then ntElem is a nullable NonTerminal. We add accumulatedFirsts.AddRange(ntElem.Firsts); item.TailFirsts.AddRange(accumulatedFirsts); item.TailIsNullable = allNullable; } //for i } //foreach prod } //method
}//method private ShiftTable GetStateShifts(ParserState state) { ShiftTable shifts = new ShiftTable(); LR0ItemList list; foreach (LRItem item in state.Items) { BnfTerm term = item.Core.NextElement; if (term == null) { continue; } LR0Item shiftedItem = item.Core.Production.LR0Items[item.Core.Position + 1]; if (!shifts.TryGetValue(term.Key, out list)) { shifts[term.Key] = list = new LR0ItemList(); } list.Add(shiftedItem); } //foreach return(shifts); } //method
public LRItem(ParserState state, LR0Item core) { State = state; Core = core; }