1/*
2 * [The "BSD license"]
3 *  Copyright (c) 2010 Terence Parr
4 *  All rights reserved.
5 *
6 *  Redistribution and use in source and binary forms, with or without
7 *  modification, are permitted provided that the following conditions
8 *  are met:
9 *  1. Redistributions of source code must retain the above copyright
10 *      notice, this list of conditions and the following disclaimer.
11 *  2. Redistributions in binary form must reproduce the above copyright
12 *      notice, this list of conditions and the following disclaimer in the
13 *      documentation and/or other materials provided with the distribution.
14 *  3. The name of the author may not be used to endorse or promote products
15 *      derived from this software without specific prior written permission.
16 *
17 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28package org.antlr.analysis;
29
30import org.antlr.grammar.v3.ANTLRParser;
31import org.antlr.misc.MultiMap;
32import org.antlr.misc.Utils;
33import org.antlr.runtime.Token;
34import org.antlr.tool.ErrorManager;
35import org.antlr.tool.Grammar;
36import org.antlr.tool.GrammarAST;
37
38import java.util.*;
39
40/** Collection of information about what is wrong with a decision as
41 *  discovered while building the DFA predictor.
42 *
43 *  The information is collected during NFA->DFA conversion and, while
44 *  some of this is available elsewhere, it is nice to have it all tracked
45 *  in one spot so a great error message can be easily had.  I also like
46 *  the fact that this object tracks it all for later perusing to make an
47 *  excellent error message instead of lots of imprecise on-the-fly warnings
48 *  (during conversion).
49 *
50 *  A decision normally only has one problem; e.g., some input sequence
51 *  can be matched by multiple alternatives.  Unfortunately, some decisions
52 *  such as
53 *
54 *  a : ( A | B ) | ( A | B ) | A ;
55 *
56 *  have multiple problems.  So in general, you should approach a decision
57 *  as having multiple flaws each one uniquely identified by a DFAState.
58 *  For example, statesWithSyntacticallyAmbiguousAltsSet tracks the set of
59 *  all DFAStates where ANTLR has discovered a problem.  Recall that a decision
60 *  is represented internall with a DFA comprised of multiple states, each of
61 *  which could potentially have problems.
62 *
63 *  Because of this, you need to iterate over this list of DFA states.  You'll
64 *  note that most of the informational methods like
65 *  getSampleNonDeterministicInputSequence() require a DFAState.  This state
66 *  will be one of the iterated states from stateToSyntacticallyAmbiguousAltsSet.
67 *
68 *  This class is not thread safe due to shared use of visited maps etc...
69 *  Only one thread should really need to access one DecisionProbe anyway.
70 */
71public class DecisionProbe {
72	public DFA dfa;
73
74	/** Track all DFA states with nondeterministic alternatives.
75	 *  By reaching the same DFA state, a path through the NFA for some input
76	 *  is able to reach the same NFA state by starting at more than one
77	 *  alternative's left edge.  Though, later, we may find that predicates
78	 *  resolve the issue, but track info anyway.
79	 *  Note that from the DFA state, you can ask for
80	 *  which alts are nondeterministic.
81	 */
82	protected Set<DFAState> statesWithSyntacticallyAmbiguousAltsSet = new HashSet<DFAState>();
83
84	/** Track just like stateToSyntacticallyAmbiguousAltsMap, but only
85	 *  for nondeterminisms that arise in the Tokens rule such as keyword vs
86	 *  ID rule.  The state maps to the list of Tokens rule alts that are
87	 *  in conflict.
88	 */
89	protected Map<DFAState, Set<Integer>> stateToSyntacticallyAmbiguousTokensRuleAltsMap =
90		new HashMap<DFAState, Set<Integer>>();
91
92	/** Was a syntactic ambiguity resolved with predicates?  Any DFA
93	 *  state that predicts more than one alternative, must be resolved
94	 *  with predicates or it should be reported to the user.
95	 */
96	protected Set<DFAState> statesResolvedWithSemanticPredicatesSet = new HashSet<DFAState>();
97
98	/** Track the predicates for each alt per DFA state;
99	 *  more than one DFA state might have syntactically ambig alt prediction.
100	 *  Maps DFA state to another map, mapping alt number to a
101	 *  SemanticContext (pred(s) to execute to resolve syntactic ambiguity).
102	 */
103	protected Map<DFAState, Map<Integer,SemanticContext>> stateToAltSetWithSemanticPredicatesMap =
104		new HashMap<DFAState, Map<Integer,SemanticContext>>();
105
106	/** Tracks alts insufficiently covered.
107	 *  For example, p1||true gets reduced to true and so leaves
108	 *  whole alt uncovered.  This maps DFA state to the set of alts
109	 */
110	protected Map<DFAState,Map<Integer, Set<Token>>> stateToIncompletelyCoveredAltsMap =
111		new HashMap<DFAState,Map<Integer, Set<Token>>>();
112
113	/** The set of states w/o emanating edges and w/o resolving sem preds. */
114	protected Set<DFAState> danglingStates = new HashSet<DFAState>();
115
116	/** The overall list of alts within the decision that have at least one
117	 *  conflicting input sequence.
118	 */
119	protected Set<Integer> altsWithProblem = new HashSet<Integer>();
120
121	/** If decision with > 1 alt has recursion in > 1 alt, it's (likely) nonregular
122	 *  lookahead.  The decision cannot be made with a DFA.
123	 *  the alts are stored in altsWithProblem.
124	 */
125	public boolean nonLLStarDecision = false;
126
127	/** Recursion is limited to a particular depth.  If that limit is exceeded
128	 *  the proposed new NFAConfiguration is recorded for the associated DFA state.
129	 */
130	protected MultiMap<Integer, NFAConfiguration> stateToRecursionOverflowConfigurationsMap =
131		new MultiMap<Integer, NFAConfiguration>();
132	/*
133	protected Map<Integer, List<NFAConfiguration>> stateToRecursionOverflowConfigurationsMap =
134		new HashMap<Integer, List<NFAConfiguration>>();
135		*/
136
137	/** Left recursion discovered.  The proposed new NFAConfiguration
138	 *  is recorded for the associated DFA state.
139	protected Map<Integer,List<NFAConfiguration>> stateToLeftRecursiveConfigurationsMap =
140		new HashMap<Integer,List<NFAConfiguration>>();
141	 */
142
143	/** Did ANTLR have to terminate early on the analysis of this decision? */
144	protected boolean timedOut = false;
145
146	/** Used to find paths through syntactically ambiguous DFA. If we've
147	 *  seen statement number before, what did we learn?
148	 */
149	protected Map<Integer, Integer> stateReachable;
150
151	public static final Integer REACHABLE_BUSY = Utils.integer(-1);
152	public static final Integer REACHABLE_NO = Utils.integer(0);
153	public static final Integer REACHABLE_YES = Utils.integer(1);
154
155	/** Used while finding a path through an NFA whose edge labels match
156	 *  an input sequence.  Tracks the input position
157	 *  we were at the last time at this node.  If same input position, then
158	 *  we'd have reached same state without consuming input...probably an
159	 *  infinite loop.  Stop.  Set<String>.  The strings look like
160	 *  stateNumber_labelIndex.
161	 */
162	protected Set<String> statesVisitedAtInputDepth;
163
164	protected Set<Integer> statesVisitedDuringSampleSequence;
165
166	public static boolean verbose = false;
167
168	public DecisionProbe(DFA dfa) {
169		this.dfa = dfa;
170	}
171
172	// I N F O R M A T I O N  A B O U T  D E C I S I O N
173
174	/** Return a string like "3:22: ( A {;} | B )" that describes this
175	 *  decision.
176	 */
177	public String getDescription() {
178		return dfa.getNFADecisionStartState().getDescription();
179	}
180
181	public boolean isReduced() {
182		return dfa.isReduced();
183	}
184
185	public boolean isCyclic() {
186		return dfa.isCyclic();
187	}
188
189	/** If no states are dead-ends, no alts are unreachable, there are
190	 *  no nondeterminisms unresolved by syn preds, all is ok with decision.
191	 */
192	public boolean isDeterministic() {
193		if ( danglingStates.size()==0 &&
194			 statesWithSyntacticallyAmbiguousAltsSet.size()==0 &&
195			 dfa.getUnreachableAlts().size()==0 )
196		{
197			return true;
198		}
199
200		if ( statesWithSyntacticallyAmbiguousAltsSet.size()>0 ) {
201			Iterator it =
202				statesWithSyntacticallyAmbiguousAltsSet.iterator();
203			while (	it.hasNext() ) {
204				DFAState d = (DFAState) it.next();
205				if ( !statesResolvedWithSemanticPredicatesSet.contains(d) ) {
206					return false;
207				}
208			}
209			// no syntactically ambig alts were left unresolved by predicates
210			return true;
211		}
212		return false;
213	}
214
215	/** Did the analysis complete it's work? */
216//	public boolean analysisTimedOut() {
217//		return timedOut;
218//	}
219
220	/** Took too long to analyze a DFA */
221	public boolean analysisOverflowed() {
222		return stateToRecursionOverflowConfigurationsMap.size()>0;
223	}
224
225	/** Found recursion in > 1 alt */
226	public boolean isNonLLStarDecision() {
227		return nonLLStarDecision;
228	}
229
230	/** How many states does the DFA predictor have? */
231	public int getNumberOfStates() {
232		return dfa.getNumberOfStates();
233	}
234
235	/** Get a list of all unreachable alternatives for this decision.  There
236	 *  may be multiple alternatives with ambiguous input sequences, but this
237	 *  is the overall list of unreachable alternatives (either due to
238	 *  conflict resolution or alts w/o accept states).
239	 */
240	public List<Integer> getUnreachableAlts() {
241		return dfa.getUnreachableAlts();
242	}
243
244	/** return set of states w/o emanating edges and w/o resolving sem preds.
245	 *  These states come about because the analysis algorithm had to
246	 *  terminate early to avoid infinite recursion for example (due to
247	 *  left recursion perhaps).
248	 */
249	public Set getDanglingStates() {
250		return danglingStates;
251	}
252
253    public Set getNonDeterministicAlts() {
254        return altsWithProblem;
255	}
256
257	/** Return the sorted list of alts that conflict within a single state.
258	 *  Note that predicates may resolve the conflict.
259	 */
260	public List getNonDeterministicAltsForState(DFAState targetState) {
261		Set nondetAlts = targetState.getNonDeterministicAlts();
262		if ( nondetAlts==null ) {
263			return null;
264		}
265		List sorted = new LinkedList();
266		sorted.addAll(nondetAlts);
267		Collections.sort(sorted); // make sure it's 1, 2, ...
268		return sorted;
269	}
270
271	/** Return all DFA states in this DFA that have NFA configurations that
272	 *  conflict.  You must report a problem for each state in this set
273	 *  because each state represents a different input sequence.
274	 */
275	public Set getDFAStatesWithSyntacticallyAmbiguousAlts() {
276		return statesWithSyntacticallyAmbiguousAltsSet;
277	}
278
279	/** Which alts were specifically turned off to resolve nondeterminisms?
280	 *  This is different than the unreachable alts.  Disabled doesn't mean that
281	 *  the alternative is totally unreachable necessarily, it just means
282	 *  that for this DFA state, that alt is disabled.  There may be other
283	 *  accept states for that alt that make an alt reachable.
284	 */
285	public Set getDisabledAlternatives(DFAState d) {
286		return d.getDisabledAlternatives();
287	}
288
289	/** If a recursion overflow is resolve with predicates, then we need
290	 *  to shut off the warning that would be generated.
291	 */
292	public void removeRecursiveOverflowState(DFAState d) {
293		Integer stateI = Utils.integer(d.stateNumber);
294		stateToRecursionOverflowConfigurationsMap.remove(stateI);
295	}
296
297	/** Return a List<Label> indicating an input sequence that can be matched
298	 *  from the start state of the DFA to the targetState (which is known
299	 *  to have a problem).
300	 */
301	public List<Label> getSampleNonDeterministicInputSequence(DFAState targetState) {
302		Set dfaStates = getDFAPathStatesToTarget(targetState);
303		statesVisitedDuringSampleSequence = new HashSet<Integer>();
304		List<Label> labels = new ArrayList<Label>(); // may access ith element; use array
305		if ( dfa==null || dfa.startState==null ) {
306			return labels;
307		}
308		getSampleInputSequenceUsingStateSet(dfa.startState,
309											targetState,
310											dfaStates,
311											labels);
312		return labels;
313	}
314
315	/** Given List<Label>, return a String with a useful representation
316	 *  of the associated input string.  One could show something different
317	 *  for lexers and parsers, for example.
318	 */
319	public String getInputSequenceDisplay(List labels) {
320        Grammar g = dfa.nfa.grammar;
321		StringBuffer buf = new StringBuffer();
322		for (Iterator it = labels.iterator(); it.hasNext();) {
323			Label label = (Label) it.next();
324			buf.append(label.toString(g));
325			if ( it.hasNext() && g.type!=Grammar.LEXER ) {
326				buf.append(' ');
327			}
328		}
329		return buf.toString();
330	}
331
332    /** Given an alternative associated with a nondeterministic DFA state,
333	 *  find the path of NFA states associated with the labels sequence.
334	 *  Useful tracing where in the NFA, a single input sequence can be
335	 *  matched.  For different alts, you should get different NFA paths.
336	 *
337	 *  The first NFA state for all NFA paths will be the same: the starting
338	 *  NFA state of the first nondeterministic alt.  Imagine (A|B|A|A):
339	 *
340	 * 	5->9-A->o
341	 *  |
342	 *  6->10-B->o
343	 *  |
344	 *  7->11-A->o
345	 *  |
346	 *  8->12-A->o
347	 *
348	 *  There are 3 nondeterministic alts.  The paths should be:
349	 *  5 9 ...
350	 *  5 6 7 11 ...
351	 *  5 6 7 8 12 ...
352	 *
353	 *  The NFA path matching the sample input sequence (labels) is computed
354	 *  using states 9, 11, and 12 rather than 5, 7, 8 because state 5, for
355	 *  example can get to all ambig paths.  Must isolate for each alt (hence,
356	 *  the extra state beginning each alt in my NFA structures).  Here,
357	 *  firstAlt=1.
358	 */
359	public List getNFAPathStatesForAlt(int firstAlt,
360									   int alt,
361									   List labels)
362	{
363		NFAState nfaStart = dfa.getNFADecisionStartState();
364		List path = new LinkedList();
365		// first add all NFA states leading up to altStart state
366		for (int a=firstAlt; a<=alt; a++) {
367			NFAState s =
368				dfa.nfa.grammar.getNFAStateForAltOfDecision(nfaStart,a);
369			path.add(s);
370		}
371
372		// add first state of actual alt
373		NFAState altStart = dfa.nfa.grammar.getNFAStateForAltOfDecision(nfaStart,alt);
374		NFAState isolatedAltStart = (NFAState)altStart.transition[0].target;
375		path.add(isolatedAltStart);
376
377		// add the actual path now
378		statesVisitedAtInputDepth = new HashSet();
379		getNFAPath(isolatedAltStart,
380				   0,
381				   labels,
382				   path);
383        return path;
384	}
385
386	/** Each state in the DFA represents a different input sequence for an
387	 *  alt of the decision.  Given a DFA state, what is the semantic
388	 *  predicate context for a particular alt.
389	 */
390    public SemanticContext getSemanticContextForAlt(DFAState d, int alt) {
391		Map altToPredMap = (Map)stateToAltSetWithSemanticPredicatesMap.get(d);
392		if ( altToPredMap==null ) {
393			return null;
394		}
395		return (SemanticContext)altToPredMap.get(Utils.integer(alt));
396	}
397
398	/** At least one alt refs a sem or syn pred */
399	public boolean hasPredicate() {
400		return stateToAltSetWithSemanticPredicatesMap.size()>0;
401	}
402
403	public Set getNondeterministicStatesResolvedWithSemanticPredicate() {
404		return statesResolvedWithSemanticPredicatesSet;
405	}
406
407	/** Return a list of alts whose predicate context was insufficient to
408	 *  resolve a nondeterminism for state d.
409	 */
410	public Map<Integer, Set<Token>> getIncompletelyCoveredAlts(DFAState d) {
411		return stateToIncompletelyCoveredAltsMap.get(d);
412	}
413
414	public void issueWarnings() {
415		// NONREGULAR DUE TO RECURSION > 1 ALTS
416		// Issue this before aborted analysis, which might also occur
417		// if we take too long to terminate
418		if ( nonLLStarDecision && !dfa.getAutoBacktrackMode() ) {
419			ErrorManager.nonLLStarDecision(this);
420		}
421
422		issueRecursionWarnings();
423
424		// generate a separate message for each problem state in DFA
425		Set resolvedStates = getNondeterministicStatesResolvedWithSemanticPredicate();
426		Set problemStates = getDFAStatesWithSyntacticallyAmbiguousAlts();
427		if ( problemStates.size()>0 ) {
428			Iterator it =
429				problemStates.iterator();
430			while (	it.hasNext() && !dfa.nfa.grammar.NFAToDFAConversionExternallyAborted() ) {
431				DFAState d = (DFAState) it.next();
432				Map<Integer, Set<Token>> insufficientAltToLocations = getIncompletelyCoveredAlts(d);
433				if ( insufficientAltToLocations!=null && insufficientAltToLocations.size()>0 ) {
434					ErrorManager.insufficientPredicates(this,d,insufficientAltToLocations);
435				}
436				// don't report problem if resolved
437				if ( resolvedStates==null || !resolvedStates.contains(d) ) {
438					// first strip last alt from disableAlts if it's wildcard
439					// then don't print error if no more disable alts
440					Set disabledAlts = getDisabledAlternatives(d);
441					stripWildCardAlts(disabledAlts);
442					if ( disabledAlts.size()>0 ) {
443						// nondeterminism; same input predicts multiple alts.
444						// but don't emit error if greedy=true explicitly set
445						boolean explicitlyGreedy = false;
446						GrammarAST blockAST =
447							d.dfa.nfa.grammar.getDecisionBlockAST(d.dfa.decisionNumber);
448						if ( blockAST!=null ) {
449							String greedyS = (String)blockAST.getBlockOption("greedy");
450							if ( greedyS!=null && greedyS.equals("true") ) explicitlyGreedy = true;
451						}
452						if ( !explicitlyGreedy) ErrorManager.nondeterminism(this,d);
453					}
454				}
455			}
456		}
457
458		Set danglingStates = getDanglingStates();
459		if ( danglingStates.size()>0 ) {
460			//System.err.println("no emanating edges for states: "+danglingStates);
461			for (Iterator it = danglingStates.iterator(); it.hasNext();) {
462				DFAState d = (DFAState) it.next();
463				ErrorManager.danglingState(this,d);
464			}
465		}
466
467		if ( !nonLLStarDecision ) {
468			List<Integer> unreachableAlts = dfa.getUnreachableAlts();
469			if ( unreachableAlts!=null && unreachableAlts.size()>0 ) {
470				// give different msg if it's an empty Tokens rule from delegate
471				boolean isInheritedTokensRule = false;
472				if ( dfa.isTokensRuleDecision() ) {
473					for (Integer altI : unreachableAlts) {
474						GrammarAST decAST = dfa.getDecisionASTNode();
475						GrammarAST altAST = (GrammarAST)decAST.getChild(altI-1);
476						GrammarAST delegatedTokensAlt =
477							(GrammarAST)altAST.getFirstChildWithType(ANTLRParser.DOT);
478						if ( delegatedTokensAlt !=null ) {
479							isInheritedTokensRule = true;
480							ErrorManager.grammarWarning(ErrorManager.MSG_IMPORTED_TOKENS_RULE_EMPTY,
481														dfa.nfa.grammar,
482														null,
483														dfa.nfa.grammar.name,
484														delegatedTokensAlt.getChild(0).getText());
485						}
486					}
487				}
488				if ( isInheritedTokensRule ) {
489				}
490				else {
491					ErrorManager.unreachableAlts(this,unreachableAlts);
492				}
493			}
494		}
495	}
496
497	/** Get the last disabled alt number and check in the grammar to see
498	 *  if that alt is a simple wildcard.  If so, treat like an else clause
499	 *  and don't emit the error.  Strip out the last alt if it's wildcard.
500	 */
501	protected void stripWildCardAlts(Set disabledAlts) {
502		List sortedDisableAlts = new ArrayList(disabledAlts);
503		Collections.sort(sortedDisableAlts);
504		Integer lastAlt =
505			(Integer)sortedDisableAlts.get(sortedDisableAlts.size()-1);
506		GrammarAST blockAST =
507			dfa.nfa.grammar.getDecisionBlockAST(dfa.decisionNumber);
508		//System.out.println("block with error = "+blockAST.toStringTree());
509		GrammarAST lastAltAST = null;
510		if ( blockAST.getChild(0).getType()==ANTLRParser.OPTIONS ) {
511			// if options, skip first child: ( options { ( = greedy false ) )
512			lastAltAST = (GrammarAST)blockAST.getChild(lastAlt.intValue());
513		}
514		else {
515			lastAltAST = (GrammarAST)blockAST.getChild(lastAlt.intValue()-1);
516		}
517		//System.out.println("last alt is "+lastAltAST.toStringTree());
518		// if last alt looks like ( ALT . <end-of-alt> ) then wildcard
519		// Avoid looking at optional blocks etc... that have last alt
520		// as the EOB:
521		// ( BLOCK ( ALT 'else' statement <end-of-alt> ) <end-of-block> )
522		if ( lastAltAST.getType()!=ANTLRParser.EOB &&
523			 lastAltAST.getChild(0).getType()== ANTLRParser.WILDCARD &&
524			 lastAltAST.getChild(1).getType()== ANTLRParser.EOA )
525		{
526			//System.out.println("wildcard");
527			disabledAlts.remove(lastAlt);
528		}
529	}
530
531	protected void issueRecursionWarnings() {
532		// RECURSION OVERFLOW
533		Set dfaStatesWithRecursionProblems =
534			stateToRecursionOverflowConfigurationsMap.keySet();
535		// now walk truly unique (unaliased) list of dfa states with inf recur
536		// Goal: create a map from alt to map<target,List<callsites>>
537		// Map<Map<String target, List<NFAState call sites>>
538		Map altToTargetToCallSitesMap = new HashMap();
539		// track a single problem DFA state for each alt
540		Map altToDFAState = new HashMap();
541		computeAltToProblemMaps(dfaStatesWithRecursionProblems,
542								stateToRecursionOverflowConfigurationsMap,
543								altToTargetToCallSitesMap, // output param
544								altToDFAState);            // output param
545
546		// walk each alt with recursion overflow problems and generate error
547		Set alts = altToTargetToCallSitesMap.keySet();
548		List sortedAlts = new ArrayList(alts);
549		Collections.sort(sortedAlts);
550		for (Iterator altsIt = sortedAlts.iterator(); altsIt.hasNext();) {
551			Integer altI = (Integer) altsIt.next();
552			Map targetToCallSiteMap =
553				(Map)altToTargetToCallSitesMap.get(altI);
554			Set targetRules = targetToCallSiteMap.keySet();
555			Collection callSiteStates = targetToCallSiteMap.values();
556			DFAState sampleBadState = (DFAState)altToDFAState.get(altI);
557			ErrorManager.recursionOverflow(this,
558										   sampleBadState,
559										   altI.intValue(),
560										   targetRules,
561										   callSiteStates);
562		}
563	}
564
565	private void computeAltToProblemMaps(Set dfaStatesUnaliased,
566										 Map configurationsMap,
567										 Map altToTargetToCallSitesMap,
568										 Map altToDFAState)
569	{
570		for (Iterator it = dfaStatesUnaliased.iterator(); it.hasNext();) {
571			Integer stateI = (Integer) it.next();
572			// walk this DFA's config list
573			List configs = (List)configurationsMap.get(stateI);
574			for (int i = 0; i < configs.size(); i++) {
575				NFAConfiguration c = (NFAConfiguration) configs.get(i);
576				NFAState ruleInvocationState = dfa.nfa.getState(c.state);
577				Transition transition0 = ruleInvocationState.transition[0];
578				RuleClosureTransition ref = (RuleClosureTransition)transition0;
579				String targetRule = ((NFAState) ref.target).enclosingRule.name;
580				Integer altI = Utils.integer(c.alt);
581				Map targetToCallSiteMap =
582					(Map)altToTargetToCallSitesMap.get(altI);
583				if ( targetToCallSiteMap==null ) {
584					targetToCallSiteMap = new HashMap();
585					altToTargetToCallSitesMap.put(altI, targetToCallSiteMap);
586				}
587				Set callSites =
588					(HashSet)targetToCallSiteMap.get(targetRule);
589				if ( callSites==null ) {
590					callSites = new HashSet();
591					targetToCallSiteMap.put(targetRule, callSites);
592				}
593				callSites.add(ruleInvocationState);
594				// track one problem DFA state per alt
595				if ( altToDFAState.get(altI)==null ) {
596					DFAState sampleBadState = dfa.getState(stateI.intValue());
597					altToDFAState.put(altI, sampleBadState);
598				}
599			}
600		}
601	}
602
603	private Set getUnaliasedDFAStateSet(Set dfaStatesWithRecursionProblems) {
604		Set dfaStatesUnaliased = new HashSet();
605		for (Iterator it = dfaStatesWithRecursionProblems.iterator(); it.hasNext();) {
606			Integer stateI = (Integer) it.next();
607			DFAState d = dfa.getState(stateI.intValue());
608			dfaStatesUnaliased.add(Utils.integer(d.stateNumber));
609		}
610		return dfaStatesUnaliased;
611	}
612
613
614	// T R A C K I N G  M E T H O D S
615
616    /** Report the fact that DFA state d is not a state resolved with
617     *  predicates and yet it has no emanating edges.  Usually this
618     *  is a result of the closure/reach operations being unable to proceed
619     */
620	public void reportDanglingState(DFAState d) {
621		danglingStates.add(d);
622	}
623
624//	public void reportAnalysisTimeout() {
625//		timedOut = true;
626//		dfa.nfa.grammar.setOfDFAWhoseAnalysisTimedOut.add(dfa);
627//	}
628
629	/** Report that at least 2 alts have recursive constructs.  There is
630	 *  no way to build a DFA so we terminated.
631	 */
632	public void reportNonLLStarDecision(DFA dfa) {
633		/*
634		System.out.println("non-LL(*) DFA "+dfa.decisionNumber+", alts: "+
635						   dfa.recursiveAltSet.toList());
636						   */
637		nonLLStarDecision = true;
638		dfa.nfa.grammar.numNonLLStar++;
639		altsWithProblem.addAll(dfa.recursiveAltSet.toList());
640	}
641
642	public void reportRecursionOverflow(DFAState d,
643										NFAConfiguration recursionNFAConfiguration)
644	{
645		// track the state number rather than the state as d will change
646		// out from underneath us; hash wouldn't return any value
647
648		// left-recursion is detected in start state.  Since we can't
649		// call resolveNondeterminism() on the start state (it would
650		// not look k=1 to get min single token lookahead), we must
651		// prevent errors derived from this state.  Avoid start state
652		if ( d.stateNumber > 0 ) {
653			Integer stateI = Utils.integer(d.stateNumber);
654			stateToRecursionOverflowConfigurationsMap.map(stateI, recursionNFAConfiguration);
655		}
656	}
657
658	public void reportNondeterminism(DFAState d, Set<Integer> nondeterministicAlts) {
659		altsWithProblem.addAll(nondeterministicAlts); // track overall list
660		statesWithSyntacticallyAmbiguousAltsSet.add(d);
661		dfa.nfa.grammar.setOfNondeterministicDecisionNumbers.add(
662			Utils.integer(dfa.getDecisionNumber())
663		);
664	}
665
666	/** Currently the analysis reports issues between token definitions, but
667	 *  we don't print out warnings in favor of just picking the first token
668	 *  definition found in the grammar ala lex/flex.
669	 */
670	public void reportLexerRuleNondeterminism(DFAState d, Set<Integer> nondeterministicAlts) {
671		stateToSyntacticallyAmbiguousTokensRuleAltsMap.put(d,nondeterministicAlts);
672	}
673
674	public void reportNondeterminismResolvedWithSemanticPredicate(DFAState d) {
675		// First, prevent a recursion warning on this state due to
676		// pred resolution
677		if ( d.abortedDueToRecursionOverflow ) {
678			d.dfa.probe.removeRecursiveOverflowState(d);
679		}
680		statesResolvedWithSemanticPredicatesSet.add(d);
681		//System.out.println("resolved with pred: "+d);
682		dfa.nfa.grammar.setOfNondeterministicDecisionNumbersResolvedWithPredicates.add(
683			Utils.integer(dfa.getDecisionNumber())
684		);
685	}
686
687	/** Report the list of predicates found for each alternative; copy
688	 *  the list because this set gets altered later by the method
689	 *  tryToResolveWithSemanticPredicates() while flagging NFA configurations
690	 *  in d as resolved.
691	 */
692	public void reportAltPredicateContext(DFAState d, Map altPredicateContext) {
693		Map copy = new HashMap();
694		copy.putAll(altPredicateContext);
695		stateToAltSetWithSemanticPredicatesMap.put(d,copy);
696	}
697
698	public void reportIncompletelyCoveredAlts(DFAState d,
699											  Map<Integer, Set<Token>> altToLocationsReachableWithoutPredicate)
700	{
701		stateToIncompletelyCoveredAltsMap.put(d, altToLocationsReachableWithoutPredicate);
702	}
703
704	// S U P P O R T
705
706	/** Given a start state and a target state, return true if start can reach
707	 *  target state.  Also, compute the set of DFA states
708	 *  that are on a path from start to target; return in states parameter.
709	 */
710	protected boolean reachesState(DFAState startState,
711								   DFAState targetState,
712								   Set states) {
713		if ( startState==targetState ) {
714			states.add(targetState);
715			//System.out.println("found target DFA state "+targetState.getStateNumber());
716			stateReachable.put(startState.stateNumber, REACHABLE_YES);
717			return true;
718		}
719
720		DFAState s = startState;
721		// avoid infinite loops
722		stateReachable.put(s.stateNumber, REACHABLE_BUSY);
723
724		// look for a path to targetState among transitions for this state
725		// stop when you find the first one; I'm pretty sure there is
726		// at most one path to any DFA state with conflicting predictions
727		for (int i=0; i<s.getNumberOfTransitions(); i++) {
728			Transition t = s.transition(i);
729			DFAState edgeTarget = (DFAState)t.target;
730			Integer targetStatus = stateReachable.get(edgeTarget.stateNumber);
731			if ( targetStatus==REACHABLE_BUSY ) { // avoid cycles; they say nothing
732				continue;
733			}
734			if ( targetStatus==REACHABLE_YES ) { // return success!
735				stateReachable.put(s.stateNumber, REACHABLE_YES);
736				return true;
737			}
738			if ( targetStatus==REACHABLE_NO ) { // try another transition
739				continue;
740			}
741			// if null, target must be REACHABLE_UNKNOWN (i.e., unvisited)
742			if ( reachesState(edgeTarget, targetState, states) ) {
743				states.add(s);
744				stateReachable.put(s.stateNumber, REACHABLE_YES);
745				return true;
746			}
747		}
748
749		stateReachable.put(s.stateNumber, REACHABLE_NO);
750		return false; // no path to targetState found.
751	}
752
753	protected Set getDFAPathStatesToTarget(DFAState targetState) {
754		Set dfaStates = new HashSet();
755		stateReachable = new HashMap();
756		if ( dfa==null || dfa.startState==null ) {
757			return dfaStates;
758		}
759		boolean reaches = reachesState(dfa.startState, targetState, dfaStates);
760		return dfaStates;
761	}
762
763	/** Given a start state and a final state, find a list of edge labels
764	 *  between the two ignoring epsilon.  Limit your scan to a set of states
765	 *  passed in.  This is used to show a sample input sequence that is
766	 *  nondeterministic with respect to this decision.  Return List<Label> as
767	 *  a parameter.  The incoming states set must be all states that lead
768	 *  from startState to targetState and no others so this algorithm doesn't
769	 *  take a path that eventually leads to a state other than targetState.
770	 *  Don't follow loops, leading to short (possibly shortest) path.
771	 */
772	protected void getSampleInputSequenceUsingStateSet(State startState,
773													   State targetState,
774													   Set states,
775													   List<Label> labels)
776	{
777		statesVisitedDuringSampleSequence.add(startState.stateNumber);
778
779		// pick the first edge in states as the one to traverse
780		for (int i=0; i<startState.getNumberOfTransitions(); i++) {
781			Transition t = startState.transition(i);
782			DFAState edgeTarget = (DFAState)t.target;
783			if ( states.contains(edgeTarget) &&
784				 !statesVisitedDuringSampleSequence.contains(edgeTarget.stateNumber) )
785			{
786				labels.add(t.label); // traverse edge and track label
787				if ( edgeTarget!=targetState ) {
788					// get more labels if not at target
789					getSampleInputSequenceUsingStateSet(edgeTarget,
790														targetState,
791														states,
792														labels);
793				}
794				// done with this DFA state as we've found a good path to target
795				return;
796			}
797		}
798		labels.add(new Label(Label.EPSILON)); // indicate no input found
799		// this happens on a : {p1}? a | A ;
800		//ErrorManager.error(ErrorManager.MSG_CANNOT_COMPUTE_SAMPLE_INPUT_SEQ);
801	}
802
803	/** Given a sample input sequence, you usually would like to know the
804	 *  path taken through the NFA.  Return the list of NFA states visited
805	 *  while matching a list of labels.  This cannot use the usual
806	 *  interpreter, which does a deterministic walk.  We need to be able to
807	 *  take paths that are turned off during nondeterminism resolution. So,
808	 *  just do a depth-first walk traversing edges labeled with the current
809	 *  label.  Return true if a path was found emanating from state s.
810	 */
811	protected boolean getNFAPath(NFAState s,     // starting where?
812								 int labelIndex, // 0..labels.size()-1
813								 List labels,    // input sequence
814								 List path)      // output list of NFA states
815	{
816		// track a visit to state s at input index labelIndex if not seen
817		String thisStateKey = getStateLabelIndexKey(s.stateNumber,labelIndex);
818		if ( statesVisitedAtInputDepth.contains(thisStateKey) ) {
819			/*
820			System.out.println("### already visited "+s.stateNumber+" previously at index "+
821						   labelIndex);
822			*/
823			return false;
824		}
825		statesVisitedAtInputDepth.add(thisStateKey);
826
827		/*
828		System.out.println("enter state "+s.stateNumber+" visited states: "+
829						   statesVisitedAtInputDepth);
830        */
831
832		// pick the first edge whose target is in states and whose
833		// label is labels[labelIndex]
834		for (int i=0; i<s.getNumberOfTransitions(); i++) {
835			Transition t = s.transition[i];
836			NFAState edgeTarget = (NFAState)t.target;
837			Label label = (Label)labels.get(labelIndex);
838			/*
839			System.out.println(s.stateNumber+"-"+
840							   t.label.toString(dfa.nfa.grammar)+"->"+
841							   edgeTarget.stateNumber+" =="+
842							   label.toString(dfa.nfa.grammar)+"?");
843			*/
844			if ( t.label.isEpsilon() || t.label.isSemanticPredicate() ) {
845				// nondeterministically backtrack down epsilon edges
846				path.add(edgeTarget);
847				boolean found =
848					getNFAPath(edgeTarget, labelIndex, labels, path);
849				if ( found ) {
850					statesVisitedAtInputDepth.remove(thisStateKey);
851					return true; // return to "calling" state
852				}
853				path.remove(path.size()-1); // remove; didn't work out
854				continue; // look at the next edge
855			}
856			if ( t.label.matches(label) ) {
857				path.add(edgeTarget);
858				/*
859				System.out.println("found label "+
860								   t.label.toString(dfa.nfa.grammar)+
861								   " at state "+s.stateNumber+"; labelIndex="+labelIndex);
862				*/
863				if ( labelIndex==labels.size()-1 ) {
864					// found last label; done!
865					statesVisitedAtInputDepth.remove(thisStateKey);
866					return true;
867				}
868				// otherwise try to match remaining input
869				boolean found =
870					getNFAPath(edgeTarget, labelIndex+1, labels, path);
871				if ( found ) {
872					statesVisitedAtInputDepth.remove(thisStateKey);
873					return true;
874				}
875				/*
876				System.out.println("backtrack; path from "+s.stateNumber+"->"+
877								   t.label.toString(dfa.nfa.grammar)+" didn't work");
878				*/
879				path.remove(path.size()-1); // remove; didn't work out
880				continue; // keep looking for a path for labels
881			}
882		}
883		//System.out.println("no epsilon or matching edge; removing "+thisStateKey);
884		// no edge was found matching label; is ok, some state will have it
885		statesVisitedAtInputDepth.remove(thisStateKey);
886		return false;
887	}
888
889	protected String getStateLabelIndexKey(int s, int i) {
890		StringBuffer buf = new StringBuffer();
891		buf.append(s);
892		buf.append('_');
893		buf.append(i);
894		return buf.toString();
895	}
896
897	/** From an alt number associated with artificial Tokens rule, return
898	 *  the name of the token that is associated with that alt.
899	 */
900	public String getTokenNameForTokensRuleAlt(int alt) {
901		NFAState decisionState = dfa.getNFADecisionStartState();
902		NFAState altState =
903			dfa.nfa.grammar.getNFAStateForAltOfDecision(decisionState,alt);
904		NFAState decisionLeft = (NFAState)altState.transition[0].target;
905		RuleClosureTransition ruleCallEdge =
906			(RuleClosureTransition)decisionLeft.transition[0];
907		NFAState ruleStartState = (NFAState)ruleCallEdge.target;
908		//System.out.println("alt = "+decisionLeft.getEnclosingRule());
909		return ruleStartState.enclosingRule.name;
910	}
911
912	public void reset() {
913		stateToRecursionOverflowConfigurationsMap.clear();
914	}
915}
916