From fd5caed6fc37dc67974fc24fdecb4921641de516 Mon Sep 17 00:00:00 2001 From: Minero Aoki Date: Sat, 12 Jan 2008 19:48:31 +0000 Subject: [PATCH] * net/loveruby/cflat/compiler/TypeChecker.java: fork DereferenceChecker, to reduce catch(SemanticError). * net/loveruby/cflat/compiler/DereferenceChecker.java: new class. * net/loveruby/cflat/ast/ExprNode.java (isAssignable, isDereferable): catch SemanticError which may occuer on type.isXXXX. * net/loveruby/cflat/compiler/Visitor.java: refactoring: rename method: #resolve -> #visitNode. * net/loveruby/cflat/compiler/Visitor.java: refactoring: rename method: #resolveNodeList -> #visitNodeList. * net/loveruby/cflat/compiler/JumpResolver.java: ditto. * net/loveruby/cflat/compiler/LocalReferenceResolver.java: ditto. * net/loveruby/cflat/compiler/TypeResolver.java: ditto. * net/loveruby/cflat/compiler/TypeChecker.java: ditto. * net/loveruby/cflat/compiler/Compiler.java: parse command line options more precisely. * net/loveruby/cflat/compiler/Compiler.java: new option --compile. * net/loveruby/cflat/compiler/Compiler.java: new option --dump-reference. * net/loveruby/cflat/compiler/Compiler.java: new option --dump-semantic. * net/loveruby/cflat/ast/VariableNode.java (dump): show resolved or not. * net/loveruby/cflat/ast/TypeNode.java (dump): ditto. * net/loveruby/cflat/ast/Dumper.java (printMember): ditto. git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@3819 1b9489fe-b721-0410-924e-b54b9192deb8 --- ChangeLog | 43 +++++ ToDo | 6 +- net/loveruby/cflat/ast/Dumper.java | 10 +- net/loveruby/cflat/ast/ExprNode.java | 15 +- net/loveruby/cflat/ast/TypeNode.java | 4 - net/loveruby/cflat/ast/VariableNode.java | 10 +- net/loveruby/cflat/compiler/Compiler.java | 121 +++++++++++--- .../cflat/compiler/DereferenceChecker.java | 148 ++++++++++++++++++ net/loveruby/cflat/compiler/JumpResolver.java | 10 +- .../compiler/LocalReferenceResolver.java | 8 +- net/loveruby/cflat/compiler/TypeChecker.java | 99 ++---------- net/loveruby/cflat/compiler/TypeResolver.java | 29 +++- net/loveruby/cflat/compiler/Visitor.java | 99 ++++++------ 13 files changed, 420 insertions(+), 182 deletions(-) create mode 100644 net/loveruby/cflat/compiler/DereferenceChecker.java diff --git a/ChangeLog b/ChangeLog index 624d337..32cd7d0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,46 @@ +Sun Jan 13 04:48:28 2008 Minero Aoki + + * net/loveruby/cflat/compiler/TypeChecker.java: fork + DereferenceChecker, to reduce catch(SemanticError). + + * net/loveruby/cflat/compiler/DereferenceChecker.java: new class. + + * net/loveruby/cflat/ast/ExprNode.java (isAssignable, + isDereferable): catch SemanticError which may occuer on + type.isXXXX. + + * net/loveruby/cflat/compiler/Visitor.java: refactoring: rename + method: #resolve -> #visitNode. + + * net/loveruby/cflat/compiler/Visitor.java: refactoring: rename + method: #resolveNodeList -> #visitNodeList. + + * net/loveruby/cflat/compiler/JumpResolver.java: ditto. + + * net/loveruby/cflat/compiler/LocalReferenceResolver.java: ditto. + + * net/loveruby/cflat/compiler/TypeResolver.java: ditto. + + * net/loveruby/cflat/compiler/TypeChecker.java: ditto. + + * net/loveruby/cflat/compiler/Compiler.java: parse command line + options more precisely. + + * net/loveruby/cflat/compiler/Compiler.java: new option --compile. + + * net/loveruby/cflat/compiler/Compiler.java: new option + --dump-reference. + + * net/loveruby/cflat/compiler/Compiler.java: new option + --dump-semantic. + + * net/loveruby/cflat/ast/VariableNode.java (dump): show resolved + or not. + + * net/loveruby/cflat/ast/TypeNode.java (dump): ditto. + + * net/loveruby/cflat/ast/Dumper.java (printMember): ditto. + Sun Jan 13 04:47:12 2008 Minero Aoki * net/loveruby/cflat/type/Type.java: make #isCompatible and diff --git a/ToDo b/ToDo index 57343a4..10ef9c2 100644 --- a/ToDo +++ b/ToDo @@ -181,8 +181,10 @@ - --dump-tokens - --dump-ast - print node location in error message -* parse command line option more precisely -* --dump-semantic +- parse command line option more precisely +- --dump-reference +- --dump-semantic +* add standard load path * generate IR * --dump-ir * control flow graph diff --git a/net/loveruby/cflat/ast/Dumper.java b/net/loveruby/cflat/ast/Dumper.java index 0e40b93..d85a495 100644 --- a/net/loveruby/cflat/ast/Dumper.java +++ b/net/loveruby/cflat/ast/Dumper.java @@ -58,8 +58,13 @@ public class Dumper { printPair(name, (t == null ? "null" : t.toString())); } + public void printMember(String name, String str, boolean isResolved) { + printPair(name, TextUtils.escapeString(str) + + (isResolved ? " (resolved)" : "")); + } + public void printMember(String name, String str) { - printPair(name, TextUtils.escapeString(str)); + printMember(name, str, false); } protected void printPair(String name, String value) { @@ -69,7 +74,8 @@ public class Dumper { public void printMember(String name, TypeNode n) { printIndent(); - stream.println(name + ": " + n.typeRef()); + stream.println(name + ": " + n.typeRef() + + (n.isResolved() ? " (resolved)" : "")); } public void printMember(String name, Node n) { diff --git a/net/loveruby/cflat/ast/ExprNode.java b/net/loveruby/cflat/ast/ExprNode.java index cb59d71..f99abbb 100644 --- a/net/loveruby/cflat/ast/ExprNode.java +++ b/net/loveruby/cflat/ast/ExprNode.java @@ -1,6 +1,7 @@ package net.loveruby.cflat.ast; import net.loveruby.cflat.type.Type; import net.loveruby.cflat.asm.*; +import net.loveruby.cflat.exception.*; abstract public class ExprNode extends Node { public ExprNode() { @@ -10,11 +11,21 @@ abstract public class ExprNode extends Node { abstract public Type type(); public boolean isCallable() { - return type().isCallable(); + try { + return type().isCallable(); + } + catch (SemanticError err) { + return false; + } } public boolean isDereferable() { - return type().isDereferable(); + try { + return type().isDereferable(); + } + catch (SemanticError err) { + return false; + } } public boolean isConstant() { diff --git a/net/loveruby/cflat/ast/TypeNode.java b/net/loveruby/cflat/ast/TypeNode.java index 74a35b9..f53bc2d 100644 --- a/net/loveruby/cflat/ast/TypeNode.java +++ b/net/loveruby/cflat/ast/TypeNode.java @@ -15,10 +15,6 @@ public class TypeNode extends Node { this.type = type; } - public void resolve(TypeTable tbl) { - // FIXME - } - public TypeRef typeRef() { return typeRef; } diff --git a/net/loveruby/cflat/ast/VariableNode.java b/net/loveruby/cflat/ast/VariableNode.java index 5b633da..c47d2e8 100644 --- a/net/loveruby/cflat/ast/VariableNode.java +++ b/net/loveruby/cflat/ast/VariableNode.java @@ -17,8 +17,8 @@ public class VariableNode extends ExprNode { return name; } - public void setEntity(Entity ent) { - entity = ent; + public boolean isResolved() { + return (entity != null); } public Entity entity() { @@ -28,6 +28,10 @@ public class VariableNode extends ExprNode { return entity; } + public void setEntity(Entity ent) { + entity = ent; + } + public Type type() { return entity().type(); } @@ -53,7 +57,7 @@ public class VariableNode extends ExprNode { } protected void _dump(Dumper d) { - d.printMember("name", name); + d.printMember("name", name, isResolved()); } public void accept(ASTVisitor visitor) { diff --git a/net/loveruby/cflat/compiler/Compiler.java b/net/loveruby/cflat/compiler/Compiler.java index f4dce72..807a2ba 100644 --- a/net/loveruby/cflat/compiler/Compiler.java +++ b/net/loveruby/cflat/compiler/Compiler.java @@ -29,36 +29,72 @@ public class Compiler { errorHandler = h; } - public void commandMain(String[] args) { + public void commandMain(String[] origArgs) { + // parse options + String mode = null; + List args = listFromArray(origArgs); + ListIterator it = args.listIterator(); + while (it.hasNext()) { + String arg = (String)it.next(); + if (arg.startsWith("-")) { + if (arg.equals("--compile") + || arg.equals("--check-syntax") + || arg.equals("--dump-tokens") + || arg.equals("--dump-ast") + || arg.equals("--dump-reference") + || arg.equals("--dump-semantic")) { + if (mode != null) { + errorExit(mode + " option and " + + arg + " option is exclusive"); + } + mode = arg; + it.remove(); + } + else if (arg.equals("--help")) { + printUsage(System.out); + System.exit(0); + } + else { + System.err.println("unknown option: " + arg); + printUsage(System.err); + System.exit(1); + } + } + } + if (mode == null) { + mode = "--compile"; + } + if (args.size() == 0) errorExit("no input file"); + if (args.size() > 1) errorExit("too many input files"); + String inputFile = (String)args.get(0); + + // execute try { - if (args.length == 0) errorExit("no argument given"); - if (args[0].equals("--dump-tokens")) { - if (args.length != 2) { - errorExit("no file input or too many files"); - } - dumpTokensFromFile(args[1]); + if (mode.equals("--compile")) { + compileFile(inputFile); } - else if (args[0].equals("--dump-ast")) { - if (args.length != 2) { - errorExit("no file input or too many files"); - } - dumpASTFromFile(args[1]); - } - else if (args[0].equals("--check-syntax")) { - if (args.length != 2) { - errorExit("no file input or too many files"); - } - if (isValidSyntax(args[1])) { + else if (mode.equals("--check-syntax")) { + if (isValidSyntax(inputFile)) { System.out.println("Syntax OK"); System.exit(0); } else { System.exit(1); } } + else if (mode.equals("--dump-tokens")) { + dumpTokensFromFile(inputFile); + } + else if (mode.equals("--dump-ast")) { + dumpASTFromFile(inputFile); + } + else if (mode.equals("--dump-reference")) { + dumpReferenceFromFile(inputFile); + } + else if (mode.equals("--dump-semantic")) { + dumpSemanticFromFile(inputFile); + } else { - if (args.length != 1) - errorExit("no file input or too many files"); - compileFile(args[0]); + throw new Error("unknown mode: " + mode); } } catch (CompileException ex) { @@ -67,6 +103,24 @@ public class Compiler { } } + protected void printUsage(PrintStream out) { + // --dump-reference is hidden option + out.println("Usage: cbc [option] file"); + out.println(" --check-syntax Syntax check only."); + out.println(" --dump-tokens Parses source file and dumps tokens."); + out.println(" --dump-ast Parses source file and dumps AST."); + out.println(" --dump-semantic Check semantics and dumps AST."); + 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 void errorExit(String msg) { errorHandler.error(msg); System.exit(1); @@ -111,9 +165,27 @@ public class Compiler { parseFile(path).dump(); } + public void dumpReferenceFromFile(String path) throws CompileException { + AST ast = parseFile(path); + TypeTable typeTable = defaultTypeTable(); + JumpResolver.resolve(ast, errorHandler); + LocalReferenceResolver.resolve(ast, errorHandler); + TypeResolver.resolve(ast, typeTable, errorHandler); + typeTable.semanticCheck(errorHandler); + DereferenceChecker.check(ast, errorHandler); + ast.dump(); + } + + public void dumpSemanticFromFile(String path) throws CompileException { + AST ast = parseFile(path); + TypeTable typeTable = defaultTypeTable(); + semanticAnalysis(ast, typeTable); + ast.dump(); + } + public void compileFile(String path) throws CompileException { AST ast = parseFile(path); - TypeTable typeTable = TypeTable.ilp32(); + TypeTable typeTable = defaultTypeTable(); semanticAnalysis(ast, typeTable); String asm = CodeGenerator.generate(ast, typeTable, errorHandler); writeFile(asmFileName(path), asm); @@ -126,9 +198,14 @@ public class Compiler { LocalReferenceResolver.resolve(ast, errorHandler); TypeResolver.resolve(ast, typeTable, errorHandler); typeTable.semanticCheck(errorHandler); + DereferenceChecker.check(ast, errorHandler); TypeChecker.check(ast, typeTable, errorHandler); } + private TypeTable defaultTypeTable() { + return TypeTable.ilp32(); + } + public AST parseFile(String path) throws CompileException { return Parser.parseFile(new File(path), loader, errorHandler); } diff --git a/net/loveruby/cflat/compiler/DereferenceChecker.java b/net/loveruby/cflat/compiler/DereferenceChecker.java new file mode 100644 index 0000000..5251189 --- /dev/null +++ b/net/loveruby/cflat/compiler/DereferenceChecker.java @@ -0,0 +1,148 @@ +package net.loveruby.cflat.compiler; +import net.loveruby.cflat.ast.*; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.exception.*; +import java.util.*; + +class DereferenceChecker extends Visitor { + static public void check(AST ast, ErrorHandler h) + throws SemanticException { + new DereferenceChecker(h).visit(ast); + } + + protected ErrorHandler errorHandler; + + public DereferenceChecker(ErrorHandler h) { + this.errorHandler = h; + } + + protected void check(Node node) { + visitNode(node); + } + + public void visit(AST ast) throws SemanticException { + Iterator vars = ast.variables(); + while (vars.hasNext()) { + DefinedVariable var = (DefinedVariable)vars.next(); + checkVariable(var); + } + Iterator funcs = ast.functions(); + while (funcs.hasNext()) { + DefinedFunction f = (DefinedFunction)funcs.next(); + check(f.body()); + } + if (errorHandler.errorOccured()) { + throw new SemanticException("compile failed."); + } + } + + // + // Statements + // + + protected void checkVariable(DefinedVariable var) { + if (var.hasInitializer()) { + check(var.initializer()); + } + } + + // + // Assignment Expressions + // + + public void visit(AssignNode node) { + super.visit(node); + checkAssignment(node); + } + + public void visit(OpAssignNode node) { + super.visit(node); + checkAssignment(node); + // check as operator + } + + protected void checkAssignment(AbstractAssignNode node) { + if (! node.lhs().isAssignable()) { + error(node, "invalid lhs expression"); + return; + } + } + + // + // Expressions + // + + public void visit(FuncallNode node) { + super.visit(node); + if (! node.expr().isCallable()) { + error(node, "calling object is not a function"); + return; + } + } + + public void visit(ArefNode node) { + super.visit(node); + if (! node.expr().isDereferable()) { + error(node, "is not indexable: " + node.expr().type()); + return; + } + check(node.index()); + } + + public void visit(MemberNode node) { + super.visit(node); + checkMemberRef(node, node.expr().type(), node.member()); + } + + public void visit(PtrMemberNode node) { + super.visit(node); + if (! node.expr().isDereferable()) { + undereferableError(node, node.expr().type()); + return; + } + checkMemberRef(node, node.dereferedType(), node.member()); + } + + protected void checkMemberRef(Node node, Type t, String memb) { + if (! t.isComplexType()) { + error(node, "is not struct/union: " + t); + return; + } + ComplexType type = t.getComplexType(); + if (! type.hasMember(memb)) { + error(node, type.toString() + " does not have member " + memb); + return; + } + } + + public void visit(DereferenceNode node) { + super.visit(node); + if (! node.expr().isDereferable()) { + undereferableError(node, node.expr().type()); + return; + } + } + + public void visit(AddressNode node) { + super.visit(node); + if (! node.expr().isAssignable()) { + error(node, "invalid LHS expression for &"); + } + } + + // + // Utilities + // + + protected void undereferableError(Node n, Type type) { + error(n, "dereferencing non-pointer expression: " + type); + } + + protected void warn(Node n, String msg) { + errorHandler.warn(n.location(), msg); + } + + protected void error(Node n, String msg) { + errorHandler.error(n.location(), msg); + } +} diff --git a/net/loveruby/cflat/compiler/JumpResolver.java b/net/loveruby/cflat/compiler/JumpResolver.java index b105601..7612361 100644 --- a/net/loveruby/cflat/compiler/JumpResolver.java +++ b/net/loveruby/cflat/compiler/JumpResolver.java @@ -7,7 +7,7 @@ import java.util.*; public class JumpResolver extends Visitor { static public void resolve(AST ast, ErrorHandler h) throws SemanticException { - new JumpResolver(h).resolveAST(ast); + new JumpResolver(h).resolve(ast); } protected ErrorHandler errorHandler; @@ -19,7 +19,7 @@ public class JumpResolver extends Visitor { errorHandler = h; } - public void resolveAST(AST ast) throws SemanticException { + public void resolve(AST ast) throws SemanticException { breakTargetStack = new LinkedList(); continueTargetStack = new LinkedList(); Iterator funcs = ast.functions(); @@ -33,6 +33,10 @@ public class JumpResolver extends Visitor { } } + protected void resolve(Node n) { + visitNode(n); + } + private BreakableStmt currentBreakTarget() throws SemanticException { if (breakTargetStack.isEmpty()) { @@ -52,7 +56,7 @@ public class JumpResolver extends Visitor { public void visit(SwitchNode node) { resolve(node.cond()); breakTargetStack.add(node); - resolveNodeList(node.cases()); + visitNodeList(node.cases()); breakTargetStack.removeLast(); } diff --git a/net/loveruby/cflat/compiler/LocalReferenceResolver.java b/net/loveruby/cflat/compiler/LocalReferenceResolver.java index 6f2b39f..65dab16 100644 --- a/net/loveruby/cflat/compiler/LocalReferenceResolver.java +++ b/net/loveruby/cflat/compiler/LocalReferenceResolver.java @@ -6,7 +6,7 @@ import java.util.*; public class LocalReferenceResolver extends Visitor { static public void resolve(AST ast, ErrorHandler handler) throws SemanticException { - new LocalReferenceResolver(handler).resolveAST(ast); + new LocalReferenceResolver(handler).resolve(ast); } protected ErrorHandler errorHandler; @@ -18,7 +18,11 @@ public class LocalReferenceResolver extends Visitor { this.errorHandler = h; } - public void resolveAST(AST ast) throws SemanticException { + protected void resolve(Node n) { + visitNode(n); + } + + public void resolve(AST ast) throws SemanticException { toplevel = ast.scope(); scopeStack = new LinkedList(); scopeStack.add(toplevel); diff --git a/net/loveruby/cflat/compiler/TypeChecker.java b/net/loveruby/cflat/compiler/TypeChecker.java index 00c0bac..fe6871d 100644 --- a/net/loveruby/cflat/compiler/TypeChecker.java +++ b/net/loveruby/cflat/compiler/TypeChecker.java @@ -19,7 +19,7 @@ class TypeChecker extends Visitor { } protected void check(Node node) { - resolve(node); + visitNode(node); } public void visit(AST ast) throws SemanticException { @@ -70,12 +70,7 @@ class TypeChecker extends Visitor { Iterator stmts = node.stmts(); while (stmts.hasNext()) { Node n = (Node)stmts.next(); - try { - check(n); - } - catch (SemanticError err) { - // ignore semantic errors - } + check(n); } } @@ -85,18 +80,13 @@ class TypeChecker extends Visitor { return; } if (var.hasInitializer()) { - try { - if (isInvalidLHSType(var.type())) { - error(var, "invalid LHS type: " + var.type()); - return; - } - check(var.initializer()); - var.setInitializer( - checkRHSType(var.initializer(), var.type())); - } - catch (SemanticError err) { - // ignore semantic errors + if (isInvalidLHSType(var.type())) { + error(var, "invalid LHS type: " + var.type()); + return; } + check(var.initializer()); + var.setInitializer( + checkRHSType(var.initializer(), var.type())); } } @@ -174,10 +164,6 @@ class TypeChecker extends Visitor { protected void checkAssignment(AbstractAssignNode node) { check(node.lhs()); check(node.rhs()); - if (! node.lhs().isAssignable()) { - error(node, "invalid lhs expression"); - return; - } if (isInvalidLHSType(node.lhs().type())) { error(node, "invalid lhs type"); return; @@ -354,36 +340,31 @@ class TypeChecker extends Visitor { // +, -, !, ~ public void visit(UnaryOpNode node) { - check(node.expr()); + super.visit(node); mustBeInteger(node.expr()); } // ++, -- public void visit(PrefixOpNode node) { - check(node.expr()); + super.visit(node); mustBeScalar(node.expr()); } // ++, -- public void visit(SuffixOpNode node) { - check(node.expr()); + super.visit(node); mustBeScalar(node.expr()); } /** * For EXPR(ARG), checks: * - * * EXPR is callable (a pointer to a function). * * The number of argument matches function prototype. * * ARG matches function prototype. * * ARG is neither a struct nor an union. */ public void visit(FuncallNode node) { - check(node.expr()); - if (! node.expr().isCallable()) { - error(node, "calling object is not a function"); - return; - } + super.visit(node); FunctionType type = node.functionType(); if (! type.acceptsArgc(node.numArgs())) { error(node, "wrong number of argments: " + node.numArgs()); @@ -407,65 +388,13 @@ class TypeChecker extends Visitor { node.replaceArgs(newArgs); } - /** - * Checks if the type of base expression of EXPR[IDX] is valid. - * EXPR must be an array or a pointer. IDX must be an integer. - */ public void visit(ArefNode node) { - check(node.expr()); - if (! node.expr().isDereferable()) { - error(node, "is not indexable: " + node.expr().type()); - return; - } - check(node.index()); + super.visit(node); mustBeInteger(node.index()); } - public void visit(MemberNode node) { - check(node.expr()); - checkMemberRef(node, node.expr().type(), node.member()); - } - - public void visit(PtrMemberNode node) { - check(node.expr()); - if (! node.expr().isDereferable()) { - undereferableError(node, node.expr().type()); - return; - } - checkMemberRef(node, node.dereferedType(), node.member()); - } - - protected void checkMemberRef(Node node, Type t, String memb) { - if (! t.isComplexType()) { - error(node, "is not struct/union: " + t); - return; - } - ComplexType type = t.getComplexType(); - if (! type.hasMember(memb)) { - error(node, type.toString() + " does not have member " + memb); - return; - } - } - - public void visit(DereferenceNode node) { - check(node.expr()); - if (! node.expr().isDereferable()) { - undereferableError(node, node.expr().type()); - return; - } - } - - public void visit(AddressNode node) { - check(node.expr()); - Type t = typeTable.pointerTo(node.expr().type()); - node.setType(t); - if (! node.expr().isAssignable()) { - error(node, "invalid LHS expression for &"); - } - } - public void visit(CastNode node) { - check(node.expr()); + super.visit(node); if (! node.expr().type().isCastableTo(node.type())) { incompatibleTypeError(node, node.expr().type(), node.type()); } diff --git a/net/loveruby/cflat/compiler/TypeResolver.java b/net/loveruby/cflat/compiler/TypeResolver.java index 71760f5..32223f1 100644 --- a/net/loveruby/cflat/compiler/TypeResolver.java +++ b/net/loveruby/cflat/compiler/TypeResolver.java @@ -1,6 +1,7 @@ package net.loveruby.cflat.compiler; import net.loveruby.cflat.ast.*; import net.loveruby.cflat.type.*; +import net.loveruby.cflat.exception.*; import java.util.*; public class TypeResolver extends Visitor { @@ -19,9 +20,9 @@ public class TypeResolver extends Visitor { public void resolveProgram(AST ast) { defineTypes(ast.types()); - resolveNodeList(ast.types()); - resolveNodeList(ast.declarations()); - resolveNodeList(ast.entities()); + visitNodeList(ast.types()); + visitNodeList(ast.declarations()); + visitNodeList(ast.entities()); } private void defineTypes(Iterator deftypes) { @@ -66,9 +67,7 @@ public class TypeResolver extends Visitor { public void visit(DefinedVariable var) { bindType(var.typeNode()); - if (var.isInitialized()) { - resolve(var.initializer()); - } + super.visit(var); // resolve initializer } public void visit(UndefinedVariable var) { @@ -77,8 +76,8 @@ public class TypeResolver extends Visitor { public void visit(DefinedFunction func) { resolveFunctionHeader(func); - resolveLocalVariables(func); - resolve(func.body()); + //resolveLocalVariables(func); + visitNode(func.body()); } public void visit(UndefinedFunction func) { @@ -101,6 +100,20 @@ public class TypeResolver extends Visitor { } } + public void visit(AddressNode node) { + super.visit(node); + // to avoid SemanticError which occurs when getting type of + // expr which is not assignable. + try { + Type t = typeTable.pointerTo(node.expr().type()); + node.setType(t); + } + catch (SemanticError err) { + Type t = typeTable.pointerTo(typeTable.voidType()); + node.setType(t); + } + } + public void visit(CastNode node) { bindType(node.typeNode()); super.visit(node); diff --git a/net/loveruby/cflat/compiler/Visitor.java b/net/loveruby/cflat/compiler/Visitor.java index 03a2b4a..74de803 100644 --- a/net/loveruby/cflat/compiler/Visitor.java +++ b/net/loveruby/cflat/compiler/Visitor.java @@ -6,14 +6,14 @@ abstract public class Visitor implements ASTVisitor { public Visitor() { } - protected void resolve(Node node) { + protected void visitNode(Node node) { node.accept(this); } - protected void resolveNodeList(Iterator ns) { + protected void visitNodeList(Iterator ns) { while (ns.hasNext()) { Node n = (Node)ns.next(); - resolve(n); + visitNode(n); } } @@ -22,6 +22,9 @@ abstract public class Visitor implements ASTVisitor { // public void visit(DefinedVariable var) { + if (var.hasInitializer()) { + visitNode(var.initializer()); + } } public void visit(UndefinedVariable var) { @@ -50,46 +53,44 @@ abstract public class Visitor implements ASTVisitor { Iterator vars = node.variables(); while (vars.hasNext()) { DefinedVariable var = (DefinedVariable)vars.next(); - if (var.hasInitializer()) { - resolve(var.initializer()); - } + visit(var); } - resolveNodeList(node.stmts()); + visitNodeList(node.stmts()); } public void visit(IfNode n) { - resolve(n.cond()); - resolve(n.thenBody()); + visitNode(n.cond()); + visitNode(n.thenBody()); if (n.elseBody() != null) { - resolve(n.elseBody()); + visitNode(n.elseBody()); } } public void visit(SwitchNode n) { - resolve(n.cond()); - resolveNodeList(n.cases()); + visitNode(n.cond()); + visitNodeList(n.cases()); } public void visit(CaseNode n) { - resolveNodeList(n.values()); - resolve(n.body()); + visitNodeList(n.values()); + visitNode(n.body()); } public void visit(WhileNode n) { - resolve(n.cond()); - resolve(n.body()); + visitNode(n.cond()); + visitNode(n.body()); } public void visit(DoWhileNode n) { - resolve(n.body()); - resolve(n.cond()); + visitNode(n.body()); + visitNode(n.cond()); } public void visit(ForNode n) { - resolve(n.init()); - resolve(n.cond()); - resolve(n.incr()); - resolve(n.body()); + visitNode(n.init()); + visitNode(n.cond()); + visitNode(n.incr()); + visitNode(n.body()); } public void visit(BreakNode n) { @@ -102,12 +103,12 @@ abstract public class Visitor implements ASTVisitor { } public void visit(LabelNode n) { - resolve(n.stmt()); + visitNode(n.stmt()); } public void visit(ReturnNode n) { if (n.expr() != null) { - resolve(n.expr()); + visitNode(n.expr()); } } @@ -116,78 +117,78 @@ abstract public class Visitor implements ASTVisitor { // public void visit(CondExprNode n) { - resolve(n.cond()); - resolve(n.thenExpr()); + visitNode(n.cond()); + visitNode(n.thenExpr()); if (n.elseExpr() != null) { - resolve(n.elseExpr()); + visitNode(n.elseExpr()); } } public void visit(LogicalOrNode node) { - resolve(node.left()); - resolve(node.right()); + visitNode(node.left()); + visitNode(node.right()); } public void visit(LogicalAndNode node) { - resolve(node.left()); - resolve(node.right()); + visitNode(node.left()); + visitNode(node.right()); } public void visit(AssignNode n) { - resolve(n.lhs()); - resolve(n.rhs()); + visitNode(n.lhs()); + visitNode(n.rhs()); } public void visit(OpAssignNode n) { - resolve(n.lhs()); - resolve(n.rhs()); + visitNode(n.lhs()); + visitNode(n.rhs()); } public void visit(BinaryOpNode n) { - resolve(n.left()); - resolve(n.right()); + visitNode(n.left()); + visitNode(n.right()); } public void visit(UnaryOpNode node) { - resolve(node.expr()); + visitNode(node.expr()); } public void visit(PrefixOpNode node) { - resolve(node.expr()); + visitNode(node.expr()); } public void visit(SuffixOpNode node) { - resolve(node.expr()); + visitNode(node.expr()); } public void visit(FuncallNode node) { - resolve(node.expr()); - resolveNodeList(node.arguments()); + visitNode(node.expr()); + visitNodeList(node.arguments()); } public void visit(ArefNode node) { - resolve(node.expr()); - resolve(node.index()); + visitNode(node.expr()); + visitNode(node.index()); } public void visit(MemberNode node) { - resolve(node.expr()); + visitNode(node.expr()); } public void visit(PtrMemberNode node) { - resolve(node.expr()); + visitNode(node.expr()); } public void visit(DereferenceNode node) { - resolve(node.expr()); + visitNode(node.expr()); } public void visit(AddressNode node) { - resolve(node.expr()); + visitNode(node.expr()); } public void visit(CastNode node) { - resolve(node.expr()); + visitNode(node.expr()); } public void visit(VariableNode node) {