Package org.antlr.analysis

Source Code of org.antlr.analysis.SemanticContext$NOT

/*
* [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.codegen.CodeGenerator;
import org.antlr.grammar.v3.ANTLRParser;
import org.antlr.tool.Grammar;
import org.antlr.tool.GrammarAST;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;

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 NFA o-p1->o-p2->o, create tree AND(p1,p2).
*  For NFA (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.
*
*  July 7, 2006: TJP altered OR to be set of operands. the Binary tree
*  made it really hard to reduce complicated || sequences to their minimum.
*  Got huge repeated || conditions.
*/
public abstract class SemanticContext {
  /** Create a default value for the semantic context shared among all
   *  NFAConfigurations 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(Predicate.INVALID_PRED_VALUE);

  /** Given a semantic context expression tree, return a tree with all
   *  nongated predicates set to true and then reduced.  So p&&(q||r) would
   *  return p&&r if q is nongated but p and r are gated.
   */
  public abstract SemanticContext getGatedPredicateContext();

  /** Generate an expression that will evaluate the semantic context,
   *  given a set of output templates.
   */
  public abstract ST genExpr(CodeGenerator generator,
                       STGroup templates,
                       DFA dfa);

  public abstract boolean hasUserSemanticPredicate(); // user-specified sempred {}? or {}?=>
  public abstract boolean isSyntacticPredicate();

  /** Notify the indicated grammar of any syn preds used within this context */
  public void trackUseOfSyntacticPredicates(Grammar g) {
  }

  public static class Predicate extends SemanticContext {
    /** The AST node in tree created from the grammar holding the predicate */
    public GrammarAST predicateAST;

    /** Is this a {...}?=> gating predicate or a normal disambiguating {..}?
     *  If any predicate in expression is gated, then expression is considered
     *  gated.
     *
     *  The simple Predicate object's predicate AST's type is used to set
     *  gated to true if type==GATED_SEMPRED.
     */
    protected boolean gated = false;

    /** syntactic predicates are converted to semantic predicates
     *  but synpreds are generated slightly differently.
     */
    protected boolean synpred = false;

    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;

    public Predicate(int constantValue) {
      predicateAST = new GrammarAST();
      this.constantValue=constantValue;
    }

    public Predicate(GrammarAST predicate) {
      this.predicateAST = predicate;
      this.gated =
        predicate.getType()==ANTLRParser.GATED_SEMPRED ||
        predicate.getType()==ANTLRParser.SYN_SEMPRED ;
      this.synpred =
        predicate.getType()==ANTLRParser.SYN_SEMPRED ||
        predicate.getType()==ANTLRParser.BACKTRACK_SEMPRED;
    }

    public Predicate(Predicate p) {
      this.predicateAST = p.predicateAST;
      this.gated = p.gated;
      this.synpred = p.synpred;
      this.constantValue = p.constantValue;
    }

    /** Two predicates are the same if they are literally the same
     *  text rather than same node in the grammar's AST.
     *  Or, if they have the same constant value, return equal.
     *  As of July 2006 I'm not sure these are needed.
     */
    @Override
    public boolean equals(Object o) {
      if ( !(o instanceof Predicate) ) {
        return false;
      }

      Predicate other = (Predicate)o;
      if (this.constantValue != other.constantValue){
        return false;
      }

      if (this.constantValue != INVALID_PRED_VALUE){
        return true;
      }

      return predicateAST.getText().equals(other.predicateAST.getText());
    }

    @Override
    public int hashCode() {
      if (constantValue != INVALID_PRED_VALUE){
        return constantValue;
      }

      if ( predicateAST ==null ) {
        return 0;
      }

      return predicateAST.getText().hashCode();
    }

    @Override
    public ST genExpr(CodeGenerator generator,
                    STGroup templates,
                    DFA dfa)
    {
      ST eST;
      if ( templates!=null ) {
        if ( synpred ) {
          eST = templates.getInstanceOf("evalSynPredicate");
        }
        else {
          eST = templates.getInstanceOf("evalPredicate");
          generator.grammar.decisionsWhoseDFAsUsesSemPreds.add(dfa);
        }
        String predEnclosingRuleName = predicateAST.enclosingRuleName;
        /*
        String decisionEnclosingRuleName =
          dfa.getNFADecisionStartState().getEnclosingRule();
        // if these rulenames are diff, then pred was hoisted out of rule
        // Currently I don't warn you about this as it could be annoying.
        // I do the translation anyway.
        */
        //eST.add("pred", this.toString());
        if ( generator!=null ) {
          eST.add("pred",
                   generator.translateAction(predEnclosingRuleName,predicateAST));
        }
      }
      else {
        eST = new ST("<pred>");
        eST.add("pred", this.toString());
        return eST;
      }
      if ( generator!=null ) {
        String description =
          generator.target.getTargetStringLiteralFromString(this.toString());
        eST.add("description", description);
      }
      return eST;
    }

    @Override
    public SemanticContext getGatedPredicateContext() {
      if ( gated ) {
        return this;
      }
      return null;
    }

    @Override
    public boolean hasUserSemanticPredicate() { // user-specified sempred
      return predicateAST !=null &&
           ( predicateAST.getType()==ANTLRParser.GATED_SEMPRED ||
           predicateAST.getType()==ANTLRParser.SEMPRED );
    }

    @Override
    public boolean isSyntacticPredicate() {
      return predicateAST !=null &&
        ( predicateAST.getType()==ANTLRParser.SYN_SEMPRED ||
          predicateAST.getType()==ANTLRParser.BACKTRACK_SEMPRED );
    }

