1 cananian 1.1.2.1 // ParseUtil.java, created Thu Nov 16 00:56:01 2000 by cananian 2 cananian 1.1.2.3 // Copyright (C) 2000 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1.2.1 package harpoon.Util; 5 cananian 1.1.2.1 6 cananian 1.1.2.1 import harpoon.ClassFile.HClass; 7 cananian 1.1.2.4 import harpoon.ClassFile.HField; 8 cananian 1.1.2.1 import harpoon.ClassFile.HMethod; 9 cananian 1.1.2.1 import harpoon.ClassFile.Linker; 10 cananian 1.1.2.1 import harpoon.ClassFile.NoSuchClassException; 11 cananian 1.1.2.1 12 cananian 1.1.2.1 import java.io.FileNotFoundException; 13 cananian 1.1.2.1 import java.io.IOException; 14 cananian 1.1.2.1 import java.io.InputStream; 15 cananian 1.1.2.1 import java.io.InputStreamReader; 16 cananian 1.1.2.1 import java.io.LineNumberReader; 17 cananian 1.1.2.1 import java.io.PrintStream; 18 cananian 1.1.2.1 /** 19 cananian 1.1.2.1 * <code>ParseUtil</code> implements simple parsers for common string 20 cananian 1.1.2.1 * data types. Input is from named resource files. 21 cananian 1.1.2.1 * 22 cananian 1.1.2.3 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 23 cananian 1.3 * @version $Id: ParseUtil.java,v 1.3 2002/08/06 21:16:20 cananian Exp $ 24 cananian 1.1.2.1 */ 25 cananian 1.1.2.1 public abstract class ParseUtil { 26 cananian 1.1.2.1 /** Reads from the given resource, ignoring '#' comments and blank lines, 27 cananian 1.1.2.1 * obeying 'include' directives, and invoking the given 28 cananian 1.1.2.1 * <code>StringParser</code> on any other lines. */ 29 cananian 1.1.2.1 public static void readResource(String resourceName, StringParser sp) 30 cananian 1.1.2.1 throws IOException { 31 cananian 1.1.2.1 InputStream is = ClassLoader.getSystemResourceAsStream(resourceName); 32 cananian 1.1.2.1 if (is==null) throw new FileNotFoundException(resourceName); 33 cananian 1.1.2.1 LineNumberReader r = new LineNumberReader(new InputStreamReader(is)); 34 cananian 1.1.2.1 String line; 35 cananian 1.1.2.1 while (null != (line=r.readLine())) { 36 cananian 1.1.2.1 line = line.trim(); // remove white space from both sides. 37 cananian 1.1.2.1 // allow comments and blank lines. 38 cananian 1.1.2.1 int hash = line.indexOf('#'); 39 cananian 1.1.2.1 if (hash>=0) line = line.substring(0, hash).trim(); 40 cananian 1.1.2.1 if (line.length()==0) continue; 41 cananian 1.1.2.1 // check if this is an 'include' directive. 42 cananian 1.1.2.1 if (line.startsWith("include ")) { 43 cananian 1.1.2.1 String nresource = line.substring(7).trim(); 44 cananian 1.1.2.1 try { 45 cananian 1.1.2.1 readResource(nresource, sp); 46 cananian 1.1.2.1 } catch (IOException ex) { 47 cananian 1.1.2.1 System.err.println("Error reading "+nresource+" on line "+ 48 cananian 1.1.2.1 r.getLineNumber()+" of "+resourceName); 49 cananian 1.1.2.1 throw ex; 50 cananian 1.1.2.1 } 51 cananian 1.1.2.1 } else try { 52 cananian 1.1.2.1 sp.parseString(line); 53 cananian 1.1.2.1 } catch (BadLineException ex) { 54 cananian 1.3 ex.filename = resourceName; 55 cananian 1.1.2.1 ex.line = r.getLineNumber(); 56 cananian 1.1.2.1 throw ex; // rethrow. 57 cananian 1.1.2.1 } 58 cananian 1.1.2.1 } 59 cananian 1.1.2.1 r.close(); 60 cananian 1.1.2.1 } 61 cananian 1.1.2.1 private static String firstWord(String str) throws BadLineException { 62 cananian 1.1.2.1 str = str.trim(); 63 cananian 1.1.2.1 int sp = str.indexOf(' '); 64 cananian 1.1.2.1 if (sp>=0) str=str.substring(0, sp); 65 cananian 1.1.2.1 if (str.length()==0) throw new BadLineException("no word on line"); 66 cananian 1.1.2.1 return str; 67 cananian 1.1.2.1 } 68 cananian 1.1.2.1 /** Parse a string as a class name. */ 69 cananian 1.1.2.1 public static HClass parseClass(Linker l, String className) 70 cananian 1.1.2.1 throws BadLineException { 71 cananian 1.1.2.1 className = firstWord(className); 72 cananian 1.1.2.1 try { 73 cananian 1.1.2.1 return l.forName(className); 74 cananian 1.1.2.1 } catch (NoSuchClassException ex) { 75 cananian 1.1.2.1 throw new BadLineException("No such class: "+className); 76 cananian 1.1.2.4 } 77 cananian 1.1.2.4 } 78 cananian 1.1.2.4 /** Parse a string as a field name. */ 79 cananian 1.1.2.4 public static HField parseField(Linker l, String fieldName) 80 cananian 1.1.2.4 throws BadLineException { 81 cananian 1.1.2.4 fieldName = firstWord(fieldName); 82 cananian 1.1.2.4 int dot = fieldName.lastIndexOf('.'); 83 cananian 1.1.2.4 if (dot < 0) 84 cananian 1.1.2.4 throw new BadLineException("No dot separating class and field: "+ 85 cananian 1.1.2.4 fieldName); 86 cananian 1.1.2.5 if (!(dot+1 < fieldName.length())) 87 cananian 1.1.2.5 throw new BadLineException("Dot at end of field: "+fieldName); 88 cananian 1.1.2.4 String field = fieldName.substring(dot+1); 89 cananian 1.1.2.4 String classN = fieldName.substring(0, dot); 90 cananian 1.1.2.4 HClass hc = parseClass(l, classN); 91 cananian 1.1.2.4 try { 92 cananian 1.1.2.4 return hc.getDeclaredField(field); 93 cananian 1.1.2.4 } catch (NoSuchFieldError ex) { 94 cananian 1.1.2.4 throw new BadLineException("No such field: "+fieldName); 95 cananian 1.1.2.1 } 96 cananian 1.1.2.1 } 97 cananian 1.1.2.1 /** Parse a string as a method name + descriptor string. */ 98 cananian 1.1.2.1 public static HMethod parseMethod(Linker l, String methodName) 99 cananian 1.1.2.1 throws BadLineException { 100 cananian 1.1.2.1 methodName = firstWord(methodName); 101 cananian 1.1.2.1 int lparen = methodName.indexOf('('); 102 cananian 1.1.2.1 if (lparen < 0) 103 cananian 1.1.2.1 throw new BadLineException("No left paren in method descriptor: "+ 104 cananian 1.1.2.1 methodName); 105 cananian 1.1.2.1 int rparen = methodName.indexOf(')', lparen); 106 cananian 1.1.2.1 if (rparen < 0) 107 cananian 1.1.2.1 throw new BadLineException("No right paren in method descriptor: "+ 108 cananian 1.1.2.1 methodName); 109 cananian 1.1.2.1 int dot = methodName.lastIndexOf('.', lparen); 110 cananian 1.1.2.1 if (dot < 0) 111 cananian 1.1.2.1 throw new BadLineException("No dot separating class and method: "+ 112 cananian 1.1.2.1 methodName); 113 cananian 1.1.2.1 String desc = methodName.substring(lparen); 114 cananian 1.1.2.5 if (!(dot+1 < lparen)) 115 cananian 1.1.2.5 throw new BadLineException("No method part: "+methodName); 116 cananian 1.1.2.1 String method = methodName.substring(dot+1, lparen); 117 cananian 1.1.2.1 String classN = methodName.substring(0, dot); 118 cananian 1.1.2.1 HClass hc = parseClass(l, classN); 119 cananian 1.1.2.2 if (desc.length()>2) try { // explicit descriptor. 120 cananian 1.1.2.2 return hc.getDeclaredMethod(method, desc); 121 cananian 1.1.2.1 } catch (NoSuchMethodError ex) { 122 cananian 1.1.2.1 throw new BadLineException("No method named "+method+" with "+ 123 cananian 1.1.2.1 "descriptor "+desc+" in "+hc); 124 cananian 1.1.2.2 } else { // no descriptor. hopefully method name is unique. 125 cananian 1.1.2.2 HMethod[] hm = hc.getDeclaredMethods(); 126 cananian 1.1.2.2 HMethod r = null; 127 cananian 1.1.2.2 for (int i=0; i<hm.length; i++) 128 cananian 1.1.2.2 if (hm[i].getName().equals(method)) 129 cananian 1.1.2.2 if (r==null) r = hm[i]; 130 cananian 1.1.2.2 else throw new BadLineException("More than one method "+ 131 cananian 1.1.2.2 "named "+method+" in "+hc); 132 cananian 1.1.2.2 if (r==null) throw new BadLineException("No method named "+method+ 133 cananian 1.1.2.2 " in "+hc); 134 cananian 1.1.2.2 return r; 135 cananian 1.1.2.1 } 136 cananian 1.1.2.1 } 137 cananian 1.1.2.1 /** Parse a string as a set. The string may be surrounded by optional 138 cananian 1.1.2.1 * curly braces, and elements may be delimited either spaces or 139 cananian 1.1.2.1 * commas or both. The given <code>StringParser</code> is invoked 140 cananian 1.1.2.1 * on each element in the set. */ 141 cananian 1.1.2.1 public static void parseSet(String s, StringParser sp) 142 cananian 1.1.2.1 throws BadLineException { 143 cananian 1.1.2.1 s = s.trim(); 144 cananian 1.1.2.1 // strip away braces from outside if present. 145 cananian 1.1.2.1 if (s.length()>1 && 146 cananian 1.1.2.1 s.charAt(0)=='{' && s.charAt(s.length()-1)=='}') 147 cananian 1.1.2.1 s = s.substring(1, s.length()-1).trim(); 148 cananian 1.1.2.1 // now get each element one-by-one. 149 cananian 1.1.2.1 while (s.length()>0) { 150 cananian 1.1.2.1 // delimiters are ' ' and ',' 151 cananian 1.1.2.1 int space = s.indexOf(' '); if (space<0) space = s.length(); 152 cananian 1.1.2.1 int comma = s.indexOf(','); if (comma<0) comma = s.length(); 153 cananian 1.1.2.1 int delimit = (space < comma) ? space : comma; 154 cananian 1.1.2.1 // this is the element: 155 cananian 1.1.2.1 sp.parseString(s.substring(0, delimit).trim()); 156 cananian 1.1.2.1 // now go on to the next. 157 cananian 1.1.2.1 if (s.length()==delimit) break; 158 cananian 1.1.2.1 s = s.substring(delimit+1).trim(); 159 cananian 1.1.2.1 } 160 cananian 1.1.2.1 } 161 cananian 1.1.2.1 /** Callback interface for the resource parsing routines. */ 162 cananian 1.1.2.1 public static interface StringParser { 163 cananian 1.1.2.1 public void parseString(String s) throws BadLineException ; 164 cananian 1.1.2.1 } 165 cananian 1.1.2.1 /** Exception thrown by the methods in <code>ParseUtil</code> 166 cananian 1.1.2.1 * to indicate an unparsable line in an input file. */ 167 cananian 1.1.2.1 public static class BadLineException extends IOException { 168 cananian 1.1.2.1 /** readResource will set this to the right value. */ 169 cananian 1.3 String filename=null; 170 cananian 1.3 /** ditto. */ 171 cananian 1.1.2.1 int line=0; 172 cananian 1.1.2.5 public BadLineException(String message) { super(message); } 173 cananian 1.1.2.1 public String toString() { 174 cananian 1.3 if (filename==null) return super.toString(); 175 cananian 1.3 return super.toString() + " ("+filename+": line "+line+")"; 176 cananian 1.1.2.1 } 177 cananian 1.1.2.1 } 178 cananian 1.1.2.1 } 179 cananian 1.2