private Prediction predictionMove(Piece p, Board board) { Board virtualBoard = new Board(board); // On créer le premier noeud PredictionTree node = new PredictionTree(ABType.MAX, new Prediction(virtualBoard, p.color)); // Max car c'est les predictions du joueur //Debug.Log(node); int maxValue = alphaBeta(node, p, smart, int.MinValue, int.MaxValue); //Debug.Log(node); Prediction predi = null; foreach (PredictionTree son in node.sons) { if (son.value == maxValue) { predi = son.prediction; break; } } //Debug.Log(predi.board); //Debug.Log( "AlphaBeta : "+ predi.getAction(p)); // On cherche alors la meilleur prédiction return(predi); }
/// <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); }
/// <summary> /// Visit(Alts) is the most important method in this class. It generates /// all prediction code, which is the majority of the code in a parser. /// </summary> public override void Visit(Alts alts) { PredictionTree tree = alts.PredictionTree; var timesUsed = new Dictionary <int, int>(); tree.CountTimesUsed(timesUsed); GenerateCodeForAlts(alts, timesUsed, tree); }
/// <summary> /// Denotes an ambiguous context which identifies the current node as consistent within the ambiguity. /// </summary> /// <param name="ambiguityContext"> /// The <see cref="PredictionTree"/> which represents the ambiguous context, or the 'paths' from which the rule of the current node /// was entered.</param> /// <remarks> /// A reduction on the rule of the node will take place, the ambiguous context needs identified so follow-based ambiguities can be isolated and handled. /// </remarks> public void DenoteReductionPoint(PredictionTree ambiguityContext, PredictionTree declarationContext) { var entry = new ProductionRuleProjectionReductionDetail { Entrypoint = declarationContext, ReductionPoint = ambiguityContext }; lock (this.steppedAmbiguityContexts) this.steppedAmbiguityContexts.Add(entry); AddRootReduction(declarationContext); }
private PredictionTree GetFollowDPathSet(FiniteAutomataMultiTargetTransitionTable <GrammarVocabulary, Tuple <int, PredictionTreeBranch> > transitionTableResult, GrammarVocabulary transition, Dictionary <PredictionTreeBranch, int[]> epDepthLookup) { //var minMinDepth = (from deviationPath in transitionTableResult[transition] // select deviationPath.Item2.MinDepth).Min(); //minDepth = minMinDepth; //epDepthLookup = epDepthLookup.ToDictionary(dps => new PredictionTreeBranch(dps.Key.Skip(minMinDepth).ToList(), dps.Key.Depth - minMinDepth, minDepth: dps.Key.MinDepth - minMinDepth), dps => dps.Value); var result = PredictionTree.GetPathSet(transition, epDepthLookup.Keys.ToList(), this, ProductionRuleProjectionType.FollowAmbiguity, PredictionDerivedFrom.LookAhead_FollowPrediction); result.SetFollowEpsilonData(provider => epDepthLookup[provider]); return(result); }
/// <summary>Creates a new <see cref="PredictionTreeFollow"/> instance with the <paramref name="initialPaths"/>, and <paramref name="edgeNode"/> provided.</summary> /// <param name="initialPaths">The <see cref="PredictionTree"/> built from the analysis of the incoming paths to a rule which are in an initial deadlock for disambiguation upon the rule entering the <paramref name="edgeNode"/>.</param> /// <param name="edgeNode">The <see cref="PredictionTreeLeaf"/> which delineates the ambiguity.</param> internal PredictionTreeFollow(PredictionTree initialPaths, PredictionTreeLeaf edgeNode) { this.initialPaths = initialPaths; this.edgeNode = edgeNode; /* * * Initial variations are used to deconstruct the incoming states * * * Necessary because certain commonality groupings yield similarities * that are only similar to the edgeNode, which means the transition * sets are identical. * * * ToDo: Verify this claim. * */ }
private LNode GenerateIfElseChain(PredictionTree tree, LNode[] branchCode, ref LNode laVar, MSet <int> switchCases) { // From the prediction table, generate a chain of if-else // statements in reverse, starting with the final "else" clause. // Skip any branches that have been claimed for use in a switch() LNode ifChain = null; bool usedTest = false; for (int i = tree.Children.Count - 1; i >= 0; i--) { if (switchCases.Contains(i)) { continue; } if (ifChain == null) { ifChain = branchCode[i]; } else { usedTest = true; var branch = tree.Children[i]; LNode test; if (tree.IsAssertionLevel) { test = GenerateTest(branch.AndPreds, tree.Lookahead, laVar); } else { var set = CGH.Optimize(branch.Set, branch.Covered); test = CGH.GenerateTest(set, laVar); } LNode @if = F.Call(S.If, test, branchCode[i]); if (!ifChain.IsIdWithoutPAttrs(S.Missing)) { @if = @if.PlusArg(ifChain); } ifChain = @if; } } if (!usedTest) { laVar = null; // unnecessary } return(ifChain); }
private void AddRootReduction(PredictionTree entry) { var currentSet = new HashList <HashList <PredictionTreeLeaf> >(); lock (this.RootLeaf._rootAmbiguityContexts) { this.Compiler.DenoteReduction(this.Rule); foreach (var path in entry) { var currentItem = new HashList <PredictionTreeLeaf>(path.Skip(path.MinDepth).Take(path.Depth - (path.MinDepth - 1))); currentSet.Add(currentItem); } this.RootLeaf._rootAmbiguityContexts.Add(currentSet); this.RootLeaf._predictionReductions.Add(entry); } }
private Prediction predictionMove(Piece p, Board board) { Board virtualBoard = new Board(board); Tuple <int, Prediction> find = data.Find(virtualBoard, p.position); // On n'a pas trouvé dans la base un déplacement Prediction result = find.Item2; if (find.Item1 == -1) { // On créer le premier noeud PredictionTree node = new PredictionTree(ABType.MAX, new Prediction(virtualBoard, p.color)); // Max car c'est les predictions du joueur //Debug.Log(node); int maxValue = alphaBeta(node, p, smart, int.MinValue, int.MaxValue); //Debug.Log(node); Prediction predi = null; foreach (PredictionTree son in node.sons) { if (son.value == maxValue) { predi = son.prediction; break; } } //Debug.Log(predi.board); //Debug.Log("Compute:" + predi.getAction(p)); // On sauvegarde le prédicat dans la base de données data.Add(predi, p.color, virtualBoard, p.position); result = predi; } else { Debug.Log("Database:" + result.getAction(p)); } // On cherche alors la meilleur prédiction return(result); }
// Syteme de calcul alpha beta // La valeur smart le nombre de prédiction que l'on réalise // la piece fournit en paramètre est la piece qui réalise l private int alphaBeta(PredictionTree node, Piece p, int smart, int alpha, int beta)/* alpha et toujours inférieur à beta*/ { if (!node.isNode()) { //Debug.Log("C'est une feuille"); return(node.value); } else if (node.type == ABType.MIN) // Noeud de type Min { int v = int.MaxValue; foreach (PredictionTree son in node.getSons(p.color, p.id, (smart == 0))) { v = Math.Min(v, alphaBeta(son, p, smart, alpha, beta)); node.value = v; if (alpha >= v) { return(v); } beta = Math.Min(beta, v); } return(v); } else // Noeud de type Max { int v = int.MinValue; foreach (PredictionTree son in node.getSons(p.color, p.id)) // On parcours tous les mins { v = Math.Max(v, alphaBeta(son, p, smart - 1, alpha, beta)); node.value = v; if (v >= beta) { return(v); } alpha = Math.Max(alpha, v); } return(v); } }
// GENERATED CODE EXAMPLE: The methods in this region generate // the for(;;) loop in this example and everything inside it, except // the calls to Match() which are generated by Visit(TerminalPred). // The generated code uses "goto" and "match" blocks in some cases // to avoid code duplication. This occurs when the matching code // requires multiple statements AND appears more than once in the // prediction tree. Otherwise, matching is done "inline" during // prediction. We generate a for(;;) loop for (...)*, and in certain // cases, we generates a do...while(false) loop for (...)?. // // rule Foo @{ (('a'|'A') 'A')* 'a'..'z' 'a'..'z' }; // public void Foo() // { // int la0, la1; // for (;;) { // la0 = LA(0); // if (la0 == 'a') { // la1 = LA(1); // if (la1 == 'A') // goto match1; // else // break; // } else if (la0 == 'A') // goto match1; // else // break; // match1: // { // Match('A', 'a'); // Match('A'); // } // } // MatchRange('a', 'z'); // MatchRange('a', 'z'); // } private void GenerateCodeForAlts(Alts alts, Dictionary<int, int> timesUsed, PredictionTree tree) { bool needError = LLPG.NeedsErrorBranch(tree, alts); if (!needError && alts.ErrorBranch != null) LLPG.Output(Warning, alts, "The error branch will not be used because the other alternatives are exhaustive (cover all cases)"); bool userDefinedError = needError && alts.ErrorBranch != null && alts.ErrorBranch != DefaultErrorBranch.Value; // Generate matching code for each arm. the "string" in each pair // becomes non-null if the matching code for that branch needs to be // split out (separated) from the prediction tree because it appears // multiple times in the tree. The string is the goto-label name. Pair<LNode, string>[] matchingCode = new Pair<LNode, string>[alts.Arms.Count + (userDefinedError ? 1 : 0)]; MSet<int> unreachable = new MSet<int>(); int separateCount = 0; for (int i = 0; i < alts.Arms.Count; i++) { if (!timesUsed.ContainsKey(i)) { unreachable.Add(i); continue; } var codeForThisArm = new WList<LNode>(); VisitWithNewTarget(alts.Arms[i], codeForThisArm); matchingCode[i].A = F.Braces(codeForThisArm.ToVList()); if (timesUsed[i] > 1 && !SimpleEnoughToRepeat(matchingCode[i].A)) { separateCount++; matchingCode[i].B = alts.Arms[i].ChooseGotoLabel() ?? "match" + (i + 1).ToString(); } } // Add matching code for the error branch, if present. Note: the // default error branch, which is produced by IPGCodeGenHelper. // ErrorBranch() is handled differently: default error code can // differ at each error point in the prediction tree. Therefore // we generate it later, on-demand. if (userDefinedError) { int i = alts.Arms.Count; var errorHandler = new WList<LNode>(); VisitWithNewTarget(alts.ErrorBranch, errorHandler); matchingCode[i].A = F.Braces(errorHandler.ToVList()); if (timesUsed[ErrorAlt] > 1 && !SimpleEnoughToRepeat(matchingCode[i].A)) { matchingCode[i].B = "error"; separateCount++; } } // Print unreachability warnings if (unreachable.Count == 1) LLPG.Output(Warning, alts, string.Format("Branch {{{0}}} is unreachable.", alts.AltName(unreachable.First()))); else if (unreachable.Count > 1) LLPG.Output(Warning, alts, string.Format("Branches {{{0}}} are unreachable.", unreachable.Select(i => alts.AltName(i)).Join(", "))); if (!timesUsed.ContainsKey(ExitAlt) && alts.Mode != LoopMode.None) LLPG.Output(Warning, alts, "Infinite loop. The exit branch is unreachable."); Symbol loopType = null; // Choose a loop type for (...)* or (...)?: if (alts.Mode == LoopMode.Star) loopType = S.For; else if (alts.Mode == LoopMode.Opt) { if (alts.HasErrorBranch(LLPG) || alts.NonExitDefaultArmRequested()) loopType = S.DoWhile; } // If the code for an arm is nontrivial and appears multiple times // in the prediction table, it will have to be split out into a // labeled block and reached via "goto". I'd rather just do a goto // from inside one "if" statement to inside another, but in C# // (unlike in CIL, and unlike in C) that is prohibited :( DeduplicateLabels(matchingCode); var extraMatching = GenerateExtraMatchingCode(matchingCode, separateCount, ref loopType); if (separateCount != 0) loopType = loopType ?? S.DoWhile; Symbol breakMode = loopType; // used to request a "goto" label in addition to the loop LNode code = GeneratePredictionTreeCode(tree, matchingCode, ref breakMode); // Add break/continue between prediction tree and extra matching code, // if necessary. if (extraMatching.Count != 0 && CodeGenHelperBase.EndMayBeReachable(code)) { loopType = loopType ?? S.DoWhile; extraMatching.Insert(0, GetContinueStmt(loopType)); } if (!extraMatching.IsEmpty) code = LNode.MergeLists(code, F.Braces(extraMatching), S.Braces); if (loopType == S.For) { // (...)* => for (;;) {} code = F.Call(S.For, F.List(), F.Missing, F.List(), code); } else if (loopType == S.DoWhile) { // (...)? becomes "do {...} while(false);" IF the exit branch is NOT the default. // If the exit branch is the default, then no loop and no "break" is needed. code = F.Call(S.DoWhile, code, F.@false); } if (breakMode != loopType && breakMode != null) { // Add "stop:" label (plus extra ";" for C# compatibility, in // case the label ends the block in which it is located.) var stopLabel = F.Call(S.Label, F.Id(breakMode)) .PlusTrailingTrivia(F.Trivia(S.TriviaRawText, ";")); code = LNode.MergeLists(code, stopLabel, S.Braces); } int oldCount = _target.Count; _target.SpliceAdd(code, S.Braces); // Add comment before code if (LLPG.AddComments) { var pos = alts.Basis.Range.Start; var comment = F.Trivia(S.TriviaSLComment, string.Format(" Line {0}: {1}", pos.Line, alts.ToString())); if (_target.Count > oldCount) _target[oldCount] = _target[oldCount].PlusAttr(comment); } }
/// <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; }
/// <summary> /// Denotes an ambiguous context which identifies the current node as consistent within the ambiguity. /// </summary> /// <param name="ambiguityContext"> /// The <see cref="PredictionTree"/> which represents the ambiguous context, or the 'paths' from which the rule of the current node /// was entered.</param> /// <remarks> /// A reduction on the rule of the node will take place, the ambiguous context needs identified so follow-based ambiguities can be isolated and handled. /// </remarks> public void DenoteReductionPoint(PredictionTree ambiguityContext) { lock (this.ambiguityContexts) this.ambiguityContexts.Add(ambiguityContext); AddRootReduction(ambiguityContext); }
/// <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 } } }
internal MultikeyedDictionary <GrammarVocabulary, int, List <Tuple <Tuple <int[], PredictionTree>[], int[]> > > ObtainTerminalAmbiguities( Dictionary <SyntacticalDFAState, PredictionTreeLeaf> fullSeries, ControlledDictionary <IOilexerGrammarProductionRuleEntry, SyntacticalDFARootState> ruleDFAs, Dictionary <IOilexerGrammarProductionRuleEntry, GrammarVocabulary> ruleLookup, GrammarSymbolSet grammarSymbols) { if (!this.Veins.DFAOriginState.IsEdge) { return(new MultikeyedDictionary <GrammarVocabulary, int, List <Tuple <Tuple <int[], PredictionTree>[], int[]> > >()); } var tempDictionary = new MultikeyedDictionary <PredictionTreeBranch, GrammarVocabulary, Tuple <int[], PredictionTree> >(); var rootNode = fullSeries[ruleDFAs[this.Rule]]; var currentIncoming = new List <PredictionTreeBranch>(rootNode.incoming); var reductions = rootNode.PointsOfReduction.ToArray(); if (reductions.Length > 0) { } var totalIncoming = new HashSet <PredictionTreeBranch>(); Dictionary <PredictionTree, PredictionTree> uniqueSet = new Dictionary <PredictionTree, PredictionTree>(); foreach (var path in currentIncoming) { var transitionTableResult = new FiniteAutomataMultiTargetTransitionTable <GrammarVocabulary, Tuple <int, PredictionTreeBranch> >(); var masterPathChop = new PredictionTreeBranch(path.Take(path.Depth).Concat(new[] { this }).ToArray(), path.Depth, false, false); masterPathChop.SetDeviations(path.GetDeviationsUpTo(path.Depth)); ObtainTerminalAmbiguitiesOnPath(masterPathChop, fullSeries, ruleDFAs, ruleLookup, transitionTableResult, grammarSymbols); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ * Construct the sequence of Path->Grammar->PathSets based * * off of the table provided by the ObtainTerminalAmbiguitiesOnPath. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **/ foreach (var transition in transitionTableResult.Keys) { var epDepthLookup = (from entry in transitionTableResult[transition] group entry.Item1 by entry.Item2).ToDictionary(k => k.Key, v => v.ToArray()); //int minDepth; //var uniqueCurrent = GetUniqueDPathSet(uniqueSet, transitionTableResult, transition, epDepthLookup); //var subPath = new PredictionTreeBranch(path.Skip(minDepth).ToList(), path.Depth - minDepth, minDepth: path.MinDepth); tempDictionary.TryAdd(path, transition, Tuple.Create((from epDepth in transitionTableResult[transition] select epDepth.Item1).ToArray(), GetFollowDPathSet(transitionTableResult, transition, epDepthLookup))); } } var regrouping = (from ksvp in tempDictionary group new { Path = ksvp.Keys.Key1, Set = ksvp.Value } by ksvp.Keys.Key2).ToDictionary(k => k.Key, v => v.ToArray()); /* * foreach (var pathSet in from key in regrouping.Keys * let value = regrouping[key] * from r in value * select r.Set) * pathSet.Item2.FixAllPaths();//*/ var comparisons = (from key in regrouping.Keys let value = regrouping[key] let kRewrite = from r in value select r.Set let commonalities = PredictionTree.GetCompoundRightSideSimilarities(kRewrite) select new { Commonalities = commonalities, Transition = key }).ToDictionary(k => k.Transition, v => v.Commonalities); var resultDictionary = new MultikeyedDictionary <GrammarVocabulary, int, List <Tuple <Tuple <int[], PredictionTree>[], int[]> > >(); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ * Once we're done, we need to rebuild the paths with the MinDepth set to * * their current Depth. This is to ensure that it the PathSets don't try * * to reduce more than necessary. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Then we take that set and perform a right-hand-side comparison between * * the elements. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This will be used later to reduce the walking necessary to isolate the * * proper machine to use to disambiguate the look-ahead. * \ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **/ foreach (var comparison in comparisons.Keys) { var comparisonElements = comparisons[comparison]; foreach (var memberCount in comparisonElements.Keys) { var comparisonElement = comparisonElements[memberCount]; resultDictionary.Add(comparison, memberCount, comparisonElement); } } return(resultDictionary); }
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); }
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())); }
// GENERATED CODE EXAMPLE: The methods in this region generate // the for(;;) loop in this example and everything inside it, except // the calls to Match() which are generated by Visit(TerminalPred). // The generated code uses "goto" and "match" blocks in some cases // to avoid code duplication. This occurs when the matching code // requires multiple statements AND appears more than once in the // prediction tree. Otherwise, matching is done "inline" during // prediction. We generate a for(;;) loop for (...)*, and in certain // cases, we generates a do...while(false) loop for (...)?. // // rule Foo @{ (('a'|'A') 'A')* 'a'..'z' 'a'..'z' }; // public void Foo() // { // int la0, la1; // for (;;) { // la0 = LA(0); // if (la0 == 'a') { // la1 = LA(1); // if (la1 == 'A') // goto match1; // else // break; // } else if (la0 == 'A') // goto match1; // else // break; // match1: // { // Match('A', 'a'); // Match('A'); // } // } // MatchRange('a', 'z'); // MatchRange('a', 'z'); // } private void GenerateCodeForAlts(Alts alts, Dictionary <int, int> timesUsed, PredictionTree tree) { bool needError = LLPG.NeedsErrorBranch(tree, alts); if (!needError && alts.ErrorBranch != null) { LLPG.Output(Warning, alts, "The error branch will not be used because the other alternatives are exhaustive (cover all cases)"); } bool userDefinedError = needError && !_recognizerMode && alts.ErrorBranch != null && alts.ErrorBranch != DefaultErrorBranch.Value; // Generate matching code for each arm. the "string" in each pair // becomes non-null if the matching code for that branch needs to be // split out (separated) from the prediction tree because it appears // multiple times in the tree. The string is the goto-label name. Pair <LNode, string>[] matchingCode = new Pair <LNode, string> [alts.Arms.Count + (userDefinedError ? 1: 0)]; MSet <int> unreachable = new MSet <int>(); int separateCount = 0; for (int i = 0; i < alts.Arms.Count; i++) { if (!timesUsed.ContainsKey(i)) { unreachable.Add(i); continue; } var codeForThisArm = new WList <LNode>(); VisitWithNewTarget(alts.Arms[i], codeForThisArm); matchingCode[i].A = F.Braces(codeForThisArm.ToVList()); if (timesUsed[i] > 1 && !SimpleEnoughToRepeat(matchingCode[i].A)) { separateCount++; matchingCode[i].B = alts.Arms[i].ChooseGotoLabel() ?? "match" + (i + 1).ToString(); } } // Add matching code for the error branch, if present. Note: the // default error branch, which is produced by IPGCodeGenHelper. // ErrorBranch() is handled differently: default error code can // differ at each error point in the prediction tree. Therefore // we generate it later, on-demand. if (userDefinedError) { int i = alts.Arms.Count; var errorHandler = new WList <LNode>(); VisitWithNewTarget(alts.ErrorBranch, errorHandler); matchingCode[i].A = F.Braces(errorHandler.ToVList()); if (timesUsed[ErrorAlt] > 1 && !SimpleEnoughToRepeat(matchingCode[i].A)) { matchingCode[i].B = "error"; separateCount++; } } // Print unreachability warnings if (unreachable.Count == 1) { LLPG.Output(Warning, alts, string.Format("Branch {{{0}}} is unreachable.", alts.AltName(unreachable.First()))); } else if (unreachable.Count > 1) { LLPG.Output(Warning, alts, string.Format("Branches {{{0}}} are unreachable.", unreachable.Select(i => alts.AltName(i)).Join(", "))); } if (!timesUsed.ContainsKey(ExitAlt) && alts.Mode != LoopMode.None) { LLPG.Output(Warning, alts, "Infinite loop. The exit branch is unreachable."); } Symbol loopType = null; // Choose a loop type for (...)* or (...)?: if (alts.Mode == LoopMode.Star) { loopType = S.For; } else if (alts.Mode == LoopMode.Opt) { if (alts.HasErrorBranch(LLPG) || alts.NonExitDefaultArmRequested()) { loopType = S.DoWhile; } } // If the code for an arm is nontrivial and appears multiple times // in the prediction table, it will have to be split out into a // labeled block and reached via "goto". I'd rather just do a goto // from inside one "if" statement to inside another, but in C# // (unlike in CIL, and unlike in C) that is prohibited :( DeduplicateLabels(matchingCode); var extraMatching = GenerateExtraMatchingCode(matchingCode, separateCount, ref loopType); if (separateCount != 0) { loopType = loopType ?? S.DoWhile; } Symbol breakMode = loopType; // used to request a "goto" label in addition to the loop LNode code = GeneratePredictionTreeCode(tree, matchingCode, ref breakMode); // Add break/continue between prediction tree and extra matching code, // if necessary. if (extraMatching.Count != 0 && CodeGenHelperBase.EndMayBeReachable(code)) { loopType = loopType ?? S.DoWhile; extraMatching.Insert(0, GetContinueStmt(loopType)); } if (!extraMatching.IsEmpty) { code = LNode.MergeLists(code, F.Braces(extraMatching), S.Braces); } if (loopType == S.For) { // (...)* => for (;;) {} code = F.Call(S.For, F.List(), F.Missing, F.List(), code); } else if (loopType == S.DoWhile) { // (...)? becomes "do {...} while(false);" IF the exit branch is NOT the default. // If the exit branch is the default, then no loop and no "break" is needed. code = F.Call(S.DoWhile, code, F.@false); } if (breakMode != loopType && breakMode != null) { // Add "stop:" label (plus extra ";" for C# compatibility, in // case the label ends the block in which it is located.) var stopLabel = F.Call(S.Label, F.Id(breakMode)) .PlusTrailingTrivia(F.Trivia(S.TriviaRawText, ";")); code = LNode.MergeLists(code, stopLabel, S.Braces); } int oldCount = _target.Count; _target.SpliceAdd(code, S.Braces); // Add comment before code if (LLPG.AddComments) { var pos = alts.Basis.Range.Start; var comment = F.Trivia(S.TriviaSLComment, string.Format(" Line {0}: {1}", pos.Line, alts.ToString())); if (_target.Count > oldCount) { _target[oldCount] = _target[oldCount].PlusAttr(comment); } } }
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); }
public void addSon(PredictionTree son) { sons.Add(son); }
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 // snippet generator (CSG) 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 (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, switchCases, branchCode, code, laVar); } block.Add(code); return F.Braces(block.ToVList()); }
private LNode GenerateIfElseChain(PredictionTree tree, LNode[] branchCode, ref LNode laVar, MSet<int> switchCases) { // From the prediction table, generate a chain of if-else // statements in reverse, starting with the final "else" clause. // Skip any branches that have been claimed for use in a switch() LNode ifChain = null; bool usedTest = false; for (int i = tree.Children.Count - 1; i >= 0; i--) { if (switchCases.Contains(i)) continue; if (ifChain == null) ifChain = branchCode[i]; else { usedTest = true; var branch = tree.Children[i]; LNode test; if (tree.IsAssertionLevel) test = GenerateTest(branch.AndPreds, tree.Lookahead, laVar); else { var set = CGH.Optimize(branch.Set, branch.Covered); test = CGH.GenerateTest(set, laVar); } LNode @if = F.Call(S.If, test, branchCode[i]); if (!ifChain.IsIdWithoutPAttrs(S.Missing)) @if = @if.PlusArg(ifChain); ifChain = @if; } } if (!usedTest) laVar = null; // unnecessary return ifChain; }
/// <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 } } }