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