예제 #1
0
        /**
         * Adding a new config means merging contexts with existing configs for
         * {@code (s, i, pi, _)}, where {@code s} is the
         * {@link ATNConfig#state}, {@code i} is the {@link ATNConfig#alt}, and
         * {@code pi} is the {@link ATNConfig#semanticContext}. We use
         * {@code (s,i,pi)} as key.
         *
         * <p>This method updates {@link #dipsIntoOuterContext} and
         * {@link #hasSemanticContext} when necessary.</p>
         */
        public bool Add(ATNConfig config, MergeCache mergeCache)
        {
            if (readOnly)
            {
                throw new Exception("This set is readonly");
            }
            if (config.semanticContext != SemanticContext.NONE)
            {
                hasSemanticContext = true;
            }
            if (config.OuterContextDepth > 0)
            {
                dipsIntoOuterContext = true;
            }
            ATNConfig existing = configLookup.GetOrAdd(config);

            if (existing == config)
            {                        // we added this new one
                cachedHashCode = -1;
                configs.Add(config); // track order here
                return(true);
            }
            // a previous (s,i,pi,_), merge with it and save result
            bool rootIsWildcard      = !fullCtx;
            PredictionContext merged = PredictionContext.Merge(existing.context, config.context, rootIsWildcard, mergeCache);

            // no need to check for existing.context, config.context in cache
            // since only way to create new graphs is "call rule" and here. We
            // cache at both places.
            existing.reachesIntoOuterContext = Math.Max(existing.reachesIntoOuterContext, config.reachesIntoOuterContext);

            // make sure to preserve the precedence filter suppression during the merge
            if (config.IsPrecedenceFilterSuppressed)
            {
                existing.SetPrecedenceFilterSuppressed(true);
            }

            existing.context = merged;             // replace context; no need to alt mapping
            return(true);
        }
예제 #2
0
        public virtual int AdaptivePredict(ITokenStream input, int decision,
								   ParserRuleContext outerContext)
        {
            if (debug || debug_list_atn_decisions)
            {
                Console.WriteLine("adaptivePredict decision " + decision +
                                       " exec LA(1)==" + GetLookaheadName(input) +
                                  " line " + input.LT(1).Line + ":" + input.LT(1).Column);
            }

            this.input = input;
            startIndex = input.Index;
            context = outerContext;
            DFA dfa = decisionToDFA[decision];
            thisDfa = dfa;

            int m = input.Mark();
            int index = startIndex;

            // Now we are certain to have a specific decision's DFA
            // But, do we still need an initial state?
            try
            {
                DFAState s0;
                if (dfa.IsPrecedenceDfa)
                {
                    // the start state for a precedence DFA depends on the current
                    // parser precedence, and is provided by a DFA method.
                    s0 = dfa.GetPrecedenceStartState(parser.Precedence);
                }
                else {
                    // the start state for a "regular" DFA is just s0
                    s0 = dfa.s0;
                }

                if (s0 == null)
                {
                    if (outerContext == null) outerContext = ParserRuleContext.EmptyContext;
                    if (debug || debug_list_atn_decisions)
                    {
                        Console.WriteLine("predictATN decision " + dfa.decision +
                                           " exec LA(1)==" + GetLookaheadName(input) +
                                           ", outerContext=" + outerContext.ToString(parser));
                    }

                    bool fullCtx = false;
                    ATNConfigSet s0_closure =
                        ComputeStartState(dfa.atnStartState,
                                          ParserRuleContext.EmptyContext,
                                          fullCtx);

                    if (dfa.IsPrecedenceDfa)
                    {
                        /* If this is a precedence DFA, we use applyPrecedenceFilter
                         * to convert the computed start state to a precedence start
                         * state. We then use DFA.setPrecedenceStartState to set the
                         * appropriate start state for the precedence level rather
                         * than simply setting DFA.s0.
                         */
                        dfa.s0.configSet = s0_closure; // not used for prediction but useful to know start configs anyway
                        s0_closure = ApplyPrecedenceFilter(s0_closure);
                        s0 = AddDFAState(dfa, new DFAState(s0_closure));
                        dfa.SetPrecedenceStartState(parser.Precedence, s0);
                    }
                    else {
                        s0 = AddDFAState(dfa, new DFAState(s0_closure));
                        dfa.s0 = s0;
                    }
                }

                int alt = ExecATN(dfa, s0, input, index, outerContext);
                if (debug)
                    Console.WriteLine("DFA after predictATN: " + dfa.ToString(parser.Vocabulary));
                return alt;
            }
            finally
            {
                mergeCache = null; // wack cache after each prediction
                thisDfa = null;
                input.Seek(index);
                input.Release(m);
            }
        }
