public bool IsNongreedyExit; // indicates a nongreedy exit branch (which takes priority in case of ambiguity) public void UpdateSet(bool addEOF) { if (Cases.Count == 0) { Set = Set.Empty; if (addEOF) { Set = Set.WithEOF(); } AndReq = new Set <AndPred>(); return; } Set = Cases[0].Set; var andI = new MSet <AndPred>(Cases[0].AndPreds); for (int i = 1; i < Cases.Count; i++) { Set = Set.Union(Cases[i].Set); andI.IntersectWith(Cases[i].AndPreds); } AndReq = (Set <AndPred>)andI; if (addEOF) { Set = Set.WithEOF(); } }
public TerminalPred Merge(TerminalPred r, bool ignoreActions = false) { if (!ignoreActions && (PreAction != r.PreAction || PostAction != r.PostAction)) { throw new InvalidOperationException("Internal error: cannot merge TerminalPreds that have actions"); } return(new TerminalPred(Basis, Set.Union(r.Set), true) { PreAction = PreAction, PostAction = PostAction }); }
protected PredictionTree ComputePredictionTree(KthSet[] kthSets) { var children = InternalList <PredictionBranch> .Empty; var thisBranch = new List <KthSet>(); int lookahead = kthSets[0].LA; Debug.Assert(kthSets.All(p => p.LA == lookahead)); IPGTerminalSet covered = CGH.EmptySet; for (;;) { thisBranch.Clear(); // e.g. given an Alts value of ('0' '0'..'7'+ | '0'..'9'+), // ComputeSetForNextBranch finds the set '0' in the first // iteration (recording both alts in 'thisBranch'), '1'..'9' // on the second iteration, and finally null. IPGTerminalSet set = ComputeSetForNextBranch(kthSets, thisBranch, covered); if (set == null) { break; } if (thisBranch.Count == 1) { var branch = thisBranch[0]; children.Add(new PredictionBranch(set, branch.Alt, covered)); } else { Debug.Assert(thisBranch.Count > 1); NarrowDownToSet(thisBranch, set); PredictionTreeOrAlt sub; if (thisBranch.Any(ks => ks.HasAnyAndPreds)) { sub = ComputeAssertionTree(thisBranch); } else { sub = ComputeNestedPredictionTree(thisBranch); } children.Add(new PredictionBranch(set, sub, covered)); } covered = covered.Union(set); } return(new PredictionTree(lookahead, children, covered)); }
protected LNode GeneratePredictionTreeCode(PredictionTree tree, Pair <LNode, string>[] matchingCode, ref Symbol haveLoop) { var braces = F.Braces(); Debug.Assert(tree.Children.Count >= 1); var alts = (Alts)_currentPred; if (tree.Children.Count == 1) { return(GetPredictionSubtreeCode(tree.Children[0], matchingCode, ref haveLoop)); } // From the prediction table, we can generate either an if-else chain: // // if (la0 >= '0' && la0 <= '7') sub_tree_1(); // else if (la0 == '-') sub_tree_2(); // else break; // // or a switch statement: // // switch(la0) { // case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': // sub_tree_1(); // break; // case '-': // sub_tree_2(); // break; // default: // goto breakfor; // } // // Assertion levels always need an if-else chain; lookahead levels // consider the complexity of switch vs if and decide which is most // appropriate. Generally "if" is slower, but a switch may require // too many labels since it doesn't support ranges like "la0 >= 'a' // && la0 <= 'z'". // // This class makes if-else chains directly (using IPGTerminalSet. // GenerateTest() to generate the test expressions), but the code // generation helper (CGH) is used to generate switch statements // because the required code may be more complex. // // We may or may not be generating code inside a for(;;) loop. If we // decide to generate a switch() statement, one of the branches will // usually need to break out of the for loop, but "break" can only // break out of the switch(). In that case, add "stop:" after the // switch() and use "goto stop" instead of "break". WList <LNode> block = new WList <LNode>(); LNode laVar = null; MSet <int> switchCases = new MSet <int>(); IPGTerminalSet[] branchSets = null; bool should = false; if (tree.UsesLA()) { laVar = F.Id("la" + tree.Lookahead.ToString()); if (!tree.IsAssertionLevel) { IPGTerminalSet covered = CGH.EmptySet; branchSets = tree.Children.Select(branch => { var set = branch.Set.Subtract(covered); covered = covered.Union(branch.Set); return(set); }).ToArray(); should = CGH.ShouldGenerateSwitch(branchSets, switchCases, tree.Children.Last.IsErrorBranch); if (!should) { switchCases.Clear(); } else if (should && haveLoop == S.For) { // Can't "break" out of the for-loop when there is a nested switch, haveLoop = GSymbol.Get(NextStopLabel()); // so use "goto stop". } } } LNode[] branchCode = new LNode[tree.Children.Count]; for (int i = 0; i < tree.Children.Count; i++) { if (tree.Children[i].IsErrorBranch) { if (_recognizerMode) { branchCode[i] = F.Call(S.Return, F.False); } else if (alts.ErrorBranch != null && alts.ErrorBranch != DefaultErrorBranch.Value) { Debug.Assert(matchingCode.Length == alts.Arms.Count + 1); branchCode[i] = matchingCode[alts.Arms.Count].A; } else { branchCode[i] = CGH.ErrorBranch(tree.TotalCoverage, tree.Lookahead); } } else { branchCode[i] = GetPredictionSubtreeCode(tree.Children[i], matchingCode, ref haveLoop); } } var code = GenerateIfElseChain(tree, branchCode, ref laVar, switchCases); if (laVar != null) { block.Insert(0, F.Assign(laVar, CGH.LA(tree.Lookahead))); _laVarsNeeded |= 1ul << tree.Lookahead; } else if (should) { laVar = CGH.LA(tree.Lookahead); } if (should) { Debug.Assert(switchCases.Count != 0); code = CGH.GenerateSwitch(branchSets, branchCode, switchCases, code ?? F.Missing, laVar); } block.Add(code); return(F.Braces(block.ToVList())); }
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); }