From 189c089088587e7cfc5fc7cbbea4ca4bbc99005b Mon Sep 17 00:00:00 2001 From: Minero Aoki Date: Tue, 12 May 2009 18:24:47 +0000 Subject: [PATCH] r4839@macbookpro: aamine | 2009-05-13 03:24:14 +0900 * compiler/Compiler.java: grand refactoring. * compiler/Options.java: refactoring: avoid ping-pong call with SourceFile. * compiler/SourceFile.java: ditto. * ast/AST.java: does not contain a TypeTable. * compiler/IRGenerator.java * compiler/TypeResolver.java * compiler/TypeChecker.java * sysdep/Linker.java: change arg order. * sysdep/GNULinker.java: ditto. git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@4210 1b9489fe-b721-0410-924e-b54b9192deb8 --- ChangeLog | 21 ++ net/loveruby/cflat/ast/AST.java | 17 -- net/loveruby/cflat/compiler/Compiler.java | 282 ++++++++++-------- net/loveruby/cflat/compiler/IRGenerator.java | 5 +- net/loveruby/cflat/compiler/Options.java | 63 ++-- net/loveruby/cflat/compiler/SourceFile.java | 26 +- net/loveruby/cflat/compiler/TypeChecker.java | 5 +- net/loveruby/cflat/compiler/TypeResolver.java | 4 +- net/loveruby/cflat/sysdep/GNULinker.java | 19 +- net/loveruby/cflat/sysdep/Linker.java | 8 +- 10 files changed, 251 insertions(+), 199 deletions(-) diff --git a/ChangeLog b/ChangeLog index da220ae..3d507c1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +Wed May 13 03:22:46 2009 Minero Aoki + + * compiler/Compiler.java: grand refactoring. + + * compiler/Options.java: refactoring: avoid ping-pong call with + SourceFile. + + * compiler/SourceFile.java: ditto. + + * ast/AST.java: does not contain a TypeTable. + + * compiler/IRGenerator.java + + * compiler/TypeResolver.java + + * compiler/TypeChecker.java + + * sysdep/Linker.java: change arg order. + + * sysdep/GNULinker.java: ditto. + Wed May 13 01:22:12 2009 Minero Aoki * net/loveruby/cflat/utils/CommandUtils.java: accept a list of diff --git a/net/loveruby/cflat/ast/AST.java b/net/loveruby/cflat/ast/AST.java index a14c22a..982479b 100644 --- a/net/loveruby/cflat/ast/AST.java +++ b/net/loveruby/cflat/ast/AST.java @@ -1,5 +1,4 @@ package net.loveruby.cflat.ast; -import net.loveruby.cflat.type.TypeTable; import net.loveruby.cflat.entity.*; import net.loveruby.cflat.ir.IR; import java.util.List; @@ -11,7 +10,6 @@ public class AST extends Node { protected Declarations declarations; protected ToplevelScope scope; protected ConstantTable constantTable; - protected TypeTable typeTable; public AST(Location source, Declarations declarations) { super(); @@ -53,21 +51,6 @@ public class AST extends Node { return declarations.defuns(); } - // called by Compiler - public void setTypeTable(TypeTable table) { - if (typeTable != null) { - throw new Error("must not happen: AST.typeTable set twice"); - } - this.typeTable = table; - } - - public TypeTable typeTable() { - if (typeTable == null) { - throw new Error("must not happen: AST.typeTable is null"); - } - return this.typeTable; - } - // called by LocalResolver public void setScope(ToplevelScope scope) { if (this.scope != null) { diff --git a/net/loveruby/cflat/compiler/Compiler.java b/net/loveruby/cflat/compiler/Compiler.java index f1140c3..f691c62 100644 --- a/net/loveruby/cflat/compiler/Compiler.java +++ b/net/loveruby/cflat/compiler/Compiler.java @@ -3,6 +3,7 @@ import net.loveruby.cflat.parser.Parser; import net.loveruby.cflat.ast.AST; import net.loveruby.cflat.ast.StmtNode; import net.loveruby.cflat.ast.ExprNode; +import net.loveruby.cflat.type.TypeTable; import net.loveruby.cflat.ir.IR; import net.loveruby.cflat.sysdep.CodeGenerator; import net.loveruby.cflat.utils.ErrorHandler; @@ -26,50 +27,51 @@ public class Compiler { } // #@@} - public void commandMain(String[] origArgs) { - Options opts = new Options(); - List srcs = null; + public void commandMain(String[] args) { + Options opts = parseOptions(args); + if (opts.mode() == CompilerMode.CheckSyntax) { + System.exit(checkSyntax(opts) ? 0 : 1); + } try { - srcs = opts.parse(Arrays.asList(origArgs)); + List srcs = opts.sourceFiles(); + build(srcs, opts); + System.exit(0); + } + catch (CompileException ex) { + errorHandler.error(ex.getMessage()); + System.exit(1); + } + } + + private Options parseOptions(String[] args) { + try { + return Options.parse(args); } catch (OptionParseError err) { errorHandler.error(err.getMessage()); errorHandler.error("Try cbc --help for option usage"); System.exit(1); - } - if (opts.mode() == CompilerMode.CheckSyntax) { - boolean failed = false; - for (SourceFile src : srcs) { - if (isValidSyntax(src, opts)) { - System.out.println(src.name() + ": Syntax OK"); - } - else { - System.out.println(src.name() + ": Syntax Error"); - failed = true; - } - } - System.exit(failed ? 1 : 0); - } - else { - try { - buildTarget(srcs, opts); - System.exit(0); - } - catch (CompileException ex) { - errorHandler.error(ex.getMessage()); - System.exit(1); - } + return null; // never reach } } - private void errorExit(String msg) { - errorHandler.error(msg); - System.exit(1); + private boolean checkSyntax(Options opts) { + boolean failed = false; + for (SourceFile src : opts.sourceFiles()) { + if (isValidSyntax(src.path(), opts)) { + System.out.println(src.path() + ": Syntax OK"); + } + else { + System.out.println(src.path() + ": Syntax Error"); + failed = true; + } + } + return !failed; } - private boolean isValidSyntax(SourceFile src, Options opts) { + private boolean isValidSyntax(String path, Options opts) { try { - parseFile(src, opts); + parseFile(path, opts); return true; } catch (SyntaxException ex) { @@ -81,107 +83,59 @@ public class Compiler { } } - // #@@range/buildTarget{ - public void buildTarget(List srcs, Options opts) + // #@@range/build{ + public void build(List srcs, Options opts) throws CompileException { for (SourceFile src : srcs) { - compileFile(src, opts); - } - if (! opts.isLinkRequired()) System.exit(0); - if (! opts.isGeneratingSharedLibrary()) { - generateExecutable(opts); - } - else { - generateSharedLibrary(opts); + if (src.isCflatSource()) { + String destPath = opts.asmFileNameOf(src); + compile(src.path(), destPath, opts); + src.setCurrentName(destPath); + } + if (! opts.isAssembleRequired()) continue; + if (src.isAssemblySource()) { + String destPath = opts.objFileNameOf(src); + assemble(src.path(), destPath, opts); + src.setCurrentName(destPath); + } } + if (! opts.isLinkRequired()) return; + link(opts); } // #@@} - public void compileFile(SourceFile src, Options opts) - throws CompileException { - if (src.isCflatSource()) { - AST ast = parseFile(src, opts); - switch (opts.mode()) { - case DumpTokens: - ast.dumpTokens(System.out); - return; - case DumpAST: - ast.dump(); - return; - case DumpStmt: - findStmt(ast).dump(); - return; - case DumpExpr: - findExpr(ast).dump(); - return; - } - ast.setTypeTable(opts.typeTable()); - semanticAnalysis(ast, opts); - switch (opts.mode()) { - case DumpReference: - return; - case DumpSemantic: - ast.dump(); - return; - } - IR ir = new IRGenerator(errorHandler).generate(ast); - if (opts.mode() == CompilerMode.DumpIR) { - ir.dump(); - return; - } - String asm = generateAssembly(ir, opts); - if (opts.mode() == CompilerMode.DumpAsm) { - System.out.println(asm); - return; - } - writeFile(src.asmFileName(opts), asm); - src.setCurrentName(src.asmFileName(opts)); - if (opts.mode() == CompilerMode.Compile) { - return; - } - } - if (! opts.isAssembleRequired()) return; - if (src.isAssemblySource()) { - assemble(src.asmFileName(opts), src.objFileName(opts), opts); - src.setCurrentName(src.objFileName(opts)); - } + public void compile(String srcPath, String destPath, + Options opts) throws CompileException { + AST ast = parseFile(srcPath, opts); + if (dumpAST(ast, opts.mode())) return; + TypeTable types = opts.typeTable(); + AST sem = semanticAnalyze(ast, types, opts); + if (dumpSemant(sem, opts.mode())) return; + IR ir = new IRGenerator(errorHandler).generate(sem, types); + if (dumpIR(ir, opts.mode())) return; + String asm = generateAssembly(ir, opts); + if (dumpAsm(asm, opts.mode())) return; + writeFile(destPath, asm); } - private StmtNode findStmt(AST ast) { - StmtNode stmt = ast.getSingleMainStmt(); - if (stmt == null) { - errorExit("source file does not contains main()"); - } - return stmt; - } - - private ExprNode findExpr(AST ast) { - ExprNode expr = ast.getSingleMainExpr(); - if (expr == null) { - errorExit("source file does not contains single expression"); - } - return expr; - } - - public AST parseFile(SourceFile src, Options opts) + public AST parseFile(String path, Options opts) throws SyntaxException, FileException { - return Parser.parseFile(new File(src.currentName()), - opts.loader(), - errorHandler, - opts.doesDebugParser()); + return Parser.parseFile(new File(path), + opts.loader(), errorHandler, opts.doesDebugParser()); } - public void semanticAnalysis(AST ast, Options opts) - throws SemanticException { + public AST semanticAnalyze(AST ast, TypeTable typeTable, + Options opts) throws SemanticException { new LocalResolver(errorHandler).resolve(ast); - new TypeResolver(errorHandler).resolve(ast); - ast.typeTable().semanticCheck(errorHandler); + new TypeResolver(errorHandler).resolve(ast, typeTable); + typeTable.semanticCheck(errorHandler); new DereferenceChecker(errorHandler).check(ast); if (opts.mode() == CompilerMode.DumpReference) { ast.dump(); - return; + return ast; } - new TypeChecker(errorHandler).check(ast); + new TypeChecker(errorHandler).check(ast, typeTable); + return ast; } public String generateAssembly(IR ir, Options opts) { @@ -189,21 +143,29 @@ public class Compiler { return gen.generate(ir); } - private void assemble(String srcPath, - String destPath, + public void assemble(String srcPath, String destPath, Options opts) throws IPCException { opts.assembler(errorHandler) .assemble(srcPath, destPath, opts.asOptions()); } - private void generateExecutable(Options opts) throws IPCException { - opts.linker(errorHandler).generateExecutable( - opts.exeFileName(), opts.ldArgs(), opts.ldOptions()); + public void link(Options opts) throws IPCException { + if (! opts.isGeneratingSharedLibrary()) { + generateExecutable(opts); + } + else { + generateSharedLibrary(opts); + } } - private void generateSharedLibrary(Options opts) throws IPCException { + public void generateExecutable(Options opts) throws IPCException { + opts.linker(errorHandler).generateExecutable( + opts.ldArgs(), opts.exeFileName(), opts.ldOptions()); + } + + public void generateSharedLibrary(Options opts) throws IPCException { opts.linker(errorHandler).generateSharedLibrary( - opts.soFileName(), opts.ldArgs(), opts.ldOptions()); + opts.ldArgs(), opts.soFileName(), opts.ldOptions()); } private void writeFile(String path, String str) @@ -227,4 +189,76 @@ public class Compiler { throw new FileException("file error"); } } + + private boolean dumpAST(AST ast, CompilerMode mode) { + switch (mode) { + case DumpTokens: + ast.dumpTokens(System.out); + return true; + case DumpAST: + ast.dump(); + return true; + case DumpStmt: + findStmt(ast).dump(); + return true; + case DumpExpr: + findExpr(ast).dump(); + return true; + default: + return false; + } + } + + private StmtNode findStmt(AST ast) { + StmtNode stmt = ast.getSingleMainStmt(); + if (stmt == null) { + errorExit("source file does not contains main()"); + } + return stmt; + } + + private ExprNode findExpr(AST ast) { + ExprNode expr = ast.getSingleMainExpr(); + if (expr == null) { + errorExit("source file does not contains single expression"); + } + return expr; + } + + private boolean dumpSemant(AST ast, CompilerMode mode) { + switch (mode) { + case DumpReference: + return true; + case DumpSemantic: + ast.dump(); + return true; + default: + return false; + } + } + + private boolean dumpIR(IR ir, CompilerMode mode) { + if (mode == CompilerMode.DumpIR) { + ir.dump(); + return true; + } + else { + return false; + } + } + + private boolean dumpAsm(String asm, CompilerMode mode) { + if (mode == CompilerMode.DumpAsm) { + System.out.println(asm); + return true; + } + else { + return false; + } + } + + private void errorExit(String msg) { + errorHandler.error(msg); + System.exit(1); + } } diff --git a/net/loveruby/cflat/compiler/IRGenerator.java b/net/loveruby/cflat/compiler/IRGenerator.java index 3eadaea..f043e54 100644 --- a/net/loveruby/cflat/compiler/IRGenerator.java +++ b/net/loveruby/cflat/compiler/IRGenerator.java @@ -20,8 +20,9 @@ class IRGenerator implements ASTVisitor { // #@@} // #@@range/generate{ - public IR generate(AST ast) throws SemanticException { - typeTable = ast.typeTable(); + public IR generate(AST ast, TypeTable typeTable) + throws SemanticException { + this.typeTable = typeTable; for (DefinedVariable var : ast.definedVariables()) { if (var.hasInitializer()) { var.setIR(transformExpr(var.initializer())); diff --git a/net/loveruby/cflat/compiler/Options.java b/net/loveruby/cflat/compiler/Options.java index 0dac6eb..40c1d97 100644 --- a/net/loveruby/cflat/compiler/Options.java +++ b/net/loveruby/cflat/compiler/Options.java @@ -12,17 +12,23 @@ import java.util.Arrays; import java.io.PrintStream; class Options { - CompilerMode mode = CompilerMode.Link; - LibraryLoader loader = new LibraryLoader(); - Platform platform = new X86Linux(); - String outputFileName; - boolean verbose = false; - boolean debugParser = false; - CodeGeneratorOptions genOptions = new CodeGeneratorOptions(); - AssemblerOptions asOptions = new AssemblerOptions(); - LinkerOptions ldOptions = new LinkerOptions(); - List ldArgs; - List sourceFiles; + static Options parse(String[] args) { + Options opts = new Options(); + opts.parseArgs(args); + return opts; + } + + private CompilerMode mode = CompilerMode.Link; + private Platform platform = new X86Linux(); + private String outputFileName; + private boolean verbose = false; + private LibraryLoader loader = new LibraryLoader(); + private boolean debugParser = false; + private CodeGeneratorOptions genOptions = new CodeGeneratorOptions(); + private AssemblerOptions asOptions = new AssemblerOptions(); + private LinkerOptions ldOptions = new LinkerOptions(); + private List ldArgs; + private List sourceFiles; CompilerMode mode() { return mode; @@ -36,29 +42,43 @@ class Options { return mode.requires(CompilerMode.Link); } - String outputFileNameFor(CompilerMode mode) { - return this.mode == mode ? outputFileName : null; + List sourceFiles() { + return sourceFiles; + } + + String asmFileNameOf(SourceFile src) { + if (outputFileName != null && mode == CompilerMode.Compile) { + return outputFileName; + } + return src.asmFileName(); + } + + String objFileNameOf(SourceFile src) { + if (outputFileName != null && mode == CompilerMode.Assemble) { + return outputFileName; + } + return src.objFileName(); } String exeFileName() { - return getOutputFileName(""); + return linkedFileName(""); } String soFileName() { - return getOutputFileName(".so"); + return linkedFileName(".so"); } - static private final String DEFAULT_OUTPUT_FILE_NAME = "a.out"; + static private final String DEFAULT_LINKER_OUTPUT = "a.out"; - private String getOutputFileName(String newExt) { + private String linkedFileName(String newExt) { if (outputFileName != null) { return outputFileName; } if (sourceFiles.size() == 1) { - return sourceFiles.get(0).linkedFileName(this, newExt); + return sourceFiles.get(0).linkedFileName(newExt); } else { - return DEFAULT_OUTPUT_FILE_NAME; + return DEFAULT_LINKER_OUTPUT; } } @@ -114,10 +134,10 @@ class Options { return ldOptions.generatingSharedLibrary; } - List parse(List argsList) { + void parseArgs(String[] origArgs) { sourceFiles = new ArrayList(); ldArgs = new ArrayList(); - ListIterator args = argsList.listIterator(); + ListIterator args = Arrays.asList(origArgs).listIterator(); while (args.hasNext()) { String arg = args.next(); if (arg.equals("--")) { @@ -244,7 +264,6 @@ class Options { && ! isLinkRequired()) { parseError("-o option requires only 1 input (except linking)"); } - return sourceFiles; } private void parseError(String msg) { diff --git a/net/loveruby/cflat/compiler/SourceFile.java b/net/loveruby/cflat/compiler/SourceFile.java index 0c4d33d..f2bf835 100644 --- a/net/loveruby/cflat/compiler/SourceFile.java +++ b/net/loveruby/cflat/compiler/SourceFile.java @@ -18,16 +18,12 @@ class SourceFile implements LdArg { return currentName; } - String name() { - return originalName(); - } - - String originalName() { - return this.originalName; + String path() { + return currentName; } String currentName() { - return this.currentName; + return currentName; } void setCurrentName(String name) { @@ -58,20 +54,16 @@ class SourceFile implements LdArg { return extName(currentName).equals(""); } - String asmFileName(Options opts) { - return or(opts.outputFileNameFor(CompilerMode.Compile), replaceExt(".s")); + String asmFileName() { + return replaceExt(".s"); } - String objFileName(Options opts) { - return or(opts.outputFileNameFor(CompilerMode.Assemble), replaceExt(".o")); + String objFileName() { + return replaceExt(".o"); } - String linkedFileName(Options opts, String newExt) { - return or(opts.outputFileName, replaceExt(newExt)); - } - - private String or(String x, String y) { - return x != null ? x : y; + String linkedFileName(String newExt) { + return replaceExt(newExt); } private String replaceExt(String ext) { diff --git a/net/loveruby/cflat/compiler/TypeChecker.java b/net/loveruby/cflat/compiler/TypeChecker.java index b64b526..c4ac44d 100644 --- a/net/loveruby/cflat/compiler/TypeChecker.java +++ b/net/loveruby/cflat/compiler/TypeChecker.java @@ -26,8 +26,9 @@ class TypeChecker extends Visitor { } // #@@range/check_AST{ - public void check(AST ast) throws SemanticException { - this.typeTable = ast.typeTable(); + public void check(AST ast, TypeTable typeTable) + throws SemanticException { + this.typeTable = typeTable; for (DefinedVariable var : ast.definedVariables()) { checkVariable(var); } diff --git a/net/loveruby/cflat/compiler/TypeResolver.java b/net/loveruby/cflat/compiler/TypeResolver.java index 5b023af..d4129d5 100644 --- a/net/loveruby/cflat/compiler/TypeResolver.java +++ b/net/loveruby/cflat/compiler/TypeResolver.java @@ -18,8 +18,8 @@ public class TypeResolver extends Visitor // #@@} // #@@range/resolveProgram{ - public void resolve(AST ast) { - this.typeTable = ast.typeTable(); + public void resolve(AST ast, TypeTable typeTable) { + this.typeTable = typeTable; defineTypes(ast.types()); // #@@range/resolveProgram_core{ for (TypeDefinition t : ast.types()) { diff --git a/net/loveruby/cflat/sysdep/GNULinker.java b/net/loveruby/cflat/sysdep/GNULinker.java index fffc6b9..e1fd10b 100644 --- a/net/loveruby/cflat/sysdep/GNULinker.java +++ b/net/loveruby/cflat/sysdep/GNULinker.java @@ -6,11 +6,12 @@ import java.util.List; import java.util.ArrayList; class GNULinker implements Linker { - static final protected String DYNAMIC_LINKER = "/lib/ld-linux.so.2"; - static final protected String C_RUNTIME_INIT = "/usr/lib/crti.o"; - static final protected String C_RUNTIME_START = "/usr/lib/crt1.o"; - static final protected String C_RUNTIME_START_PIE = "/usr/lib/Scrt1.o"; - static final protected String C_RUNTIME_FINI = "/usr/lib/crtn.o"; + // 32bit Linux dependent + static final private String DYNAMIC_LINKER = "/lib/ld-linux.so.2"; + static final private String C_RUNTIME_INIT = "/usr/lib/crti.o"; + static final private String C_RUNTIME_START = "/usr/lib/crt1.o"; + static final private String C_RUNTIME_START_PIE = "/usr/lib/Scrt1.o"; + static final private String C_RUNTIME_FINI = "/usr/lib/crtn.o"; ErrorHandler errorHandler; @@ -18,8 +19,8 @@ class GNULinker implements Linker { this.errorHandler = errorHandler; } - public void generateExecutable(String destPath, - List args, LinkerOptions opts) throws IPCException { + public void generateExecutable(List args, + String destPath, LinkerOptions opts) throws IPCException { List cmd = new ArrayList(); cmd.add("ld"); cmd.add("-dynamic-linker"); @@ -46,8 +47,8 @@ class GNULinker implements Linker { CommandUtils.invoke(cmd, errorHandler, opts.verbose); } - public void generateSharedLibrary(String destPath, - List args, LinkerOptions opts) throws IPCException { + public void generateSharedLibrary(List args, + String destPath, LinkerOptions opts) throws IPCException { List cmd = new ArrayList(); cmd.add("ld"); cmd.add("-shared"); diff --git a/net/loveruby/cflat/sysdep/Linker.java b/net/loveruby/cflat/sysdep/Linker.java index 77d97c7..55460b3 100644 --- a/net/loveruby/cflat/sysdep/Linker.java +++ b/net/loveruby/cflat/sysdep/Linker.java @@ -3,8 +3,8 @@ import net.loveruby.cflat.exception.IPCException; import java.util.List; public interface Linker { - void generateExecutable(String destPath, - List args, LinkerOptions opts) throws IPCException; - void generateSharedLibrary(String destPath, - List args, LinkerOptions opts) throws IPCException; + void generateExecutable(List args, String destPath, + LinkerOptions opts) throws IPCException; + void generateSharedLibrary(List args, String destPath, + LinkerOptions opts) throws IPCException; }