diff --git a/runtime/Java/src/org/antlr/v4/runtime/RuleContext.java b/runtime/Java/src/org/antlr/v4/runtime/RuleContext.java index 53d73771a..1a09746ba 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/RuleContext.java +++ b/runtime/Java/src/org/antlr/v4/runtime/RuleContext.java @@ -73,33 +73,12 @@ public class RuleContext implements RuleNode { */ public int invokingState = -1; - /** Computing the hashCode is very expensive and closureBusy() - * uses it to track when it's seen a state|ctx before to avoid - * infinite loops. As we add new contexts, record the hash code - * as this.invokingState + parent.cachedHashCode. Avoids walking - * up the tree for every hashCode(). Note that this caching works - * because a context is a monotonically growing tree of context nodes - * and nothing on the stack is ever modified...ctx just grows - * or shrinks. - */ - protected int cachedHashCode; - public RuleContext() {} public RuleContext(RuleContext parent, int invokingState) { this.parent = parent; //if ( parent!=null ) System.out.println("invoke "+stateNumber+" from "+parent); this.invokingState = invokingState; - - this.cachedHashCode = invokingState; - if ( parent!=null ) { - this.cachedHashCode += parent.cachedHashCode; - } - } - - @Override - public int hashCode() { - return cachedHashCode; // works with tests; don't recompute. } public int depth() { @@ -112,100 +91,6 @@ public class RuleContext implements RuleNode { return n; } - /** Two contexts are equals() if both have - * same call stack; walk upwards to the root. - * Note that you may be comparing contexts in different alt trees. - * - * The hashCode is cheap as it's computed once upon each context - * push on the stack. Using it to make equals() more efficient. - */ - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } else if (!(o instanceof RuleContext)) { - return false; - } - - RuleContext other = (RuleContext)o; - if ( this.hashCode() != other.hashCode() ) { - return false; // can't be same if hash is different - } - - // System.out.println("comparing "+this+" with "+other); - RuleContext sp = this; - while ( sp!=null && other!=null ) { - if ( sp == other ) return true; - if ( sp.invokingState != other.invokingState) return false; - sp = sp.parent; - other = other.parent; - } - if ( !(sp==null && other==null) ) { - return false; // both pointers must be at their roots after walk - } - return true; - } - - /** Two contexts conflict() if they are equals() or one is a stack suffix - * of the other. For example, contexts [21 12 $] and [21 9 $] do not - * conflict, but [21 $] and [21 12 $] do conflict. Note that I should - * probably not show the $ in this case. There is a dummy node for each - * stack that just means empty; $ is a marker that's all. - * - * This is used in relation to checking conflicts associated with a - * single NFA state's configurations within a single DFA state. - * If there are configurations s and t within a DFA state such that - * s.state=t.state && s.alt != t.alt && s.ctx conflicts t.ctx then - * the DFA state predicts more than a single alt--it's nondeterministic. - * Two contexts conflict if they are the same or if one is a suffix - * of the other. - * - * When comparing contexts, if one context has a stack and the other - * does not then they should be considered the same context. The only - * way for an NFA state p to have an empty context and a nonempty context - * is the case when closure falls off end of rule without a call stack - * and re-enters the rule with a context. This resolves the issue I - * discussed with Sriram Srinivasan Feb 28, 2005 about not terminating - * fast enough upon nondeterminism. - */ - public boolean conflictsWith(RuleContext other) { - return this.suffix(other) || this.equals(other); - } - - /** [$] suffix any context - * [21 $] suffix [21 12 $] - * [21 12 $] suffix [21 $] - * [21 18 $] suffix [21 18 12 9 $] - * [21 18 12 9 $] suffix [21 18 $] - * [21 12 $] not suffix [21 9 $] - * - * Example "[21 $] suffix [21 12 $]" means: rule r invoked current rule - * from state 21. Rule s invoked rule r from state 12 which then invoked - * current rule also via state 21. While the context prior to state 21 - * is different, the fact that both contexts emanate from state 21 implies - * that they are now going to track perfectly together. Once they - * converged on state 21, there is no way they can separate. In other - * words, the prior stack state is not consulted when computing where to - * go in the closure operation. x$ and xy$ are considered the same stack. - * If x is popped off then $ and y$ remain; they are now an empty and - * nonempty context comparison. So, if one stack is a suffix of - * another, then it will still degenerate to the simple empty stack - * comparison case. - */ - protected boolean suffix(RuleContext other) { - RuleContext sp = this; - // if one of the contexts is empty, it never enters loop and returns true - while ( sp.parent!=null && other.parent!=null ) { - if ( sp.invokingState != other.invokingState ) { - return false; - } - sp = sp.parent; - other = other.parent; - } - //System.out.println("suffix"); - return true; - } - /** A context is empty if there is no invoking state; meaning nobody call * current context. */