    @Override
    public void trackUseOfSyntacticPredicates(Grammar g) {
      if ( synpred ) {
        g.synPredNamesUsedInDFA.add(predicateAST.getText());
      }
    }

    @Override
    public String toString() {
      if ( predicateAST ==null ) {
        return "<nopred>";
      }
      return predicateAST.getText();
    }
  }

  public static class TruePredicate extends Predicate {
    public TruePredicate() {
      super(TRUE_PRED);
    }

    @Override
    public ST genExpr(CodeGenerator generator,
                    STGroup templates,
                    DFA dfa)
    {
      if ( templates!=null ) {
        return templates.getInstanceOf("true_value");
      }
      return new ST("true");
    }

    @Override
    public boolean hasUserSemanticPredicate() {
      return false; // not user specified.
    }

    @Override
    public String toString() {
      return "true"; // not used for code gen, just DOT and print outs
    }
  }

  public static class FalsePredicate extends Predicate {
    public FalsePredicate() {
      super(FALSE_PRED);
    }

    @Override
    public ST genExpr(CodeGenerator generator,
                    STGroup templates,
                    DFA dfa)
    {
      if ( templates!=null ) {
        return templates.getInstanceOf("false");
      }
      return new ST("false");
    }

    @Override
    public boolean hasUserSemanticPredicate() {
      return false; // not user specified.
    }

    @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 SemanticContext getGatedPredicateContext() {
      SemanticContext result = null;
      for (SemanticContext semctx : operands) {
        SemanticContext gatedPred = semctx.getGatedPredicateContext();
        if ( gatedPred!=null ) {
          result = combinePredicates(result, gatedPred);
        }
      }
      return result;
    }

    @Override
    public boolean hasUserSemanticPredicate() {
      for (SemanticContext semctx : operands) {
        if ( semctx.hasUserSemanticPredicate() ) {
          return true;
        }
      }
      return false;
    }

    @Override
    public boolean isSyntacticPredicate() {
      for (SemanticContext semctx : operands) {
        if ( semctx.isSyntacticPredicate() ) {
          return true;
        }
      }
      return false;
    }

    @Override
    public void trackUseOfSyntacticPredicates(Grammar g) {
      for (SemanticContext semctx : operands) {
        semctx.trackUseOfSyntacticPredicates(g);
      }
    }

    @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() {
      StringBuilder buf = new StringBuilder();
      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 abstract int calculateHashCode();
  }

  public static class AND extends CommutativePredicate {
    public AND(SemanticContext a, SemanticContext b) {
      super(a,b);
    }

    public AND(HashSet<SemanticContext> contexts) {
      super(contexts);
    }

    @Override
    public ST genExpr(CodeGenerator generator,
                    STGroup templates,
                    DFA dfa)
    {
      ST result = null;
      for (SemanticContext operand : operands) {
        if (result == null) {
          result = operand.genExpr(generator, templates, dfa);
          continue;
        }

        ST eST;
        if ( templates!=null ) {
          eST = templates.getInstanceOf("andPredicates");
        }
        else {
          eST = new ST("(<left>&&<right>)");
        }
        eST.add("left", result);
        eST.add("right", operand.genExpr(generator,templates,dfa));
        result = eST;
      }

      return result;
    }

    @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 ST genExpr(CodeGenerator generator,
                    STGroup templates,
                    DFA dfa)
    {
      ST eST;
      if ( templates!=null ) {
        eST = templates.getInstanceOf("orPredicates");
      }
      else {
        eST = new ST("(<operands; separator=\"||\">)");
      }
      for (SemanticContext semctx : operands) {
        eST.add("operands", semctx.genExpr(generator,templates,dfa));
      }
      return eST;
    }

    @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 ST genExpr(CodeGenerator generator,
                    STGroup templates,
                    DFA dfa)
    {
      ST eST;
      if ( templates!=null ) {
        eST = templates.getInstanceOf("notPredicate");
      }
      else {
        eST = new ST("!(<pred>)");
      }
      eST.add("pred", ctx.genExpr(generator,templates,dfa));
      return eST;
    }

    @Override
    public SemanticContext getGatedPredicateContext() {
      SemanticContext p = ctx.getGatedPredicateContext();
      if ( p==null ) {
        return null;
      }
      return new NOT(p);
    }

    @Override
    public boolean hasUserSemanticPredicate() {
      return ctx.hasUserSemanticPredicate();
    }

    @Override
    public boolean isSyntacticPredicate() {
      return ctx.isSyntacticPredicate();
    }

    @Override
    public void trackUseOfSyntacticPredicates(Grammar g) {
      ctx.trackUseOfSyntacticPredicates(g);
    }

    @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");
    AND result = new AND(a,b);
    if (result.operands.size() == 1) {
      return result.operands.iterator().next();
    }

    return result;
  }

  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.isEmpty())
      return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b };

    opsA.removeAll(result);
    if (opsA.isEmpty())
      a = new TruePredicate();
    else if (opsA.size() == 1)
      a = opsA.iterator().next();
    else
      a = new AND(opsA);

    opsB.removeAll(result);
    if (opsB.isEmpty())
      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.isEmpty())
      return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b };

    opsA.removeAll(result);
    if (opsA.isEmpty())
      a = new FalsePredicate();
    else if (opsA.size() == 1)
      a = opsA.iterator().next();
    else
      a = new OR(opsA);

    opsB.removeAll(result);
    if (opsB.isEmpty())
      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;
  }
}
TOP

Related Classes of org.antlr.analysis.SemanticContext$NOT

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.