/* * [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.misc.IntSet; import org.antlr.misc.MultiMap; import org.antlr.misc.OrderedHashSet; import org.antlr.misc.Utils; import org.antlr.tool.Grammar; import java.util.*; /** A DFA state represents a set of possible NFA configurations. * As Aho, Sethi, Ullman p. 117 says "The DFA uses its state * to keep track of all possible states the NFA can be in after * reading each input symbol. That is to say, after reading * input a1a2..an, the DFA is in a state that represents the * subset T of the states of the NFA that are reachable from the * NFA's start state along some path labeled a1a2..an." * In conventional NFA->DFA conversion, therefore, the subset T * would be a bitset representing the set of states the * NFA could be in. We need to track the alt predicted by each * state as well, however. More importantly, we need to maintain * a stack of states, tracking the closure operations as they * jump from rule to rule, emulating rule invocations (method calls). * Recall that NFAs do not normally have a stack like a pushdown-machine * so I have to add one to simulate the proper lookahead sequences for * the underlying LL grammar from which the NFA was derived. * * I use a list of NFAConfiguration objects. An NFAConfiguration * is both a state (ala normal conversion) and an NFAContext describing * the chain of rules (if any) followed to arrive at that state. There * is also the semantic context, which is the "set" of predicates found * on the path to this configuration. * * A DFA state may have multiple references to a particular state, * but with different NFAContexts (with same or different alts) * meaning that state was reached via a different set of rule invocations. */ public class DFAState extends State { public static final int INITIAL_NUM_TRANSITIONS = 4; public static final int PREDICTED_ALT_UNSET = NFA.INVALID_ALT_NUMBER-1; /** We are part of what DFA? Use this ref to get access to the * context trees for an alt. */ public DFA dfa; /** Track the transitions emanating from this DFA state. The List * elements are Transition objects. */ protected List transitions = new ArrayList(INITIAL_NUM_TRANSITIONS); /** When doing an acyclic DFA, this is the number of lookahead symbols * consumed to reach this state. This value may be nonzero for most * dfa states, but it is only a valid value if the user has specified * a max fixed lookahead. */ protected int k; /** The NFA->DFA algorithm may terminate leaving some states * without a path to an accept state, implying that upon certain * input, the decision is not deterministic--no decision about * predicting a unique alternative can be made. Recall that an * accept state is one in which a unique alternative is predicted. */ protected int acceptStateReachable = DFA.REACHABLE_UNKNOWN; /** Rather than recheck every NFA configuration in a DFA state (after * resolving) in findNewDFAStatesAndAddDFATransitions just check * this boolean. Saves a linear walk perhaps DFA state creation. * Every little bit helps. */ protected boolean resolvedWithPredicates = false; /** If a closure operation finds that we tried to invoke the same * rule too many times (stack would grow beyond a threshold), it * marks the state has aborted and notifies the DecisionProbe. */ public boolean abortedDueToRecursionOverflow = false; /** If we detect recursion on more than one alt, decision is non-LL(*), * but try to isolate it to only those states whose closure operations * detect recursion. There may be other alts that are cool: * * a : recur '.' * | recur ';' * | X Y // LL(2) decision; don't abort and use k=1 plus backtracking * | X Z * ; * * 12/13/2007: Actually this has caused problems. If k=*, must terminate * and throw out entire DFA; retry with k=1. Since recursive, do not * attempt more closure ops as it may take forever. Exception thrown * now and we simply report the problem. If synpreds exist, I'll retry * with k=1. */ protected boolean abortedDueToMultipleRecursiveAlts = false; /** Build up the hash code for this state as NFA configurations * are added as it's monotonically increasing list of configurations. */ protected int cachedHashCode; protected int cachedUniquelyPredicatedAlt = PREDICTED_ALT_UNSET; public int minAltInConfigurations=Integer.MAX_VALUE; public boolean atLeastOneConfigurationHasAPredicate = false; /** The set of NFA configurations (state,alt,context) for this DFA state */ public OrderedHashSet nfaConfigurations = new OrderedHashSet(); public List configurationsWithLabeledEdges = new ArrayList(); /** Used to prevent the closure operation from looping to itself and * hence looping forever. Sensitive to the NFA state, the alt, and * the stack context. This just the nfa config set because we want to * prevent closures only on states contributed by closure not reach * operations. * * Two configurations identical including semantic context are * considered the same closure computation. @see NFAToDFAConverter.closureBusy(). */ protected Set closureBusy = new HashSet(); /** As this state is constructed (i.e., as NFA states are added), we * can easily check for non-epsilon transitions because the only * transition that could be a valid label is transition(0). When we * process this node eventually, we'll have to walk all states looking * for all possible transitions. That is of the order: size(label space) * times size(nfa states), which can be pretty damn big. It's better * to simply track possible labels. */ protected OrderedHashSet