cbc/net/loveruby/cflat/compiler/Options.java

366 lines
13 KiB
Java

package net.loveruby.cflat.compiler;
import net.loveruby.cflat.type.TypeTable;
import net.loveruby.cflat.asm.*;
import net.loveruby.cflat.exception.*;
import java.util.*;
import java.io.*;
// package scope
class Options {
protected String mode;
protected TypeTable typeTable;
protected LibraryLoader loader;
protected String outputFileName;
protected boolean verbose;
protected boolean debugParser;
protected CodeGeneratorOptions genOptions;
protected List asOptions; // List<String>
protected List ldArgs; // List<LdArg>
protected boolean noStartFiles = false;
protected boolean noDefaultLibs = false;
public Options(TypeTable typeTable, LibraryLoader loader) {
this.typeTable = typeTable;
this.loader = loader;
this.genOptions = new CodeGeneratorOptions();
this.asOptions = new ArrayList();
this.ldArgs = new ArrayList();
}
public boolean isMode(String m) {
return mode.equals(m);
}
public boolean isAssembleRequired() {
return modeLevel(mode) >= MODE_LEVEL_ASSEMBLE;
}
public boolean isLinkRequired() {
return modeLevel(mode) >= MODE_LEVEL_LINK;
}
static final protected String defaultMode = "link";
static protected List modeLevels;
static final protected int MODE_LEVEL_ASSEMBLE;
static final protected int MODE_LEVEL_LINK;
static {
modeLevels = new ArrayList();
modeLevels.add("--check-syntax");
modeLevels.add("--dump-tokens");
modeLevels.add("--dump-ast");
modeLevels.add("--dump-semantic");
modeLevels.add("--dump-reference");
modeLevels.add("--dump-asm");
modeLevels.add("-S");
modeLevels.add("-c"); // assemble required
modeLevels.add(defaultMode); // link required
MODE_LEVEL_ASSEMBLE = modeLevels.indexOf("-c");
MODE_LEVEL_LINK = modeLevels.indexOf(defaultMode);
};
protected int modeLevel(String mode) {
int idx = modeLevels.indexOf(mode);
if (idx < 0) throw new Error("unknown compiler mode: " + mode);
return idx;
}
public String outputFileNameFor(String mode) {
return isMode(mode) ? outputFileName : null;
}
public String exeFileName() {
if (outputFileName != null) return outputFileName;
List srcs = sourceFiles();
if (srcs.size() == 1) {
SourceFile src = (SourceFile)srcs.get(0);
return src.exeFileName(this);
}
else {
return "a.out";
}
}
protected List sourceFiles() {
Iterator args = ldArgs.iterator();
List result = new ArrayList();
while (args.hasNext()) {
LdArg arg = (LdArg)args.next();
if (arg.isSourceFile()) {
result.add(arg);
}
}
return result;
}
public TypeTable typeTable() {
return this.typeTable;
}
public LibraryLoader loader() {
return this.loader;
}
public String outputFileName() {
return this.outputFileName;
}
public boolean isVerboseMode() {
return this.verbose;
}
public boolean doesDebugParser() {
return this.debugParser;
}
public CodeGeneratorOptions genOptions() {
return genOptions;
}
// List<String>
public List asOptions() {
return this.asOptions;
}
// List<ldArg>
public List ldArgs() {
return this.ldArgs;
}
public boolean noStartFiles() {
return this.noStartFiles;
}
public boolean noDefaultLibs() {
return this.noDefaultLibs;
}
/** Returns List<SourceFile>. */
public List parse(List argsList) {
ListIterator args = argsList.listIterator();
List srcs = new ArrayList();
while (args.hasNext()) {
String arg = (String)args.next();
// FIXME: stdin
if (arg.equals("-")) {
System.err.println("FIXME: stdin is not supported yet");
System.exit(1);
}
else if (arg.equals("--")) {
// "--" Stops command line processing
break;
}
else if (arg.startsWith("-")) {
if (arg.equals("--check-syntax")
|| arg.equals("--dump-tokens")
|| arg.equals("--dump-ast")
|| arg.equals("--dump-stmt")
|| arg.equals("--dump-reference")
|| arg.equals("--dump-semantic")
|| arg.equals("-S")
|| arg.equals("--dump-asm")
|| arg.equals("-c")) {
if (mode != null) {
parseError(mode + " option and "
+ arg + " option is exclusive");
}
mode = arg;
}
else if (arg.startsWith("-I")) {
loader.addLoadPath(getOptArg(arg, args));
}
else if (arg.equals("--debug-parser")) {
debugParser = true;
}
else if (arg.startsWith("-o")) {
outputFileName = getOptArg(arg, args);
}
else if (arg.equals("-fpic")) {
genOptions.generatePIC();
}
else if (arg.equals("-fPIC")) {
genOptions.generatePIC();
}
// FIXME: PIE
//else if (arg.equals("-fpie"))
//else if (arg.equals("-fPIE"))
else if (arg.startsWith("-O")) {
String type = arg.substring(2);
if (! type.matches("^([0123s]|)$")) {
parseError("unknown optimization switch: " + arg);
}
genOptions.setOptimizationLevel(type.equals("0") ? 0 : 1);
}
else if (arg.equals("--verbose-asm")) {
genOptions.generateVerboseAsm();
}
else if (arg.startsWith("-Wa,")) {
asOptions.addAll(parseCommaSeparatedOptions(arg));
}
else if (arg.equals("-Xassembler")) {
asOptions.add(nextArg(arg, args));
}
else if (arg.equals("-static")) {
ldArgs.add(new LdOption(arg));
}
else if (arg.equals("-shared")) {
// FIXME: ?? any more work is required??
ldArgs.add(new LdOption(arg));
}
//else if (arg.equals("-pie"))
else if (arg.startsWith("-L")) {
ldArgs.add(new LdOption("-L" + getOptArg(arg, args)));
}
else if (arg.startsWith("-l")) {
ldArgs.add(new LdOption("-l" + getOptArg(arg, args)));
}
else if (arg.equals("-nostartfiles")) {
noStartFiles = true;
}
else if (arg.equals("-nodefaultlibs")) {
noDefaultLibs = true;
}
else if (arg.equals("-nostdlib")) {
noStartFiles = true;
noDefaultLibs = true;
}
else if (arg.startsWith("-Wl,")) {
Iterator opts = parseCommaSeparatedOptions(arg).iterator();
while (opts.hasNext()) {
String opt = (String)opts.next();
ldArgs.add(new LdOption(opt));
}
}
else if (arg.equals("-Xlinker")) {
ldArgs.add(new LdOption(nextArg(arg, args)));
}
else if (arg.equals("-v")) {
verbose = true;
}
else if (arg.equals("--version")) {
System.out.println(Compiler.ProgramID
+ " version " + Compiler.Version);
System.exit(0);
}
else if (arg.equals("--help")) {
printUsage(System.out);
System.exit(0);
}
else {
parseError("unknown option: " + arg);
}
}
else {
// source file
addSourceFile(srcs, ldArgs, arg);
}
}
// args has more arguments when "--" is appeared.
while (args.hasNext()) {
String arg = (String)args.next();
addSourceFile(srcs, ldArgs, arg);
}
if (srcs.isEmpty()) parseError("no input file");
if (mode == null) {
mode = defaultMode;
}
if (! isLinkRequired() && outputFileName != null && srcs.size() > 1) {
parseError("-o option requires only 1 input not on linking");
}
return srcs;
}
protected void parseError(String msg) {
throw new OptionParseError(msg);
}
protected void addSourceFile(List srcs, List ldArgs, String sourceName) {
SourceFile src = new SourceFile(sourceName);
srcs.add(src);
// Original argument order does matter when linking.
ldArgs.add(src);
}
protected String getOptArg(String opt, ListIterator args) {
String path = opt.substring(2);
if (path.length() != 0) { // -Ipath
return path;
}
else { // -I path
return nextArg(opt, args);
}
}
protected String nextArg(String opt, ListIterator args) {
if (! args.hasNext()) {
parseError("missing argument for " + opt);
}
return (String)args.next();
}
/** "-Wl,-rpath,/usr/local/lib" -> ["-rpath", "/usr/local/lib"] */
protected List parseCommaSeparatedOptions(String opt) {
List opts = arrayToList(opt.split(","));
opts.remove(0); // remove "-Wl" etc.
if (opts.isEmpty()) {
parseError("missing argument for " + opt);
}
return opts;
}
protected List arrayToList(Object[] ary) {
List result = new ArrayList();
for (int i = 0; i < ary.length; i++) {
result.add(ary[i]);
}
return result;
}
public void printUsage(PrintStream out) {
out.println("Usage: cbc [options] file...");
out.println("Global Options:");
out.println(" --check-syntax Checks syntax and quit.");
out.println(" --dump-tokens Dumps tokens and quit.");
out.println(" --dump-ast Dumps AST and quit.");
out.println(" --dump-semantic Dumps AST after semantic check and quit.");
// --dump-reference is hidden option
out.println(" -S Generates an assembly source and quit.");
out.println(" --dump-asm Prints an assembly source and quit.");
out.println(" -c Generates an object file and quit.");
out.println(" -o PATH Places output in file PATH.");
out.println(" -v Turn on verbose mode.");
out.println(" --version Shows compiler version and quit.");
out.println(" --help Prints this message and quit.");
out.println("");
out.println("Parser Options:");
out.println(" -I PATH Adds PATH as import file directory.");
out.println(" --debug-parser Dumps parsing process.");
out.println("");
out.println("Code Generator Options:");
out.println(" -O Enables optimization.");
out.println(" -O1, -O2, -O3 Equivalent to -O.");
out.println(" -Os Equivalent to -O.");
out.println(" -O0 Disables optimization (default).");
out.println(" -fPIC Generates PIC assembly.");
//out.println(" -fPIE Generates PIE assembly.");
out.println(" --verbose-asm Generate assembly with verbose comments.");
out.println("");
out.println("Assembler Options:");
out.println(" -Wa,OPT Passes OPT to the assembler (as).");
out.println(" -Xassembler OPT Passes OPT to the assembler (as).");
out.println("");
out.println("Linker Options:");
out.println(" -l LIB Links the library LIB.");
out.println(" -L PATH Adds PATH as library directory.");
out.println(" -shared Generates shared library rather than executable.");
out.println(" -static Linkes only with static libraries.");
//out.println(" -pie Generates PIE.");
out.println(" -nostartfiles Do not link startup files.");
out.println(" -nodefaultlibs Do not link default libraries.");
out.println(" -nostdlib Enables -nostartfiles and -nodefaultlibs.");
out.println(" -Wl,OPT Passes OPT to the linker (ld).");
out.println(" -Xlinker OPT Passes OPT to the linker (ld).");
}
}