1/* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later. 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 */ 15 16package sample.preproc; 17 18import java.io.IOException; 19import java.io.BufferedReader; 20import java.io.FileReader; 21import java.io.BufferedWriter; 22import java.io.FileWriter; 23import java.util.Vector; 24import javassist.CannotCompileException; 25import javassist.CtClass; 26import javassist.ClassPool; 27 28/** 29 * This is a preprocessor for Java source programs using annotated 30 * import declarations. 31 * 32 * <ul><pre> 33 * import <i>class-name</i> by <i>assistant-name</i> [(<i>arg1, arg2, ...</i>)] 34 * </pre></ul> 35 * 36 * <p>To process this annotation, run this class as follows: 37 * 38 * <ul><pre> 39 * java sample.preproc.Compiler sample.j 40 * </pre></ul> 41 * 42 * <p>This command produces <code>sample.java</code>, which only includes 43 * regular import declarations. Also, the Javassist program 44 * specified by <i>assistant-name</i> is executed so that it produces 45 * class files under the <code>./tmpjvst</code> directory. The class 46 * specified by <i>assistant-name</i> must implement 47 * <code>sample.preproc.Assistant</code>. 48 * 49 * @see sample.preproc.Assistant 50 */ 51 52public class Compiler { 53 protected BufferedReader input; 54 protected BufferedWriter output; 55 protected ClassPool classPool; 56 57 /** 58 * Constructs a <code>Compiler</code> with a source file. 59 * 60 * @param inputname the name of the source file. 61 */ 62 public Compiler(String inputname) throws CannotCompileException { 63 try { 64 input = new BufferedReader(new FileReader(inputname)); 65 } 66 catch (IOException e) { 67 throw new CannotCompileException("cannot open: " + inputname); 68 } 69 70 String outputname = getOutputFilename(inputname); 71 if (outputname.equals(inputname)) 72 throw new CannotCompileException("invalid source name: " 73 + inputname); 74 75 try { 76 output = new BufferedWriter(new FileWriter(outputname)); 77 } 78 catch (IOException e) { 79 throw new CannotCompileException("cannot open: " + outputname); 80 } 81 82 classPool = ClassPool.getDefault(); 83 } 84 85 /** 86 * Starts preprocessing. 87 */ 88 public void process() throws IOException, CannotCompileException { 89 int c; 90 CommentSkipper reader = new CommentSkipper(input, output); 91 while ((c = reader.read()) != -1) { 92 output.write(c); 93 if (c == 'p') { 94 if (skipPackage(reader)) 95 break; 96 } 97 else if (c == 'i') 98 readImport(reader); 99 else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') 100 break; 101 } 102 103 while ((c = input.read()) != -1) 104 output.write(c); 105 106 input.close(); 107 output.close(); 108 } 109 110 private boolean skipPackage(CommentSkipper reader) throws IOException { 111 int c; 112 c = reader.read(); 113 output.write(c); 114 if (c != 'a') 115 return true; 116 117 while ((c = reader.read()) != -1) { 118 output.write(c); 119 if (c == ';') 120 break; 121 } 122 123 return false; 124 } 125 126 private void readImport(CommentSkipper reader) 127 throws IOException, CannotCompileException 128 { 129 int word[] = new int[5]; 130 int c; 131 for (int i = 0; i < 5; ++i) { 132 word[i] = reader.read(); 133 output.write(word[i]); 134 } 135 136 if (word[0] != 'm' || word[1] != 'p' || word[2] != 'o' 137 || word[3] != 'r' || word[4] != 't') 138 return; // syntax error? 139 140 c = skipSpaces(reader, ' '); 141 StringBuffer classbuf = new StringBuffer(); 142 while (c != ' ' && c != '\t' && c != '\n' && c != '\r' 143 && c != ';' && c != -1) { 144 classbuf.append((char)c); 145 c = reader.read(); 146 } 147 148 String importclass = classbuf.toString(); 149 c = skipSpaces(reader, c); 150 if (c == ';') { 151 output.write(importclass); 152 output.write(';'); 153 return; 154 } 155 if (c != 'b') 156 syntaxError(importclass); 157 158 reader.read(); // skip 'y' 159 160 StringBuffer assistant = new StringBuffer(); 161 Vector args = new Vector(); 162 c = readAssistant(reader, importclass, assistant, args); 163 c = skipSpaces(reader, c); 164 if (c != ';') 165 syntaxError(importclass); 166 167 runAssistant(importclass, assistant.toString(), args); 168 } 169 170 void syntaxError(String importclass) throws CannotCompileException { 171 throw new CannotCompileException("Syntax error. Cannot import " 172 + importclass); 173 } 174 175 int readAssistant(CommentSkipper reader, String importclass, 176 StringBuffer assistant, Vector args) 177 throws IOException, CannotCompileException 178 { 179 int c = readArgument(reader, assistant); 180 c = skipSpaces(reader, c); 181 if (c == '(') { 182 do { 183 StringBuffer arg = new StringBuffer(); 184 c = readArgument(reader, arg); 185 args.addElement(arg.toString()); 186 c = skipSpaces(reader, c); 187 } while (c == ','); 188 189 if (c != ')') 190 syntaxError(importclass); 191 192 return reader.read(); 193 } 194 195 return c; 196 } 197 198 int readArgument(CommentSkipper reader, StringBuffer buf) 199 throws IOException 200 { 201 int c = skipSpaces(reader, ' '); 202 while ('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' 203 || '0' <= c && c <= '9' || c == '.' || c == '_') { 204 buf.append((char)c); 205 c = reader.read(); 206 } 207 208 return c; 209 } 210 211 int skipSpaces(CommentSkipper reader, int c) throws IOException { 212 while (c == ' ' || c == '\t' || c == '\n' || c == '\r') { 213 if (c == '\n' || c == '\r') 214 output.write(c); 215 216 c = reader.read(); 217 } 218 219 return c; 220 } 221 222 /** 223 * Is invoked if this compiler encoutenrs: 224 * 225 * <ul><pre> 226 * import <i>class name</i> by <i>assistant</i> (<i>args1</i>, <i>args2</i>, ...); 227 * </pre></ul> 228 * 229 * @param classname class name 230 * @param assistantname assistant 231 * @param argv args1, args2, ... 232 */ 233 private void runAssistant(String importname, String assistantname, 234 Vector argv) 235 throws IOException, CannotCompileException 236 { 237 Class assistant; 238 Assistant a; 239 int s = argv.size(); 240 String[] args = new String[s]; 241 for (int i = 0; i < s; ++i) 242 args[i] = (String)argv.elementAt(i); 243 244 try { 245 assistant = Class.forName(assistantname); 246 } 247 catch (ClassNotFoundException e) { 248 throw new CannotCompileException("Cannot find " + assistantname); 249 } 250 251 try { 252 a = (Assistant)assistant.newInstance(); 253 } 254 catch (Exception e) { 255 throw new CannotCompileException(e); 256 } 257 258 CtClass[] imports = a.assist(classPool, importname, args); 259 s = imports.length; 260 if (s < 1) 261 output.write(" java.lang.Object;"); 262 else { 263 output.write(' '); 264 output.write(imports[0].getName()); 265 output.write(';'); 266 for (int i = 1; i < s; ++i) { 267 output.write(" import "); 268 output.write(imports[1].getName()); 269 output.write(';'); 270 } 271 } 272 } 273 274 private String getOutputFilename(String input) { 275 int i = input.lastIndexOf('.'); 276 if (i < 0) 277 i = input.length(); 278 279 return input.substring(0, i) + ".java"; 280 } 281 282 public static void main(String[] args) { 283 if (args.length > 0) 284 try { 285 Compiler c = new Compiler(args[0]); 286 c.process(); 287 } 288 catch (IOException e) { 289 System.err.println(e); 290 } 291 catch (CannotCompileException e) { 292 System.err.println(e); 293 } 294 else { 295 System.err.println("Javassist version " + CtClass.version); 296 System.err.println("No source file is specified."); 297 } 298 } 299} 300 301class CommentSkipper { 302 private BufferedReader input; 303 private BufferedWriter output; 304 305 public CommentSkipper(BufferedReader reader, BufferedWriter writer) { 306 input = reader; 307 output = writer; 308 } 309 310 public int read() throws IOException { 311 int c; 312 while ((c = input.read()) != -1) 313 if (c != '/') 314 return c; 315 else { 316 c = input.read(); 317 if (c == '/') 318 skipCxxComments(); 319 else if (c == '*') 320 skipCComments(); 321 else 322 output.write('/'); 323 } 324 325 return c; 326 } 327 328 private void skipCxxComments() throws IOException { 329 int c; 330 output.write("//"); 331 while ((c = input.read()) != -1) { 332 output.write(c); 333 if (c == '\n' || c == '\r') 334 break; 335 } 336 } 337 338 private void skipCComments() throws IOException { 339 int c; 340 boolean star = false; 341 output.write("/*"); 342 while ((c = input.read()) != -1) { 343 output.write(c); 344 if (c == '*') 345 star = true; 346 else if(star && c == '/') 347 break; 348 else 349 star = false; 350 } 351 } 352} 353