public static ParseGraph ConstructGraph(Config config) { var productions = ExtractProductions(config); var provider = new SegmentSetProvider(productions); return(ConstructGraph(config, provider)); }
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())); }
static void PopulateLookaheads(SegmentSetProvider provider, Graph graph) { var pending = new Queue <KeyValuePair <Graph.State, ParseItem> >(); var eofSet = SegmentSet.New(new Segment[] { Segment.EOF }); foreach (var state in graph.StartStates) { foreach (var item in state.Label) { if (item.Production.Target.IsInitial) { state.Label.SetLookahead(item, eofSet); pending.Enqueue(new KeyValuePair <Graph.State, ParseItem>(state, item)); } } } while (pending.Count > 0) { var pair = pending.Dequeue(); var thisState = pair.Key; var thisItem = pair.Value; var thisLookahead = thisState.Label.GetLookahead(thisItem); var next = thisItem.Production.Segments[thisItem.Position]; foreach (var transition in thisState.ToTransitions) { if (transition.Label != next) { continue; } var nextItem = thisItem.NextItem(); if (transition.ToState.Label.TryUnionLookahead(nextItem, thisLookahead) && nextItem.Position != nextItem.Production.Segments.Length) { pending.Enqueue(new KeyValuePair <Graph.State, ParseItem>(transition.ToState, nextItem)); } break; } if (!next.IsTerminal) { var follow = provider.GetFollowSets(thisItem.Production, thisItem.Position); if (follow.ContainsSegment(null)) { follow = thisLookahead.Union(follow.Subtract(SegmentSet.EpsilonSet)); } foreach (var nextItem in thisState.Label) { if (nextItem.Position != 0) { continue; } if (nextItem.Production.Target != next) { continue; } if (thisState.Label.TryUnionLookahead(nextItem, follow) && nextItem.Position != nextItem.Production.Segments.Length) { pending.Enqueue(new KeyValuePair <Graph.State, ParseItem>(thisState, nextItem)); } } } } }