All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.antlr.analysis.DecisionProbe Maven / Gradle / Ivy

There is a newer version: 3.5.3
Show newest version
/*
 * [The "BSD license"]
 *  Copyright (c) 2010 Terence Parr
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *  1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.antlr.analysis;

import org.antlr.grammar.v3.ANTLRParser;
import org.antlr.misc.MultiMap;
import org.antlr.misc.Utils;
import org.antlr.runtime.Token;
import org.antlr.tool.ErrorManager;
import org.antlr.tool.Grammar;
import org.antlr.tool.GrammarAST;

import java.util.*;

/** Collection of information about what is wrong with a decision as
 *  discovered while building the DFA predictor.
 *
 *  The information is collected during NFA→DFA conversion and, while
 *  some of this is available elsewhere, it is nice to have it all tracked
 *  in one spot so a great error message can be easily had.  I also like
 *  the fact that this object tracks it all for later perusing to make an
 *  excellent error message instead of lots of imprecise on-the-fly warnings
 *  (during conversion).
 *
 *  A decision normally only has one problem; e.g., some input sequence
 *  can be matched by multiple alternatives.  Unfortunately, some decisions
 *  such as
 *
 *  a : ( A | B ) | ( A | B ) | A ;
 *
 *  have multiple problems.  So in general, you should approach a decision
 *  as having multiple flaws each one uniquely identified by a DFAState.
 *  For example, statesWithSyntacticallyAmbiguousAltsSet tracks the set of
 *  all DFAStates where ANTLR has discovered a problem.  Recall that a decision
 *  is represented internall with a DFA comprised of multiple states, each of
 *  which could potentially have problems.
 *
 *  Because of this, you need to iterate over this list of DFA states.  You'll
 *  note that most of the informational methods like
 *  getSampleNonDeterministicInputSequence() require a DFAState.  This state
 *  will be one of the iterated states from stateToSyntacticallyAmbiguousAltsSet.
 *
 *  This class is not thread safe due to shared use of visited maps etc...
 *  Only one thread should really need to access one DecisionProbe anyway.
 */
public class DecisionProbe {
	public DFA dfa;

	/** Track all DFA states with nondeterministic alternatives.
	 *  By reaching the same DFA state, a path through the NFA for some input
	 *  is able to reach the same NFA state by starting at more than one
	 *  alternative's left edge.  Though, later, we may find that predicates
	 *  resolve the issue, but track info anyway.
	 *  Note that from the DFA state, you can ask for
	 *  which alts are nondeterministic.
	 */
	protected Set statesWithSyntacticallyAmbiguousAltsSet = new HashSet();

	/** Track just like stateToSyntacticallyAmbiguousAltsMap, but only
	 *  for nondeterminisms that arise in the Tokens rule such as keyword vs
	 *  ID rule.  The state maps to the list of Tokens rule alts that are
	 *  in conflict.
	 */
	protected Map> stateToSyntacticallyAmbiguousTokensRuleAltsMap =
		new HashMap>();

	/** Was a syntactic ambiguity resolved with predicates?  Any DFA
	 *  state that predicts more than one alternative, must be resolved
	 *  with predicates or it should be reported to the user.
	 */
	protected Set statesResolvedWithSemanticPredicatesSet = new HashSet();

	/** Track the predicates for each alt per DFA state;
	 *  more than one DFA state might have syntactically ambig alt prediction.
	 *  Maps DFA state to another map, mapping alt number to a
	 *  SemanticContext (pred(s) to execute to resolve syntactic ambiguity).
	 */
	protected Map> stateToAltSetWithSemanticPredicatesMap =
		new HashMap>();

	/** Tracks alts insufficiently covered.
	 *  For example, p1||true gets reduced to true and so leaves
	 *  whole alt uncovered.  This maps DFA state to the set of alts
	 */
	protected Map>> stateToIncompletelyCoveredAltsMap =
		new HashMap>>();

	/** The set of states w/o emanating edges and w/o resolving sem preds. */
	protected Set danglingStates = new HashSet();

	/** The overall list of alts within the decision that have at least one
	 *  conflicting input sequence.
	 */
	protected Set altsWithProblem = new HashSet();

	/** If decision with > 1 alt has recursion in > 1 alt, it's (likely) nonregular
	 *  lookahead.  The decision cannot be made with a DFA.
	 *  the alts are stored in altsWithProblem.
	 */
	public boolean nonLLStarDecision = false;

	/** Recursion is limited to a particular depth.  If that limit is exceeded
	 *  the proposed new NFAConfiguration is recorded for the associated DFA state.
	 */
	protected MultiMap stateToRecursionOverflowConfigurationsMap =
		new MultiMap();
	/*
	protected Map> stateToRecursionOverflowConfigurationsMap =
		new HashMap>();
		*/

	/** Left recursion discovered.  The proposed new NFAConfiguration
	 *  is recorded for the associated DFA state.
	protected Map> stateToLeftRecursiveConfigurationsMap =
		new HashMap>();
	 */

	/** Did ANTLR have to terminate early on the analysis of this decision? */
	protected boolean timedOut = false;

