• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
28 package org.antlr.analysis;
29 
30 import org.antlr.grammar.v3.ANTLRParser;
31 import org.antlr.misc.MultiMap;
32 import org.antlr.misc.Utils;
33 import org.antlr.runtime.Token;
34 import org.antlr.tool.ErrorManager;
35 import org.antlr.tool.Grammar;
36 import org.antlr.tool.GrammarAST;
37 
38 import 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  */
71 public 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 
DecisionProbe(DFA dfa)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 	 */
getDescription()177 	public String getDescription() {
178 		return dfa.getNFADecisionStartState().getDescription();
179 	}
180 
isReduced()181 	public boolean isReduced() {
182 		return dfa.isReduced();
183 	}
184 
isCyclic()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 	 */
isDeterministic()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 */
analysisOverflowed()221 	public boolean analysisOverflowed() {
222 		return stateToRecursionOverflowConfigurationsMap.size()>0;
223 	}
224 
225 	/** Found recursion in > 1 alt */
isNonLLStarDecision()226 	public boolean isNonLLStarDecision() {
227 		return nonLLStarDecision;
228 	}
229 
230 	/** How many states does the DFA predictor have? */
getNumberOfStates()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 	 */
getUnreachableAlts()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 	 */
getDanglingStates()249 	public Set getDanglingStates() {
250 		return danglingStates;
251 	}
252 
getNonDeterministicAlts()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 	 */
getNonDeterministicAltsForState(DFAState targetState)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 	 */
getDFAStatesWithSyntacticallyAmbiguousAlts()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 	 */
getDisabledAlternatives(DFAState d)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 	 */
removeRecursiveOverflowState(DFAState d)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 	 */
getSampleNonDeterministicInputSequence(DFAState targetState)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 	 */
getInputSequenceDisplay(List labels)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 	 */
getNFAPathStatesForAlt(int firstAlt, int alt, List labels)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 	 */
getSemanticContextForAlt(DFAState d, int alt)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 */
hasPredicate()399 	public boolean hasPredicate() {
400 		return stateToAltSetWithSemanticPredicatesMap.size()>0;
401 	}
402 
getNondeterministicStatesResolvedWithSemanticPredicate()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 	 */
getIncompletelyCoveredAlts(DFAState d)410 	public Map<Integer, Set<Token>> getIncompletelyCoveredAlts(DFAState d) {
411 		return stateToIncompletelyCoveredAltsMap.get(d);
412 	}
413 
issueWarnings()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 	 */
stripWildCardAlts(Set disabledAlts)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 
issueRecursionWarnings()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 
computeAltToProblemMaps(Set dfaStatesUnaliased, Map configurationsMap, Map altToTargetToCallSitesMap, Map altToDFAState)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 
getUnaliasedDFAStateSet(Set dfaStatesWithRecursionProblems)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      */
reportDanglingState(DFAState d)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 	 */
reportNonLLStarDecision(DFA dfa)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 
reportRecursionOverflow(DFAState d, NFAConfiguration recursionNFAConfiguration)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 
reportNondeterminism(DFAState d, Set<Integer> nondeterministicAlts)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 	 */
reportLexerRuleNondeterminism(DFAState d, Set<Integer> nondeterministicAlts)670 	public void reportLexerRuleNondeterminism(DFAState d, Set<Integer> nondeterministicAlts) {
671 		stateToSyntacticallyAmbiguousTokensRuleAltsMap.put(d,nondeterministicAlts);
672 	}
673 
reportNondeterminismResolvedWithSemanticPredicate(DFAState d)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 	 */
reportAltPredicateContext(DFAState d, Map altPredicateContext)692 	public void reportAltPredicateContext(DFAState d, Map altPredicateContext) {
693 		Map copy = new HashMap();
694 		copy.putAll(altPredicateContext);
695 		stateToAltSetWithSemanticPredicatesMap.put(d,copy);
696 	}
697 
reportIncompletelyCoveredAlts(DFAState d, Map<Integer, Set<Token>> altToLocationsReachableWithoutPredicate)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 	 */
reachesState(DFAState startState, DFAState targetState, Set states)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 
getDFAPathStatesToTarget(DFAState targetState)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 	 */
getSampleInputSequenceUsingStateSet(State startState, State targetState, Set states, List<Label> labels)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 	 */
getNFAPath(NFAState s, int labelIndex, List labels, List path)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 
getStateLabelIndexKey(int s, int i)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 	 */
getTokenNameForTokensRuleAlt(int alt)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 
reset()912 	public void reset() {
913 		stateToRecursionOverflowConfigurationsMap.clear();
914 	}
915 }
916