예제 #3
0
        protected virtual ATNConfigSet ComputeReachSet(ATNConfigSet closure, int t, bool fullCtx)
        {
            if (debug)
                Console.WriteLine("in computeReachSet, starting closure: " + closure);

            if (mergeCache == null)
            {
                mergeCache = new MergeCache();
            }

            ATNConfigSet intermediate = new ATNConfigSet(fullCtx);

            /* Configurations already in a rule stop state indicate reaching the end
             * of the decision rule (local context) or end of the start rule (full
             * context). Once reached, these configurations are never updated by a
             * closure operation, so they are handled separately for the performance
             * advantage of having a smaller intermediate set when calling closure.
             *
             * For full-context reach operations, separate handling is required to
             * ensure that the alternative matching the longest overall sequence is
             * chosen when multiple such configurations can match the input.
             */
            List<ATNConfig> skippedStopStates = null;

            // First figure out where we can reach on input t
            foreach (ATNConfig c in closure.configs)
            {
                if (debug) Console.WriteLine("testing " + GetTokenName(t) + " at " + c.ToString());

                if (c.state is RuleStopState)
                {
                    if (fullCtx || t == IntStreamConstants.EOF)
                    {
                        if (skippedStopStates == null)
                        {
                            skippedStopStates = new List<ATNConfig>();
                        }

                        skippedStopStates.Add(c);
                    }

                    continue;
                }

                int n = c.state.NumberOfTransitions;
                for (int ti = 0; ti < n; ti++)
                {               // for each transition
                    Transition trans = c.state.Transition(ti);
                    ATNState target = GetReachableTarget(trans, t);
                    if (target != null)
                    {
                        intermediate.Add(new ATNConfig(c, target), mergeCache);
                    }
                }
            }

            // Now figure out where the reach operation can take us...

            ATNConfigSet reach = null;

            /* This block optimizes the reach operation for intermediate sets which
             * trivially indicate a termination state for the overall
             * adaptivePredict operation.
             *
             * The conditions assume that intermediate
             * contains all configurations relevant to the reach set, but this
             * condition is not true when one or more configurations have been
             * withheld in skippedStopStates, or when the current symbol is EOF.
             */
            if (skippedStopStates == null && t != TokenConstants.EOF)
            {
                if (intermediate.Count == 1)
                {
                    // Don't pursue the closure if there is just one state.
                    // It can only have one alternative; just add to result
                    // Also don't pursue the closure if there is unique alternative
                    // among the configurations.
                    reach = intermediate;
                }
                else if (GetUniqueAlt(intermediate) != ATN.INVALID_ALT_NUMBER)
                {
                    // Also don't pursue the closure if there is unique alternative
                    // among the configurations.
                    reach = intermediate;
                }
            }

            /* If the reach set could not be trivially determined, perform a closure
             * operation on the intermediate set to compute its initial value.
             */
            if (reach == null)
            {
                reach = new ATNConfigSet(fullCtx);
                HashSet<ATNConfig> closureBusy = new HashSet<ATNConfig>();
                bool treatEofAsEpsilon = t == TokenConstants.EOF;
                foreach (ATNConfig c in intermediate.configs)
                {
                    Closure(c, reach, closureBusy, false, fullCtx, treatEofAsEpsilon);
                }
            }

            if (t == IntStreamConstants.EOF)
            {
                /* After consuming EOF no additional input is possible, so we are
                 * only interested in configurations which reached the end of the
                 * decision rule (local context) or end of the start rule (full
                 * context). Update reach to contain only these configurations. This
                 * handles both explicit EOF transitions in the grammar and implicit
                 * EOF transitions following the end of the decision or start rule.
                 *
                 * When reach==intermediate, no closure operation was performed. In
                 * this case, removeAllConfigsNotInRuleStopState needs to check for
                 * reachable rule stop states as well as configurations already in
                 * a rule stop state.
                 *
                 * This is handled before the configurations in skippedStopStates,
                 * because any configurations potentially added from that list are
                 * already guaranteed to meet this condition whether or not it's
                 * required.
                 */
                reach = RemoveAllConfigsNotInRuleStopState(reach, reach == intermediate);
            }

            /* If skippedStopStates is not null, then it contains at least one
             * configuration. For full-context reach operations, these
             * configurations reached the end of the start rule, in which case we
             * only add them back to reach if no configuration during the current
             * closure operation reached such a state. This ensures adaptivePredict
             * chooses an alternative matching the longest overall sequence when
             * multiple alternatives are viable.
             */
            if (skippedStopStates != null && (!fullCtx || !PredictionMode.HasConfigInRuleStopState(reach.configs)))
            {
                foreach (ATNConfig c in skippedStopStates)
                {
                    reach.Add(c, mergeCache);
                }
            }

            if (reach.Empty)
                return null;
            return reach;
        }
