diff --git a/ChangeLog b/ChangeLog index 700b17b..35d7a59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,84 @@ +Mon May 18 03:01:22 2009 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: change function pointer + syntax: int(*)(int,int) -> int(int,int)*. Function type is + int(int,int). + + * net/loveruby/cflat/parser/Parser.jj: function returns function + type, not pointer to function. + + * net/loveruby/cflat/compiler/TypeResolver.java: resolve all + function headers first, then resolve bodies. + + * net/loveruby/cflat/compiler/TypeResolver.java: generate a + pointer for array-type expression. + + * net/loveruby/cflat/compiler/TypeResolver.java: isDereferable -> + isPointer. + + * net/loveruby/cflat/compiler/TypeChecker.java: ditto. + + * net/loveruby/cflat/compiler/DereferenceChecker.java: ditto. + + * net/loveruby/cflat/compiler/IRGenerator.java: ditto. + + * net/loveruby/cflat/compiler/IRGenerator.java: + shouldEvaluatedToAddress -> isLoadable (check arrays and + functions, not only arrays). + + * net/loveruby/cflat/type/Type.java: remove #isDereferable. + + * net/loveruby/cflat/type/UserType.java: ditto. + + * net/loveruby/cflat/type/ArrayType.java: is not a scalar. + + * net/loveruby/cflat/type/ArrayType.java: is not dereferable + itself. + + * net/loveruby/cflat/type/PointerType.java: is incompatible with + arrays. + + * net/loveruby/cflat/type/IntegerType.java: ditto. + + * net/loveruby/cflat/type/FunctionType.java: is callable. + + * net/loveruby/cflat/type/ParamTypeRefs.java: x[] -> x* for param + types. + + * net/loveruby/cflat/type/TypeTable.java: new method + #getParamType. + + * net/loveruby/cflat/ast/ExprNode.java: new method #isLvalue. + + * net/loveruby/cflat/ast/ExprNode.java: new method #isAssignable. + + * net/loveruby/cflat/ast/ExprNode.java: new method #isLoadable. + + * net/loveruby/cflat/ast/CastNode.java: delegate them. + + * net/loveruby/cflat/ast/LHSNode.java: new super class of LHS + nodes. + + * net/loveruby/cflat/ast/VariableNode.java: ditto. + + * net/loveruby/cflat/ast/DereferenceNode.java: ditto. + + * net/loveruby/cflat/ast/ArefNode.java: ditto. + + * net/loveruby/cflat/ast/MemberNode.java: ditto. + + * net/loveruby/cflat/ast/PtrMemberNode.java: ditto. + + * net/loveruby/cflat/entity/Entity.java: remove #cannotLoad. + + * net/loveruby/cflat/entity/Function.java: ditto. + + * net/loveruby/cflat/entity/Variable.java: ditto. + + * net/loveruby/cflat/entity/Constant.java: ditto. + + * net/loveruby/cflat/ir/Addr.java: is not LHS node now. + Sun May 17 16:37:26 2009 Minero Aoki * import/dlfcn.hb: new declaration file dlfcn.hb. diff --git a/net/loveruby/cflat/ast/ArefNode.java b/net/loveruby/cflat/ast/ArefNode.java index a741d91..282a8f1 100644 --- a/net/loveruby/cflat/ast/ArefNode.java +++ b/net/loveruby/cflat/ast/ArefNode.java @@ -1,35 +1,22 @@ package net.loveruby.cflat.ast; import net.loveruby.cflat.type.*; -public class ArefNode extends ExprNode { - protected ExprNode expr, index; +public class ArefNode extends LHSNode { + private ExprNode expr, index; public ArefNode(ExprNode expr, ExprNode index) { this.expr = expr; this.index = index; } - public Type type() { - return expr.type().baseType(); - } - - public ExprNode expr() { - return expr; - } - - public ExprNode index() { - return index; - } - - public boolean isAssignable() { - return true; - } + public ExprNode expr() { return expr; } + public ExprNode index() { return index; } // isMultiDimension a[x][y][z] = true. // isMultiDimension a[x][y] = true. // isMultiDimension a[x] = false. public boolean isMultiDimension() { - return (expr instanceof ArefNode) && !expr.type().isPointer(); + return (expr instanceof ArefNode) && !expr.origType().isPointer(); } // Returns base expression of (multi-dimension) array. @@ -40,17 +27,19 @@ public class ArefNode extends ExprNode { // element size of this (multi-dimension) array public long elementSize() { - return type().allocSize(); + return origType().allocSize(); } public long length() { - return ((ArrayType)expr.type()).length(); + return ((ArrayType)expr.origType()).length(); } - public boolean isConstantAddress() { - return false; + protected Type origType() { + return expr.origType().baseType(); } + public boolean isConstantAddress() { return false; } + public Location location() { return expr.location(); } diff --git a/net/loveruby/cflat/ast/CastNode.java b/net/loveruby/cflat/ast/CastNode.java index 329a777..f59feac 100644 --- a/net/loveruby/cflat/ast/CastNode.java +++ b/net/loveruby/cflat/ast/CastNode.java @@ -26,9 +26,8 @@ public class CastNode extends ExprNode { return expr; } - public boolean shouldEvaluatedToAddress() { - return expr.shouldEvaluatedToAddress(); - } + public boolean isLvalue() { return expr.isLvalue(); } + public boolean isAssignable() { return expr.isAssignable(); } public boolean isEffectiveCast() { return type().size() > expr.type().size(); diff --git a/net/loveruby/cflat/ast/DereferenceNode.java b/net/loveruby/cflat/ast/DereferenceNode.java index 1891145..2a974e0 100644 --- a/net/loveruby/cflat/ast/DereferenceNode.java +++ b/net/loveruby/cflat/ast/DereferenceNode.java @@ -1,18 +1,35 @@ package net.loveruby.cflat.ast; import net.loveruby.cflat.type.*; -public class DereferenceNode extends UnaryOpNode { - public DereferenceNode(ExprNode n) { - super("*", n); +public class DereferenceNode extends LHSNode { + private ExprNode expr; + + public DereferenceNode(ExprNode expr) { + this.expr = expr; } - public Type type() { - return expr().type().baseType(); + protected Type origType() { + return expr.type().baseType(); + } + + public ExprNode expr() { + return expr; + } + + public void setExpr(ExprNode expr) { + this.expr = expr; } - public boolean isAssignable() { return true; } public boolean isConstantAddress() { return false; } + public Location location() { + return expr.location(); + } + + protected void _dump(Dumper d) { + d.printMember("expr", expr); + } + public E accept(ASTVisitor visitor) { return visitor.visit(this); } diff --git a/net/loveruby/cflat/ast/ExprNode.java b/net/loveruby/cflat/ast/ExprNode.java index 50b94ce..9d72655 100644 --- a/net/loveruby/cflat/ast/ExprNode.java +++ b/net/loveruby/cflat/ast/ExprNode.java @@ -8,10 +8,16 @@ abstract public class ExprNode extends Node { } abstract public Type type(); + protected Type origType() { return type(); } - public boolean isConstant() { - return false; - } + public long allocSize() { return type().allocSize(); } + + public boolean isConstant() { return false; } + public boolean isParameter() { return false; } + + public boolean isLvalue() { return false; } + public boolean isAssignable() { return false; } + public boolean isLoadable() { return false; } public boolean isCallable() { try { @@ -22,10 +28,10 @@ abstract public class ExprNode extends Node { } } - // #@@range/isDereferable{ - public boolean isDereferable() { + // #@@range/isPointer{ + public boolean isPointer() { try { - return type().isDereferable(); + return type().isPointer(); } catch (SemanticError err) { return false; @@ -33,18 +39,6 @@ abstract public class ExprNode extends Node { } // #@@} - public boolean isAssignable() { - return false; - } - - public boolean isParameter() { - return false; - } - - public boolean shouldEvaluatedToAddress() { - return type().isArray(); - } - // used by IRGenerator public boolean isConstantAddress() { return false; diff --git a/net/loveruby/cflat/ast/LHSNode.java b/net/loveruby/cflat/ast/LHSNode.java new file mode 100644 index 0000000..2e9953b --- /dev/null +++ b/net/loveruby/cflat/ast/LHSNode.java @@ -0,0 +1,28 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.Type; + +abstract public class LHSNode extends ExprNode { + protected Type type, origType; + + public Type type() { + return type != null ? type : origType(); + } + + public void setType(Type t) { + this.type = t; + } + + abstract protected Type origType(); + + public long allocSize() { return origType().allocSize(); } + + public boolean isLvalue() { return true; } + public boolean isAssignable() { return isLoadable(); } + + public boolean isLoadable() { + Type t = origType(); + return !t.isArray() && !t.isFunction(); + } + + abstract public boolean isConstantAddress(); +} diff --git a/net/loveruby/cflat/ast/MemberNode.java b/net/loveruby/cflat/ast/MemberNode.java index 4bfcb2d..e6c2cac 100644 --- a/net/loveruby/cflat/ast/MemberNode.java +++ b/net/loveruby/cflat/ast/MemberNode.java @@ -3,19 +3,15 @@ import net.loveruby.cflat.type.Type; import net.loveruby.cflat.type.CompositeType; import net.loveruby.cflat.exception.*; -public class MemberNode extends ExprNode { - protected ExprNode expr; - protected String member; +public class MemberNode extends LHSNode { + private ExprNode expr; + private String member; public MemberNode(ExprNode expr, String member) { this.expr = expr; this.member = member; } - public Type type() { - return baseType().memberType(member); - } - public CompositeType baseType() { try { return expr.type().getCompositeType(); @@ -37,15 +33,11 @@ public class MemberNode extends ExprNode { return baseType().memberOffset(member); } - // #@@range/isAssignable{ - public boolean isAssignable() { - return true; + protected Type origType() { + return baseType().memberType(member); } - // #@@} - public boolean isConstantAddress() { - return false; - } + public boolean isConstantAddress() { return false; } public Location location() { return expr.location(); diff --git a/net/loveruby/cflat/ast/PtrMemberNode.java b/net/loveruby/cflat/ast/PtrMemberNode.java index 1af8ab4..d62d070 100644 --- a/net/loveruby/cflat/ast/PtrMemberNode.java +++ b/net/loveruby/cflat/ast/PtrMemberNode.java @@ -4,7 +4,7 @@ import net.loveruby.cflat.type.CompositeType; import net.loveruby.cflat.type.PointerType; import net.loveruby.cflat.exception.*; -public class PtrMemberNode extends ExprNode { +public class PtrMemberNode extends LHSNode { public ExprNode expr; public String member; @@ -13,10 +13,6 @@ public class PtrMemberNode extends ExprNode { this.member = member; } - public Type type() { - return dereferedCompositeType().memberType(member); - } - public CompositeType dereferedCompositeType() { try { PointerType pt = expr.type().getPointerType(); @@ -45,18 +41,16 @@ public class PtrMemberNode extends ExprNode { return member; } - public boolean isAssignable() { - return true; - } - - public boolean isConstantAddress() { - return false; - } - public long offset() { return dereferedCompositeType().memberOffset(member); } + protected Type origType() { + return dereferedCompositeType().memberType(member); + } + + public boolean isConstantAddress() { return false; } + public Location location() { return expr.location(); } diff --git a/net/loveruby/cflat/ast/TypeNode.java b/net/loveruby/cflat/ast/TypeNode.java index 60f817b..c776ad0 100644 --- a/net/loveruby/cflat/ast/TypeNode.java +++ b/net/loveruby/cflat/ast/TypeNode.java @@ -2,8 +2,8 @@ package net.loveruby.cflat.ast; import net.loveruby.cflat.type.*; public class TypeNode extends Node { - protected TypeRef typeRef; - protected Type type; + TypeRef typeRef; + Type type; public TypeNode(TypeRef ref) { super(); @@ -24,12 +24,16 @@ public class TypeNode extends Node { } public void setType(Type t) { - if (isResolved()) throw new Error("TypeNode#setType called twice"); + if (type != null) { + throw new Error("TypeNode#setType called twice"); + } type = t; } public Type type() { - if (type == null) throw new Error("TypeNode not resolved"); + if (type == null) { + throw new Error("TypeNode not resolved: " + typeRef); + } return type; } diff --git a/net/loveruby/cflat/ast/VariableNode.java b/net/loveruby/cflat/ast/VariableNode.java index f3408e0..14eb39b 100644 --- a/net/loveruby/cflat/ast/VariableNode.java +++ b/net/loveruby/cflat/ast/VariableNode.java @@ -3,13 +3,12 @@ import net.loveruby.cflat.type.Type; import net.loveruby.cflat.entity.Entity; import net.loveruby.cflat.entity.DefinedVariable; -public class VariableNode extends ExprNode { - protected Location location; - protected String name; - protected Entity entity; +public class VariableNode extends LHSNode { + private Location location; + private String name; + private Entity entity; public VariableNode(Location loc, String name) { - super(); this.location = loc; this.name = name; } @@ -38,35 +37,28 @@ public class VariableNode extends ExprNode { entity = ent; } - public Type type() { - return entity().type(); - } - public TypeNode typeNode() { return entity().typeNode(); } - public boolean isAssignable() { - return true; - } - public boolean isParameter() { return entity().isParameter(); } - public boolean shouldEvaluatedToAddress() { - return entity().cannotLoad(); + protected Type origType() { + return entity().type(); } - public boolean isConstantAddress() { - return true; - } + public boolean isConstantAddress() { return true; } public Location location() { return location; } protected void _dump(Dumper d) { + if (type != null) { + d.printMember("type", type); + } d.printMember("name", name, isResolved()); } diff --git a/net/loveruby/cflat/compiler/Compiler.java b/net/loveruby/cflat/compiler/Compiler.java index f691c62..dbd17bc 100644 --- a/net/loveruby/cflat/compiler/Compiler.java +++ b/net/loveruby/cflat/compiler/Compiler.java @@ -129,11 +129,11 @@ public class Compiler { new LocalResolver(errorHandler).resolve(ast); new TypeResolver(errorHandler).resolve(ast, typeTable); typeTable.semanticCheck(errorHandler); - new DereferenceChecker(errorHandler).check(ast); if (opts.mode() == CompilerMode.DumpReference) { ast.dump(); return ast; } + new DereferenceChecker(errorHandler).check(ast); new TypeChecker(errorHandler).check(ast, typeTable); return ast; } diff --git a/net/loveruby/cflat/compiler/DereferenceChecker.java b/net/loveruby/cflat/compiler/DereferenceChecker.java index e8ce3d6..86e1812 100644 --- a/net/loveruby/cflat/compiler/DereferenceChecker.java +++ b/net/loveruby/cflat/compiler/DereferenceChecker.java @@ -100,7 +100,7 @@ class DereferenceChecker extends Visitor { return null; } - protected void checkAssignment(AbstractAssignNode node) { + private void checkAssignment(AbstractAssignNode node) { if (! node.lhs().isAssignable()) { semanticError(node, "invalid lhs expression"); } @@ -136,7 +136,7 @@ class DereferenceChecker extends Visitor { public Void visit(ArefNode node) { super.visit(node); - if (! node.expr().isDereferable()) { + if (! node.expr().isPointer()) { semanticError(node, "indexing non-array/pointer expression"); } return null; @@ -150,7 +150,7 @@ class DereferenceChecker extends Visitor { public Void visit(PtrMemberNode node) { super.visit(node); - if (! node.expr().isDereferable()) { + if (! node.expr().isPointer()) { undereferableError(node); } checkMemberRef(node, node.dereferedType(), node.member()); @@ -172,7 +172,7 @@ class DereferenceChecker extends Visitor { // #@@range/DereferenceNode{ public Void visit(DereferenceNode node) { super.visit(node); - if (! node.expr().isDereferable()) { + if (! node.expr().isPointer()) { undereferableError(node); } return null; @@ -182,8 +182,8 @@ class DereferenceChecker extends Visitor { // #@@range/AddressNode{ public Void visit(AddressNode node) { super.visit(node); - if (! node.expr().isAssignable()) { - semanticError(node, "invalid LHS expression for &"); + if (! node.expr().isLvalue()) { + semanticError(node, "invalid expression for &"); } return null; } @@ -197,6 +197,14 @@ class DereferenceChecker extends Visitor { return null; } + public Void visit(CastNode node) { + super.visit(node); + if (node.type().isArray()) { + semanticError(node, "cast specifies array type"); + } + return null; + } + // // Utilities // diff --git a/net/loveruby/cflat/compiler/IRGenerator.java b/net/loveruby/cflat/compiler/IRGenerator.java index cf366fa..9d98173 100644 --- a/net/loveruby/cflat/compiler/IRGenerator.java +++ b/net/loveruby/cflat/compiler/IRGenerator.java @@ -482,7 +482,7 @@ class IRGenerator implements ASTVisitor { switch (op) { case ADD: case SUB: - if (lhsType.isDereferable()) { + if (lhsType.isPointer()) { return new Bin(rhs.type(), Op.MUL, rhs, ptrDiff(lhsType.baseType().size())); } @@ -565,11 +565,11 @@ class IRGenerator implements ASTVisitor { Expr right = transformExpr(node.right()); Expr left = transformExpr(node.left()); if (node.operator().equals("+") || node.operator().equals("-")) { - if (node.left().type().isDereferable()) { + if (node.left().type().isPointer()) { right = new Bin(ptrDiffType(), Op.MUL, right, ptrDiff(node.left().type().baseType().size())); } - else if (node.right().type().isDereferable()) { + else if (node.right().type().isPointer()) { left = new Bin(ptrDiffType(), Op.MUL, left, ptrDiff(node.right().type().baseType().size())); } @@ -626,9 +626,7 @@ class IRGenerator implements ASTVisitor { Expr addr = new Bin(pointer(), Op.ADD, addressOf(transformExpr(node.expr())), intValue(node.offset())); - return node.shouldEvaluatedToAddress() - ? addr - : deref(addr, node.type()); + return node.isLoadable() ? deref(addr, node.type()) : addr; } // #@@} @@ -636,7 +634,7 @@ class IRGenerator implements ASTVisitor { Expr addr = new Bin(pointer(), Op.ADD, transformExpr(node.expr()), intValue(node.offset())); - return node.shouldEvaluatedToAddress() ? addr : deref(addr, node.type()); + return node.isLoadable() ? deref(addr, node.type()) : addr; } public Expr visit(DereferenceNode node) { @@ -645,12 +643,7 @@ class IRGenerator implements ASTVisitor { public Expr visit(AddressNode node) { Expr e = transformExpr(node.expr()); - if (node.expr().shouldEvaluatedToAddress()) { - return e; - } - else { - return addressOf(e); - } + return node.expr().isLoadable() ? addressOf(e) : e; } public Expr visit(CastNode node) { @@ -669,7 +662,7 @@ class IRGenerator implements ASTVisitor { } public Expr visit(SizeofExprNode node) { - return intValue(node.expr().type().allocSize()); + return intValue(node.expr().allocSize()); } public Expr visit(SizeofTypeNode node) { @@ -681,7 +674,7 @@ class IRGenerator implements ASTVisitor { return transformExpr(node.entity().value()); } Var var = new Var(varType(node.type()), node.entity()); - return node.shouldEvaluatedToAddress() ? addressOf(var) : var; + return node.isLoadable() ? var : addressOf(var); } public Expr visit(IntegerLiteralNode node) { diff --git a/net/loveruby/cflat/compiler/TypeChecker.java b/net/loveruby/cflat/compiler/TypeChecker.java index c4ac44d..31e88b8 100644 --- a/net/loveruby/cflat/compiler/TypeChecker.java +++ b/net/loveruby/cflat/compiler/TypeChecker.java @@ -164,7 +164,7 @@ class TypeChecker extends Visitor { if (! checkLHS(node.lhs())) return null; if (! checkRHS(node.rhs())) return null; if (node.operator().equals("+") || node.operator().equals("-")) { - if (node.lhs().type().isDereferable()) { + if (node.lhs().type().isPointer()) { mustBeInteger(node.rhs(), node.operator()); node.setRHS(integralPromotedExpr(node.rhs())); return null; @@ -290,7 +290,7 @@ class TypeChecker extends Visitor { * * pointer - integer */ protected void expectsSameIntegerOrPointerDiff(BinaryOpNode node) { - if (node.left().type().isDereferable()) { + if (node.left().type().isPointer()) { if (node.left().type().baseType().isVoid()) { wrongTypeError(node.left(), node.operator()); return; @@ -300,7 +300,7 @@ class TypeChecker extends Visitor { node.setRight(integralPromotedExpr(node.right())); node.setType(node.left().type()); } - else if (node.right().type().isDereferable()) { + else if (node.right().type().isPointer()) { if (node.operator().equals("-")) { error(node, "invalid operation integer-pointer"); return; @@ -342,13 +342,13 @@ class TypeChecker extends Visitor { protected void expectsComparableScalars(BinaryOpNode node) { if (! mustBeScalar(node.left(), node.operator())) return; if (! mustBeScalar(node.right(), node.operator())) return; - if (node.left().type().isDereferable()) { + if (node.left().type().isPointer()) { ExprNode right = forcePointerType(node.left(), node.right()); node.setRight(right); node.setType(node.left().type()); return; } - if (node.right().type().isDereferable()) { + if (node.right().type().isPointer()) { ExprNode left = forcePointerType(node.right(), node.left()); node.setLeft(left); node.setType(node.right().type()); @@ -433,7 +433,7 @@ class TypeChecker extends Visitor { } node.setAmount(1); } - else if (node.expr().type().isDereferable()) { + else if (node.expr().type().isPointer()) { if (node.expr().type().baseType().isVoid()) { // We cannot increment/decrement void* wrongTypeError(node.expr(), node.operator()); diff --git a/net/loveruby/cflat/compiler/TypeResolver.java b/net/loveruby/cflat/compiler/TypeResolver.java index 0c27449..3ef868a 100644 --- a/net/loveruby/cflat/compiler/TypeResolver.java +++ b/net/loveruby/cflat/compiler/TypeResolver.java @@ -31,6 +31,18 @@ public class TypeResolver extends Visitor for (Entity e : ast.entities()) { e.accept(this); } + + for (DefinedVariable var : ast.definedVariables()) { + if (var.hasInitializer()) { + visitExpr(var.initializer()); + } + } + for (Constant c : ast.constants()) { + visitExpr(c.value()); + } + for (DefinedFunction f : ast.definedFunctions()) { + visitStmt(f.body()); + } // #@@} } // #@@} @@ -100,9 +112,6 @@ public class TypeResolver extends Visitor // #@@range/DefinedVariable{ public Void visit(DefinedVariable var) { bindType(var.typeNode()); - if (var.hasInitializer()) { - visitExpr(var.initializer()); - } return null; } // #@@} @@ -114,14 +123,12 @@ public class TypeResolver extends Visitor public Void visit(Constant c) { bindType(c.typeNode()); - visitExpr(c.value()); return null; } // #@@range/DefinedFunction{ public Void visit(DefinedFunction func) { resolveFunctionHeader(func); - visitStmt(func.body()); return null; } // #@@} @@ -135,11 +142,8 @@ public class TypeResolver extends Visitor protected void resolveFunctionHeader(Function func) { bindType(func.typeNode()); for (Parameter param : func.parameters()) { - Type t = typeTable.get(param.typeNode().typeRef()); // arrays must be converted to pointers in a function parameter. - if (t.isArray()) { - t = typeTable.pointerTo(t.getArrayType().baseType()); - } + Type t = typeTable.getParamType(param.typeNode().typeRef()); param.typeNode().setType(t); } } @@ -151,7 +155,12 @@ public class TypeResolver extends Visitor public Void visit(BlockNode node) { for (DefinedVariable var : node.variables()) { - var.accept(this); + bindType(var.typeNode()); + } + for (DefinedVariable var : node.variables()) { + if (var.hasInitializer()) { + visitExpr(var.initializer()); + } } visitStmts(node.stmts()); return null; @@ -159,11 +168,10 @@ 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 base = node.expr().type(); - if (node.expr().shouldEvaluatedToAddress()) { + if (! node.expr().isLoadable()) { + // node.expr.type is already pointer. node.setType(base); } else { @@ -177,6 +185,54 @@ public class TypeResolver extends Visitor return null; } + public Void visit(DereferenceNode node) { + super.visit(node); + handleImplicitAddress(node); + return null; + } + + public Void visit(MemberNode node) { + super.visit(node); + handleImplicitAddress(node); + return null; + } + + public Void visit(PtrMemberNode node) { + super.visit(node); + handleImplicitAddress(node); + return null; + } + + public Void visit(ArefNode node) { + super.visit(node); + handleImplicitAddress(node); + return null; + } + + public Void visit(VariableNode node) { + super.visit(node); + handleImplicitAddress(node); + return null; + } + + private void handleImplicitAddress(LHSNode node) { + try { + if (! node.isLoadable()) { + Type t = node.type(); + if (t.isArray()) { + // int[4] ary; ary; should generate int* + node.setType(typeTable.pointerTo(t.baseType())); + } + else { + node.setType(typeTable.pointerTo(t)); + } + } + } + catch (SemanticError err) { + // #isLoadable may cause SemanticError, ignore it + } + } + public Void visit(CastNode node) { bindType(node.typeNode()); super.visit(node); diff --git a/net/loveruby/cflat/entity/Constant.java b/net/loveruby/cflat/entity/Constant.java index 6dcaf10..38ad60c 100644 --- a/net/loveruby/cflat/entity/Constant.java +++ b/net/loveruby/cflat/entity/Constant.java @@ -12,7 +12,7 @@ public class Constant extends Entity { this.value = value; } - public boolean cannotLoad() { return false; } + public boolean isAssignable() { return false; } public boolean isDefined() { return true; } public boolean isInitialized() { return true; } public boolean isConstant() { return true; } diff --git a/net/loveruby/cflat/entity/Entity.java b/net/loveruby/cflat/entity/Entity.java index 431d171..0306020 100644 --- a/net/loveruby/cflat/entity/Entity.java +++ b/net/loveruby/cflat/entity/Entity.java @@ -70,8 +70,6 @@ abstract public class Entity return (nRefered > 0); } - abstract public boolean cannotLoad(); - public void setMemref(MemoryReference mem) { this.memref = mem; } diff --git a/net/loveruby/cflat/entity/Function.java b/net/loveruby/cflat/entity/Function.java index d8630df..c84463a 100644 --- a/net/loveruby/cflat/entity/Function.java +++ b/net/loveruby/cflat/entity/Function.java @@ -14,27 +14,19 @@ abstract public class Function extends Entity { super(priv, t, name); } - public boolean isFunction() { return true; } public boolean isInitialized() { return true; } + abstract public boolean isDefined(); abstract public List parameters(); - public FunctionType functionType() { - return type().getPointerType().baseType().getFunctionType(); - } - public Type returnType() { - return functionType().returnType(); + return type().getFunctionType().returnType(); } public boolean isVoid() { return returnType().isVoid(); } - public boolean cannotLoad() { - return true; - } - public void setCallingSymbol(Symbol sym) { if (this.callingSymbol != null) { throw new Error("must not happen: Function#callingSymbol was set again"); diff --git a/net/loveruby/cflat/entity/Variable.java b/net/loveruby/cflat/entity/Variable.java index c737993..1361ac4 100644 --- a/net/loveruby/cflat/entity/Variable.java +++ b/net/loveruby/cflat/entity/Variable.java @@ -6,8 +6,4 @@ abstract public class Variable extends Entity { public Variable(boolean priv, TypeNode type, String name) { super(priv, type, name); } - - public boolean cannotLoad() { - return type().isArray(); - } } diff --git a/net/loveruby/cflat/ir/Addr.java b/net/loveruby/cflat/ir/Addr.java index f271a2b..043ce90 100644 --- a/net/loveruby/cflat/ir/Addr.java +++ b/net/loveruby/cflat/ir/Addr.java @@ -24,10 +24,6 @@ public class Addr extends Expr { return entity.memref(); } - public Addr addressNode(Type type) { - return this; - } - public Entity getEntityForce() { return entity; } diff --git a/net/loveruby/cflat/parser/Parser.jj b/net/loveruby/cflat/parser/Parser.jj index ef00c55..9b5b1c2 100644 --- a/net/loveruby/cflat/parser/Parser.jj +++ b/net/loveruby/cflat/parser/Parser.jj @@ -536,18 +536,16 @@ Constant defconst(): DefinedFunction defun(): { boolean priv; - TypeRef ref; + TypeRef ret; String n; Params ps; BlockNode body; } { - priv=storage() ref=typeref() n=name() "(" ps=params() ")" body=block() + priv=storage() ret=typeref() n=name() "(" ps=params() ")" body=block() { - ParamTypeRefs paramref = ps.parametersTypeRef(); - TypeNode t = new TypeNode(new PointerTypeRef( - new FunctionTypeRef(ref, paramref))); - return new DefinedFunction(priv, t, n, ps, body); + TypeRef t = new FunctionTypeRef(ret, ps.parametersTypeRef()); + return new DefinedFunction(priv, new TypeNode(t), n, ps, body); } } // #@@} @@ -692,17 +690,15 @@ Slot slot(): // #@@range/funcdecl{ UndefinedFunction funcdecl(): { - TypeRef ref; + TypeRef ret; String n; Params ps; } { - ref=typeref() n=name() "(" ps=params() ")" ";" + ret=typeref() n=name() "(" ps=params() ")" ";" { - ParamTypeRefs paramref = ps.parametersTypeRef(); - TypeNode t = new TypeNode(new PointerTypeRef( - new FunctionTypeRef(ref, paramref))); - return new UndefinedFunction(t, n, ps); + TypeRef t = new FunctionTypeRef(ret, ps.parametersTypeRef()); + return new UndefinedFunction(new TypeNode(t), n, ps); } } // #@@} @@ -749,9 +745,9 @@ TypeRef typeref(): { ref = new PointerTypeRef(ref); } - | "(" "*" ")" "(" params=param_typerefs() ")" + | "(" params=param_typerefs() ")" { - ref = new PointerTypeRef(new FunctionTypeRef(ref, params)); + ref = new FunctionTypeRef(ref, params); } )* { diff --git a/net/loveruby/cflat/type/ArrayType.java b/net/loveruby/cflat/type/ArrayType.java index ddd3660..af64ba1 100644 --- a/net/loveruby/cflat/type/ArrayType.java +++ b/net/loveruby/cflat/type/ArrayType.java @@ -17,8 +17,7 @@ public class ArrayType extends Type { } public boolean isArray() { return true; } - public boolean isDereferable() { return true; } - public boolean isScalar() { return true; } + public boolean isScalar() { return false; } public boolean isSigned() { return false; } public boolean isAllocatedArray() { @@ -66,12 +65,12 @@ public class ArrayType extends Type { public boolean isSameType(Type other) { // length is not important - if (! other.isDereferable()) return false; + if (!other.isPointer() && !other.isArray()) return false; return baseType.isSameType(other.baseType()); } public boolean isCompatible(Type target) { - if (! target.isDereferable()) return false; + if (!target.isPointer() && !target.isArray()) return false; if (target.baseType().isVoid()) { return true; } @@ -80,7 +79,7 @@ public class ArrayType extends Type { } public boolean isCastableTo(Type target) { - return target.isDereferable(); + return target.isPointer() || target.isArray(); } public String toString() { diff --git a/net/loveruby/cflat/type/FunctionType.java b/net/loveruby/cflat/type/FunctionType.java index 73deb61..2d15602 100644 --- a/net/loveruby/cflat/type/FunctionType.java +++ b/net/loveruby/cflat/type/FunctionType.java @@ -12,6 +12,7 @@ public class FunctionType extends Type { } public boolean isFunction() { return true; } + public boolean isCallable() { return true; } public boolean isSameType(Type other) { if (! other.isFunction()) return false; @@ -68,7 +69,7 @@ public class FunctionType extends Type { String sep = ""; StringBuffer buf = new StringBuffer(); buf.append(returnType.toString()); - buf.append(" (*)("); + buf.append("("); for (Type t : paramTypes.types()) { buf.append(sep); buf.append(t.toString()); diff --git a/net/loveruby/cflat/type/IntegerType.java b/net/loveruby/cflat/type/IntegerType.java index fd00636..17bc59a 100644 --- a/net/loveruby/cflat/type/IntegerType.java +++ b/net/loveruby/cflat/type/IntegerType.java @@ -42,7 +42,7 @@ public class IntegerType extends Type { } public boolean isCastableTo(Type target) { - return (target.isInteger() || target.isDereferable()); + return (target.isInteger() || target.isPointer()); } public long size() { diff --git a/net/loveruby/cflat/type/ParamTypeRefs.java b/net/loveruby/cflat/type/ParamTypeRefs.java index 7ebd615..ecb63b4 100644 --- a/net/loveruby/cflat/type/ParamTypeRefs.java +++ b/net/loveruby/cflat/type/ParamTypeRefs.java @@ -19,7 +19,7 @@ public class ParamTypeRefs extends ParamSlots { public ParamTypes internTypes(TypeTable table) { List types = new ArrayList(); for (TypeRef ref : paramDescriptors) { - types.add(table.get(ref)); + types.add(table.getParamType(ref)); } return new ParamTypes(location, types, vararg); } diff --git a/net/loveruby/cflat/type/PointerType.java b/net/loveruby/cflat/type/PointerType.java index 9300b9d..125afb2 100644 --- a/net/loveruby/cflat/type/PointerType.java +++ b/net/loveruby/cflat/type/PointerType.java @@ -12,9 +12,6 @@ public class PointerType extends Type { public boolean isPointer() { return true; } public boolean isScalar() { return true; } public boolean isSigned() { return false; } - // #@@range/isDereferable{ - public boolean isDereferable() { return true; } - // #@@} public boolean isCallable() { return baseType.isFunction(); } public long size() { @@ -31,12 +28,12 @@ public class PointerType extends Type { } public boolean isSameType(Type other) { - if (! other.isDereferable()) return false; + if (!other.isPointer()) return false; return baseType.isSameType(other.baseType()); } public boolean isCompatible(Type other) { - if (! other.isDereferable()) return false; + if (!other.isPointer()) return false; if (baseType.isVoid()) { return true; } @@ -47,7 +44,7 @@ public class PointerType extends Type { } public boolean isCastableTo(Type other) { - return other.isDereferable() || other.isInteger(); + return other.isPointer() || other.isInteger(); } public String toString() { diff --git a/net/loveruby/cflat/type/Type.java b/net/loveruby/cflat/type/Type.java index a91ff19..005eeed 100644 --- a/net/loveruby/cflat/type/Type.java +++ b/net/loveruby/cflat/type/Type.java @@ -24,7 +24,6 @@ public abstract class Type { public boolean isFunction() { return false; } // Ability methods (unary) - public boolean isDereferable() { return false; } public boolean isAllocatedArray() { return false; } public boolean isIncompleteArray() { return false; } public boolean isScalar() { return false; } diff --git a/net/loveruby/cflat/type/TypeTable.java b/net/loveruby/cflat/type/TypeTable.java index 886858e..54ac62a 100644 --- a/net/loveruby/cflat/type/TypeTable.java +++ b/net/loveruby/cflat/type/TypeTable.java @@ -90,6 +90,12 @@ public class TypeTable { return type; } + // array is really a pointer on parameters. + public Type getParamType(TypeRef ref) { + Type t = get(ref); + return t.isArray() ? pointerTo(t.baseType()) : t; + } + public int intSize() { return this.intSize; } diff --git a/net/loveruby/cflat/type/UserType.java b/net/loveruby/cflat/type/UserType.java index 5a94fbe..9028515 100644 --- a/net/loveruby/cflat/type/UserType.java +++ b/net/loveruby/cflat/type/UserType.java @@ -39,7 +39,6 @@ public class UserType extends NamedType { public boolean isUserType() { return true; } public boolean isFunction() { return realType().isFunction(); } - public boolean isDereferable() { return realType().isDereferable(); } public boolean isCallable() { return realType().isCallable(); } public boolean isScalar() { return realType().isScalar(); } diff --git a/test/funcptr.cb b/test/funcptr.cb index d6059db..2a92ee9 100644 --- a/test/funcptr.cb +++ b/test/funcptr.cb @@ -1,11 +1,28 @@ import stdio; int -main(int argc, char **argv) +main(int argc, char** argv) { - int (*)(char*) f; + int (char*, ...)* f; - f = puts; + f = printf; f("OK"); + + f = &printf; + f(";OK"); + + f = myputs; + f(";OK"); + + f = &myputs; + f(";OK"); + + puts(""); return 0; } + +static int +myputs(char *s, ...) +{ + return printf("%s", s); +} diff --git a/test/funcptr2.cb b/test/funcptr2.cb deleted file mode 100644 index 4de8484..0000000 --- a/test/funcptr2.cb +++ /dev/null @@ -1,13 +0,0 @@ -import stdio; - -void myputs(char* str) { puts(str); } - -int -main(int argc, char **argv) -{ - void (*)(char*) f; - - f = myputs; - f("OK"); - return 0; -} diff --git a/test/funcptr3.cb b/test/funcptr3.cb deleted file mode 100644 index d90f951..0000000 --- a/test/funcptr3.cb +++ /dev/null @@ -1,11 +0,0 @@ -import stdio; - -int -main(int argc, char **argv) -{ - int (*)(char*) f; - - f = &puts; - f("OK"); - return 0; -} diff --git a/test/funcptr4.cb b/test/funcptr4.cb deleted file mode 100644 index fece80a..0000000 --- a/test/funcptr4.cb +++ /dev/null @@ -1,13 +0,0 @@ -import stdio; - -void myputs(char* str) { puts(str); } - -int -main(int argc, char **argv) -{ - void (*)(char*) f; - - f = &myputs; - f("OK"); - return 0; -} diff --git a/test/test_cbc.sh b/test/test_cbc.sh index 7e85ad0..e8efaa7 100644 --- a/test/test_cbc.sh +++ b/test/test_cbc.sh @@ -98,7 +98,7 @@ test_10_assign() { assert_out "3;4;3;12;4;1;1;7;5;1;4;e;H;76;75;1;3;6;82;81" ./opassign assert_out "0;1;2;2;3;3;4;5;5" ./inc assert_out "4;3;2;2;1;1;0" ./dec - assert_compile_success textwrite.cb + assert_compile_error textwrite.cb } test_12_if() { @@ -244,10 +244,7 @@ test_25_block() { } test_26_funcptr() { - assert_out "OK" ./funcptr - assert_out "OK" ./funcptr2 - assert_out "OK" ./funcptr3 - assert_out "OK" ./funcptr4 + assert_out "OK;OK;OK;OK" ./funcptr assert_compile_error defun-semcheck.cb assert_compile_error defun-semcheck2.cb assert_compile_error defun-semcheck3.cb diff --git a/test/usertype.cb b/test/usertype.cb index d6af83b..fa4ed9d 100644 --- a/test/usertype.cb +++ b/test/usertype.cb @@ -22,7 +22,7 @@ typedef struct s struct_s; typedef union u union_u; typedef int[8] ints8; typedef int* intptr; -typedef int (*)(char*) msgfunc; +typedef int (char*)* msgfunc; typedef sint sint2; int