mirror of
https://github.com/2003scape/deep-c-rsc.git
synced 2024-03-22 05:49:51 -04:00
497 lines
20 KiB
Java
497 lines
20 KiB
Java
/*
|
|
* @(#) $(JCGO)/jtrsrc/com/ivmaisoft/jcgo/Main.java --
|
|
* a part of JCGO translator.
|
|
**
|
|
* Project: JCGO (http://www.ivmaisoft.com/jcgo/)
|
|
* Copyright (C) 2001-2012 Ivan Maidanski <ivmai@mail.ru>
|
|
* All rights reserved.
|
|
*/
|
|
|
|
/*
|
|
* This is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
**
|
|
* This software 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 (GPL) for more details.
|
|
**
|
|
* Linking this library statically or dynamically with other modules is
|
|
* making a combined work based on this library. Thus, the terms and
|
|
* conditions of the GNU General Public License cover the whole
|
|
* combination.
|
|
**
|
|
* As a special exception, the copyright holders of this library give you
|
|
* permission to link this library with independent modules to produce an
|
|
* executable, regardless of the license terms of these independent
|
|
* modules, and to copy and distribute the resulting executable under
|
|
* terms of your choice, provided that you also meet, for each linked
|
|
* independent module, the terms and conditions of the license of that
|
|
* module. An independent module is a module which is not derived from
|
|
* or based on this library. If you modify this library, you may extend
|
|
* this exception to your version of the library, but you are not
|
|
* obligated to do so. If you do not wish to do so, delete this
|
|
* exception statement from your version.
|
|
*/
|
|
|
|
package com.ivmaisoft.jcgo;
|
|
|
|
import java.io.*;
|
|
import java.util.Enumeration;
|
|
|
|
/**
|
|
* This is the main class.
|
|
*/
|
|
|
|
public final class Main {
|
|
|
|
static final String VERSION = Integer.toString(VerInfo.VER_NUM / 100) + "."
|
|
+ Integer.toString((VerInfo.VER_NUM / 10) % 10)
|
|
+ Integer.toString(VerInfo.VER_NUM % 10);
|
|
|
|
static final String VER_ABBR = "JCGO_"
|
|
+ VERSION.substring(0, VERSION.length() - 3)
|
|
+ VERSION.substring(VERSION.length() - 2);
|
|
|
|
static CompilationUnit curUnit;
|
|
|
|
static final ClassDictionary dict = new ClassDictionary();
|
|
|
|
private Main() {
|
|
}
|
|
|
|
static void showProgInfo() {
|
|
System.out.println("JCGO v" + VERSION
|
|
+ " - Java source to C code translator");
|
|
System.out.println(VerInfo.COPYRIGHT_AUTHOR);
|
|
System.out.println(VerInfo.COPYRIGHT);
|
|
System.out.println("This is free software. All rights reserved."
|
|
+ " See LICENSE and README files.");
|
|
System.out.println("");
|
|
}
|
|
|
|
private static void showUsage() {
|
|
System.out
|
|
.println("Usage: jcgo [options] <target_class> [<additional_class1> ...]");
|
|
System.out.println("Options:");
|
|
System.out.println(" -sourcepath <pathlist> "
|
|
+ " Specify where to find input source files");
|
|
System.out.println(" -d <directory> "
|
|
+ " Specify where to place generated files");
|
|
System.out.println(" -verbose " + " Verbose mode");
|
|
System.out.println(" -r[[p]c][g|[p]m][[p]f] <packageOrClass> "
|
|
+ " Force class members reflection");
|
|
System.out.println("@<filename> "
|
|
+ " Specify additional classes in the file");
|
|
System.out.println("");
|
|
}
|
|
|
|
public static void main(String[] argv) {
|
|
int consumed = getAmountOfUsedMemory();
|
|
try {
|
|
boolean showHelp = false;
|
|
if (argv.length == 0 || (argv.length == 1 && argv[0].equals("-h"))) {
|
|
showProgInfo();
|
|
showUsage();
|
|
showHelp = true;
|
|
}
|
|
if (showHelp) {
|
|
System.exit(0);
|
|
}
|
|
boolean skipClinitTrace = false;
|
|
String progBasePath = getProgBasePath();
|
|
String mainClassName = null;
|
|
ObjQueue classnames = new ObjQueue();
|
|
for (int i = 0; i < argv.length; i++) {
|
|
if (argv[i].startsWith("-")) {
|
|
if (argv[i].equals("-t")) {
|
|
skipClinitTrace = true;
|
|
} else if (!processSimpleOption(argv[i])) {
|
|
if (i + 1 >= argv.length) {
|
|
System.err
|
|
.println("missing argument for last option");
|
|
System.exit(2);
|
|
}
|
|
if (argv[i].equals("-sourcepath")
|
|
|| argv[i].equals("-src")) {
|
|
dict.javaFiles.setClassPath(argv[i + 1],
|
|
progBasePath);
|
|
} else if (!processOptionWithArg(argv[i], argv[i + 1])) {
|
|
System.err.println("invalid option: " + argv[i]);
|
|
System.exit(2);
|
|
}
|
|
i++;
|
|
}
|
|
} else {
|
|
String className = argv[i];
|
|
if (className.charAt(0) == '@') {
|
|
readResponseFile(
|
|
classnames,
|
|
className.length() == 1 && i + 1 < argv.length ? argv[++i]
|
|
: className.substring(1), progBasePath);
|
|
} else if (mainClassName != null) {
|
|
classnames.addLast(dict.javaFiles
|
|
.toClassName(className));
|
|
} else {
|
|
mainClassName = dict.javaFiles.toClassName(className);
|
|
}
|
|
}
|
|
}
|
|
if (mainClassName == null) {
|
|
System.err.println("Target class must be specified");
|
|
System.exit(2);
|
|
}
|
|
dict.javaFiles.setClassPath();
|
|
String[] sortednames = strsQueueToSortedArr(classnames);
|
|
if (dict.outPath.length() == 0) {
|
|
if (isOutPathRequired(progBasePath)) {
|
|
System.err
|
|
.println("Use -d to specify existing directory for output");
|
|
System.exit(2);
|
|
}
|
|
(new File(dict.outPath = "jcgo_Out")).mkdir();
|
|
}
|
|
int time = (int) System.currentTimeMillis();
|
|
ClassDefinition mainClass = processFirst(mainClassName);
|
|
for (int i = 0; i < sortednames.length; i++) {
|
|
ObjQueue proxyIfaceNames = dict.nameMapper
|
|
.decodeProxyClassName(sortednames[i]);
|
|
if (proxyIfaceNames != null) {
|
|
Enumeration en = proxyIfaceNames.elements();
|
|
while (en.hasMoreElements()) {
|
|
dict.get((String) en.nextElement())
|
|
.predefineClass(null);
|
|
}
|
|
} else {
|
|
dict.get(sortednames[i]).predefineClass(null);
|
|
}
|
|
}
|
|
processAll(mainClass, sortednames, time, skipClinitTrace);
|
|
} catch (TranslateException e) {
|
|
System.err.println(e.getMessage());
|
|
System.exit(6);
|
|
} catch (RuntimeException e) {
|
|
if (dict.verbose) {
|
|
e.printStackTrace(System.out);
|
|
}
|
|
System.err.println(e.toString());
|
|
System.exit(7);
|
|
} catch (OutOfMemoryError e) {
|
|
System.err.print(" Out of memory ");
|
|
try {
|
|
System.err.print("(consumed "
|
|
+ Integer.toString(getAmountOfUsedMemory() - consumed)
|
|
+ " KiB)");
|
|
} catch (OutOfMemoryError ee) {
|
|
}
|
|
System.err.println("");
|
|
System.exit(255);
|
|
}
|
|
System.exit(0);
|
|
}
|
|
|
|
private static boolean processSimpleOption(String option) {
|
|
if (option.equals("-verbose") || option.equals("-v")) {
|
|
dict.verbose = true;
|
|
return true;
|
|
} else if (option.equals("-v2")) {
|
|
dict.verbose = dict.verboseTracing = true;
|
|
return true;
|
|
} else if (option.equals("-e")) {
|
|
dict.ignoreErrs = true;
|
|
return true;
|
|
} else if (option.startsWith("-l") && dict.failOnClassLimit == 0) {
|
|
dict.failOnClassLimit = (new ConstValue(option.substring(2)))
|
|
.getIntValue();
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static boolean processOptionWithArg(String option, String value) {
|
|
if (option.equals("-d") && dict.outPath.length() == 0) {
|
|
if (!new File(value).isDirectory()) {
|
|
System.err.println("Output directory does not exist: " + value);
|
|
System.exit(2);
|
|
}
|
|
dict.outPath = value;
|
|
return true;
|
|
} else if (option.startsWith("-r")) {
|
|
processReflectOption(option.substring(2), value);
|
|
return true;
|
|
} else if (option.equals("-c") && dict.failOnClassName == null) {
|
|
dict.failOnClassName = value;
|
|
return true;
|
|
} else if (option.equals("-f") && dict.failOnFieldName == null) {
|
|
dict.failOnFieldName = value;
|
|
return true;
|
|
} else if (option.equals("-m") && dict.failOnMethodId == null) {
|
|
dict.failOnMethodId = value;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static void processReflectOption(String flags, String packageOrClass) {
|
|
if (packageOrClass.equals("*") || packageOrClass.equals(".*")) {
|
|
packageOrClass = "";
|
|
}
|
|
if (dict.forcedReflectClassOrPkg.put(packageOrClass, flags) != null
|
|
|| packageOrClass.indexOf('/', 0) > 0
|
|
|| (File.separatorChar != '/' && packageOrClass.indexOf(
|
|
File.separatorChar, 0) > 0)) {
|
|
System.err.println("Invalid or duplicate -r<flags> for: "
|
|
+ (packageOrClass.length() > 0 ? packageOrClass
|
|
: "(unnamed package)"));
|
|
System.exit(2);
|
|
}
|
|
}
|
|
|
|
private static String[] strsQueueToSortedArr(ObjQueue queue) {
|
|
String[] strs = new String[queue.countSize()];
|
|
queue.copyInto(strs);
|
|
String[] sortedstrs = new String[strs.length];
|
|
System.arraycopy(strs, 0, sortedstrs, 0, strs.length);
|
|
ClassDefinition.mergeSort(strs, sortedstrs, 0, strs.length);
|
|
return sortedstrs;
|
|
}
|
|
|
|
private static boolean isOutPathRequired(String progBasePath) {
|
|
String userDir = ".";
|
|
try {
|
|
userDir = System.getProperty("user.dir", userDir);
|
|
} catch (SecurityException e) {
|
|
}
|
|
return userDir.equals(progBasePath) || progBasePath.equals(".")
|
|
|| userDir.startsWith(progBasePath + File.separator);
|
|
}
|
|
|
|
private static String getProgBasePath() {
|
|
String pathList = "";
|
|
try {
|
|
pathList = System.getProperty("java.class.path", pathList);
|
|
} catch (SecurityException e) {
|
|
}
|
|
int pos = 0;
|
|
String firstBasePath = ".";
|
|
do {
|
|
int next = pathList.indexOf(File.pathSeparatorChar, pos);
|
|
if (next < 0) {
|
|
next = pathList.length();
|
|
}
|
|
String basePath = getParentPathIfJar(pathList.substring(pos, next));
|
|
if ((new File(basePath, "goclsp")).isDirectory())
|
|
return basePath;
|
|
if (firstBasePath.equals(".")) {
|
|
firstBasePath = basePath;
|
|
}
|
|
pos = next + 1;
|
|
} while (pathList.length() >= pos);
|
|
return firstBasePath;
|
|
}
|
|
|
|
static String getParentPathIfJar(String path) {
|
|
if ((path.endsWith(".jar") || path.endsWith(".Jar")
|
|
|| path.endsWith(".JAR") || path.endsWith(".zip")
|
|
|| path.endsWith(".Zip") || path.endsWith(".ZIP"))
|
|
&& (path = (new File(path)).getParent()) == null) {
|
|
path = "";
|
|
}
|
|
return path.length() > 0 ? path : ".";
|
|
}
|
|
|
|
private static int getAmountOfUsedMemory() {
|
|
return (int) ((Runtime.getRuntime().totalMemory() - Runtime
|
|
.getRuntime().freeMemory()) >> 10);
|
|
}
|
|
|
|
static void parseJavaFile(String classname) {
|
|
String fileName = dict.javaFiles.classFilename(classname, true);
|
|
if (fileName == null) {
|
|
System.err.println("Cannot find class: " + classname);
|
|
System.exit(5);
|
|
}
|
|
dict.filesParsed++;
|
|
dict.message("Parsing file: " + fileName);
|
|
Scanner.Init(fileName);
|
|
dict.inBytesCount += (int) (new File(fileName)).length();
|
|
Parser.Parse();
|
|
Term t = curUnit;
|
|
if (Scanner.err.count > 0)
|
|
throw new TranslateException("Lexical error in file: " + fileName);
|
|
Context c = new Context();
|
|
c.fileName = fileName;
|
|
t.processPass0(c);
|
|
t.processPass1(c);
|
|
}
|
|
|
|
static ObjQueue readFileOfLines(String fname) {
|
|
ObjQueue lines = new ObjQueue();
|
|
try {
|
|
BufferedReader infile = new BufferedReader(new FileReader(fname));
|
|
// Portability - use the following for Java 1.0
|
|
// DataInputStream infile = new DataInputStream(new
|
|
// BufferedInputStream(new FileInputStream(fname)));
|
|
String str;
|
|
while ((str = infile.readLine()) != null) {
|
|
lines.addLast(str);
|
|
}
|
|
infile.close();
|
|
} catch (IOException e) {
|
|
lines = null;
|
|
}
|
|
return lines;
|
|
}
|
|
|
|
private static void readResponseFile(ObjQueue classnames, String fname,
|
|
String progBasePath) {
|
|
ObjQueue lines = readFileOfLines(JavaSrcFiles.adjustPathPrefix(fname,
|
|
progBasePath));
|
|
if (lines == null) {
|
|
System.err.println("Cannot read response file: " + fname);
|
|
System.exit(2);
|
|
}
|
|
Enumeration en = lines.elements();
|
|
while (en.hasMoreElements()) {
|
|
String str = ((String) en.nextElement()).trim();
|
|
char ch;
|
|
if (str.length() > 0 && (ch = str.charAt(0)) != '!' && ch != '#'
|
|
&& ch != ';') {
|
|
String path = cutLinePrefix(str, "-sourcepath");
|
|
int pos;
|
|
if (path != null || (path = cutLinePrefix(str, "-src")) != null) {
|
|
dict.javaFiles.setClassPath(path, progBasePath);
|
|
} else if (str.startsWith("-r")
|
|
&& ((pos = str.indexOf(' ', 2)) >= 0 || (pos = str
|
|
.indexOf('\t', 2)) >= 0)) {
|
|
processReflectOption(str.substring(2, pos),
|
|
str.substring(pos + 1).trim());
|
|
} else {
|
|
classnames.addLast(dict.javaFiles.toClassName(str));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static String cutLinePrefix(String str, String prefix) {
|
|
return str.startsWith(prefix) && str.length() > prefix.length()
|
|
&& str.charAt(prefix.length()) <= ' ' ? str.substring(
|
|
prefix.length() + 1).trim() : null;
|
|
}
|
|
|
|
private static ClassDefinition processFirst(String classname) {
|
|
System.out.println("Initializing...");
|
|
dict.setupCoreClasses();
|
|
ClassDefinition mainClass = dict.get(classname);
|
|
MethodDefinition md = mainClass.getMethod(Names.SIGN_MAIN);
|
|
if (md == null || !md.isClassMethod()) {
|
|
dict.fatal(mainClass.passOneContext().fileName, 1,
|
|
"Cannot find static method: main(String[])");
|
|
}
|
|
dict.get(Names.JAVA_LANG_CLASS).define(mainClass);
|
|
dict.get(Names.JAVA_LANG_STRING).define(mainClass);
|
|
return mainClass;
|
|
}
|
|
|
|
private static ObjVector namesToClassLiterals(ObjQueue classNames) {
|
|
ObjVector parmSig = new ObjVector();
|
|
Enumeration en = classNames.elements();
|
|
while (en.hasMoreElements()) {
|
|
parmSig.addElement(dict.get((String) en.nextElement()));
|
|
}
|
|
return parmSig;
|
|
}
|
|
|
|
private static void processAll(ClassDefinition mainClass,
|
|
String[] sortednames, int time, boolean skipClinitTrace) {
|
|
System.out.println("Analysis pass...");
|
|
mainClass.markMethod(Names.SIGN_MAIN);
|
|
for (int i = 0; i < sortednames.length; i++) {
|
|
ObjQueue proxyIfaceNames = dict.nameMapper
|
|
.decodeProxyClassName(sortednames[i]);
|
|
if (proxyIfaceNames == null
|
|
|| dict.addProxyClass(
|
|
namesToClassLiterals(proxyIfaceNames), null) == null) {
|
|
ClassDefinition cd = dict.get(sortednames[i]);
|
|
cd.markUsed();
|
|
cd.markAllNatives();
|
|
dict.dynClassesToTrace.put(cd, cd);
|
|
}
|
|
}
|
|
mainClass.markAllPublicStaticMethods();
|
|
dict.producePassOne();
|
|
boolean mainReflected = false;
|
|
if (dict.forcedReflectClassOrPkg.size() > 0) {
|
|
ObjQueue forcedClassNames = new ObjQueue();
|
|
Enumeration en = dict.forcedReflectClassOrPkg.keys();
|
|
while (en.hasMoreElements()) {
|
|
String packageOrClass = (String) en.nextElement();
|
|
if (packageOrClass.length() > 0
|
|
&& !packageOrClass.endsWith(".*")) {
|
|
forcedClassNames.addLast(packageOrClass);
|
|
}
|
|
}
|
|
sortednames = strsQueueToSortedArr(forcedClassNames);
|
|
if (sortednames.length > 0) {
|
|
for (int i = 0; i < sortednames.length; i++) {
|
|
dict.get(sortednames[i]).define(mainClass);
|
|
}
|
|
if (dict.hasReflectedMethods) {
|
|
mainClass.reflectAllPublicStaticMethods();
|
|
mainReflected = true;
|
|
}
|
|
dict.producePassOne();
|
|
}
|
|
}
|
|
if (dict.hasReflectedMethods && !mainReflected
|
|
&& mainClass.reflectAllPublicStaticMethods()) {
|
|
dict.producePassOne();
|
|
}
|
|
dict.allowConstStr = Main.dict.get(Names.JAVA_LANG_STRING)
|
|
.otherInstanceFieldsUnused(Names.fieldsOrderString);
|
|
System.out.println("Output pass...");
|
|
dict.mainClass = mainClass;
|
|
Enumeration en = dict.usedClasses();
|
|
while (en.hasMoreElements()) {
|
|
((ClassDefinition) en.nextElement()).prepareMethodsForOutput();
|
|
}
|
|
dict.get(Names.JAVA_LANG_OBJECT).produceOutputRecursive(
|
|
new ObjHashSet());
|
|
System.out.println("Writing class tables...");
|
|
ClassDefinition.setSpecialVirtual();
|
|
Enumeration en2 = dict.usedClasses();
|
|
while (en2.hasMoreElements()) {
|
|
((ClassDefinition) en2.nextElement()).finishClass();
|
|
}
|
|
System.out.println("Creating main file...");
|
|
mainClass.buildMain(skipClinitTrace);
|
|
System.out.println("Parsed: " + Integer.toString(dict.filesParsed)
|
|
+ " java files (" + Integer.toString(dict.inBytesCount >> 10)
|
|
+ " KiB). Analyzed: " + Integer.toString(dict.methodsAnalyzed)
|
|
+ " methods.");
|
|
System.out.println("Produced: " + Integer.toString(dict.outFilesCount)
|
|
+ " c/h files (" + Integer.toString(dict.outBytesCount >> 10)
|
|
+ " KiB).");
|
|
System.out.println("Contains: " + Integer.toString(dict.methodsWritten)
|
|
+ " java methods, " + Integer.toString(dict.normalCalls)
|
|
+ " normal and " + Integer.toString(dict.indirectCalls)
|
|
+ " indirect calls.");
|
|
System.out
|
|
.println("Done conversion in "
|
|
+ Integer.toString(((int) System.currentTimeMillis() - time) / 1000)
|
|
+ " seconds. Total heap size: "
|
|
+ Integer.toString((int) (Runtime.getRuntime()
|
|
.totalMemory() >> 10)) + " KiB.");
|
|
if (dict.errorsCnt > 0) {
|
|
System.out.println("");
|
|
System.out.println(" Translated with " + dict.errorsCnt
|
|
+ " errors!");
|
|
System.exit(3);
|
|
}
|
|
}
|
|
}
|