pluotsorbet/java/tools/Jpp.java

399 строки
9.0 KiB
Java

/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
import java.io.*;
/**
* A simple Java preprocessor. It process the following kind of directives
* in Java code:
* \/\* #ifdef <LABEL> \*\/
* \/\* #ifndef <LABEL> \*\/
* \/\* #else \*\/
* \/\* #endif \*\/
* The directives have to be embedded in a comment.
*/
public class Jpp {
FileInputStream input;
FileOutputStream output;
static String IFDEF = "#ifdef";
static String IFNDEF = "#ifndef";
static String ELSE = "#else";
static String ENDIF = "#endif";
String labels[];
int nLabels = 0;
boolean space = true;
boolean trace = false;
public static void main(String [] args) {
if (args.length < 1)
prUsage();
String input = null;
String labels[] = new String[256];
String destDir = null, destFile = null;
int n = 0;
boolean space = true;
boolean trace = false;
int i = 0;
while (i < args.length) {
if (args[i].startsWith("-D")) {
labels[n++] = args[i].substring(2);
} else if (args[i].equals("-d")) {
if (i == args.length)
prUsage();
i++;
destDir = args[i];
} else if (args[i].equals("-o")) {
if (i == args.length)
prUsage();
i++;
destFile = args[i];
} else if (args[i].equals("-nospace")) {
space = false;
} else if (args[i].equals("-trace")) {
trace = true;
} else {
if (args[i].endsWith(".jpp"))
input = args[i];
}
i++;
}
if (input == null)
prUsage();
if (destDir != null && destFile != null)
prUsage();
Jpp jpp = new Jpp();
jpp.process(input, labels, n, destDir, destFile, space, trace);
}
static void prUsage() {
System.err.println(
"java Jpp <input>.jpp -D<label1> ... -D<labeln> " +
"[-d <output directory>] [-o <output file>] [-nospace] [-trace]");
System.exit(-1);
}
void process(String inFile, String labels[], int nLabels, String destDir,
String destFile, boolean space, boolean trace) {
this.labels = labels;
this.nLabels = nLabels;
this.space = space;
this.trace = trace;
String outFile;
String separator = System.getProperty("file.separator");
if (destFile != null) {
try {
int idx = destFile.lastIndexOf(separator);
if (idx != -1) {
String dir = destFile.substring(0, idx);
File f = new File(dir);
f.mkdirs();
}
} catch (Exception e) {
System.err.println(e);
}
outFile = destFile;
} else if (destDir != null) {
int idx = inFile.lastIndexOf(separator);
if (idx != -1)
outFile = inFile.substring(idx+1, inFile.length()-3) + "java";
else
outFile = inFile.substring(0, inFile.length()-3) + "java";
outFile = destDir + separator + outFile;
} else
outFile = inFile.substring(0, inFile.length()-3) + "java";
(new File(outFile)).getParentFile().mkdirs();
try {
input = new FileInputStream(inFile);
} catch (IOException e) {
System.err.println("Cannot open input file: " + inFile + ":\n" + e);
System.exit(-1);
}
try {
output = new FileOutputStream(outFile);
} catch (IOException e) {
System.err.println("Cannot create output file: " + outFile +
":\n" + e);
System.exit(-1);
}
try {
processCode(true, false, null, 0);
} catch (IOException e) {
System.err.println(e);
System.exit(-1);
}
}
boolean processCode(boolean include, boolean endif,
String token, int level)
throws IOException {
byte bary[] = new byte[1024];
int b;
int commentCount = 0;
int idx = 0;
int bidx[] = new int[1];
byte cr[] = new byte[1];
while (true) {
b = input.read();
if (b < 0)
break;
if ((b == '/' || b == '*') && commentCount == 1) {
bary[idx++] = (byte)b;
// Found the comment block.
bidx[0] = idx;
cr[0] = -1;
String tk = getToken(bary, bidx, cr);
if (tk == null)
break;
idx = bidx[0];
if (tk.equals(IFDEF) || tk.equals(IFNDEF)) {
bidx[0] = idx;
cr[0] = -1;
String tk2 = getToken(bary, bidx, cr);
if (tk2 == null)
break;
idx = bidx[0];
skipComments(b == '/', cr[0]);
boolean elseFound;
boolean incl;
if (trace)
trace(tk, tk2, level+1);
if (include) {
if ((tk.equals(IFDEF) && isDefined(tk2)) ||
(tk.equals(IFNDEF) && !isDefined(tk2))) {
incl = true;
} else {
incl = false;
}
elseFound = processCode(incl, true, tk2, level+1);
if (elseFound)
elseFound = processCode(!incl, true, tk2, level+1);
} else {
elseFound = processCode(false, true, tk2, level+1);
if (elseFound)
elseFound = processCode(false, true, tk2, level+1);
}
if (elseFound)
throw new IOException("Unmatched #else");
idx = 0;
} else if (tk.equals(ELSE)) {
if (trace)
trace(tk, "for " + token, level);
if (!endif)
throw new IOException("Unmatched #else");
skipComments(b == '/', cr[0]);
idx = 0;
return true;
} else if (tk.equals(ENDIF)) {
if (trace)
trace(tk, "for " + token, level);
if (!endif)
throw new IOException("Unmatched #endif");
skipComments(b == '/', cr[0]);
idx = 0;
return false;
} else {
// No match.
// Write the code if it should be included.
// Otherwise, only write the CR to maintain
// the line numbers.
if (include)
output.write(bary, 0, idx);
else if (space)
replaceCR(bary, 0, idx);
idx = 0;
}
commentCount = 0;
} else if (b == '/') {
commentCount = 1;
bary[idx++] = (byte)b;
} else {
if (commentCount != 0) {
// Write the code if it should be included.
// Otherwise, only write the CR to maintain
// the line numbers.
if (include)
output.write(bary, 0, idx);
else if (space)
replaceCR(bary, 0, idx);
idx = 0;
commentCount = 0;
}
if (include)
output.write(b);
else if (space && (b == 10 || b == 13))
output.write(b);
}
}
if (endif)
throw new IOException("Missing #endif");
return false;
}
void skipComments(boolean slash, byte cr) throws IOException {
int b;
// Handle double slash type of comments.
if (slash) {
if (cr != -1) {
if (space)
output.write(cr);
return;
}
while (true) {
b = input.read();
if (b < 0)
break;
if (b == 10 || b == 13) {
if (space)
output.write(b);
break;
}
}
return;
}
int commentCount = 0;
while (true) {
b = input.read();
if (b < 0)
throw new IOException("Incomplete comments block");
if (b == '*') {
commentCount = 1;
} else if (b == '/' && commentCount == 1) {
commentCount = 0;
break;
} else {
if (space && (b == 10 || b == 13))
output.write(b);
commentCount = 0;
}
}
}
/**
* Parse the characters to only write te CR's.
*/
void replaceCR(byte b[], int off, int len) throws IOException {
for (int i = 0; i < len; i++) {
if (space && (b[off+i] == 10 || b[off+i] == 13))
output.write(b[off+i]);
}
}
/**
* Extract the next token.
*/
byte token[] = new byte[1024];
String getToken(byte bary[], int idx[], byte cr[]) throws IOException {
int b;
int i = 0;
// Discard the leading spaces.
do {
b = input.read();
if (b < 0)
break;
bary[idx[0]++] = (byte)b;
} while (b == ' ' || b == '\t' || b == '*' || b == '/' ||
b == 10 || b == 13);
while (true) {
if (b == ' ' || b == '\t' || b == 10 || b == 13) {
if (cr != null && (b == 10 || b == 13))
cr[0] = (byte)b;
break;
} else
token[i++] = (byte)b;
b = input.read();
if (b < 0)
break;
bary[idx[0]++] = (byte)b;
}
if (i == 0)
return null;
return new String(token, 0, i);
}
/**
* Check if the label is defined.
*/
boolean isDefined(String label) {
for (int i = 0; i < nLabels; i++) {
if (label.equals(labels[i]))
return true;
}
if (System.getProperty(label) != null)
return true;
return false;
}
void trace(String tk1, String tk2, int level) {
for (; level > 0; level--)
System.out.print(" ");
System.out.println(tk1 + " " + tk2);
}
}