	/** Used to find paths through syntactically ambiguous DFA. If we've
	 *  seen statement number before, what did we learn?
	 */
	protected Map stateReachable;

	public static final Integer REACHABLE_BUSY = Utils.integer(-1);
	public static final Integer REACHABLE_NO = Utils.integer(0);
	public static final Integer REACHABLE_YES = Utils.integer(1);

	/** Used while finding a path through an NFA whose edge labels match
	 *  an input sequence.  Tracks the input position
	 *  we were at the last time at this node.  If same input position, then
	 *  we'd have reached same state without consuming input...probably an
	 *  infinite loop.  Stop.  Set<String>.  The strings look like
	 *  stateNumber_labelIndex.
	 */
	protected Set statesVisitedAtInputDepth;

	protected Set statesVisitedDuringSampleSequence;

	public static boolean verbose = false;

	public DecisionProbe(DFA dfa) {
		this.dfa = dfa;
	}

	// I N F O R M A T I O N  A B O U T  D E C I S I O N

	/** Return a string like "3:22: ( A {;} | B )" that describes this
	 *  decision.
	 */
	public String getDescription() {
		return dfa.getNFADecisionStartState().getDescription();
	}

	public boolean isReduced() {
		return dfa.isReduced();
	}

	public boolean isCyclic() {
		return dfa.isCyclic();
	}

	/** If no states are dead-ends, no alts are unreachable, there are
	 *  no nondeterminisms unresolved by syn preds, all is ok with decision.
	 */
	public boolean isDeterministic() {
		if ( danglingStates.isEmpty() &&
			 statesWithSyntacticallyAmbiguousAltsSet.isEmpty() &&
			 dfa.getUnreachableAlts().isEmpty() )
		{
			return true;
		}

		if ( statesWithSyntacticallyAmbiguousAltsSet.size()>0 ) {
			for (DFAState d : statesWithSyntacticallyAmbiguousAltsSet) {
				if ( !statesResolvedWithSemanticPredicatesSet.contains(d) ) {
					return false;
				}
			}
			// no syntactically ambig alts were left unresolved by predicates
			return true;
		}
		return false;
	}

	/** Did the analysis complete it's work? */
//	public boolean analysisTimedOut() {
//		return timedOut;
//	}

	/** Took too long to analyze a DFA */
	public boolean analysisOverflowed() {
		return stateToRecursionOverflowConfigurationsMap.size()>0;
	}

	/** Found recursion in > 1 alt */
	public boolean isNonLLStarDecision() {
		return nonLLStarDecision;
	}

	/** How many states does the DFA predictor have? */
	public int getNumberOfStates() {
		return dfa.getNumberOfStates();
	}

	/** Get a list of all unreachable alternatives for this decision.  There
	 *  may be multiple alternatives with ambiguous input sequences, but this
	 *  is the overall list of unreachable alternatives (either due to
	 *  conflict resolution or alts w/o accept states).
	 */
	public List getUnreachableAlts() {
		return dfa.getUnreachableAlts();
	}

	/** return set of states w/o emanating edges and w/o resolving sem preds.
	 *  These states come about because the analysis algorithm had to
	 *  terminate early to avoid infinite recursion for example (due to
	 *  left recursion perhaps).
	 */
	public Set getDanglingStates() {
		return danglingStates;
	}

    public Set getNonDeterministicAlts() {
        return altsWithProblem;
	}

	/** Return the sorted list of alts that conflict within a single state.
	 *  Note that predicates may resolve the conflict.
	 */
	public List getNonDeterministicAltsForState(DFAState targetState) {
		Set nondetAlts = targetState.getNonDeterministicAlts();
		if ( nondetAlts==null ) {
			return null;
		}
		List sorted = new LinkedList();
		sorted.addAll(nondetAlts);
		Collections.sort(sorted); // make sure it's 1, 2, ...
		return sorted;
	}

	/** Return all DFA states in this DFA that have NFA configurations that
	 *  conflict.  You must report a problem for each state in this set
	 *  because each state represents a different input sequence.
	 */
	public Set getDFAStatesWithSyntacticallyAmbiguousAlts() {
		return statesWithSyntacticallyAmbiguousAltsSet;
	}

	/** Which alts were specifically turned off to resolve nondeterminisms?
	 *  This is different than the unreachable alts.  Disabled doesn't mean that
	 *  the alternative is totally unreachable necessarily, it just means
	 *  that for this DFA state, that alt is disabled.  There may be other
	 *  accept states for that alt that make an alt reachable.
	 */
	public Set getDisabledAlternatives(DFAState d) {
		return d.getDisabledAlternatives();
	}

	/** If a recursion overflow is resolve with predicates, then we need
	 *  to shut off the warning that would be generated.
	 */
	public void removeRecursiveOverflowState(DFAState d) {
		Integer stateI = Utils.integer(d.stateNumber);
		stateToRecursionOverflowConfigurationsMap.remove(stateI);
	}

	/** Return a List<Label> indicating an input sequence that can be matched
	 *  from the start state of the DFA to the targetState (which is known
	 *  to have a problem).
	 */
	public List




© 2015 - 2024 Weber Informatics LLC | Privacy Policy