forked from jasder/antlr
pull v3 pred ctx tree stuff
[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9475]
This commit is contained in:
parent
d9a499f8f7
commit
c0262d569b
|
@ -0,0 +1,541 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2011 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.v4.runtime.atn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/** A binary tree structure used to record the semantic context in which
|
||||
* an NFA configuration is valid. It's either a single predicate or
|
||||
* a tree representing an operation tree such as: p1&&p2 or p1||p2.
|
||||
*
|
||||
* For ATN o-p1->o-p2->o, create tree AND(p1,p2).
|
||||
* For ATN (1)-p1->(2)
|
||||
* | ^
|
||||
* | |
|
||||
* (3)-p2----
|
||||
* we will have to combine p1 and p2 into DFA state as we will be
|
||||
* adding NFA configurations for state 2 with two predicates p1,p2.
|
||||
* So, set context for combined NFA config for state 2: OR(p1,p2).
|
||||
*
|
||||
* I have scoped the AND, NOT, OR, and Predicate subclasses of
|
||||
* SemanticContext within the scope of this outer class.
|
||||
*
|
||||
* Pulled from v3; lots of fixes by Sam Harwell in v3 I notice.
|
||||
*/
|
||||
public abstract class SemanticContext {
|
||||
/** Create a default value for the semantic context shared among all
|
||||
* ATNConfigs that do not have an actual semantic context.
|
||||
* This prevents lots of if!=null type checks all over; it represents
|
||||
* just an empty set of predicates.
|
||||
*/
|
||||
public static final SemanticContext EMPTY_SEMANTIC_CONTEXT = new Predicate();
|
||||
|
||||
public static class Predicate extends SemanticContext {
|
||||
public final int ruleIndex;
|
||||
public final int predIndex;
|
||||
public final boolean isCtxDependent; // e.g., $i ref in pred
|
||||
|
||||
// public static final int INVALID_PRED_VALUE = -2;
|
||||
// public static final int FALSE_PRED = 0;
|
||||
// public static final int TRUE_PRED = ~0;
|
||||
|
||||
/** sometimes predicates are known to be true or false; we need
|
||||
* a way to represent this without resorting to a target language
|
||||
* value like true or TRUE.
|
||||
*/
|
||||
// protected int constantValue = INVALID_PRED_VALUE;
|
||||
|
||||
protected Predicate() {
|
||||
this.ruleIndex = -1;
|
||||
this.predIndex = -1;
|
||||
this.isCtxDependent = false;
|
||||
}
|
||||
|
||||
public Predicate(int ruleIndex, int predIndex, boolean isCtxDependent) {
|
||||
this.ruleIndex = ruleIndex;
|
||||
this.predIndex = predIndex;
|
||||
this.isCtxDependent = isCtxDependent;
|
||||
}
|
||||
|
||||
public Predicate(Predicate p) {
|
||||
this.ruleIndex = p.ruleIndex;
|
||||
this.predIndex = p.predIndex;
|
||||
this.isCtxDependent = p.isCtxDependent;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if ( !(o instanceof Predicate) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( this != o ) return false;
|
||||
|
||||
Predicate other = (Predicate)o;
|
||||
return this.ruleIndex == other.ruleIndex &&
|
||||
this.predIndex == other.predIndex;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return ruleIndex+predIndex;
|
||||
}
|
||||
public String toString() {
|
||||
return ruleIndex+":"+predIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TruePredicate extends Predicate {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this == o || o instanceof TruePredicate;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "true"; // not used for code gen, just DOT and print outs
|
||||
}
|
||||
}
|
||||
|
||||
public static class FalsePredicate extends Predicate {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this == o || o instanceof FalsePredicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "false"; // not used for code gen, just DOT and print outs
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class CommutativePredicate extends SemanticContext {
|
||||
protected final Set<SemanticContext> operands = new HashSet<SemanticContext>();
|
||||
protected int hashCode;
|
||||
|
||||
public CommutativePredicate(SemanticContext a, SemanticContext b) {
|
||||
if (a.getClass() == this.getClass()){
|
||||
CommutativePredicate predicate = (CommutativePredicate)a;
|
||||
operands.addAll(predicate.operands);
|
||||
}
|
||||
else {
|
||||
operands.add(a);
|
||||
}
|
||||
|
||||
if (b.getClass() == this.getClass()){
|
||||
CommutativePredicate predicate = (CommutativePredicate)b;
|
||||
operands.addAll(predicate.operands);
|
||||
}
|
||||
else {
|
||||
operands.add(b);
|
||||
}
|
||||
|
||||
hashCode = calculateHashCode();
|
||||
}
|
||||
|
||||
public CommutativePredicate(HashSet<SemanticContext> contexts){
|
||||
for (SemanticContext context : contexts){
|
||||
if (context.getClass() == this.getClass()){
|
||||
CommutativePredicate predicate = (CommutativePredicate)context;
|
||||
operands.addAll(predicate.operands);
|
||||
}
|
||||
else {
|
||||
operands.add(context);
|
||||
}
|
||||
}
|
||||
|
||||
hashCode = calculateHashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
|
||||
if (obj.getClass() == this.getClass()) {
|
||||
CommutativePredicate commutative = (CommutativePredicate)obj;
|
||||
Set<SemanticContext> otherOperands = commutative.operands;
|
||||
if (operands.size() != otherOperands.size())
|
||||
return false;
|
||||
|
||||
return operands.containsAll(otherOperands);
|
||||
}
|
||||
|
||||
if (obj instanceof NOT) {
|
||||
NOT not = (NOT)obj;
|
||||
if (not.ctx instanceof CommutativePredicate && not.ctx.getClass() != this.getClass()) {
|
||||
Set<SemanticContext> otherOperands = ((CommutativePredicate)not.ctx).operands;
|
||||
if (operands.size() != otherOperands.size())
|
||||
return false;
|
||||
|
||||
ArrayList<SemanticContext> temp = new ArrayList<SemanticContext>(operands.size());
|
||||
for (SemanticContext context : otherOperands) {
|
||||
temp.add(not(context));
|
||||
}
|
||||
|
||||
return operands.containsAll(temp);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(){
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("(");
|
||||
int i = 0;
|
||||
for (SemanticContext semctx : operands) {
|
||||
if ( i>0 ) {
|
||||
buf.append(getOperandString());
|
||||
}
|
||||
buf.append(semctx.toString());
|
||||
i++;
|
||||
}
|
||||
buf.append(")");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public abstract String getOperandString();
|
||||
|
||||
public abstract SemanticContext combinePredicates(SemanticContext left, SemanticContext right);
|
||||
|
||||
public int calculateHashCode() {
|
||||
int hashcode = 0;
|
||||
for (SemanticContext context : operands) {
|
||||
hashcode = hashcode ^ context.hashCode();
|
||||
}
|
||||
|
||||
return hashcode;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AND extends CommutativePredicate {
|
||||
public AND(SemanticContext a, SemanticContext b) {
|
||||
super(a,b);
|
||||
}
|
||||
|
||||
public AND(HashSet<SemanticContext> contexts) {
|
||||
super(contexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperandString() {
|
||||
return "&&";
|
||||
}
|
||||
|
||||
@Override
|
||||
public SemanticContext combinePredicates(SemanticContext left, SemanticContext right) {
|
||||
return SemanticContext.and(left, right);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public int calculateHashCode() {
|
||||
// int hashcode = 0;
|
||||
// for (SemanticContext context : operands) {
|
||||
// hashcode = hashcode ^ context.hashCode();
|
||||
// }
|
||||
//
|
||||
// return hashcode;
|
||||
// }
|
||||
}
|
||||
|
||||
public static class OR extends CommutativePredicate {
|
||||
public OR(SemanticContext a, SemanticContext b) {
|
||||
super(a,b);
|
||||
}
|
||||
|
||||
public OR(HashSet<SemanticContext> contexts) {
|
||||
super(contexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperandString() {
|
||||
return "||";
|
||||
}
|
||||
|
||||
@Override
|
||||
public SemanticContext combinePredicates(SemanticContext left, SemanticContext right) {
|
||||
return SemanticContext.or(left, right);
|
||||
}
|
||||
//
|
||||
// @Override
|
||||
// public int calculateHashCode() {
|
||||
// int hashcode = 0;
|
||||
// for (SemanticContext context : operands) {
|
||||
// hashcode = ~hashcode ^ context.hashCode();
|
||||
// }
|
||||
//
|
||||
// return hashcode;
|
||||
// }
|
||||
}
|
||||
|
||||
public static class NOT extends SemanticContext {
|
||||
protected SemanticContext ctx;
|
||||
public NOT(SemanticContext ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if ( !(object instanceof NOT) ) {
|
||||
return false;
|
||||
}
|
||||
return this.ctx.equals(((NOT)object).ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ~ctx.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "!("+ctx+")";
|
||||
}
|
||||
}
|
||||
|
||||
public static SemanticContext and(SemanticContext a, SemanticContext b) {
|
||||
//System.out.println("AND: "+a+"&&"+b);
|
||||
if (a instanceof FalsePredicate || b instanceof FalsePredicate)
|
||||
return new FalsePredicate();
|
||||
|
||||
SemanticContext[] terms = factorOr(a, b);
|
||||
SemanticContext commonTerms = terms[0];
|
||||
a = terms[1];
|
||||
b = terms[2];
|
||||
|
||||
boolean factored = commonTerms != null && commonTerms != EMPTY_SEMANTIC_CONTEXT && !(commonTerms instanceof TruePredicate);
|
||||
if (factored) {
|
||||
return or(commonTerms, and(a, b));
|
||||
}
|
||||
|
||||
//System.Console.Out.WriteLine( "AND: " + a + "&&" + b );
|
||||
if (a instanceof FalsePredicate || b instanceof FalsePredicate)
|
||||
return new FalsePredicate();
|
||||
|
||||
if ( a==EMPTY_SEMANTIC_CONTEXT || a==null ) {
|
||||
return b;
|
||||
}
|
||||
if ( b==EMPTY_SEMANTIC_CONTEXT || b==null ) {
|
||||
return a;
|
||||
}
|
||||
|
||||
if (a instanceof TruePredicate)
|
||||
return b;
|
||||
|
||||
if (b instanceof TruePredicate)
|
||||
return a;
|
||||
|
||||
//// Factoring takes care of this case
|
||||
//if (a.Equals(b))
|
||||
// return a;
|
||||
|
||||
//System.out.println("## have to AND");
|
||||
return new AND(a,b);
|
||||
}
|
||||
|
||||
public static SemanticContext or(SemanticContext a, SemanticContext b) {
|
||||
//System.out.println("OR: "+a+"||"+b);
|
||||
if (a instanceof TruePredicate || b instanceof TruePredicate)
|
||||
return new TruePredicate();
|
||||
|
||||
SemanticContext[] terms = factorAnd(a, b);
|
||||
SemanticContext commonTerms = terms[0];
|
||||
a = terms[1];
|
||||
b = terms[2];
|
||||
boolean factored = commonTerms != null && commonTerms != EMPTY_SEMANTIC_CONTEXT && !(commonTerms instanceof FalsePredicate);
|
||||
if (factored) {
|
||||
return and(commonTerms, or(a, b));
|
||||
}
|
||||
|
||||
if ( a==EMPTY_SEMANTIC_CONTEXT || a==null || a instanceof FalsePredicate ) {
|
||||
return b;
|
||||
}
|
||||
|
||||
if ( b==EMPTY_SEMANTIC_CONTEXT || b==null || b instanceof FalsePredicate ) {
|
||||
return a;
|
||||
}
|
||||
|
||||
if ( a instanceof TruePredicate || b instanceof TruePredicate || commonTerms instanceof TruePredicate ) {
|
||||
return new TruePredicate();
|
||||
}
|
||||
|
||||
//// Factoring takes care of this case
|
||||
//if (a.equals(b))
|
||||
// return a;
|
||||
|
||||
if ( a instanceof NOT ) {
|
||||
NOT n = (NOT)a;
|
||||
// check for !p||p
|
||||
if ( n.ctx.equals(b) ) {
|
||||
return new TruePredicate();
|
||||
}
|
||||
}
|
||||
else if ( b instanceof NOT ) {
|
||||
NOT n = (NOT)b;
|
||||
// check for p||!p
|
||||
if ( n.ctx.equals(a) ) {
|
||||
return new TruePredicate();
|
||||
}
|
||||
}
|
||||
|
||||
//System.out.println("## have to OR");
|
||||
OR result = new OR(a,b);
|
||||
if (result.operands.size() == 1)
|
||||
return result.operands.iterator().next();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static SemanticContext not(SemanticContext a) {
|
||||
if (a instanceof NOT) return ((NOT)a).ctx;
|
||||
|
||||
if (a instanceof TruePredicate) return new FalsePredicate();
|
||||
else if (a instanceof FalsePredicate) return new TruePredicate();
|
||||
|
||||
return new NOT(a);
|
||||
}
|
||||
|
||||
// Factor so (a && b) == (result && a && b)
|
||||
public static SemanticContext[] factorAnd(SemanticContext a, SemanticContext b) {
|
||||
if (a == EMPTY_SEMANTIC_CONTEXT || a == null || a instanceof FalsePredicate) {
|
||||
return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b };
|
||||
}
|
||||
if (b == EMPTY_SEMANTIC_CONTEXT || b == null || b instanceof FalsePredicate) {
|
||||
return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b };
|
||||
}
|
||||
|
||||
if (a instanceof TruePredicate || b instanceof TruePredicate) {
|
||||
return new SemanticContext[] {
|
||||
new TruePredicate(), EMPTY_SEMANTIC_CONTEXT, EMPTY_SEMANTIC_CONTEXT
|
||||
};
|
||||
}
|
||||
|
||||
HashSet<SemanticContext> opsA = new HashSet<SemanticContext>(getAndOperands(a));
|
||||
HashSet<SemanticContext> opsB = new HashSet<SemanticContext>(getAndOperands(b));
|
||||
|
||||
HashSet<SemanticContext> result = new HashSet<SemanticContext>(opsA);
|
||||
result.retainAll(opsB);
|
||||
if (result.size() == 0) {
|
||||
return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b };
|
||||
}
|
||||
|
||||
opsA.removeAll(result);
|
||||
if (opsA.size() == 0) a = new TruePredicate();
|
||||
else if (opsA.size() == 1) a = opsA.iterator().next();
|
||||
else a = new AND(opsA);
|
||||
|
||||
opsB.removeAll(result);
|
||||
if (opsB.size() == 0) b = new TruePredicate();
|
||||
else if (opsB.size() == 1) b = opsB.iterator().next();
|
||||
else b = new AND(opsB);
|
||||
|
||||
if (result.size() == 1) {
|
||||
return new SemanticContext[] { result.iterator().next(), a, b };
|
||||
}
|
||||
|
||||
return new SemanticContext[] { new AND(result), a, b };
|
||||
}
|
||||
|
||||
// Factor so (a || b) == (result || a || b)
|
||||
public static SemanticContext[] factorOr(SemanticContext a, SemanticContext b) {
|
||||
HashSet<SemanticContext> opsA = new HashSet<SemanticContext>(getOrOperands(a));
|
||||
HashSet<SemanticContext> opsB = new HashSet<SemanticContext>(getOrOperands(b));
|
||||
|
||||
HashSet<SemanticContext> result = new HashSet<SemanticContext>(opsA);
|
||||
result.retainAll(opsB);
|
||||
if (result.size() == 0) {
|
||||
return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b };
|
||||
}
|
||||
|
||||
opsA.removeAll(result);
|
||||
if (opsA.size() == 0) a = new FalsePredicate();
|
||||
else if (opsA.size() == 1) a = opsA.iterator().next();
|
||||
else a = new OR(opsA);
|
||||
|
||||
opsB.removeAll(result);
|
||||
if (opsB.size() == 0) b = new FalsePredicate();
|
||||
else if (opsB.size() == 1) b = opsB.iterator().next();
|
||||
else b = new OR(opsB);
|
||||
|
||||
if (result.size() == 1) {
|
||||
return new SemanticContext[] { result.iterator().next(), a, b };
|
||||
}
|
||||
|
||||
return new SemanticContext[] { new OR(result), a, b };
|
||||
}
|
||||
|
||||
public static Collection<SemanticContext> getAndOperands(SemanticContext context) {
|
||||
if (context instanceof AND) return ((AND)context).operands;
|
||||
|
||||
if (context instanceof NOT) {
|
||||
Collection<SemanticContext> operands = getOrOperands(((NOT)context).ctx);
|
||||
List<SemanticContext> result = new ArrayList<SemanticContext>(operands.size());
|
||||
for (SemanticContext operand : operands) {
|
||||
result.add(not(operand));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ArrayList<SemanticContext> result = new ArrayList<SemanticContext>();
|
||||
result.add(context);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Collection<SemanticContext> getOrOperands(SemanticContext context) {
|
||||
if (context instanceof OR) return ((OR)context).operands;
|
||||
|
||||
if (context instanceof NOT) {
|
||||
Collection<SemanticContext> operands = getAndOperands(((NOT)context).ctx);
|
||||
List<SemanticContext> result = new ArrayList<SemanticContext>(operands.size());
|
||||
for (SemanticContext operand : operands) {
|
||||
result.add(not(operand));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ArrayList<SemanticContext> result = new ArrayList<SemanticContext>();
|
||||
result.add(context);
|
||||
return result;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue