/* * Initial condition: we have state S with conflicts on lookaheads in Sc.Conflicts. * Each reduce item Ir in S has a set of lookahead sources Ir.ReducedLookaheadSources. * Our goal is to a create non-canonical state ncState with proper lookaheds, create jumps to this state * on jump lookaheads from S to ncState, remove these jump lookaheads from lookahead sets of reduce items * and replace them with non-canonical non-terminal lookaheads. * 1. Compute all jump lookaheads jL and non-canonical lookaheads ncL for state Sc. * 2. Collect relevant lookahead sources in lkhSources set. For each lookahead source lkhSrc in all reduce items, * if lkhSrc.Current.Firsts includes a jump lookahead in jL, include it into lkhSources. * 3. Collect item cores for non-canonical state into ncCores. For each production Prod in productions * of current non-terminal of all items in lkhSources, if Prod.Firsts contains a jump lookahead, then add initial LR0 item of Prod * to ncCores. * 4. Add to ncCores all shift items in state Sc that have Current term in jump lookaheads. We need to include * such shift items from original state into non-canonical state to allow proper resolution of shift-reduce * conflicts. We let shift items in current state "compete" with possible reductions to non-canonical lookaheads * inside non-canonical state. * 5. Create (or find existing) non-canonical state Sn from ncCores. * 6. Assign lookbacks to items in ncState. For each item Src in lkhSources, for each production Prod * in Src.Current.Productions, if Prod.DirectFirsts contains jump lookahead, then: * find LR item I in Sn with I.Core == Prod.LR0Items[0]; do the following: I.Lookbacks.Add(Src.Transition). * 7. For state S for each reduce item I adjust I.Lookaheads: remove jump lookaheads from I.Lookaheads, * and add those non-canonical lookaheads that are in I.AllLookaheads */ //TODO: one thing to look at - see if all items in ncState should lead to reduce item in some state. // There may be items (most likely top ones, expansions of original reduced lookahead) that never get // to full reduce, because we switch back to canonical state on reduction of some "child" non-terminal and // continue through canonical states from there. // So we don't need to generate target transition states for these items (unreachable states). // The main trouble is that unreachable state may introduce conflicts that in fact are never realized. #endregion private void SwitchStateToNLalrLookaheads(ParserState state) { //1. Compute minimal (most expanded) non-canonical lookaheads that resolve all conflicts ComputeStateNonCanonicalLookaheads(state); var stateData = state.BuilderData; //2. Collect reduced lookahead sources and non-terminal lookaheads var lkhSources = new LRItemSet(); var ntSet = new NonTerminalSet(); //All non-terminals in current positions of lkhSources foreach (var reduceItem in stateData.ReduceItems) { foreach (var lkhSource in reduceItem.ReducedLookaheadSources) { var ntLkh = lkhSource.Core.Current as NonTerminal; if (ntLkh == null) { continue; } if (!ntLkh.Firsts.Overlaps(stateData.JumpLookaheads)) { continue; } lkhSources.Add(lkhSource); ntSet.Add(ntLkh); } } //2. Collect core set for non-canonical state var ncCoreSet = new LR0ItemSet(); foreach (var ntLkh in ntSet) { foreach (var prod in ntLkh.Productions) { if (prod.Firsts.Overlaps(stateData.JumpLookaheads)) { ncCoreSet.Add(prod.LR0Items[0]); } } } //4. Add shift items foreach (var shiftItem in stateData.ShiftItems) { if (stateData.JumpLookaheads.Contains(shiftItem.Core.Current)) { ncCoreSet.Add(shiftItem.Core); } } //5. Find or create non-canonical state var oldStateCount = Data.States.Count; var ncState = FindOrCreateState(ncCoreSet, "SN"); //if not found, state is created and added to state list and state hash bool ncStateIsNew = Data.States.Count > oldStateCount; stateData.JumpTarget = ncState; //6. Setup appropriate lookbacks in items in ncState; // first set lookbacks for items originated from lookaheads of reduce items in original state. foreach (var lkhSource in lkhSources) { var ntLkh = lkhSource.Core.Current as NonTerminal; foreach (var prod in ntLkh.Productions) { if (prod.Firsts.Overlaps(stateData.JumpLookaheads)) { var ncItem = ncState.BuilderData.AllItems.FindByCore(prod.LR0Items[0]); ncItem.Lookbacks.Add(lkhSource.Transition); } //if } } //foreach lkhSource //Now items orginated from shift items in original state in step 4 above // just copy lookbacks foreach (var shiftItem in stateData.ShiftItems) { if (stateData.JumpLookaheads.Contains(shiftItem.Core.Current)) { var ncItem = ncState.BuilderData.ShiftItems.FindByCore(shiftItem.Core); shiftItem.ShiftedItem = ncItem; ncItem.Lookbacks.UnionWith(shiftItem.Lookbacks); if (ncItem.Transition != null) { ncItem.Transition.Include(shiftItem.Transition.Includes); } } } PropagateLookbacksAndTransitionsThruShifts(ncState); //7. Adjust reduce items lookaheads in original state foreach (var reduceItem in stateData.ReduceItems) { foreach (var jumpLkh in stateData.JumpLookaheads) { if (reduceItem.Lookaheads.Contains(jumpLkh)) { reduceItem.Lookaheads.Remove(jumpLkh); } } foreach (var ncLkh in stateData.NonCanonicalLookaheads) { if (reduceItem.AllLookaheads.Contains(ncLkh)) { reduceItem.Lookaheads.Add(ncLkh); } } }//foreach reduceItem // 8. Create jump action to non-canonical state, remove shifts on jump lookaheads state.JumpAction = ParserAction.CreateJump(ncState); foreach (var jumpTerm in state.BuilderData.JumpLookaheads) { if (state.Actions.ContainsKey(jumpTerm)) { state.Actions.Remove(jumpTerm); } } //9. Complete generating states state.BuilderData.Conflicts.ExceptWith(state.BuilderData.JumpLookaheads); }//method