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