예제 #4
0
        public static PredictionContext MergeArrays(
            ArrayPredictionContext a,
            ArrayPredictionContext b,
            bool rootIsWildcard,
            MergeCache mergeCache)
        {
            if (mergeCache != null)
            {
                PredictionContext previous = mergeCache.Get(a, b);
                if (previous != null)
                {
                    return(previous);
                }
                previous = mergeCache.Get(b, a);
                if (previous != null)
                {
                    return(previous);
                }
            }

            // merge sorted payloads a + b => M
            int i = 0;             // walks a
            int j = 0;             // walks b
            int k = 0;             // walks target M array

            int[] mergedReturnStates =
                new int[a.returnStates.Length + b.returnStates.Length];
            PredictionContext[] mergedParents =
                new PredictionContext[a.returnStates.Length + b.returnStates.Length];
            // walk and merge to yield mergedParents, mergedReturnStates
            while (i < a.returnStates.Length && j < b.returnStates.Length)
            {
                PredictionContext a_parent = a.parents[i];
                PredictionContext b_parent = b.parents[j];
                if (a.returnStates[i] == b.returnStates[j])
                {
                    // same payload (stack tops are equal), must yield merged singleton
                    int payload = a.returnStates[i];
                    // $+$ = $
                    bool both_dollar = payload == EMPTY_RETURN_STATE &&
                                       a_parent == null && b_parent == null;
                    bool ax_ax = (a_parent != null && b_parent != null) &&
                                 a_parent.Equals(b_parent);                                        // ax+ax -> ax
                    if (both_dollar || ax_ax)
                    {
                        mergedParents[k]      = a_parent;                    // choose left
                        mergedReturnStates[k] = payload;
                    }
                    else               // ax+ay -> a'[x,y]
                    {
                        PredictionContext mergedParent =
                            Merge(a_parent, b_parent, rootIsWildcard, mergeCache);
                        mergedParents[k]      = mergedParent;
                        mergedReturnStates[k] = payload;
                    }
                    i++;                     // hop over left one as usual
                    j++;                     // but also skip one in right side since we merge
                }
                else if (a.returnStates[i] < b.returnStates[j])
                {                 // copy a[i] to M
                    mergedParents[k]      = a_parent;
                    mergedReturnStates[k] = a.returnStates[i];
                    i++;
                }
                else                   // b > a, copy b[j] to M
                {
                    mergedParents[k]      = b_parent;
                    mergedReturnStates[k] = b.returnStates[j];
                    j++;
                }
                k++;
            }

            // copy over any payloads remaining in either array
            if (i < a.returnStates.Length)
            {
                for (int p = i; p < a.returnStates.Length; p++)
                {
                    mergedParents[k]      = a.parents[p];
                    mergedReturnStates[k] = a.returnStates[p];
                    k++;
                }
            }
            else
            {
                for (int p = j; p < b.returnStates.Length; p++)
                {
                    mergedParents[k]      = b.parents[p];
                    mergedReturnStates[k] = b.returnStates[p];
                    k++;
                }
            }

            // trim merged if we combined a few that had same stack tops
            if (k < mergedParents.Length)
            {             // write index < last position; trim
                if (k == 1)
                {         // for just one merged element, return singleton top
                    PredictionContext a_ = SingletonPredictionContext.Create(mergedParents[0], mergedReturnStates[0]);
                    if (mergeCache != null)
                    {
                        mergeCache.Put(a, b, a_);
                    }
                    return(a_);
                }
                mergedParents      = Arrays.CopyOf(mergedParents, k);
                mergedReturnStates = Arrays.CopyOf(mergedReturnStates, k);
            }

            PredictionContext M = new ArrayPredictionContext(mergedParents, mergedReturnStates);

            // if we created same array as a or b, return that instead
            // TODO: track whether this is possible above during merge sort for speed
            if (M.Equals(a))
            {
                if (mergeCache != null)
                {
                    mergeCache.Put(a, b, a);
                }
                return(a);
            }
            if (M.Equals(b))
            {
                if (mergeCache != null)
                {
                    mergeCache.Put(a, b, b);
                }
                return(b);
            }

            CombineCommonParents(mergedParents);

            if (mergeCache != null)
            {
                mergeCache.Put(a, b, M);
            }
            return(M);
        }
