diff --git a/ChangeLog b/ChangeLog index e99ae3b..aba93a5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Mon May 18 04:52:25 2009 Minero Aoki + + * net/loveruby/cflat/compiler/TypeChecker.java: allow ptr-ptr. + + * net/loveruby/cflat/compiler/IRGenerator.java: implement ptr-ptr. + + * net/loveruby/cflat/type/VoidType.java: VoidType#size is 1. + + * net/loveruby/cflat/ast/ExprNode.java: new helper method + #baseType. + Mon May 18 03:50:55 2009 Minero Aoki * net/loveruby/cflat/sysdep/x86/CodeGenerator.java (optimize): diff --git a/net/loveruby/cflat/ast/ExprNode.java b/net/loveruby/cflat/ast/ExprNode.java index 9d72655..0fd1da4 100644 --- a/net/loveruby/cflat/ast/ExprNode.java +++ b/net/loveruby/cflat/ast/ExprNode.java @@ -11,6 +11,7 @@ abstract public class ExprNode extends Node { protected Type origType() { return type(); } public long allocSize() { return type().allocSize(); } + public long baseSize() { return type().baseType().size(); } public boolean isConstant() { return false; } public boolean isParameter() { return false; } diff --git a/net/loveruby/cflat/compiler/IRGenerator.java b/net/loveruby/cflat/compiler/IRGenerator.java index e1fa6b6..44cea3f 100644 --- a/net/loveruby/cflat/compiler/IRGenerator.java +++ b/net/loveruby/cflat/compiler/IRGenerator.java @@ -565,13 +565,21 @@ 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().isPointer()) { - right = new Bin(ptrDiffType(), Op.MUL, - right, ptrDiff(node.left().type().baseType().size())); + if (node.left().isPointer() && node.right().isPointer()) { + Expr tmp = new Bin(asmType(node.type()), + Op.internBinary(node.operator(), + node.type().isSigned()), + left, right); + return new Bin(ptrDiffType(), Op.S_DIV, + tmp, ptrDiff(node.left().baseSize())); } - else if (node.right().type().isPointer()) { + else if (node.left().isPointer()) { + right = new Bin(ptrDiffType(), Op.MUL, + right, ptrDiff(node.left().baseSize())); + } + else if (node.right().isPointer()) { left = new Bin(ptrDiffType(), Op.MUL, - left, ptrDiff(node.right().type().baseType().size())); + left, ptrDiff(node.right().baseSize())); } } return new Bin(asmType(node.type()), diff --git a/net/loveruby/cflat/compiler/TypeChecker.java b/net/loveruby/cflat/compiler/TypeChecker.java index 31e88b8..f2843b6 100644 --- a/net/loveruby/cflat/compiler/TypeChecker.java +++ b/net/loveruby/cflat/compiler/TypeChecker.java @@ -288,25 +288,25 @@ class TypeChecker extends Visitor { * * integer + pointer * * integer - integer * * pointer - integer + * * pointer - pointer */ - protected void expectsSameIntegerOrPointerDiff(BinaryOpNode node) { - if (node.left().type().isPointer()) { - if (node.left().type().baseType().isVoid()) { - wrongTypeError(node.left(), node.operator()); + private void expectsSameIntegerOrPointerDiff(BinaryOpNode node) { + if (node.left().isPointer() && node.right().isPointer()) { + if (node.operator().equals("+")) { + error(node, "invalid operation: pointer + pointer"); return; } + node.setType(typeTable.ptrDiffType()); + } + else if (node.left().isPointer()) { mustBeInteger(node.right(), node.operator()); // promote integer for pointer calculation node.setRight(integralPromotedExpr(node.right())); node.setType(node.left().type()); } - else if (node.right().type().isPointer()) { + else if (node.right().isPointer()) { if (node.operator().equals("-")) { - error(node, "invalid operation integer-pointer"); - return; - } - if (node.right().type().baseType().isVoid()) { - wrongTypeError(node.right(), node.operator()); + error(node, "invalid operation: integer - pointer"); return; } mustBeInteger(node.left(), node.operator()); diff --git a/net/loveruby/cflat/type/VoidType.java b/net/loveruby/cflat/type/VoidType.java index eb62135..b67f226 100644 --- a/net/loveruby/cflat/type/VoidType.java +++ b/net/loveruby/cflat/type/VoidType.java @@ -7,7 +7,7 @@ public class VoidType extends Type { public boolean isVoid() { return true; } public long size() { - throw new Error("VoidType#size called"); + return 1; } public boolean equals(Object other) { diff --git a/test/ptrdiff.cb b/test/ptrdiff.cb new file mode 100644 index 0000000..02ab211 --- /dev/null +++ b/test/ptrdiff.cb @@ -0,0 +1,16 @@ +import stdio; + +int +main(int argc, char** argv) +{ + int x, y; + void *p = &x; + void *q = &y; + + printf("%d", q - p); + printf(";%d", q - (p + 1)); + printf(";%d", q - (1 + p)); + printf(";%d", q - (p - 1)); + puts(""); + return 0; +} diff --git a/test/test_cbc.sh b/test/test_cbc.sh index e8efaa7..3c6ba89 100644 --- a/test/test_cbc.sh +++ b/test/test_cbc.sh @@ -209,6 +209,7 @@ test_22_pointer() { assert_out "1;2;3;4;5;6;77;78" ./ptrmemb assert_out "7" ./ptrmemb2 assert_out "OK;OK;OK;OK" ./addressof + assert_out "-4;-5;-5;-3" ./ptrdiff assert_compile_error deref-semcheck1.cb assert_compile_error deref-semcheck2.cb assert_compile_error deref-semcheck3.cb