/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. * Use of this file is governed by the BSD 3-clause license that * can be found in the LICENSE.txt file in the project root. */ #pragma once #include "Recognizer.h" #include "atn/ATN.h" #include "atn/ATNState.h" namespace antlr4 { namespace atn { struct PredictionContextHasher; struct PredictionContextComparer; class PredictionContextMergeCache; typedef std::unordered_set, PredictionContextHasher, PredictionContextComparer> PredictionContextCache; class ANTLR4CPP_PUBLIC PredictionContext { public: /// Represents $ in local context prediction, which means wildcard. /// *+x = *. static const Ref EMPTY; /// Represents $ in an array in full context mode, when $ /// doesn't mean wildcard: $ + x = [$,x]. Here, /// $ = EMPTY_RETURN_STATE. // ml: originally Integer.MAX_VALUE, which would be -1 for us, but this is already used in places where // -1 is converted to unsigned, so we use a different value here. Any value does the job provided it doesn't // conflict with real return states. static const size_t EMPTY_RETURN_STATE = static_cast(-10); // std::numeric_limits::max() - 9; private: static const size_t INITIAL_HASH = 1; public: static size_t globalNodeCount; const size_t id; /// /// Stores the computed hash code of this . The hash /// code is computed in parts to match the following reference algorithm. /// ///
    ///  private int referenceHashCode() {
    ///      int hash = ();
    ///
    ///      for (int i = 0; i < ; i++) {
    ///          hash = (hash, (i));
    ///      }
    ///
    ///      for (int i = 0; i < ; i++) {
    ///          hash = (hash, (i));
    ///      }
    ///
    ///      hash = (hash, 2 * );
    ///      return hash;
    ///  }
    /// 
///
const size_t cachedHashCode; protected: PredictionContext(size_t cachedHashCode); ~PredictionContext(); public: /// Convert a RuleContext tree to a PredictionContext graph. /// Return EMPTY if outerContext is empty. static Ref fromRuleContext(const ATN &atn, RuleContext *outerContext); virtual size_t size() const = 0; virtual Ref getParent(size_t index) const = 0; virtual size_t getReturnState(size_t index) const = 0; virtual bool operator == (const PredictionContext &o) const = 0; /// This means only the EMPTY (wildcard? not sure) context is in set. virtual bool isEmpty() const; virtual bool hasEmptyPath() const; virtual size_t hashCode() const; protected: static size_t calculateEmptyHashCode(); static size_t calculateHashCode(Ref parent, size_t returnState); static size_t calculateHashCode(const std::vector> &parents, const std::vector &returnStates); public: // dispatch static Ref merge(const Ref &a, const Ref &b, bool rootIsWildcard, PredictionContextMergeCache *mergeCache); /// /// Merge two instances. /// ///

/// /// Stack tops equal, parents merge is same; return left graph.
/// /// ///

/// /// Same stack top, parents differ; merge parents giving array node, then /// remainders of those graphs. A new root node is created to point to the /// merged parents.
/// /// ///

/// /// Different stack tops pointing to same parent. Make array node for the /// root where both element in the root point to the same (original) /// parent.
/// /// ///

/// /// Different stack tops pointing to different parents. Make array node for /// the root where each element points to the corresponding original /// parent.
/// ///

/// the first /// the second /// {@code true} if this is a local-context merge, /// otherwise false to indicate a full-context merge /// static Ref mergeSingletons(const Ref &a, const Ref &b, bool rootIsWildcard, PredictionContextMergeCache *mergeCache); /** * Handle case where at least one of {@code a} or {@code b} is * {@link #EMPTY}. In the following diagrams, the symbol {@code $} is used * to represent {@link #EMPTY}. * *

Local-Context Merges

* *

These local-context merge operations are used when {@code rootIsWildcard} * is true.

* *

{@link #EMPTY} is superset of any graph; return {@link #EMPTY}.
*

* *

{@link #EMPTY} and anything is {@code #EMPTY}, so merged parent is * {@code #EMPTY}; return left graph.
*

* *

Special case of last merge if local context.
*

* *

Full-Context Merges

* *

These full-context merge operations are used when {@code rootIsWildcard} * is false.

* *

* *

Must keep all contexts; {@link #EMPTY} in array is a special value (and * null parent).
*

* *

* * @param a the first {@link SingletonPredictionContext} * @param b the second {@link SingletonPredictionContext} * @param rootIsWildcard {@code true} if this is a local-context merge, * otherwise false to indicate a full-context merge */ static Ref mergeRoot(const Ref &a, const Ref &b, bool rootIsWildcard); /** * Merge two {@link ArrayPredictionContext} instances. * *

Different tops, different parents.
*

* *

Shared top, same parents.
*

* *

Shared top, different parents.
*

* *

Shared top, all shared parents.
*

* *

Equal tops, merge parents and reduce top to * {@link SingletonPredictionContext}.
*

*/ static Ref mergeArrays(const Ref &a, const Ref &b, bool rootIsWildcard, PredictionContextMergeCache *mergeCache); protected: /// Make pass over all M parents; merge any equal() ones. /// @returns true if the list has been changed (i.e. duplicates where found). static bool combineCommonParents(std::vector> &parents); public: static std::string toDOTString(const Ref &context); static Ref getCachedContext(const Ref &context, PredictionContextCache &contextCache, std::map, Ref> &visited); // ter's recursive version of Sam's getAllNodes() static std::vector> getAllContextNodes(const Ref &context); static void getAllContextNodes_(const Ref &context, std::vector> &nodes, std::set &visited); virtual std::string toString() const; virtual std::string toString(Recognizer *recog) const; std::vector toStrings(Recognizer *recognizer, int currentState); std::vector toStrings(Recognizer *recognizer, const Ref &stop, int currentState); }; struct PredictionContextHasher { size_t operator () (const Ref &k) const { return k->hashCode(); } }; struct PredictionContextComparer { bool operator () (const Ref &lhs, const Ref &rhs) const { if (lhs == rhs) // Object identity. return true; return (lhs->hashCode() == rhs->hashCode()) && (*lhs == *rhs); } }; class PredictionContextMergeCache { public: Ref put(Ref const& key1, Ref const& key2, Ref const& value); Ref get(Ref const& key1, Ref const& key2); void clear(); std::string toString() const; size_t count() const; private: std::unordered_map, std::unordered_map, Ref, PredictionContextHasher, PredictionContextComparer>, PredictionContextHasher, PredictionContextComparer> _data; }; } // namespace atn } // namespace antlr4