예제 #5
0
        public static PredictionContext MergeSingletons(
            SingletonPredictionContext a,
            SingletonPredictionContext b,
            bool rootIsWildcard,
            MergeCache mergeCache)
        {
            if (mergeCache != null)
            {
                PredictionContext previous = mergeCache.Get(a, b);
                if (previous != null)
                {
                    return(previous);
                }
                previous = mergeCache.Get(b, a);
                if (previous != null)
                {
                    return(previous);
                }
            }

            PredictionContext rootMerge = MergeRoot(a, b, rootIsWildcard);

            if (rootMerge != null)
            {
                if (mergeCache != null)
                {
                    mergeCache.Put(a, b, rootMerge);
                }
                return(rootMerge);
            }

            if (a.returnState == b.returnState)
            {             // a == b
                PredictionContext parent = Merge(a.parent, b.parent, rootIsWildcard, mergeCache);
                // if parent is same as existing a or b parent or reduced to a parent, return it
                if (parent == a.parent)
                {
                    return(a);                                    // ax + bx = ax, if a=b
                }
                if (parent == b.parent)
                {
                    return(b);                                    // ax + bx = bx, if a=b
                }
                // else: ax + ay = a'[x,y]
                // merge parents x and y, giving array node with x,y then remainders
                // of those graphs.  dup a, a' points at merged array
                // new joined parent so create new singleton pointing to it, a'
                PredictionContext a_ = SingletonPredictionContext.Create(parent, a.returnState);
                if (mergeCache != null)
                {
                    mergeCache.Put(a, b, a_);
                }
                return(a_);
            }
            else               // a != b payloads differ
            // see if we can collapse parents due to $+x parents if local ctx
            {
                int[] payloads = new int[2];
                PredictionContext[] parents = new PredictionContext[2];
                PredictionContext   pc;
                PredictionContext   singleParent = null;
                if (a == b || (a.parent != null && a.parent.Equals(b.parent)))
                {                 // ax + bx = [a,b]x
                    singleParent = a.parent;
                }
                if (singleParent != null)
                {                   // parents are same
                    // sort payloads and use same parent
                    if (a.returnState > b.returnState)
                    {
                        payloads[0] = b.returnState;
                        payloads[1] = a.returnState;
                    }
                    else
                    {
                        payloads[0] = a.returnState;
                        payloads[1] = b.returnState;
                    }
                    parents[0] = singleParent;
                    parents[1] = singleParent;
                    pc         = new ArrayPredictionContext(parents, payloads);
                    if (mergeCache != null)
                    {
                        mergeCache.Put(a, b, pc);
                    }
                    return(pc);
                }
                // parents differ and can't merge them. Just pack together
                // into array; can't merge.
                // ax + by = [ax,by]
                // sort by payload
                if (a.returnState > b.returnState)
                {
                    payloads[0] = b.returnState;
                    payloads[1] = a.returnState;
                    parents[0]  = b.parent;
                    parents[1]  = a.parent;
                }
                else
                {
                    payloads[0] = a.returnState;
                    payloads[1] = b.returnState;
                    parents[0]  = a.parent;
                    parents[1]  = b.parent;
                }
                pc = new ArrayPredictionContext(parents, payloads);
                if (mergeCache != null)
                {
                    mergeCache.Put(a, b, pc);
                }
                return(pc);
            }
        }
예제 #6
0
        internal static PredictionContext Merge(PredictionContext a, PredictionContext b, bool rootIsWildcard, MergeCache mergeCache)
        {
            if (a == b || a.Equals(b))
            {
                return(a);
            }
            if (a is SingletonPredictionContext && b is SingletonPredictionContext)
            {
                return(MergeSingletons((SingletonPredictionContext)a,
                                       (SingletonPredictionContext)b,
                                       rootIsWildcard, mergeCache));
            }

            // At least one of a or b is array
            // If one is $ and rootIsWildcard, return $ as * wildcard
            if (rootIsWildcard)
            {
                if (a is EmptyPredictionContext)
                {
                    return(a);
                }
                if (b is EmptyPredictionContext)
                {
                    return(b);
                }
            }

            // convert singleton so both are arrays to normalize
            if (a is SingletonPredictionContext)
            {
                a = new ArrayPredictionContext((SingletonPredictionContext)a);
            }
            if (b is SingletonPredictionContext)
            {
                b = new ArrayPredictionContext((SingletonPredictionContext)b);
            }
            return(MergeArrays((ArrayPredictionContext)a, (ArrayPredictionContext)b,
                               rootIsWildcard, mergeCache));
        }