static ParseItemSet Closure(SegmentSetProvider provider, ParseItemSet kernelItems) { var lookup = new Dictionary <ParseItem, bool>(); var itemsToAdd = new Queue <ParseItem>(); EnqueueRange(itemsToAdd, kernelItems); while (itemsToAdd.Count > 0) { var item = itemsToAdd.Dequeue(); var production = item.Production; if (!lookup.ContainsKey(item)) { lookup.Add(item, true); if (item.Position < production.Segments.Length) { var next = production.Segments[item.Position]; if (!next.IsTerminal) { EnqueueRange(itemsToAdd, provider.CreateParseItems(next)); } } } } return(ParseItemSet.New(lookup.Keys)); }
static ParseGraph ConstructGraph(Config config, SegmentSetProvider provider) { var graphBuilder = new Graph.Builder(); var map = new Dictionary <ParseItemSet, Graph.State>(); var queue = new Queue <Graph.State>(); var startStates = new List <Graph.State>(); var topLevelSegments = new List <Segment>(); foreach (var segment in provider.InitialSegments) { var initialKernel = ParseItemSet.New(provider.CreateParseItems(segment)); var initialState = graphBuilder.NewState(true, Closure(provider, initialKernel)); map.Add(initialKernel, initialState); queue.Enqueue(initialState); startStates.Add(initialState); topLevelSegments.Add(new Segment(segment.Name, false)); } while (queue.Count > 0) { var fromState = queue.Dequeue(); foreach (var pair in fromState.Label.GetTransitionKernels()) { if (!map.TryGetValue(pair.Value, out var toState)) { toState = graphBuilder.NewState(false, Closure(provider, pair.Value)); map.Add(pair.Value, toState); queue.Enqueue(toState); } graphBuilder.AddTransition(fromState, toState, pair.Key); } } var graph = graphBuilder.Graph; PopulateLookaheads(provider, graph); ParseGraphOptimiser.Optimise(config, graphBuilder); return(new ParseGraph(graph, topLevelSegments.ToArray(), startStates.ToArray())); }
ParseItem[] FindTrivialItems(ParseItemSet set) { var count = set.Count; var items = new ParseItem[count]; var tokens = new Segment[count]; var write = 0; set.CopyTo(items, 0); // Consider only incomplete items. for (var i = 0; i < count; i++) { var item = items[i]; var production = item.Production; if (item.Position < production.Segments.Length) { items[write] = items[i]; tokens[write] = production.Segments[item.Position]; write++; } } if (write == 0) { return(null); } count = write; write = 0; Array.Sort(tokens, items, 0, count); var duplicate = false; var prevToken = tokens[0]; var prevItem = items[0]; // Discard items that share the "next" segment or have a non-trivial action. for (var i = 1; i < count; i++) { var nextToken = tokens[i]; var nextItem = items[i]; if (nextToken == prevToken) { duplicate = true; } else { if (duplicate) { duplicate = false; } else if (!prevItem.Production.Target.IsInitial && _trivialLookup[prevItem.Production]) { items[write] = prevItem; tokens[write] = prevToken; write++; } prevToken = nextToken; prevItem = nextItem; } } if (!duplicate && !prevItem.Production.Target.IsInitial && _trivialLookup[prevItem.Production]) { items[write] = prevItem; tokens[write] = prevToken; write++; } if (write == 0) { return(null); } count = write; if (count < items.Length) { Array.Resize(ref items, count); } return(items); }