protected LNode GetPredictionSubtreeCode(PredictionBranch branch, Pair <LNode, string>[] matchingCode, ref Symbol haveLoop) { if (branch.Sub.Tree != null) { return(GeneratePredictionTreeCode(branch.Sub.Tree, matchingCode, ref haveLoop)); } else { Debug.Assert(branch.Sub.Alt != ErrorAlt); if (branch.Sub.Alt == ExitAlt) { return(GetExitStmt(haveLoop)); } else { var code = matchingCode[branch.Sub.Alt].A; if (code.Calls(S.Braces, 1)) { return(code.Args[0].Clone()); } else { return(code.Clone()); } } } }
/// <summary>Recursively merges adjacent duplicate cases in prediction trees. /// The tree is modified in-place, but in case a tree collapses to a single /// alternative, the return value indicates which single alternative.</summary> private PredictionTreeOrAlt SimplifyPredictionTree(PredictionTree tree) { for (int i = 0; i < tree.Children.Count; i++) { PredictionBranch pb = tree.Children[i]; if (pb.Sub.Tree != null) { pb.Sub = SimplifyPredictionTree(pb.Sub.Tree); } } for (int i = tree.Children.Count - 1; i > 0; i--) { PredictionBranch a = tree.Children[i - 1], b = tree.Children[i]; if (a.Sub.Equals(b.Sub)) { // Merge a and b if (a.Set != null) { a.Set = a.Set.Union(b.Set); } a.CombineAndPredsWith(b.AndPreds); tree.Children.RemoveAt(i); } } if (tree.Children.Count == 1) { return(tree.Children[0].Sub); } return(tree); }
private PredictionTreeOrAlt ComputeAssertionTree2(List <KthSet> alts, Set <AndPred> matched) { int lookahead = alts[0].LA; var children = InternalList <PredictionBranch> .Empty; MSet <AndPred> falsified = new MSet <AndPred>(); // Each KthSet represents a branch of the Alts for which we are // generating a prediction tree; so if we find an and-predicate // that, by failing, will exclude one or more KthSets, that's // probably the fastest way to get closer to completing the tree. // Any predicate in KthSet.AndReq (that isn't in matched) satisfies // this condition. var bestAndPreds = alts.SelectMany(alt => alt.AndReq).Where(ap => !matched.Contains(ap)).ToList(); var altsLeft = alts.Select(alt => alt.Clone(true)).ToList(); foreach (AndPred andPred in bestAndPreds) { AutoAddBranchForAndPred(ref children, andPred, altsLeft, matched, falsified); if (altsLeft.Count == 0) { break; } } // Testing any single AndPred will not exclude any KthSets, so // we'll proceed the slow way: pick any unmatched AndPred and test // it. If it fails then the Transition(s) associated with it can be // excluded. List <AndPred> predsLeft = altsLeft.SelectMany(alt => alt.Cases) .SelectMany(t => t.AndPreds) .Where(ap => !matched.Contains(ap)) .Distinct().ToList(); foreach (var andPred in predsLeft) { AutoAddBranchForAndPred(ref children, andPred, altsLeft, matched, falsified); if (altsLeft.Count == 0) { break; } } if (children.Count == 0) { // If no AndPreds were tested, proceed to the next level of prediction. Debug.Assert(falsified.Count == 0); return(ComputeNestedPredictionTree(altsLeft)); } // If there are any "unguarded" cases left after falsifying all // the AndPreds, add a branch for them. Debug.Assert(falsified.Count > 0); if (altsLeft.Count > 0) { var final = new PredictionBranch(new Set <AndPred>(), ComputeNestedPredictionTree(altsLeft)); children.Add(final); } return(new PredictionTree(lookahead, children, null)); }
private void AutoAddBranchForAndPred(ref InternalList <PredictionBranch> children, AndPred andPred, List <KthSet> alts, Set <AndPred> matched, MSet <AndPred> falsified) { if (!falsified.Contains(andPred)) { var innerMatched = matched.With(andPred); var result = new PredictionBranch(new Set <AndPred>().With(andPred), ComputeAssertionTree2(alts, innerMatched)); falsified.Add(andPred); RemoveFalsifiedCases(alts, falsified); children.Add(result); } }
protected LNode GetPredictionSubtreeCode(PredictionBranch branch, Pair<LNode, string>[] matchingCode, ref Symbol haveLoop) { if (branch.Sub.Tree != null) return GeneratePredictionTreeCode(branch.Sub.Tree, matchingCode, ref haveLoop); else { Debug.Assert(branch.Sub.Alt != ErrorAlt); if (branch.Sub.Alt == ExitAlt) { return GetExitStmt(haveLoop); } else { var code = matchingCode[branch.Sub.Alt].A; if (code.Calls(S.Braces, 1)) return code.Args[0].Clone(); else return code.Clone(); } } }
void ScanTree(PredictionTree tree, Alts alts, DList <Prematched> path) { int oldCount = path.Count; while (path.Count <= tree.Lookahead) { path.Add(new Prematched { Terminals = Anything }); } Prematched pm = path.Last; if (tree.IsAssertionLevel) { foreach (PredictionBranch b in tree.Children) { var old = pm.AndPreds.Clone(); var verified = Enumerable.Aggregate(b.AndPreds, (set1, set2) => (set1.Union(set2))); // usually empty if more than one pm.AndPreds.UnionWith(verified); if (b.Sub.Tree != null) { ScanTree(b.Sub.Tree, alts, path); } else { Debug.Assert(b.Sub.Alt != ErrorAlt); if (b.Sub.Alt == ExitAlt) { _apply.ApplyPrematchData(alts.Next, path); } else { _apply.ApplyPrematchData(alts.Arms[b.Sub.Alt], path); } } pm.AndPreds = old; } } else // !IsAssertionLevel (terminal-matching level) { bool needErrorBranch = LLPG.NeedsErrorBranch(tree, alts); for (int i = 0; i < tree.Children.Count; i++) { PredictionBranch b = tree.Children[i]; IPGTerminalSet set = b.Set; if (!needErrorBranch && i + 1 == tree.Children.Count) { // Add all the default cases set = set.Union(tree.TotalCoverage.Inverted()); } pm.Terminals = set; if (b.Sub.Tree != null) { ScanTree(b.Sub.Tree, alts, path); } else { if (b.Sub.Alt == ExitAlt) { _apply.ApplyPrematchData(alts.Next, path); } else if (b.Sub.Alt != ErrorAlt) { _apply.ApplyPrematchData(alts.Arms[b.Sub.Alt], path); } } } path.PopLast(); } path.Resize(oldCount); }
/// <summary>Extends each level of the prediction tree so that it has /// total coverage. For example, a typicaly prediction tree might have /// branches for 'a'..'z' and '0..'9'; this method will add coverage for /// all other possible inputs. It does this either by adding an error /// branch, or by extending the set handled by the default branch of /// each level.</summary> private void AddElseCases(Alts alts, PredictionTree tree) { foreach (var branch in tree.Children) { if (branch.Sub.Tree != null) { AddElseCases(alts, branch.Sub.Tree); } } if (tree.IsAssertionLevel) { tree.Children.Last.AndPreds.Clear(); tree.Children.Last.AndPreds.Add(Set <AndPred> .Empty); } else if (!tree.TotalCoverage.ContainsEverything) { var rest = tree.TotalCoverage.Inverted(); if (alts.HasErrorBranch(LLPG)) { tree.Children.Add(new PredictionBranch(rest, new PredictionTreeOrAlt { Alt = ErrorAlt }, tree.TotalCoverage)); } else { // No error branch, so use default arm #if false // First try: this tends to produce less intuitive code. Neither // version is objectively better; sometimes this version gives // faster code and sometimes the other version gives faster code. int defaultArm = alts.DefaultArmInt(); foreach (PredictionBranch branch in tree.Children) { if (branch.Sub.Tree == null && branch.Sub.Alt == defaultArm) { branch.Set = branch.Set.Union(rest); goto done; } } if (alts.DefaultArm != null) { tree.Children.Add(new PredictionBranch(rest, defaultArm, tree.TotalCoverage)); } else { tree.Children.Last.Set = tree.Children.Last.Set.Union(rest); } done :; #else PredictionBranch last = tree.Children.Last; if (alts.DefaultArm != null && (last.Sub.Tree != null || last.Sub.Alt != alts.DefaultArm.Value)) { tree.Children.Add(new PredictionBranch(rest, alts.DefaultArm.Value, tree.TotalCoverage)); } else { last.Set = last.Set.Union(rest); } #endif } } }
private void AutoAddBranchForAndPred(ref InternalList<PredictionBranch> children, AndPred andPred, List<KthSet> alts, Set<AndPred> matched, MSet<AndPred> falsified) { if (!falsified.Contains(andPred)) { var innerMatched = matched.With(andPred); var result = new PredictionBranch(new Set<AndPred>().With(andPred), ComputeAssertionTree2(alts, innerMatched)); falsified.Add(andPred); RemoveFalsifiedCases(alts, falsified); children.Add(result); } }
private PredictionTreeOrAlt ComputeAssertionTree2(List<KthSet> alts, Set<AndPred> matched) { int lookahead = alts[0].LA; var children = InternalList<PredictionBranch>.Empty; MSet<AndPred> falsified = new MSet<AndPred>(); // Each KthSet represents a branch of the Alts for which we are // generating a prediction tree; so if we find an and-predicate // that, by failing, will exclude one or more KthSets, that's // probably the fastest way to get closer to completing the tree. // Any predicate in KthSet.AndReq (that isn't in matched) satisfies // this condition. var bestAndPreds = alts.SelectMany(alt => alt.AndReq).Where(ap => !matched.Contains(ap)).ToList(); var altsLeft = alts.Select(alt => alt.Clone(true)).ToList(); foreach (AndPred andPred in bestAndPreds) { AutoAddBranchForAndPred(ref children, andPred, altsLeft, matched, falsified); if (altsLeft.Count == 0) break; } // Testing any single AndPred will not exclude any KthSets, so // we'll proceed the slow way: pick any unmatched AndPred and test // it. If it fails then the Transition(s) associated with it can be // excluded. List<AndPred> predsLeft = altsLeft.SelectMany(alt => alt.Cases) .SelectMany(t => t.AndPreds) .Where(ap => !matched.Contains(ap)) .Distinct().ToList(); foreach (var andPred in predsLeft) { AutoAddBranchForAndPred(ref children, andPred, altsLeft, matched, falsified); if (altsLeft.Count == 0) break; } if (children.Count == 0) { // If no AndPreds were tested, proceed to the next level of prediction. Debug.Assert(falsified.Count == 0); return ComputeNestedPredictionTree(altsLeft); } // If there are any "unguarded" cases left after falsifying all // the AndPreds, add a branch for them. Debug.Assert(falsified.Count > 0); if (altsLeft.Count > 0) { var final = new PredictionBranch(new Set<AndPred>(), ComputeNestedPredictionTree(altsLeft)); children.Add(final); } return new PredictionTree(lookahead, children, null); }