コード例 #1
0
ファイル: AlphaBeta.cs プロジェクト: pi-aire/pom
    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);
    }
コード例 #2
0
 /// <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);
 }
コード例 #3
0
            /// <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);
            }
コード例 #4
0
        /// <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);
        }
コード例 #5
0
        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);
        }
コード例 #6
0
        /// <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.
             * */
        }
コード例 #7
0
            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);
            }
コード例 #8
0
        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);
            }
        }
コード例 #9
0
ファイル: AlphaBetaMemory.cs プロジェクト: pi-aire/pom
    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);
    }
コード例 #10
0
ファイル: AlphaBeta.cs プロジェクト: pi-aire/pom
 // 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);
     }
 }
コード例 #11
0
			// 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);
				}
			}
コード例 #12
0
ファイル: AnalysisVisitors.cs プロジェクト: qwertie/ecsharp
			/// <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;
			}
コード例 #13
0
 /// <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);
 }
コード例 #14
0
ファイル: AnalysisVisitors.cs プロジェクト: qwertie/ecsharp
			/// <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
					}
				}
			}
コード例 #15
0
        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);
        }
コード例 #16
0
            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);
            }
コード例 #17
0
            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()));
            }
コード例 #18
0
            // 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);
                    }
                }
            }
コード例 #19
0
ファイル: AnalysisVisitors.cs プロジェクト: qwertie/ecsharp
			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);
			}
コード例 #20
0
ファイル: PredictionTree.cs プロジェクト: pi-aire/pom
 public void addSon(PredictionTree son)
 {
     sons.Add(son);
 }
コード例 #21
0
			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());
			}
コード例 #22
0
			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;
			}
コード例 #23
0
            /// <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
                    }
                }
            }