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

PredicateProcessor.java

00001 package edu.ksu.cis.bandera.abstraction.predicate.parser;
00002 
00003 /**
00004  * Main class
00005  * Creation date: (4/8/01 10:08:26 PM)
00006  * @author: Roby Joehanes
00007  */
00008 import java.util.*;
00009 import java.io.*;
00010 import ca.mcgill.sable.soot.grimp.*;
00011 import ca.mcgill.sable.soot.jimple.*;
00012 import ca.mcgill.sable.soot.*;
00013 import edu.ksu.cis.bandera.jext.*;
00014 import edu.ksu.cis.bandera.jjjc.*;
00015 
00016 public class PredicateProcessor implements PredicateParserVisitor {
00017     private static PredicateProcessor visitor = new PredicateProcessor();
00018     private static Grimp grimp = Grimp.v();
00019     private Value baseValue = null;
00020     private static SootClassManager scm = null;
00021 /**
00022  * GrimpPredicate constructor comment.
00023  */
00024 public PredicateProcessor() {
00025     super();
00026 }
00027 public Value binOpProcess(List el, String tok, Object data)
00028 {
00029     if (el.size() == 0) throw new RuntimeException("Token or expression list is zero!");
00030     Value v1 = null, v2 = null;
00031 
00032     for (Iterator ei = el.iterator(); ei.hasNext(); )
00033     {
00034         v2 = (Value) ((SimpleNode) ei.next()).jjtAccept(this, data);
00035         if (v1 != null)
00036         {
00037             if (tok.equals("|"))
00038             {
00039                 v1 = grimp.newOrExpr(v1, v2);
00040             } else if (tok.equals("&"))
00041             {
00042                 v1 = grimp.newAndExpr(v1, v2);
00043             } else if (tok.equals("^"))
00044             {
00045                 v1 = grimp.newXorExpr(v1, v2);
00046             } else if (tok.equals("||"))
00047             {
00048                 v1 = new LogicalOrExpr(v1, v2);
00049             } else if (tok.equals("&&"))
00050             {
00051                 v1 = new LogicalAndExpr(v1, v2);
00052             } else throw new RuntimeException("Error: Undefined token '"+tok+"'");
00053         } else v1 = v2;
00054     }
00055 
00056     return v1;
00057 }
00058 public List convert(ASTCompilationUnit top)
00059 {
00060     return (List) top.jjtAccept(visitor,null);
00061 }
00062 private Value fieldAccess(String s)
00063 {
00064     String context = getContext(s);
00065     if (context == null)  return null;  // Simple names, quit
00066     
00067     // probably qualified name or in format of ClassName.blah
00068     String field;
00069     if (s.length() > context.length())
00070         field = s.substring(context.length() + 1);
00071     else field = s; /* throw new RuntimeException("Illegal field specified by '"+s+"'"); */
00072     return fieldAccess(context,field);
00073 }
00074 private Value fieldAccess(String clsName, String field)
00075 {
00076     return fieldAccess(clsName, field, null);
00077 }
00078 private Value fieldAccess(String clsName, String field, Value base)
00079 {
00080     // Field is in the form of xxxx.xxxx.xxx.xxx etc... (so it's raw)
00081     SootClass sc;
00082     SootField sf;
00083     String temp = field;
00084     int idx;
00085     String s;
00086     if (base == null) base = grimp.newLocal("this", RefType.v(clsName));
00087     if (field.equals("this")) return base;
00088     if (field == null || field.equals("")) throw new RuntimeException("Field access violation!");
00089 
00090 
00091     do {
00092 
00093         sc = getSootClass(base.getType().toString());
00094         if (sc == null) throw new RuntimeException("SootClass '"+base.getType().toString()+"' is not found!");
00095 
00096         idx = temp.indexOf('.');
00097         if (idx > -1)
00098         {
00099             s = temp.substring(0, idx);
00100             temp = temp.substring(idx + 1);
00101         } else
00102         {
00103             s = temp; temp = null;
00104         }
00105 
00106         if (!sc.declaresField(s)) return null; // We don't have such field;
00107 
00108         try
00109         {
00110             sf = sc.getField(s);
00111         } catch (Exception e)
00112         {
00113             /*try
00114             {
00115                 sf = sc.getField(s, RefType.v(base.getType().toString()));
00116             } catch (Exception e2)*/
00117             {
00118                 throw new RuntimeException("Unable to reference field '" + s + "': " + e.getMessage());
00119             }
00120         }
00121 
00122         if (Modifier.isStatic(sf.getModifiers()))
00123         {
00124             base = grimp.newStaticFieldRef(sf);
00125         } else
00126         {
00127             base = grimp.newInstanceFieldRef(base, sf);
00128         }
00129     } while (temp != null);
00130 
00131     return base;
00132 }
00133 private String getContext(String s)
00134 {
00135     if (getSootClass(s) != null) return s;  // Short-circuit trivial cases
00136 
00137     String context = s;
00138     int idx;
00139     do {
00140         idx = context.lastIndexOf('.');
00141         if (idx > -1)
00142         {
00143             context = context.substring(0,idx);
00144             if (getSootClass(context) != null) return context;
00145         }
00146     } while (idx > -1);
00147     return null;
00148 }
00149 private Value getLocal(PredicateImpl pred, String loc)
00150 {
00151     SootClass sc = pred.getClassContext();
00152     if (sc == null) throw new RuntimeException("Error: Class '"+pred.getClassName()+"' is not found!");
00153     SootMethod sm = pred.getMethodContext();
00154 
00155     JimpleBody jb = (JimpleBody) sm.getBody(Jimple.v());
00156 
00157     Value v = null;
00158     int idx = loc.indexOf('.');
00159     if (idx > -1)
00160     {
00161         // Dotted access here
00162         String first = loc.substring(0,idx);
00163         String rest = loc.substring(idx+1);
00164         if (!jb.declaresLocal(first)) return null;
00165         v = jb.getLocal(first);
00166         v = fieldAccess(sm.getName(), rest, v);
00167     } else
00168     {
00169         if (!jb.declaresLocal(loc)) return null;
00170         v = jb.getLocal(loc);
00171     }
00172 
00173     return v;
00174 }
00175 public static SootClass getSootClass(String name)
00176 {
00177     SootClass sc = scm.managesClass(name) ? scm.getClass(name) : null;
00178     return sc;
00179 }
00180 public static SootMethod getSootMethod(String cls, String method, List type)
00181 {
00182     SootClass sc = getSootClass(cls);
00183     if (sc == null) throw new RuntimeException("Cannot find class name '"+cls+"'");
00184 
00185     // Incompatible type conversion.
00186     ca.mcgill.sable.util.LinkedList ll = new ca.mcgill.sable.util.LinkedList();
00187     for (Iterator i = type.iterator(); i.hasNext(); )
00188     {
00189         ll.addLast(i.next());
00190     }
00191 
00192     SootMethod sm = sc.getMethod(method, ll);
00193     if (sm == null) System.out.println("Warning: The method '"+method+"' on class '"+cls+"' with "+type+" is not found!");
00194     return sm;
00195 }
00196 public static void main(String[] args)
00197 {
00198     if (args.length == 3)
00199     {
00200         try {
00201             CompilationManager.setDoBSL(false);
00202             CompilationManager.reset();
00203             CompilationManager.setFilename(args[2]+File.separator+args[0]);
00204             CompilationManager.setClasspath(args[2]);
00205             CompilationManager.setIncludedPackagesOrTypes(new String[0]);
00206 
00207             CompilationManager.compile();
00208             if (CompilationManager.getExceptions().size() > 0)
00209             {
00210                 throw new RuntimeException("Compilation failed!\n");
00211             }
00212             System.out.println("Compiled successfully!\n");
00213 
00214             System.out.println("Parsing: " + args[2]+File.separator+args[1]);
00215             FileInputStream in = new FileInputStream(args[2]+File.separator+args[1]);
00216             List pred = process(in, CompilationManager.getSootClassManager());
00217             if (pred == null)
00218                 System.out.println("Error!");
00219         } catch (Exception e)
00220         {
00221             System.out.println("Waaaah! " + e.getMessage());
00222         }
00223     }
00224 }
00225 public Value multiBinOpProcess(List el, List tl, Object data)
00226 {
00227     if (tl.size() == 0 || el.size() == 0) throw new RuntimeException("Token or expression list is zero!");
00228     if (tl.size() != el.size()-1) throw new RuntimeException("Unbalanced operator and operands!");
00229     Iterator ti = tl.iterator();
00230     Value v1 = null, v2 = null;
00231 
00232     for (Iterator ei = el.iterator(); ei.hasNext(); )
00233     {
00234         v2 = (Value) ((SimpleNode) ei.next()).jjtAccept(this, data);
00235         if (v1 != null)
00236         {
00237             String tok = (String) ti.next();
00238             if (tok.equals("<<"))
00239             {
00240                 v1 = grimp.newShlExpr(v1, v2);
00241             } else if (tok.equals(">>"))
00242             {
00243                 v1 = grimp.newShrExpr(v1, v2);
00244             } else if (tok.equals(">>>"))
00245             {
00246                 v1 = grimp.newUshrExpr(v1, v2);
00247             } else if (tok.equals("+"))
00248             {
00249                 v1 = grimp.newAddExpr(v1, v2);
00250             } else if (tok.equals("-"))
00251             {
00252                 v1 = grimp.newSubExpr(v1, v2);
00253             } else if (tok.equals("*"))
00254              {
00255                  v1 = grimp.newMulExpr(v1, v2);
00256              } else if (tok.equals("/"))
00257              {
00258                  v1 = grimp.newDivExpr(v1, v2);
00259              } else if (tok.equals("%"))
00260              {
00261                  v1 = grimp.newRemExpr(v1, v2);
00262              } else if (tok.equals("=="))
00263              {
00264                  v1 = grimp.newEqExpr(v1, v2);
00265              } else if (tok.equals("!="))
00266              {
00267                  v1 = grimp.newNeExpr(v1, v2);
00268             } else throw new RuntimeException("Error: Undefined token '"+tok+"'");
00269         } else v1 = v2;
00270     }
00271 
00272     return v1;
00273 }
00274 public static List process(InputStream in, SootClassManager cm) throws Exception
00275 {
00276     ASTCompilationUnit node = PredicateParser.parse(in);
00277     scm = cm;
00278     List pred = visitor.convert(node);
00279     return pred;
00280 }
00281 /**
00282  * visit method comment.
00283  */
00284 public Object visit(ASTAddSubExpr node, Object data) {
00285     return multiBinOpProcess(node.getExprList(), node.getTokenList(), data);
00286 }
00287 /**
00288  * visit method comment.
00289  */
00290 public Object visit(ASTAndExpr node, Object data) {
00291     return binOpProcess(node.getExprList(), node.getToken(), data);
00292 }
00293 /**
00294  * visit method comment.
00295  */
00296 public Object visit(ASTArguments node, Object data) {
00297     List args = node.getArguments();
00298     LinkedList l = new LinkedList();
00299 
00300     for (Iterator i = args.iterator(); i.hasNext(); )
00301     {
00302         l.addLast(((SimpleNode) i.next()).jjtAccept(this, data));
00303     }
00304     return l;
00305 }
00306 /**
00307  * visit method comment.
00308  */
00309 public Object visit(ASTArrayExpr node, Object data) {
00310     Value arr = (Value) node.getExpr().jjtAccept(this, data);
00311     String s = node.getTag();
00312     if (s != null) // The first
00313     {
00314         arr = grimp.newArrayRef(fieldAccess(s),arr);
00315     } else   // The trailing []
00316     {
00317         if (baseValue == null) throw new RuntimeException("We've gotta have a base value!");
00318         arr = grimp.newArrayRef(baseValue,arr);
00319     }
00320 
00321     return arr;
00322 }
00323 /**
00324  * visit method comment.
00325  */
00326 public Object visit(ASTBitAndExpr node, Object data) {
00327     return binOpProcess(node.getExprList(), node.getToken(), data);
00328 }
00329 /**
00330  * visit method comment.
00331  */
00332 public Object visit(ASTBitOrExpr node, Object data) {
00333     return binOpProcess(node.getExprList(), node.getToken(), data);
00334 }
00335 /**
00336  * visit method comment.
00337  */
00338 public Object visit(ASTBitXorExpr node, Object data) {
00339     return binOpProcess(node.getExprList(), node.getToken(), data);
00340 }
00341 /**
00342  * visit method comment.
00343  */
00344 public Object visit(ASTCastExpr node, Object data) {
00345     Value v = (Value) node.getExpr().jjtAccept(this,data);
00346     Type  t = (Type) node.getType().jjtAccept(this,data);
00347     return grimp.newCastExpr(v,t);
00348 }
00349 /**
00350  * visit method comment.
00351  */
00352 public Object visit(ASTCastLookahead node, Object data) {
00353     throw new RuntimeException("CastLookahead is unused!");
00354 }
00355 /**
00356  * visit method comment.
00357  */
00358 public Object visit(ASTCompilationUnit node, Object data) {
00359     List ll = node.getPredicate();
00360 
00361     if (ll == null || ll.isEmpty()) throw new RuntimeException("Predicate Processor: No predicates are mentioned!");
00362     for (Iterator i = ll.iterator(); i.hasNext(); )
00363     {
00364         PredicateImpl p = (PredicateImpl) i.next();
00365         p.resolveArgs(this);
00366         p.setExpr((Value) p.getExprAST().jjtAccept(this,p));
00367     }
00368     return ll;
00369 }
00370 /**
00371  * visit method comment.
00372  */
00373 public Object visit(ASTCondExpr node, Object data) {
00374     SimpleNode ts = node.getTestExpr(), th = node.getThenExpr(), el = node.getElseExpr(), result;
00375 
00376     Value v1 = (Value) ts.jjtAccept(this, data);
00377     Value v2 = (Value) th.jjtAccept(this, data);
00378     Value v3 = (Value) el.jjtAccept(this, data);
00379 
00380     return new HookExpr(v1, v2, v3);
00381 }
00382 /**
00383  * visit method comment.
00384  */
00385 public Object visit(ASTDotClassExpr node, Object data) {
00386     if (baseValue != null) throw new RuntimeException("dot class expression: Invalid combination!");
00387 
00388     Type t = (Type) node.getExpr().jjtAccept(this,data);
00389     Vector param = new Vector();
00390     ca.mcgill.sable.util.LinkedList l = new ca.mcgill.sable.util.LinkedList();
00391 
00392     l.addLast(node.getTag());
00393     param.add("java.lang.String");
00394 
00395     return grimp.newStaticInvokeExpr(getSootMethod("java.lang.Class","forName",param),l);
00396 }
00397 /**
00398  * visit method comment.
00399  */
00400 public Object visit(ASTDottedExpr node, Object data) {
00401     if (baseValue == null) throw new RuntimeException("dotted expression: Invalid combination!");
00402     return fieldAccess(((PredicateImpl) data).getClassName(), node.getTag(), baseValue);
00403 }
00404 /**
00405  * visit method comment.
00406  */
00407 public Object visit(ASTEqExpr node, Object data) {
00408     return multiBinOpProcess(node.getExprList(), node.getTokenList(), data);
00409 }
00410 /**
00411  * visit method comment.
00412  */
00413 public Object visit(ASTInstanceOfExpr node, Object data) {
00414     Value v = (Value) node.getExpr().jjtAccept(this,data);
00415     Type t = (Type) node.getType().jjtAccept(this,data);
00416     return grimp.newInstanceOfExpr(v,t);
00417 }
00418 /**
00419  * visit method comment.
00420  */
00421 public Object visit(ASTLiteral node, Object data) {
00422     Object l = node.getLiteral();
00423 
00424     if (l == null) return NullConstant.v();
00425     if (l instanceof Integer) return IntConstant.v(((Integer) l).intValue());
00426     if (l instanceof Long) return LongConstant.v(((Long) l).longValue());
00427     if (l instanceof Float) return FloatConstant.v(((Float) l).floatValue());
00428     if (l instanceof Double) return DoubleConstant.v(((Double) l).doubleValue());
00429     if (l instanceof Boolean) return null;
00430     if (l instanceof Character) return null;
00431     if (l instanceof String) return StringConstant.v((String) l);
00432 
00433     throw new RuntimeException("Undefined Literal!");
00434 }
00435 /**
00436  * visit method comment.
00437  */
00438 public Object visit(ASTMulDivExpr node, Object data) {
00439     return multiBinOpProcess(node.getExprList(), node.getTokenList(), data);
00440 }
00441 /**
00442  * visit method comment.
00443  */
00444 public Object visit(ASTName node, Object data) {
00445     return node.getTag();
00446 }
00447 /**
00448  * visit method comment.
00449  */
00450 public Object visit(ASTOrExpr node, Object data) {
00451     return binOpProcess(node.getExprList(), node.getToken(), data);
00452 }
00453 /**
00454  * visit method comment.
00455  */
00456 public Object visit(ASTPrimaryExpr node, Object data) {
00457 
00458     baseValue = null;
00459     for (Iterator i = node.getNodes().iterator(); i.hasNext(); )
00460     {
00461         SimpleNode n = (SimpleNode) i.next();
00462     
00463         if (n instanceof ASTName)
00464         {
00465             if (baseValue != null) throw new RuntimeException("Name expression: Invalid combination!");
00466             String s = (String) n.jjtAccept(this,data);
00467             // No trailling ends, then we're accessing field.
00468             if (!i.hasNext())
00469             {
00470                 if (getContext(s) == null)
00471                 {
00472                     // Deal with locals or field.
00473                     PredicateImpl pred = (PredicateImpl) data;
00474 
00475                     Value v = getLocal(pred,s); // Is it a local?
00476                     if (v != null)
00477                     {
00478                         return v; // Yup...
00479                     }
00480 
00481                     v = fieldAccess(pred.getClassName(),s); // Is it a field?
00482                     if (v != null)
00483                     {
00484                         return v; // Yup...
00485                     }
00486 
00487                     // Nope? Uh oh... an error happens...
00488                     throw new RuntimeException("Invalid reference on '"+s+"'");
00489 
00490                 } else
00491                 {
00492                     // So, we have a fully qualified name
00493                     Value v = (Value) fieldAccess(s);
00494                     if (v != null) return v; // Success? Good for you...
00495 
00496                     // Nope? Uh oh... an error happens...
00497                     throw new RuntimeException("Invalid reference on '"+s+"'");
00498                 }
00499                 
00500             } else throw new RuntimeException("Unhandled case!");
00501         } else if (n instanceof ASTLiteral)
00502         {
00503             if (baseValue != null) throw new RuntimeException("Literal expression: Invalid combination!");
00504 
00505             Value v = (Value) n.jjtAccept(this,data);
00506             if (!i.hasNext()) return v;
00507             if (i.hasNext() && !(v instanceof StringConstant))
00508             {
00509                  throw new RuntimeException("Illegal literal expression: It can't be trailled by any other things!");
00510             }
00511             // We're sure at this point v is a string constant and has a trailling nodes.
00512             // But, we won't handle that anyway, so bail out!
00513             throw new RuntimeException("String literal with method call: Unhandled case!");
00514         } else if (n instanceof ASTThisExpr)
00515         {
00516             baseValue = (Value) n.jjtAccept(this,data);
00517         } else if (n instanceof ASTSuperExpr)
00518         {
00519             baseValue = (Value) n.jjtAccept(this,data);
00520         } else if (n instanceof ASTDottedExpr)
00521         {
00522             baseValue = (Value) n.jjtAccept(this,data);
00523         } else if (n instanceof ASTDotClassExpr)
00524         {
00525             baseValue = (Value) n.jjtAccept(this,data);
00526         } else if (n instanceof ASTArrayExpr)
00527         {
00528             baseValue = (Value) n.jjtAccept(this,data);
00529         } else throw new RuntimeException("Unexpected nodes!");
00530     }
00531     if (baseValue == null) throw new RuntimeException("Unexpected end of nodes!");
00532     return baseValue;
00533 }
00534 /**
00535  * visit method comment.
00536  */
00537 public Object visit(ASTPrimitiveType node, Object data) {
00538     throw new RuntimeException("PrimitiveType is unused! It's already bypassed");
00539 }
00540 /**
00541  * visit method comment.
00542  */
00543 public Object visit(ASTRelationalExpr node, Object data) {
00544     Value v1 = (Value) node.getOp1().jjtAccept(this, data);
00545     Value v2 = (Value) node.getOp2().jjtAccept(this, data);
00546     String tok = node.getTag();
00547 
00548     if (tok.equals("<"))
00549     {
00550         return grimp.newLtExpr(v1, v2);
00551     } else if (tok.equals(">"))
00552     {
00553         return grimp.newGtExpr(v1, v2);
00554     } else if (tok.equals("<="))
00555     {
00556         return grimp.newLeExpr(v1, v2);
00557     } else if (tok.equals(">="))
00558     {
00559         return grimp.newGeExpr(v1, v2);
00560     } else throw new RuntimeException("Error: Undefined token '"+tok+"'");
00561 }
00562 /**
00563  * visit method comment.
00564  */
00565 public Object visit(ASTShiftExpr node, Object data) {
00566     return multiBinOpProcess(node.getExprList(), node.getTokenList(), data);
00567 }
00568 /**
00569  * visit method comment.
00570  */
00571 public Object visit(ASTSuperExpr node, Object data) {
00572     if (baseValue == null)
00573         return grimp.newThisRef(((PredicateImpl) data).getClassContext().getSuperClass());
00574     else
00575     {
00576         if (baseValue instanceof ThisRef)
00577             return grimp.newThisRef(getSootClass(baseValue.getType().toString()).getSuperClass());
00578         else throw new RuntimeException("Invalid combination on 'super' exception");
00579     }
00580 }
00581 /**
00582  * visit method comment.
00583  */
00584 public Object visit(ASTThisExpr node, Object data) {
00585     if (baseValue != null) throw new RuntimeException("'this' expression: Invalid combination!");
00586     return grimp.newThisRef(((PredicateImpl) data).getClassContext());
00587 }
00588 /**
00589  * visit method comment.
00590  */
00591 public Object visit(ASTType node, Object data) {
00592     String type = node.getBaseType();
00593     int dim = node.getDimension();
00594     Type t;
00595 
00596     if (type.equals("int")) t = IntType.v();
00597     else if (type.equals("long")) t = LongType.v();
00598     else if (type.equals("boolean")) t = BooleanType.v();
00599     else if (type.equals("char")) t = CharType.v();
00600     else if (type.equals("short")) t = ShortType.v();
00601     else if (type.equals("byte")) t = ByteType.v();
00602     else if (type.equals("float")) t = FloatType.v();
00603     else if (type.equals("double")) t = DoubleType.v();
00604     else t = RefType.v(type);
00605 
00606     if (dim > 0) t = ArrayType.v((BaseType) t, dim);
00607 
00608     return t;
00609 }
00610 /**
00611  * visit method comment.
00612  */
00613 public Object visit(ASTUnaryExpr node, Object data) {
00614     return node.getExpr().jjtAccept(this,data);
00615 }
00616 /**
00617  * visit method comment.
00618  */
00619 public Object visit(ASTUnaryMathExpr node, Object data) {
00620     Value v = (Value) (node.getExpr().jjtAccept(this,data));
00621     String tok = node.getTag();
00622     if (tok.equals("+"))
00623     {
00624         // do nothing
00625     } else if (tok.equals("-"))
00626     {
00627         v = grimp.newNegExpr(v);
00628     } else if (tok.equals("~"))
00629     {
00630         // ~x = -1 - x;
00631         Type t = v.getType();
00632         if (t instanceof ArrayType) t = ((ArrayType) t).baseType;
00633         if (t.equals(IntType.v()) || t.equals(ShortType.v()) || t.equals(ByteType.v()))
00634         {
00635             v = grimp.newSubExpr(IntConstant.v(-1), v);
00636         } else if (t.equals(LongType.v()))
00637         {
00638             v = grimp.newSubExpr(LongConstant.v(-1), v);
00639         } else throw new RuntimeException("Error: Cannot apply ~ operator to "+t.toString()+" on "+v.toString());
00640     } else if (tok.equals("!"))
00641     {
00642         v = new LogicalNotExpr(v);
00643     } else throw new RuntimeException("Error: Unexpected token '"+tok+"'");
00644      return v;
00645 }
00646 /**
00647  * visit method comment.
00648  */
00649 public Object visit(SimpleNode node, Object data) {
00650     throw new RuntimeException("SimpleNode is unused!");
00651 }
00652 }

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