//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]; BnfTerm currTerm = item.Core.Current; if (currTerm == null || !(currTerm is NonTerminal)) { continue; } //1. Add normal closure items NonTerminal currNt = currTerm as NonTerminal; foreach (Production prod in currNt.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); }
private void CreateParserStates() { Data.States.Clear(); _stateHash = new ParserStateTable(); CreateInitialAndFinalStates(); string augmRootKey = Data.AugmentedRoot.Key; // Iterate through states (while new ones are created) and create shift transitions and new states for (int index = 0; index < Data.States.Count; index++) { ParserState state = Data.States[index]; AddClosureItems(state); //Get keys of all possible shifts ShiftTable shiftTable = GetStateShifts(state); //Each key in shifts dict is an input element // Value is LR0ItemList of shifted LR0Items for this input element. foreach (string input in shiftTable.Keys) { LR0ItemList shiftedCoreItems = shiftTable[input]; ParserState newState = FindOrCreateState(shiftedCoreItems); ActionRecord newAction = new ActionRecord(input, ParserActionType.Shift, newState, null); state.Actions[input] = newAction; //link original LRItems in original state to derived LRItems in newState foreach (LR0Item coreItem in shiftedCoreItems) { LRItem fromItem = FindItem(state, coreItem.Production, coreItem.Position - 1); LRItem toItem = FindItem(newState, coreItem.Production, coreItem.Position); if (!fromItem.PropagateTargets.Contains(toItem)) { fromItem.PropagateTargets.Add(toItem); } //copy hints from core items into the newAction newAction.ShiftItems.Add(fromItem); } //foreach coreItem } //foreach input } //for index Data.FinalState = Data.InitialState.Actions[augmRootKey].NewState; } //method
public ParserState(string name, LRItem item) { Name = name; Items.Add(item); }