* 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
This commit is contained in:
Minero Aoki 2008-01-04 21:36:54 +00:00
parent 4314a6b35c
commit 6524517b78
10 changed files with 108 additions and 59 deletions

View File

@ -1,3 +1,40 @@
Sat Jan 5 06:36:44 2008 Minero Aoki <aamine@loveruby.net>
* 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 <aamine@loveruby.net>
* test/test.sh: new function assert_compile_error to check if

View File

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

View File

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

View File

@ -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.

View File

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

View File

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

View File

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

View File

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

19
test/array-semcheck2.cb Normal file
View File

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

View File

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