public sealed override object VisitCFG(ControlFlowGraph x) { OnVisitCFG(x); ExploredColor = x.NewColor(); ChangedColor = x.NewColor(); RepairedColor = x.NewColor(); _updatedBlocks = null; // Traverse the whole graph and possibly obtain new versions of start and exit var updatedStart = (StartBlock)Accept(x.Start); var updatedExit = TryGetNewVersion(x.Exit); // Assume that yields and unreachable blocks stay the same var yields = x.Yields; var unreachableBlocks = x.UnreachableBlocks; // Fix the structure of the graph if any changes were performed if (_updatedBlocks != null) { Debug.Assert(updatedStart != x.Start); // Rescan and repair nodes and edges if any blocks were modified var repairer = new GraphRepairer(this); updatedStart = (StartBlock)updatedStart.Accept(repairer); updatedExit = TryGetNewVersion(x.Exit); // Handle newly unreachable blocks var newlyUnreachableBlocks = _possiblyUnreachableBlocks?.Where(b => !IsExplored(b)).ToList() // Confirm that they are unexplored ?? Enumerable.Empty <BoundBlock>(); if (newlyUnreachableBlocks.Any()) { // Scan all the newly unreachable blocks (for yields, declarations,...) var unreachableProcessor = new UnreachableProcessor(this, ExploredColor); newlyUnreachableBlocks.ForEach(b => b.Accept(unreachableProcessor)); // Remove the discovered yields from the next CFG version if (unreachableProcessor.Yields != null) { yields = yields.RemoveRange(unreachableProcessor.Yields); } } // Repair all the unreachable blocks so that they reference the updated versions of the blocks // (enables to properly produce reachability diagnostics) unreachableBlocks = unreachableBlocks.Concat(newlyUnreachableBlocks) .Select(b => (BoundBlock)b.Accept(repairer)) .ToImmutableArray(); } // Create a new CFG from the new versions of blocks and edges (expressions and statements are reused where unchanged) return(x.Update( updatedStart, updatedExit, x.Labels, // Keep all the labels, they are here only for the diagnostic purposes yields, unreachableBlocks)); }
public void TestUnreach2() { Gramm gr = new Gramm(); gr.Terms.Add("a"); gr.Terms.Add("+"); gr.NonTerms.Add("A"); gr.NonTerms.Add("B"); gr.NonTerms.Add("C"); gr.NonTerms.Add("D"); gr.St = "B"; gr.Rules.Add(new Rule("A", new List <string>() { "a", "A" })); gr.Rules.Add(new Rule("A", new List <string>() { "+", "D" })); gr.Rules.Add(new Rule("B", new List <string>() { "B", "A" })); gr.Rules.Add(new Rule("B", new List <string>() { "A", "B", "+" })); gr.Rules.Add(new Rule("C", new List <string>() { "a", "A", "a" })); gr.Rules.Add(new Rule("C", new List <string>() { "D", "+", "A" })); gr.Rules.Add(new Rule("D", new List <string>() { "B", "C" })); gr.Rules.Add(new Rule("D", new List <string>() { "a" })); Gramm newGr = UnreachableProcessor.RemoveUnreachable(gr); Assert.IsTrue(newGr.NonTerms.Contains("A")); Assert.IsTrue(newGr.NonTerms.Contains("B")); Assert.IsTrue(newGr.NonTerms.Contains("C")); Assert.IsTrue(newGr.NonTerms.Contains("D")); Assert.AreEqual(8, newGr.Rules.Count); Assert.IsNotNull(newGr.Rules.Find(x => x.Left == "C")); }