/** Walk each configuration and if they are all the same alt, return * that alt else return NFA.INVALID_ALT_NUMBER. Ignore resolved * configurations, but don't ignore resolveWithPredicate configs * because this state should not be an accept state. We need to add * this to the work list and then have semantic predicate edges * emanating from it. */ public virtual int GetUniquelyPredictedAlt() { if (cachedUniquelyPredicatedAlt != PREDICTED_ALT_UNSET) { return(cachedUniquelyPredicatedAlt); } int alt = NFA.INVALID_ALT_NUMBER; int numConfigs = nfaConfigurations.Size(); for (int i = 0; i < numConfigs; i++) { NFAConfiguration configuration = (NFAConfiguration)nfaConfigurations.Get(i); // ignore anything we resolved; predicates will still result // in transitions out of this state, so must count those // configurations; i.e., don't ignore resolveWithPredicate configs if (configuration.resolved) { continue; } if (alt == NFA.INVALID_ALT_NUMBER) { alt = configuration.alt; // found first nonresolved alt } else if (configuration.alt != alt) { return(NFA.INVALID_ALT_NUMBER); } } this.cachedUniquelyPredicatedAlt = alt; return(alt); }
/** Walk each configuration and if they are all the same alt, return * that alt else return NFA.INVALID_ALT_NUMBER. Ignore resolved * configurations, but don't ignore resolveWithPredicate configs * because this state should not be an accept state. We need to add * this to the work list and then have semantic predicate edges * emanating from it. */ public virtual int GetUniquelyPredictedAlt() { if (_cachedUniquelyPredicatedAlt.HasValue) { return(_cachedUniquelyPredicatedAlt.Value); } int alt = NFA.INVALID_ALT_NUMBER; int numConfigs = _nfaConfigurations.Count; for (int i = 0; i < numConfigs; i++) { NFAConfiguration configuration = _nfaConfigurations[i]; // ignore anything we resolved; predicates will still result // in transitions out of this state, so must count those // configurations; i.e., don't ignore resolveWithPredicate configs if (configuration.Resolved) { continue; } if (alt == NFA.INVALID_ALT_NUMBER) { alt = configuration.Alt; // found first nonresolved alt } else if (configuration.Alt != alt) { return(NFA.INVALID_ALT_NUMBER); } } this._cachedUniquelyPredicatedAlt = alt; return(alt); }
public virtual NFAConfiguration AddNFAConfiguration(NFAState state, int alt, NFAContext context, SemanticContext semanticContext) { NFAConfiguration c = new NFAConfiguration(state.StateNumber, alt, context, semanticContext); AddNFAConfiguration(state, c); return(c); }
/** An NFA configuration is equal to another if both have * the same state, the predict the same alternative, and * syntactic/semantic contexts are the same. I don't think * the state|alt|ctx could be the same and have two different * semantic contexts, but might as well define equals to be * everything. */ public override bool Equals(object o) { if (o == null) { return(false); } NFAConfiguration other = (NFAConfiguration)o; return(this.state == other.state && this.alt == other.alt && this.context.Equals(other.context) && this.semanticContext.Equals(other.semanticContext)); }
/** When more than one alternative can match the same input, the first * alternative is chosen to resolve the conflict. The other alts * are "turned off" by setting the "resolved" flag in the NFA * configurations. Return the set of disabled alternatives. For * * a : A | A | A ; * * this method returns {2,3} as disabled. This does not mean that * the alternative is totally unreachable, it just means that for this * DFA state, that alt is disabled. There may be other accept states * for that alt. */ public virtual ICollection <int> GetDisabledAlternatives() { HashSet <int> disabled = new HashSet <int>(); int numConfigs = nfaConfigurations.Size(); for (int i = 0; i < numConfigs; i++) { NFAConfiguration configuration = (NFAConfiguration)nfaConfigurations.Get(i); if (configuration.resolved) { disabled.Add(configuration.alt); } } return(disabled); }
public virtual void ReportRecursionOverflow(DFAState d, NFAConfiguration recursionNFAConfiguration) { // track the state number rather than the state as d will change // out from underneath us; hash wouldn't return any value // left-recursion is detected in start state. Since we can't // call resolveNondeterminism() on the start state (it would // not look k=1 to get min single token lookahead), we must // prevent errors derived from this state. Avoid start state if (d.stateNumber > 0) { int stateI = d.stateNumber; _stateToRecursionOverflowConfigurationsMap.Map(stateI, recursionNFAConfiguration); } }
/** Get the set of all alts mentioned by all NFA configurations in this * DFA state. */ public virtual HashSet <int> GetAltSet() { int numConfigs = nfaConfigurations.Size(); HashSet <int> alts = new HashSet <int>(); for (int i = 0; i < numConfigs; i++) { NFAConfiguration configuration = (NFAConfiguration)nfaConfigurations.Get(i); alts.Add(configuration.alt); } if (alts.Count == 0) { return(null); } return(alts); }
/** Print all NFA states plus what alts they predict */ public override String ToString() { StringBuilder buf = new StringBuilder(); buf.Append(StateNumber + ":{"); for (int i = 0; i < _nfaConfigurations.Count; i++) { NFAConfiguration configuration = (NFAConfiguration)_nfaConfigurations[i]; if (i > 0) { buf.Append(", "); } buf.Append(configuration); } buf.Append("}"); return(buf.ToString()); }
/** Print all NFA states plus what alts they predict */ public override String ToString() { StringBuilder buf = new StringBuilder(); buf.Append(stateNumber + ":{"); for (int i = 0; i < nfaConfigurations.Size(); i++) { NFAConfiguration configuration = (NFAConfiguration)nfaConfigurations.Get(i); if (i > 0) { buf.Append(", "); } buf.Append(configuration); } buf.Append("}"); return(buf.ToString()); }
/** Add an NFA configuration to this DFA node. Add uniquely * an NFA state/alt/syntactic&semantic context (chain of invoking state(s) * and semantic predicate contexts). * * I don't see how there could be two configurations with same * state|alt|synCtx and different semantic contexts because the * semantic contexts are computed along the path to a particular state * so those two configurations would have to have the same predicate. * Nonetheless, the addition of configurations is unique on all * configuration info. I guess I'm saying that syntactic context * implies semantic context as the latter is computed according to the * former. * * As we add configurations to this DFA state, track the set of all possible * transition labels so we can simply walk it later rather than doing a * loop over all possible labels in the NFA. */ public virtual void AddNFAConfiguration(NFAState state, NFAConfiguration c) { if (_nfaConfigurations.Contains(c)) { return; } _nfaConfigurations.Add(c); // track min alt rather than compute later if (c.Alt < _minAltInConfigurations) { _minAltInConfigurations = c.Alt; } if (c.SemanticContext != SemanticContext.EmptySemanticContext) { _atLeastOneConfigurationHasAPredicate = true; } // update hashCode; for some reason using context.hashCode() also // makes the GC take like 70% of the CPU and is slow! _cachedHashCode += c.State + c.Alt; // update reachableLabels // We're adding an NFA state; check to see if it has a non-epsilon edge if (state.transition[0] != null) { Label label = state.transition[0].Label; if (!(label.IsEpsilon || label.IsSemanticPredicate)) { // this NFA state has a non-epsilon edge, track for fast // walking later when we do reach on this DFA state we're // building. _configurationsWithLabeledEdges.Add(c); if (state.transition[1] == null) { // later we can check this to ignore o-A->o states in closure c.SingleAtomTransitionEmanating = true; } AddReachableLabel(label); } } }
/** Return the uniquely mentioned alt from the NFA configurations; * Ignore the resolved bit etc... Return INVALID_ALT_NUMBER * if there is more than one alt mentioned. */ public virtual int GetUniqueAlt() { int alt = NFA.INVALID_ALT_NUMBER; int numConfigs = _nfaConfigurations.Count; for (int i = 0; i < numConfigs; i++) { NFAConfiguration configuration = _nfaConfigurations[i]; if (alt == NFA.INVALID_ALT_NUMBER) { alt = configuration.Alt; // found first alt } else if (configuration.Alt != alt) { return(NFA.INVALID_ALT_NUMBER); } } return(alt); }
private void ComputeAltToProblemMaps(IEnumerable <int> dfaStatesUnaliased, IDictionary <int, IList <NFAConfiguration> > configurationsMap, IDictionary <int, IDictionary <string, ICollection <NFAState> > > altToTargetToCallSitesMap, IDictionary <int, DFAState> altToDFAState) { foreach (int stateI in dfaStatesUnaliased) { // walk this DFA's config list IList <NFAConfiguration> configs; configurationsMap.TryGetValue(stateI, out configs); for (int i = 0; i < configs.Count; i++) { NFAConfiguration c = (NFAConfiguration)configs[i]; NFAState ruleInvocationState = _dfa.Nfa.GetState(c.State); Transition transition0 = ruleInvocationState.transition[0]; RuleClosureTransition @ref = (RuleClosureTransition)transition0; string targetRule = ((NFAState)@ref.Target).enclosingRule.Name; int altI = c.Alt; IDictionary <string, ICollection <NFAState> > targetToCallSiteMap; altToTargetToCallSitesMap.TryGetValue(altI, out targetToCallSiteMap); if (targetToCallSiteMap == null) { targetToCallSiteMap = new Dictionary <string, ICollection <NFAState> >(); altToTargetToCallSitesMap[altI] = targetToCallSiteMap; } ICollection <NFAState> callSites; targetToCallSiteMap.TryGetValue(targetRule, out callSites); if (callSites == null) { callSites = new HashSet <NFAState>(); targetToCallSiteMap[targetRule] = callSites; } callSites.Add(ruleInvocationState); // track one problem DFA state per alt DFAState state; if (!altToDFAState.TryGetValue(altI, out state) || state == null) { DFAState sampleBadState = _dfa.GetState(stateI); altToDFAState[altI] = sampleBadState; } } } }
/** For gated productions, we need an OR'd list of all predicates for the * target of an edge so we can gate the edge based upon the predicates * associated with taking that path (if any). * * For syntactic predicates, we only want to generate predicate * evaluations as it transitions to an accept state; waste to * do it earlier. So, only add gated preds derived from manually- * specified syntactic predicates if this is an accept state. * * Also, since configurations w/o gated predicates are like true * gated predicates, finding a configuration whose alt has no gated * predicate implies we should evaluate the predicate to true. This * means the whole edge has to be ungated. Consider: * * X : ('a' | {p}?=> 'a') * | 'a' 'b' * ; * * Here, you 'a' gets you from s0 to s1 but you can't test p because * plain 'a' is ok. It's also ok for starting alt 2. Hence, you can't * test p. Even on the edge going to accept state for alt 1 of X, you * can't test p. You can get to the same place with and w/o the context. * Therefore, it is never ok to test p in this situation. * * TODO: cache this as it's called a lot; or at least set bit if >1 present in state */ public virtual SemanticContext GetGatedPredicatesInNFAConfigurations() { SemanticContext unionOfPredicatesFromAllAlts = null; int numConfigs = _nfaConfigurations.Count; for (int i = 0; i < numConfigs; i++) { NFAConfiguration configuration = (NFAConfiguration)_nfaConfigurations[i]; SemanticContext gatedPredExpr = configuration.SemanticContext.GatedPredicateContext; if (gatedPredExpr == null) { // if we ever find a configuration w/o a gated predicate // (even if it's a nongated predicate), we cannot gate // the indident edges. return(null); } else if (IsAcceptState || !configuration.SemanticContext.IsSyntacticPredicate) { // at this point we have a gated predicate and, due to elseif, // we know it's an accept or not a syn pred. In this case, // it's safe to add the gated predicate to the union. We // only want to add syn preds if it's an accept state. Other // gated preds can be used with edges leading to accept states. if (unionOfPredicatesFromAllAlts == null) { unionOfPredicatesFromAllAlts = gatedPredExpr; } else { unionOfPredicatesFromAllAlts = SemanticContext.Or(unionOfPredicatesFromAllAlts, gatedPredExpr); } } } if (unionOfPredicatesFromAllAlts is SemanticContext.TruePredicate) { return(null); } return(unionOfPredicatesFromAllAlts); }
public virtual HashSet <SemanticContext> GetGatedSyntacticPredicatesInNFAConfigurations() { int numConfigs = _nfaConfigurations.Count; HashSet <SemanticContext> synpreds = new HashSet <SemanticContext>(); for (int i = 0; i < numConfigs; i++) { NFAConfiguration configuration = (NFAConfiguration)_nfaConfigurations[i]; SemanticContext gatedPredExpr = configuration.SemanticContext.GatedPredicateContext; // if this is a manual syn pred (gated and syn pred), add if (gatedPredExpr != null && configuration.SemanticContext.IsSyntacticPredicate) { synpreds.Add(configuration.SemanticContext); } } if (synpreds.Count == 0) { return(null); } return(synpreds); }
/** Walk each NFA configuration in this DFA state looking for a conflict * where (s|i|ctx) and (s|j|ctx) exist, indicating that state s with * context conflicting ctx predicts alts i and j. Return an Integer set * of the alternative numbers that conflict. Two contexts conflict if * they are equal or one is a stack suffix of the other or one is * the empty context. * * Use a hash table to record the lists of configs for each state * as they are encountered. We need only consider states for which * there is more than one configuration. The configurations' predicted * alt must be different or must have different contexts to avoid a * conflict. * * Don't report conflicts for DFA states that have conflicting Tokens * rule NFA states; they will be resolved in favor of the first rule. */ protected virtual HashSet <int> GetConflictingAlts() { // TODO this is called multiple times: cache result? //[email protected]("getNondetAlts for DFA state "+stateNumber); HashSet <int> nondeterministicAlts = new HashSet <int>(); // If only 1 NFA conf then no way it can be nondeterministic; // save the overhead. There are many o-a->o NFA transitions // and so we save a hash map and iterator creation for each // state. int numConfigs = _nfaConfigurations.Count; if (numConfigs <= 1) { return(null); } // First get a list of configurations for each state. // Most of the time, each state will have one associated configuration. MultiMap <int, NFAConfiguration> stateToConfigListMap = new MultiMap <int, NFAConfiguration>(); for (int i = 0; i < numConfigs; i++) { NFAConfiguration configuration = (NFAConfiguration)_nfaConfigurations[i]; int stateI = configuration.State; stateToConfigListMap.Map(stateI, configuration); } // potential conflicts are states with > 1 configuration and diff alts ICollection <int> states = stateToConfigListMap.Keys.ToArray(); int numPotentialConflicts = 0; foreach (int stateI in states) { bool thisStateHasPotentialProblem = false; IList <NFAConfiguration> configsForState; stateToConfigListMap.TryGetValue(stateI, out configsForState); int alt = 0; int numConfigsForState = configsForState.Count; for (int i = 0; i < numConfigsForState && numConfigsForState > 1; i++) { NFAConfiguration c = (NFAConfiguration)configsForState[i]; if (alt == 0) { alt = c.Alt; } else if (c.Alt != alt) { /* * [email protected]("potential conflict in state "+stateI+ * " configs: "+configsForState); */ // 11/28/2005: don't report closures that pinch back // together in Tokens rule. We want to silently resolve // to the first token definition ala lex/flex by ignoring // these conflicts. // Also this ensures that lexers look for more and more // characters (longest match) before resorting to predicates. // TestSemanticPredicates.testLexerMatchesLongestThenTestPred() // for example would terminate at state s1 and test predicate // meaning input "ab" would test preds to decide what to // do but it should match rule C w/o testing preds. if (dfa.Nfa.Grammar.type != GrammarType.Lexer || !dfa.NFADecisionStartState.enclosingRule.Name.Equals(Grammar.ArtificialTokensRuleName)) { numPotentialConflicts++; thisStateHasPotentialProblem = true; } } } if (!thisStateHasPotentialProblem) { // remove NFA state's configurations from // further checking; no issues with it // (can't remove as it's concurrent modification; set to null) stateToConfigListMap[stateI] = null; } } // a fast check for potential issues; most states have none if (numPotentialConflicts == 0) { return(null); } // we have a potential problem, so now go through config lists again // looking for different alts (only states with potential issues // are left in the states set). Now we will check context. // For example, the list of configs for NFA state 3 in some DFA // state might be: // [3|2|[28 18 $], 3|1|[28 $], 3|1, 3|2] // I want to create a map from context to alts looking for overlap: // [28 18 $] -> 2 // [28 $] -> 1 // [$] -> 1,2 // Indeed a conflict exists as same state 3, same context [$], predicts // alts 1 and 2. // walk each state with potential conflicting configurations foreach (int stateI in states) { IList <NFAConfiguration> configsForState; stateToConfigListMap.TryGetValue(stateI, out configsForState); // compare each configuration pair s, t to ensure: // s.ctx different than t.ctx if s.alt != t.alt int numConfigsForState = 0; if (configsForState != null) { numConfigsForState = configsForState.Count; } for (int i = 0; i < numConfigsForState; i++) { NFAConfiguration s = configsForState[i]; for (int j = i + 1; j < numConfigsForState; j++) { NFAConfiguration t = configsForState[j]; // conflicts means s.ctx==t.ctx or s.ctx is a stack // suffix of t.ctx or vice versa (if alts differ). // Also a conflict if s.ctx or t.ctx is empty if (s.Alt != t.Alt && s.Context.ConflictsWith(t.Context)) { nondeterministicAlts.Add(s.Alt); nondeterministicAlts.Add(t.Alt); } } } } if (nondeterministicAlts.Count == 0) { return(null); } return(nondeterministicAlts); }
public AnalysisRecursionOverflowException(DFAState ovfState, NFAConfiguration proposedNFAConfiguration) { _ovfState = ovfState; _proposedNFAConfiguration = proposedNFAConfiguration; }