deep-c-rsc/JCGO/jtrsrc/com/ivmaisoft/jcgo/Main.java
2021-07-16 17:12:20 -05:00

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);
}
}
}