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