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;
}