/// <summary> /// Compute the collection of Lr states by recursively applying productions from root state until no new states are added. /// </summary> private void CreateLrItemsAndStates() { var rootProduction = Grammar.Productions[0]; var rootItem = LrItems.GetOrAdd(rootProduction, 0, 1); var rootState = LrStates.GetOrAdd(ComputeClosure(new SortedSet <LrItem> { rootItem })); var open = new Queue <LrState>(); open.Enqueue(rootState); while (open.Count > 0) { var state = open.Dequeue(); var gotos = new LrState[Grammar.Tokens.Length]; var gotoPrecedences = new ushort?[Grammar.Tokens.Length]; foreach (var token in Enumerable.Range(0, Grammar.Tokens.Length)) { bool bAdded; ushort?precedence; var gotoState = GotoLr(state, token, out bAdded, out precedence); gotos[token] = gotoState; gotoPrecedences[token] = precedence; if (bAdded) { open.Enqueue(gotoState); } } state.Gotos = gotos; state.GotoPrecedences = gotoPrecedences; } }
/// <summary> /// Given the set of items in state, calculate for each token the closed set of items that can result from processing said token. /// </summary> /// <param name="state">The staring state.</param> /// <param name="token">The token to process.</param> /// <param name="bAdded">Return true if new state was added.</param> /// <param name="precedence">Return the precedence of the goto.</param> /// <returns>Returns the resulting LrState or null of unable to process the specified token on any of the state items.</returns> private LrState GotoLr(LrState state, int token, out bool bAdded, out ushort?precedence) { ushort?prec = null; var targetItems = new SortedSet <LrItem>(); foreach (var item in state.Items) { if (item.CanIncrement && (item.NextToken == token)) { var newItem = LrItems.GetOrAdd(item.Production, item.ProductionProgress + 1, item.LookAheadSymbol); targetItems.Add(newItem); if (!prec.HasValue) { prec = item.Production.Precedence; } else if (item.Production.Precedence > prec) { prec = item.Production.Precedence; } } } if (targetItems.Count == 0) { bAdded = false; precedence = null; return(null); } var targetItemsWithClosure = ComputeClosure(targetItems); var targetState = LrStates.GetOrAdd(targetItemsWithClosure, out bAdded); precedence = prec; return(targetState); }