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
This commit is contained in:
Minero Aoki 2009-05-12 18:24:47 +00:00
parent 9c8af78a97
commit 189c089088
10 changed files with 251 additions and 199 deletions

View File

@ -1,3 +1,24 @@
Wed May 13 03:22:46 2009 Minero Aoki <aamine@loveruby.net>
* 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 <aamine@loveruby.net>
* net/loveruby/cflat/utils/CommandUtils.java: accept a list of

View File

@ -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) {

View File

@ -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<SourceFile> 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<SourceFile> 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<SourceFile> srcs, Options opts)
// #@@range/build{
public void build(List<SourceFile> 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);
}
}

View File

@ -20,8 +20,9 @@ class IRGenerator implements ASTVisitor<Void, Expr> {
// #@@}
// #@@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()));

View File

@ -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<LdArg> ldArgs;
List<SourceFile> 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<LdArg> ldArgs;
private List<SourceFile> 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<SourceFile> 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<SourceFile> parse(List<String> argsList) {
void parseArgs(String[] origArgs) {
sourceFiles = new ArrayList<SourceFile>();
ldArgs = new ArrayList<LdArg>();
ListIterator<String> args = argsList.listIterator();
ListIterator<String> 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) {

View File

@ -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) {

View File

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

View File

@ -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()) {

View File

@ -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<String> args, LinkerOptions opts) throws IPCException {
public void generateExecutable(List<String> args,
String destPath, LinkerOptions opts) throws IPCException {
List<String> cmd = new ArrayList<String>();
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<String> args, LinkerOptions opts) throws IPCException {
public void generateSharedLibrary(List<String> args,
String destPath, LinkerOptions opts) throws IPCException {
List<String> cmd = new ArrayList<String>();
cmd.add("ld");
cmd.add("-shared");

View File

@ -3,8 +3,8 @@ import net.loveruby.cflat.exception.IPCException;
import java.util.List;
public interface Linker {
void generateExecutable(String destPath,
List<String> args, LinkerOptions opts) throws IPCException;
void generateSharedLibrary(String destPath,
List<String> args, LinkerOptions opts) throws IPCException;
void generateExecutable(List<String> args, String destPath,
LinkerOptions opts) throws IPCException;
void generateSharedLibrary(List<String> args, String destPath,
LinkerOptions opts) throws IPCException;
}