зеркало из https://github.com/mozilla/pluotsorbet.git
399 строки
9.0 KiB
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);
|
|
}
|
|
}
|
|
|