Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

CaseNode.java

00001 package edu.ksu.cis.bandera.spin;
00002 
00003 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00004  * Bandera, a Java(TM) analysis and transformation toolkit           *
00005  * Copyright (C) 1998, 1999   James Corbett (corbett@hawaii.edu)     *
00006  * All rights reserved.                                              *
00007  *                                                                   *
00008  * This work was done as a project in the SAnToS Laboratory,         *
00009  * Department of Computing and Information Sciences, Kansas State    *
00010  * University, USA (http://www.cis.ksu.edu/santos).                  *
00011  * It is understood that any modification not identified as such is  *
00012  * not covered by the preceding statement.                           *
00013  *                                                                   *
00014  * This work is free software; you can redistribute it and/or        *
00015  * modify it under the terms of the GNU Library General Public       *
00016  * License as published by the Free Software Foundation; either      *
00017  * version 2 of the License, or (at your option) any later version.  *
00018  *                                                                   *
00019  * This work is distributed in the hope that it will be useful,      *
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *
00022  * Library General Public License for more details.                  *
00023  *                                                                   *
00024  * You should have received a copy of the GNU Library General Public *
00025  * License along with this toolkit; if not, write to the             *
00026  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,      *
00027  * Boston, MA  02111-1307, USA.                                      *
00028  *                                                                   *
00029  * Java is a trademark of Sun Microsystems, Inc.                     *
00030  *                                                                   *
00031  * To submit a bug report, send a comment, or get the latest news on *
00032  * this project and other SAnToS projects, please visit the web-site *
00033  *                http://www.cis.ksu.edu/santos                      *
00034  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00035 import java.io.*;
00036 import java.util.*;
00037 
00038 import edu.ksu.cis.bandera.bir.*;
00039 
00040 /**
00041  * Case node of case tree. 
00042  * <p>
00043  * A case node represents a conditional expression.  Each case has
00044  * a condition and a value (another case tree node).
00045  * The cases must be mutually exclusive and 
00046  * the last case must be the default (i.e., is the value of the
00047  * expression if all the previous conditions are false).
00048  */
00049 
00050 public class CaseNode implements TreeNode {
00051     
00052     int size = 0;               // number of cases
00053     Case [] data;               // cases
00054 
00055     public CaseNode() { this(10); }
00056     public CaseNode(int capacity) {
00057     data = new Case[capacity];
00058     }
00059     public CaseNode(Case x) {
00060     this(10);
00061     addElement(x);
00062     }
00063     public void addCase(String cond, TreeNode node) {
00064     addElement(new Case(cond,node));
00065     }
00066     public void addCase(String cond, String expr) {
00067     addElement(new Case(cond,new ExprNode(expr)));
00068     }
00069     public void addElement(Case x) {
00070     if (x == null)
00071         throw new RuntimeException("Element cannot be null");
00072     if (size == data.length)
00073         expand();
00074     data[size++] = x;
00075     }
00076     public void addTrapCase(String cond, String desc, boolean fatal) {
00077     addElement(new Case(cond,new TrapNode(desc,fatal)));
00078     }
00079     /**
00080      * Make a copy of this CaseNode (and its Cases).
00081      */
00082 
00083     public Object clone() {
00084     CaseNode result = new CaseNode(this.data.length);
00085     for (int i = 0; i < this.size(); i++)
00086         result.addElement((Case)this.elementAt(i).clone());
00087     return result;
00088     }
00089     /**
00090      * Compose this case node with another case tree.
00091      * <p>
00092      * Basically this just clones the original case tree all the
00093      * way down to the leaves so that when we append the other
00094      * tree to the leaf, we don't change the original case tree.
00095      * <p>
00096      * The context argument is used to allow nodes to update
00097      * their parent pointers.
00098      */
00099 
00100     public TreeNode compose(TreeNode tree, Case context) {
00101     CaseNode result = (CaseNode) this.clone();
00102     for (int i = 0; i < result.size(); i++) {
00103         Case c = result.elementAt(i);
00104         c.parent = context;
00105         c.node = c.node.compose(tree,c);
00106     }
00107     return result;
00108     }
00109     /**
00110      * Check if case is inconsistent (conflicts with some parent case's
00111      * condition).
00112      * <p>
00113      * We do a simple text-based match on the expressions looking for
00114      * certain common patterns.  This is not a general constraint
00115      * consistency check (which is OK, since if we fail to detect
00116      * an inconsistency, it just results in more PROMELA code, not
00117      * an incorrect model).
00118      * <p>
00119      * In particular, we look for conditions of the form "x == S"
00120      * and "x == R" where S does not equal R.
00121      */
00122 
00123     boolean conditionInconsistent(String cond, Case context) {
00124     // Punt if not an equality or contains &&, ||, !
00125     if (cond.indexOf("==") < 0 || cond.indexOf("&&") >= 0 
00126         || cond.indexOf("||") >= 0 || cond.indexOf("!") >= 0)
00127         return false;
00128     while (context != null) {
00129         // Assume cond is of the form: var == val
00130         String var = cond.substring(0,cond.indexOf("=="));
00131         String val = cond.substring(cond.indexOf("=="));
00132         int pos = context.cond.indexOf("==");
00133         if (pos > 0 && context.cond.substring(0,pos).equals(var)
00134         && ! context.cond.substring(pos).equals(val)) 
00135         return true;
00136         context = context.parent;
00137     }
00138     return false;
00139     }
00140     /**
00141      * Check if condition is redundant (appears as condition of some 
00142      * parent case).
00143      */
00144 
00145     boolean conditionRedundant(String cond, Case context) {
00146     while (context != null) {
00147         if (context.cond.equals(cond))
00148         return true;
00149         context = context.parent;
00150     }
00151     return false;
00152     }
00153     public Case elementAt(int pos) {
00154     if (pos < 0 || pos >= size) 
00155         throw new RuntimeException("Position invalid: " + pos);
00156     return data[pos];
00157     }
00158     // Grow case array
00159     void expand() {
00160     Case [] newData = new Case[data.length * 2];
00161     for (int i = 0; i < data.length; i++) 
00162         newData[i] = data[i];
00163     data = newData;
00164     }
00165     public Case firstElement() { return elementAt(0); }
00166     public TreeNode getCase(String cond) {
00167     for (int i = 0; i < size(); i++) 
00168         if (elementAt(i).cond.equals(cond))
00169         return elementAt(i).node;
00170     throw new RuntimeException("No such case: " + cond);
00171     }
00172     /**
00173      * Collect all leaf cases (Case nodes with ExprNode values) 
00174      * into the vector.
00175      */
00176 
00177     public Vector getLeafCases(Vector leafCases) {
00178     for (int i = 0; i < size(); i++) 
00179         if (elementAt(i).node instanceof CaseNode)
00180         elementAt(i).node.getLeafCases(leafCases);
00181         else if (elementAt(i).node instanceof ExprNode) 
00182         leafCases.addElement(elementAt(i));
00183     // Note: we don't count traps as leaves
00184     return leafCases;
00185     }
00186     /**
00187      * Collect all leaves (ExprNodes) into the vector.
00188      */
00189 
00190     public Vector getLeaves(Vector leaves) {
00191     for (int i = 0; i < size(); i++) 
00192         elementAt(i).node.getLeaves(leaves);
00193     return leaves;
00194     }
00195     void indent(int level) {
00196     for (int i = 0; i < level; i++)
00197         System.out.print("   ");
00198     }
00199     public int indexOf(Case x) {
00200     for (int i = 0; i < size; i++) 
00201         if (data[i] == x)
00202         return i;
00203     return -1;
00204     }
00205     public void insertElementAt(Case x, int pos) {
00206     if (x == null)
00207         throw new RuntimeException("Element cannot be null");
00208     if (size == data.length)
00209         expand();
00210     if (pos > size || pos < 0)
00211         throw new RuntimeException("Position invalid: " + pos);
00212     // Auto expand like Vector
00213     for (int i = size; i > pos; i--) 
00214         data[i] = data[i-1];
00215     data[pos] = x;
00216     size++;
00217     }
00218     public void print(int level) {
00219     System.out.println();
00220     for (int i = 0; i < size(); i++) {
00221         Case c = elementAt(i);
00222         indent(level);
00223         System.out.print(c.cond + " => ");
00224         c.node.print(level+1);
00225     }
00226     }
00227     public int size() { return size; }
00228     /**
00229      * Specialize a case tree to a given context.
00230      * <p>
00231      * Like compose() above, this clones the case tree
00232      * as it walks over it (the second case tree being composed),
00233      * and it specializes as it constructs the new cases.
00234      * In particular:
00235      * <ul>
00236      * <li> If some case's condition appeared in
00237      *   a parent case, then we specialize the CaseExpr
00238      *   to the value of that case's condition.
00239      * <li> If the first N-1 case conditions are inconsistent with the
00240      *  conditions in the parent cases, then we specialize the CaseExpr
00241      *  to the value of the last case.
00242      * </ul>
00243      */
00244 
00245     public TreeNode specialize(ExprNode leaf, Case context) {
00246     CaseNode result = (CaseNode) this.clone();
00247     int numInconsistent = 0;
00248     for (int i = 0; i < result.size(); i++) {
00249         Case c = result.elementAt(i);
00250         if (conditionRedundant(c.cond, context) 
00251         || ((i == (result.size() - 1)) 
00252             && (i == numInconsistent)))
00253         return c.node.specialize(leaf,context);
00254         if (conditionInconsistent(c.cond, context)) 
00255         numInconsistent++;
00256         c.parent = context;
00257         c.node = c.node.specialize(leaf,c);
00258     }
00259     return result;  
00260     }
00261 }

Generated at Thu Feb 7 06:41:48 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001