mirror of https://github.com/aamine/cbc
* 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:
parent
4314a6b35c
commit
6524517b78
37
ChangeLog
37
ChangeLog
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(); }
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue