forked from jasder/antlr
Remove the RuleContext.hashCode, equals, conflictsWith, and suffix methods since they produce unexpected behavior for ParserRuleContext and are no longer used for adaptivePredict
This commit is contained in:
parent
27cb0e4012
commit
6421e312a4
|
@ -73,33 +73,12 @@ public class RuleContext implements RuleNode {
|
||||||
*/
|
*/
|
||||||
public int invokingState = -1;
|
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() {}
|
||||||
|
|
||||||
public RuleContext(RuleContext parent, int invokingState) {
|
public RuleContext(RuleContext parent, int invokingState) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
//if ( parent!=null ) System.out.println("invoke "+stateNumber+" from "+parent);
|
//if ( parent!=null ) System.out.println("invoke "+stateNumber+" from "+parent);
|
||||||
this.invokingState = invokingState;
|
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() {
|
public int depth() {
|
||||||
|
@ -112,100 +91,6 @@ public class RuleContext implements RuleNode {
|
||||||
return n;
|
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
|
/** A context is empty if there is no invoking state; meaning nobody call
|
||||||
* current context.
|
* current context.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue