* net/loveruby/cflat/compiler/Compiler.java: handle multiple source files.

* net/loveruby/cflat/compiler/Options.java: new class forked from Compiler.java.  Command option parser.
* net/loveruby/cflat/compiler/SourceFile.java: new class.
* net/loveruby/cflat/compiler/LdOption.java: new class.
* net/loveruby/cflat/compiler/LdArg.java: new interface.
* net/loveruby/cflat/exception/OptionParseError.java: new error class.
* test: test multiple input.


git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@4016 1b9489fe-b721-0410-924e-b54b9192deb8
This commit is contained in:
Minero Aoki 2008-09-14 15:51:46 +00:00
parent 688d709302
commit 9a0bfed9f0
12 changed files with 641 additions and 242 deletions

View File

@ -1,3 +1,22 @@
Mon Sep 15 00:43:29 2008 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/compiler/Compiler.java: handle multiple
source files.
* net/loveruby/cflat/compiler/Options.java: new class forked from
Compiler.java. Command option parser.
* net/loveruby/cflat/compiler/SourceFile.java: new class.
* net/loveruby/cflat/compiler/LdOption.java: new class.
* net/loveruby/cflat/compiler/LdArg.java: new interface.
* net/loveruby/cflat/exception/OptionParseError.java: new error
class.
* test: test multiple input.
Sun Sep 14 20:08:19 2008 Minero Aoki <aamine@loveruby.net> Sun Sep 14 20:08:19 2008 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/compiler/Compiler.java: use CflatToken to * net/loveruby/cflat/compiler/Compiler.java: use CflatToken to

View File

@ -8,10 +8,11 @@ import java.util.*;
import java.io.*; import java.io.*;
public class Compiler { public class Compiler {
static final private String programId = "cbc"; static final public String ProgramID = "cbc";
static final public String Version = "1.0.0";
static public void main(String[] args) { static public void main(String[] args) {
new Compiler(programId).commandMain(args); new Compiler(ProgramID).commandMain(args);
} }
protected ErrorHandler errorHandler; protected ErrorHandler errorHandler;
@ -25,19 +26,41 @@ public class Compiler {
} }
public void commandMain(String[] origArgs) { public void commandMain(String[] origArgs) {
Options opts = parseOptions(listFromArray(origArgs)); Options opts = new Options(defaultTypeTable(), new LibraryLoader());
List srcs = null;
try {
srcs = opts.parse(Arrays.asList(origArgs));
}
catch (OptionParseError err) {
errorHandler.error(err.getMessage());
errorHandler.error("Try cbc --help for option usage");
System.exit(1);
}
if (opts.isMode("--check-syntax")) { if (opts.isMode("--check-syntax")) {
if (isValidSyntax(opts)) { Iterator inputs = srcs.iterator();
System.out.println("Syntax OK"); boolean failed = false;
System.exit(0); while (inputs.hasNext()) {
} SourceFile src = (SourceFile)inputs.next();
else { if (isValidSyntax(src, opts)) {
System.exit(1); System.out.println(src.name() + ": Syntax OK");
}
else {
System.out.println(src.name() + ": Syntax Error");
failed = true;
}
} }
System.exit(failed ? 1 : 0);
} }
else { else {
try { try {
compileFile(opts); Iterator inputs = srcs.iterator();
while (inputs.hasNext()) {
SourceFile src = (SourceFile)inputs.next();
compileFile(src, opts);
}
if (! opts.isLinkRequired()) System.exit(0);
generateExecutable(opts);
System.exit(0);
} }
catch (CompileException ex) { catch (CompileException ex) {
errorHandler.error(ex.getMessage()); errorHandler.error(ex.getMessage());
@ -46,148 +69,14 @@ public class Compiler {
} }
} }
class Options {
public String mode;
public String inputFile;
public String outputFile;
public boolean verbose;
public boolean debugParser;
//public boolean debugBuild;
public TypeTable typeTable;
public LibraryLoader loader;
//public List asOpts; // List<String>
//public List ldOpts; // List<String>
//public List ldArgs; // List<LdArg>
public boolean isMode(String m) {
return mode == null ? false : mode.equals(m);
}
}
protected Options parseOptions(List args) {
ListIterator it = args.listIterator();
Options opts = new Options();
opts.typeTable = defaultTypeTable();
opts.loader = new LibraryLoader();
while (it.hasNext()) {
String arg = (String)it.next();
if (arg.equals("-")) {
System.err.println("FIXME: stdin is not supported yet");
System.exit(1);
}
else if (arg.equals("--")) {
// "--" Stops command line processing
it.remove();
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 (opts.mode != null) {
errorExit(opts.mode + " option and "
+ arg + " option is exclusive");
}
opts.mode = arg;
}
else if (arg.startsWith("-I")) {
opts.loader.addLoadPath(getOptArg(arg, it));
}
else if (arg.equals("--debug-parser")) {
opts.debugParser = true;
}
else if (arg.startsWith("-o")) {
opts.outputFile = getOptArg(arg, it);
}
// FIXME: compile options
//else if (arg.equals("-fPIC"))
//else if (arg.startsWith("-O"))
// FIXME: assemble options
//else if (arg.startsWith("-Wa,"))
//else if (arg.equals("-Xassembler"))
// FIXME: link options
//else if (arg.equals("-static"))
//else if (arg.equals("-shared"))
//else if (arg.startsWith("-L"))
//else if (arg.startsWith("-l"))
//else if (arg.startsWith("-Wl,"))
//else if (arg.equals("-Xlinker"))
else if (arg.equals("-v")) {
opts.verbose = true;
}
else if (arg.equals("--help")) {
printUsage(System.out);
System.exit(0);
}
else {
System.err.println("unknown option: " + arg);
printUsage(System.err);
System.exit(1);
}
it.remove();
}
}
// FIXME: handle many input files
if (args.size() == 0) errorExit("no input file");
if (args.size() > 1) errorExit("too many input files");
opts.inputFile = (String)args.get(0);
return opts;
}
protected void printUsage(PrintStream out) {
// --dump-reference is hidden option
out.println("Usage: cbc [option] file");
out.println(" --check-syntax Checks syntax.");
out.println(" --debug-parser Dumps parsing process.");
out.println(" --dump-tokens Parses source file and dumps tokens.");
out.println(" --dump-ast Parses source file and dumps AST.");
out.println(" --dump-semantic Checks semantics and dumps AST.");
out.println(" -S Generates an assembly source.");
out.println(" --dump-asm Dumps an assembly source.");
out.println(" -c Generates an object file.");
out.println(" -I PATH Adds import file loading path.");
out.println(" -o PATH Places output in file PATH.");
out.println(" --help Prints this message and quit.");
}
private List listFromArray(Object[] a) {
List list = new ArrayList();
for (int i = 0; i < a.length; i++) {
list.add(a[i]);
}
return list;
}
private String getOptArg(String arg, ListIterator it) {
String path = arg.substring(2);
if (path.length() != 0) { // -Ipath
return path;
}
else { // -I path
if (! it.hasNext()) {
errorExit("-I option missing argument");
}
it.remove();
return (String)it.next();
}
}
private void errorExit(String msg) { private void errorExit(String msg) {
errorHandler.error(msg); errorHandler.error(msg);
System.exit(1); System.exit(1);
} }
protected boolean isValidSyntax(Options opts) { protected boolean isValidSyntax(SourceFile src, Options opts) {
try { try {
parseFile(opts); parseFile(src, opts);
return true; return true;
} }
catch (SyntaxException ex) { catch (SyntaxException ex) {
@ -199,39 +88,44 @@ public class Compiler {
} }
} }
protected void compileFile(Options opts) throws CompileException { protected void compileFile(SourceFile src, Options opts)
AST ast = parseFile(opts); throws CompileException {
if (opts.isMode("--dump-tokens")) { if (src.isCflatSource()) {
dumpTokens(ast.sourceTokens(), System.out); AST ast = parseFile(src, opts);
return; if (opts.isMode("--dump-tokens")) {
dumpTokens(ast.sourceTokens(), System.out);
return;
}
if (opts.isMode("--dump-ast")) {
ast.dump();
return;
}
if (opts.isMode("--dump-stmt")) {
findStmt(ast).dump();
return;
}
semanticAnalysis(ast, opts);
if (opts.isMode("--dump-reference")) return;
if (opts.isMode("--dump-semantic")) {
ast.dump();
return;
}
String asm = generateAssembly(ast, opts);
if (opts.isMode("--dump-asm")) {
System.out.println(asm);
return;
}
writeFile(src.asmFileName(opts), asm);
src.setCurrentName(src.asmFileName(opts));
if (opts.isMode("-S")) {
return;
}
} }
if (opts.isMode("--dump-ast")) { if (! opts.isAssembleRequired()) return;
ast.dump(); if (src.isAssemblySource()) {
return; assemble(src.asmFileName(opts), src.objFileName(opts), opts);
src.setCurrentName(src.objFileName(opts));
} }
if (opts.isMode("--dump-stmt")) {
findStmt(ast).dump();
return;
}
semanticAnalysis(ast, opts);
if (opts.isMode("--dump-semantic")) {
ast.dump();
return;
}
String asm = CodeGenerator.generate(ast, opts.typeTable, errorHandler);
if (opts.isMode("--dump-asm")) {
System.out.println(asm);
return;
}
writeFile(asmFileName(opts), asm);
if (opts.isMode("-S")) {
return;
}
assemble(asmFileName(opts), objFileName(opts), opts);
if (opts.isMode("-c")) {
return;
}
link(objFileName(opts), exeFileName(opts), opts);
} }
protected void dumpTokens(Iterator tokens, PrintStream s) { protected void dumpTokens(Iterator tokens, PrintStream s) {
@ -267,61 +161,66 @@ public class Compiler {
return null; // never reach return null; // never reach
} }
protected AST parseFile(Options opts) protected AST parseFile(SourceFile src, Options opts)
throws SyntaxException, FileException { throws SyntaxException, FileException {
return Parser.parseFile(new File(opts.inputFile), return Parser.parseFile(new File(src.currentName()),
opts.loader, opts.loader(),
errorHandler, errorHandler,
opts.debugParser); opts.doesDebugParser());
} }
protected void semanticAnalysis(AST ast, Options opts) protected void semanticAnalysis(AST ast, Options opts)
throws SemanticException { throws SemanticException {
JumpResolver.resolve(ast, errorHandler); JumpResolver.resolve(ast, errorHandler);
LocalReferenceResolver.resolve(ast, errorHandler); LocalReferenceResolver.resolve(ast, errorHandler);
TypeResolver.resolve(ast, opts.typeTable, errorHandler); TypeResolver.resolve(ast, opts.typeTable(), errorHandler);
opts.typeTable.semanticCheck(errorHandler); opts.typeTable().semanticCheck(errorHandler);
DereferenceChecker.check(ast, errorHandler); DereferenceChecker.check(ast, errorHandler);
if (opts.isMode("--dump-reference")) { if (opts.isMode("--dump-reference")) {
ast.dump(); ast.dump();
System.exit(1); return;
} }
new TypeChecker(opts.typeTable, errorHandler).check(ast); new TypeChecker(opts.typeTable(), errorHandler).check(ast);
}
protected String generateAssembly(AST ast, Options opts) {
return CodeGenerator.generate(ast, opts.typeTable(), errorHandler);
} }
protected void assemble(String srcPath, protected void assemble(String srcPath,
String destPath, String destPath,
Options opts) throws IPCException { Options opts) throws IPCException {
String[] cmd = { List cmd = new ArrayList();
"as", cmd.add("as");
"-o", destPath, cmd.addAll(opts.asOptions());
srcPath cmd.add("-o");
}; cmd.add(destPath);
invoke(cmd, opts.verbose); cmd.add(srcPath);
invoke(cmd, opts.isVerboseMode());
} }
protected void link(String srcPath, protected void generateExecutable(Options opts) throws IPCException {
String destPath, List cmd = new ArrayList();
Options opts) throws IPCException { cmd.add("ld");
String[] cmd = { // FIXME: -dynamic-linker required only on dynamic linking
"ld", cmd.add("-dynamic-linker");
"-dynamic-linker", "/lib/ld-linux.so.2", cmd.add("/lib/ld-linux.so.2");
"/usr/lib/crt1.o", if (! opts.noStartFiles()) cmd.add("/usr/lib/crt1.o");
"/usr/lib/crti.o", if (! opts.noStartFiles()) cmd.add("/usr/lib/crti.o");
srcPath, cmd.addAll(opts.ldArgs());
"/usr/lib/libc_nonshared.a", if (! opts.noDefaultLibs()) cmd.add("-lc");
"-lc", if (! opts.noStartFiles()) cmd.add("/usr/lib/crtn.o");
"/usr/lib/crtn.o", cmd.add("-o");
"-o", destPath cmd.add(opts.exeFileName());
}; invoke(cmd, opts.isVerboseMode());
invoke(cmd, opts.verbose);
} }
public void invoke(String[] cmd, boolean debug) throws IPCException { protected void invoke(List cmdArgs, boolean debug) throws IPCException {
if (debug) { if (debug) {
dumpCommand(cmd); dumpCommand(cmdArgs.iterator());
} }
try { try {
String[] cmd = stringListToArray(cmdArgs);
Process proc = Runtime.getRuntime().exec(cmd); Process proc = Runtime.getRuntime().exec(cmd);
proc.waitFor(); proc.waitFor();
passThrough(proc.getInputStream()); passThrough(proc.getInputStream());
@ -342,11 +241,23 @@ public class Compiler {
} }
} }
protected void dumpCommand(String[] cmd) { protected String[] stringListToArray(List list) {
String[] a = new String[list.size()];
int idx = 0;
Iterator it = list.iterator();
while (it.hasNext()) {
Object o = it.next();
a[idx++] = o.toString();
}
return a;
}
protected void dumpCommand(Iterator args) {
String sep = ""; String sep = "";
for (int i = 0; i < cmd.length; i++) { while (args.hasNext()) {
String arg = args.next().toString();
System.out.print(sep); sep = " "; System.out.print(sep); sep = " ";
System.out.print(cmd[i]); System.out.print(arg);
} }
System.out.println(""); System.out.println("");
} }
@ -380,35 +291,4 @@ public class Compiler {
throw new FileException("file error"); throw new FileException("file error");
} }
} }
protected String asmFileName(Options opts) {
return opts.isMode("-S") && opts.outputFile != null
? opts.outputFile
: baseName(opts.inputFile, true) + ".s";
}
protected String objFileName(Options opts) {
return opts.isMode("-c") && opts.outputFile != null
? opts.outputFile
: baseName(opts.inputFile, true) + ".o";
}
protected String exeFileName(Options opts) {
return opts.outputFile != null
? opts.outputFile
: baseName(opts.inputFile, true);
}
protected String baseName(String path) {
return new File(path).getName();
}
protected String baseName(String path, boolean stripExt) {
if (stripExt) {
return new File(path).getName().replaceFirst("\\.[^.]*$", "");
}
else {
return baseName(path);
}
}
} }

View File

@ -0,0 +1,7 @@
package net.loveruby.cflat.compiler;
// package private
interface LdArg {
abstract public String toString();
abstract public boolean isSourceFile();
}

View File

@ -0,0 +1,18 @@
package net.loveruby.cflat.compiler;
// package private
class LdOption implements LdArg {
protected String option;
public LdOption(String option) {
this.option = option;
}
public boolean isSourceFile() {
return false;
}
public String toString() {
return this.option;
}
}

View File

@ -0,0 +1,345 @@
package net.loveruby.cflat.compiler;
import net.loveruby.cflat.type.TypeTable;
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 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.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;
}
// 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);
}
// FIXME: PIC, PIE
//else if (arg.equals("-fpie"))
//else if (arg.equals("-fPIC"))
//else if (arg.equals("-fpie"))
//else if (arg.equals("-fPIE"))
// FIXME: optimization
//else if (arg.startsWith("-O"))
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")) {
ldArgs.add(new LdOption(arg));
}
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)));
}
// FIXME: -pie
//else if (arg.equals("-pie"))
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("Generic Options:");
out.println(" --check-syntax Checks syntax.");
out.println(" --dump-tokens Parses source file and dumps tokens.");
out.println(" --dump-ast Parses source file and dumps AST.");
out.println(" --dump-semantic Checks semantics and dumps AST.");
// --dump-reference is hidden option
out.println(" -S Generates an assembly source.");
out.println(" --dump-asm Dumps an assembly source.");
out.println(" -c Generates an object file.");
out.println(" -o PATH Places output in file PATH.");
out.println(" -v Verbose mode.");
out.println(" --version Shows compiler version.");
out.println(" --help Prints this message and quit.");
out.println("");
out.println("Parser Options:");
out.println(" --debug-parser Dumps parsing process.");
out.println("");
out.println("Compiler Options:");
out.println(" -I PATH Adds PATH as import file directory.");
//out.println(" -O Enables optimization.");
//out.println(" -O1, -O2, -O3 Equivalent to -O.");
//out.println(" -Os Equivalent to -O.");
//out.println(" -O0 Disables optimization.");
//out.println(" -fPIC Generates PIC assembly.");
//out.println(" -fPIE Generates PIE assembly.");
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 Linkes with shared library (default).");
//out.println(" -static Linkes with static library.");
//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).");
}
}

View File

@ -0,0 +1,100 @@
package net.loveruby.cflat.compiler;
import java.io.File;
// package private
class SourceFile implements LdArg {
protected String originalName;
protected String currentName;
public SourceFile(String name) {
this.originalName = name;
this.currentName = name;
}
public String name() {
return originalName();
}
public String originalName() {
return this.originalName;
}
public String currentName() {
return this.currentName;
}
public void setCurrentName(String name) {
this.currentName = name;
}
public boolean isCflatSource() {
return extName(currentName).equals(".cb");
}
public boolean isAssemblySource() {
return extName(currentName).equals(".s");
}
public boolean isObjectFile() {
return extName(currentName).equals(".o");
}
public boolean isSharedLibrary() {
return extName(currentName).equals(".so");
}
public boolean isStaticLibrary() {
return extName(currentName).equals(".a");
}
public boolean isExecutable() {
return extName(currentName).equals("");
}
public String asmFileName(Options opts) {
return or(opts.outputFileNameFor("-S"), replaceExt(".s"));
}
public String objFileName(Options opts) {
return or(opts.outputFileNameFor("-c"), replaceExt(".o"));
}
public String exeFileName(Options opts) {
return or(opts.outputFileName, replaceExt(""));
}
protected String or(String x, String y) {
return x != null ? x : y;
}
protected String replaceExt(String ext) {
return baseName(originalName, true) + ext;
}
protected String baseName(String path) {
return new File(path).getName();
}
protected String baseName(String path, boolean stripExt) {
if (stripExt) {
return new File(path).getName().replaceFirst("\\.[^.]*$", "");
}
else {
return baseName(path);
}
}
protected String extName(String path) {
int idx = path.lastIndexOf(".");
if (idx < 0) return "";
return path.substring(idx);
}
public boolean isSourceFile() {
return true;
}
public String toString() {
return currentName;
}
}

View File

@ -0,0 +1,7 @@
package net.loveruby.cflat.exception;
public class OptionParseError extends Error {
public OptionParseError(String msg) {
super(msg);
}
}

View File

@ -180,6 +180,20 @@ assert_not_coredump() {
return 0 return 0
} }
assert_file() {
local path="$1"; shift
shunit_begin_test
if [ ! -f "$path" ]
then
echo "not exist or not a file: $file"
echo "----"
shunit_test_failed
return 1
fi
return 0
}
assert_not_exist() { assert_not_exist() {
local file="$1"; shift local file="$1"; shift

1
test/src1.cb Normal file
View File

@ -0,0 +1 @@
int f(int x) { return x * x; }

1
test/src1.hb Normal file
View File

@ -0,0 +1 @@
extern int f(int x);

2
test/src2.cb Normal file
View File

@ -0,0 +1,2 @@
import src1;
int main(int argc, char **argv) { return f(2); }

View File

@ -289,6 +289,11 @@ test_32_noreturn() {
assert_stat 0 ./noreturn assert_stat 0 ./noreturn
} }
test_33_multipleinput() {
assert_compile_success src1.cb src2.cb -o src
assert_status 4 ./src
}
### ###
### Local Assertions ### Local Assertions
### ###