From 6524517b78e3468e4ec2368cb175147d53887389 Mon Sep 17 00:00:00 2001 From: Minero Aoki Date: Fri, 4 Jan 2008 21:36:54 +0000 Subject: [PATCH] * net/loveruby/cflat/compiler/TypeChecker.java: reject invalid RHS type explicitly. * net/loveruby/cflat/compiler/TypeChecker.java: reject void paramters. * net/loveruby/cflat/compiler/TypeChecker.java: allow all type of arrays for RHS. * net/loveruby/cflat/compiler/CodeGenerator.java (variableNode): generate address for allocated array on RHS. * net/loveruby/cflat/compiler/CodeGenerator.java (ArefNode): expects expr generates pointer by compile(). * net/loveruby/cflat/compiler/CodeGenerator.java (compileLHS/ArefNode): unallocated array is a pointer. * net/loveruby/cflat/type/Type.java: new method #isPointerAlike. * net/loveruby/cflat/type/ArrayType.java: implement it. * net/loveruby/cflat/type/PointerType.java: implement it. * net/loveruby/cflat/asm/Assembler.java: new method #comment, to add comment. * test/array-semcheck2.cb: check assignment to unallocated array. * test/array-semcheck2.cb: check dereference of unallocated array. * test/Makefile: build it. * test/test.sh: run it. git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@3794 1b9489fe-b721-0410-924e-b54b9192deb8 --- ChangeLog | 37 +++++++++ net/loveruby/cflat/asm/Assembler.java | 4 + .../cflat/compiler/CodeGenerator.java | 22 +++--- net/loveruby/cflat/compiler/TypeChecker.java | 77 ++++++++----------- net/loveruby/cflat/type/ArrayType.java | 2 + net/loveruby/cflat/type/PointerType.java | 1 + net/loveruby/cflat/type/Type.java | 2 + test/Makefile | 2 +- test/array-semcheck2.cb | 19 +++++ test/test.sh | 1 + 10 files changed, 108 insertions(+), 59 deletions(-) create mode 100644 test/array-semcheck2.cb diff --git a/ChangeLog b/ChangeLog index b57a1e4..7560adf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,40 @@ +Sat Jan 5 06:36:44 2008 Minero Aoki + + * net/loveruby/cflat/compiler/TypeChecker.java: reject invalid RHS + type explicitly. + + * net/loveruby/cflat/compiler/TypeChecker.java: reject void + paramters. + + * net/loveruby/cflat/compiler/TypeChecker.java: allow all type of + arrays for RHS. + + * net/loveruby/cflat/compiler/CodeGenerator.java (variableNode): + generate address for allocated array on RHS. + + * net/loveruby/cflat/compiler/CodeGenerator.java (ArefNode): + expects expr generates pointer by compile(). + + * net/loveruby/cflat/compiler/CodeGenerator.java + (compileLHS/ArefNode): unallocated array is a pointer. + + * net/loveruby/cflat/type/Type.java: new method #isPointerAlike. + + * net/loveruby/cflat/type/ArrayType.java: implement it. + + * net/loveruby/cflat/type/PointerType.java: implement it. + + * net/loveruby/cflat/asm/Assembler.java: new method #comment, to + add comment. + + * test/array-semcheck2.cb: check assignment to unallocated array. + + * test/array-semcheck2.cb: check dereference of unallocated array. + + * test/Makefile: build it. + + * test/test.sh: run it. + Sat Jan 5 04:27:29 2008 Minero Aoki * test/test.sh: new function assert_compile_error to check if diff --git a/net/loveruby/cflat/asm/Assembler.java b/net/loveruby/cflat/asm/Assembler.java index 99be20d..0c6d3e1 100644 --- a/net/loveruby/cflat/asm/Assembler.java +++ b/net/loveruby/cflat/asm/Assembler.java @@ -44,6 +44,10 @@ public class Assembler { list.add("\t" + op + "\t" + arg1 + ", " + arg2 + ", " + arg3); } + public void comment(String str) { + list.add("\t# " + str); + } + public void line(String str) { list.add(str); } diff --git a/net/loveruby/cflat/compiler/CodeGenerator.java b/net/loveruby/cflat/compiler/CodeGenerator.java index 6c92a86..acecdc2 100644 --- a/net/loveruby/cflat/compiler/CodeGenerator.java +++ b/net/loveruby/cflat/compiler/CodeGenerator.java @@ -361,7 +361,7 @@ static public void p(String s) { System.err.println(s); } } public void visit(VariableNode node) { - if (node.type().isArray()) { + if (node.type().isAllocatedArray()) { as.leaq(node.address(), reg("ax")); } else { @@ -372,22 +372,18 @@ static public void p(String s) { System.err.println(s); } static final String PTRREG = "bx"; public void visit(ArefNode node) { - if (node.expr().type().isArray()) { - compileLHS(node.expr()); - as.pushq(reg(PTRREG)); - } - else if (node.expr().type().isPointer()) { + if (node.expr().type().isPointerAlike()) { compile(node.expr()); as.pushq(reg("ax")); } else { - throw new Error("aref expr is not an array/a pointer"); + compileLHS(node.expr()); + as.pushq(reg(PTRREG)); } compile(node.index()); - as.movq(reg("ax"), reg("cx")); - as.imulq(imm(node.type().size()), reg("cx")); + as.imulq(imm(node.type().size()), reg("ax")); as.popq(reg(PTRREG)); - as.addq(reg("cx"), reg(PTRREG)); + as.addq(reg("ax"), reg(PTRREG)); loadWords(node.type(), addr(PTRREG), "ax"); } @@ -429,6 +425,7 @@ static public void p(String s) { System.err.println(s); } } protected void compileLHS(Node node) { +as.comment("compileLHS: " + node.getClass().getName() + " {"); if (node instanceof VariableNode) { // FIXME: support static variables VariableNode n = (VariableNode)node; @@ -438,9 +435,9 @@ static public void p(String s) { System.err.println(s); } ArefNode n = (ArefNode)node; as.pushq(reg("ax")); compile(n.index()); - as.imulq(imm(n.type().size()), reg("ax")); // unsigned? + as.imulq(imm(n.type().size()), reg("ax")); as.pushq(reg("ax")); - if (n.expr().type().isPointer()) { + if (n.expr().type().isPointerAlike()) { compile(n.expr()); as.movq(reg("ax"), reg(PTRREG)); } @@ -487,6 +484,7 @@ static public void p(String s) { System.err.println(s); } else { throw new Error("wrong type for compileLHS"); } +as.comment("compileLHS: }"); } protected void opAssignInit(AbstractAssignNode node) { diff --git a/net/loveruby/cflat/compiler/TypeChecker.java b/net/loveruby/cflat/compiler/TypeChecker.java index 2a1598b..3ea3a6e 100644 --- a/net/loveruby/cflat/compiler/TypeChecker.java +++ b/net/loveruby/cflat/compiler/TypeChecker.java @@ -41,14 +41,9 @@ class TypeChecker extends Visitor { } protected void checkReturnType(DefinedFunction f) { - if (f.returnType().isArray()) { - errorHandler.error("returns an array: " + f.name()); - } - else if (f.returnType().isStruct()) { - errorHandler.error("returns a struct: " + f.name()); - } - else if (f.returnType().isUnion()) { - errorHandler.error("returns a union: " + f.name()); + if (isInvalidReturnType(f.returnType())) { + errorHandler.error("returns invalid type: " + f.returnType()); + return; } } @@ -56,7 +51,7 @@ class TypeChecker extends Visitor { Iterator params = f.parameters(); while (params.hasNext()) { Parameter param = (Parameter)params.next(); - if (isInvalidArgType(param.type())) { + if (isInvalidParameterType(param.type())) { errorHandler.error("invalid parameter type: " + param.type()); } } @@ -88,7 +83,7 @@ class TypeChecker extends Visitor { if (var.hasInitializer()) { try { if (isInvalidLHSType(var.type())) { - errorHandler.error("invalid lhs type"); + errorHandler.error("invalid LHS type: " + var.type()); return; } check(var.initializer()); @@ -101,10 +96,6 @@ class TypeChecker extends Visitor { } } - protected boolean isInvalidVariableType(Type t) { - return t.isVoid(); - } - // // Statement Nodes // @@ -229,13 +220,12 @@ class TypeChecker extends Visitor { node.setRHS(checkRHSType(node.rhs(), node.lhs().type())); } - protected boolean isInvalidLHSType(Type type) { - return type.isStruct() || type.isUnion() - || type.isArray() || type.isVoid(); - } - protected ExprNode checkRHSType(ExprNode rhs, Type l) { Type r = rhs.type(); + if (isInvalidRHSType(r)) { + errorHandler.error("invalid rhs type: " + r); + return rhs; + } if (l.isSameType(r)) { return rhs; } @@ -251,6 +241,27 @@ class TypeChecker extends Visitor { } } + protected boolean isInvalidReturnType(Type t) { + return t.isStruct() || t.isUnion() || t.isArray(); + } + + protected boolean isInvalidParameterType(Type t) { + return isInvalidLHSType(t); + } + + protected boolean isInvalidVariableType(Type t) { + return t.isVoid(); + } + + protected boolean isInvalidLHSType(Type t) { + return t.isStruct() || t.isUnion() + || t.isAllocatedArray() || t.isVoid(); + } + + protected boolean isInvalidRHSType(Type t) { + return t.isStruct() || t.isUnion() || t.isVoid(); + } + // // Condition Expression Node // @@ -481,7 +492,7 @@ class TypeChecker extends Visitor { Type param = (Type)params.next(); ExprNode arg = (ExprNode)args.next(); check(arg); - newArgs.add(checkArgType(arg, param)); + newArgs.add(checkRHSType(arg, param)); } while (args.hasNext()) { ExprNode arg = (ExprNode)args.next(); @@ -491,32 +502,6 @@ class TypeChecker extends Visitor { node.replaceArgs(newArgs); } - /** Checks argument type and insert implicit cast if needed. */ - protected ExprNode checkArgType(ExprNode arg, Type param) { - if (isInvalidArgType(arg.type())) { - errorHandler.error("invalid argument type: " + arg.type()); - return arg; - } - if (arg.type().isSameType(param)) { - return arg; - } - else if (arg.type().isCompatible(param)) { - return newCastNode(param, arg); - } - else { - incompatibleTypeError(arg.type(), param); - return arg; - } - } - - /** - * Return true if the type t is invalid for function argument. - */ - protected boolean isInvalidArgType(Type t) { - return t.isStruct() || t.isUnion() - || t.isAllocatedArray() || t.isVoid(); - } - /** * 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. diff --git a/net/loveruby/cflat/type/ArrayType.java b/net/loveruby/cflat/type/ArrayType.java index d954c9a..0dd4d78 100644 --- a/net/loveruby/cflat/type/ArrayType.java +++ b/net/loveruby/cflat/type/ArrayType.java @@ -18,7 +18,9 @@ public class ArrayType extends Type { public boolean isArray() { return true; } public boolean isAllocated() { return length != undefined; } public boolean isAllocatedArray() { return isAllocated(); } + public boolean isUnallocatedArray() { return !isAllocated(); } public boolean isDereferable() { return true; } + public boolean isPointerAlike() { return isUnallocatedArray(); } public Type baseType() { return baseType; diff --git a/net/loveruby/cflat/type/PointerType.java b/net/loveruby/cflat/type/PointerType.java index ae14d51..da4136a 100644 --- a/net/loveruby/cflat/type/PointerType.java +++ b/net/loveruby/cflat/type/PointerType.java @@ -10,6 +10,7 @@ public class PointerType extends Type { } public boolean isPointer() { return true; } + public boolean isPointerAlike() { return true; } public boolean isDereferable() { return true; } public boolean isCallable() { return baseType.isFunction(); } diff --git a/net/loveruby/cflat/type/Type.java b/net/loveruby/cflat/type/Type.java index c5144d9..77ba65e 100644 --- a/net/loveruby/cflat/type/Type.java +++ b/net/loveruby/cflat/type/Type.java @@ -21,6 +21,7 @@ public abstract class Type { public boolean isPointer() { return false; } public boolean isArray() { return false; } public boolean isAllocatedArray() { return false; } + public boolean isUnallocatedArray() { return false; } public boolean isStruct() { return false; } public boolean isUnion() { return false; } public boolean isComplexType() { return false; } @@ -29,6 +30,7 @@ public abstract class Type { // Ability methods (unary) public boolean isDereferable() { return false; } + public boolean isPointerAlike() { return false; } public boolean isCallable() { return false; } // Ability methods (binary) diff --git a/test/Makefile b/test/Makefile index d946f4f..a7a1727 100644 --- a/test/Makefile +++ b/test/Makefile @@ -17,7 +17,7 @@ CBPROGS = zero one hello hello2 hello3 hello4 integer string \ charops shortops intops longops \ ucharops ushortops uintops ulongops \ block cast defvar mbc assoc \ - pointer-semcheck1 \ + pointer-semcheck1 array-semcheck2 \ ANT = jant diff --git a/test/array-semcheck2.cb b/test/array-semcheck2.cb new file mode 100644 index 0000000..8ea9a02 --- /dev/null +++ b/test/array-semcheck2.cb @@ -0,0 +1,19 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int[1] a; + a[0] = 0; + f(a); + return 0; +} + +void +f(int[] x) +{ + int save = *x; + int i = 0; + x = &i; + printf("%d;%d;%d\n", save, x[0], *x); +} diff --git a/test/test.sh b/test/test.sh index f511553..fc55597 100755 --- a/test/test.sh +++ b/test/test.sh @@ -136,6 +136,7 @@ assert_compile_error continue-semcheck.cb assert_out "1;5;9" ./array assert_compile_error aref-semcheck.cb assert_compile_error array-semcheck1.cb +assert_out "0;0;0" ./array-semcheck2 assert_out "11;22" ./struct assert_status 0 ./struct-semcheck