* net/loveruby/cflat/compiler/TypeChecker.java: check return type.

* net/loveruby/cflat/compiler/JumpResolver.java: set exiting function to ReturnNode.
* net/loveruby/cflat/ast/ReturnNode.java: new method #setExpr.
* net/loveruby/cflat/ast/ReturnNode.java: new method #function.
* net/loveruby/cflat/ast/ReturnNode.java: new method #setFunction.
* net/loveruby/cflat/ast/Function.java: new method #isVoid.
* net/loveruby/cflat/ast/Function.java: new method #returnType.
* net/loveruby/cflat/ast/Function.java: new method #functionType.
* net/loveruby/cflat/type/TypeRef.java: new method #getPointerTypeRef.
* net/loveruby/cflat/type/TypeRef.java: new method #getArrayTypeRef.
* net/loveruby/cflat/type/TypeRef.java: new method #getStructTypeRef.
* net/loveruby/cflat/type/TypeRef.java: new method #getUnionTypeRef.
* net/loveruby/cflat/type/TypeRef.java: new method #getFunctionTypeRef.
* net/loveruby/cflat/type/TypeRef.java: #isFunctionType -> #isFunction.
* net/loveruby/cflat/type/FunctionTypeRef.java: ditto.
* net/loveruby/cflat/type/TypeRef.java: #isVoidTypeRef -> #isVoid.
* net/loveruby/cflat/type/VoidTypeRef.java: ditto.
* net/loveruby/cflat/type/TypeRef.java: #isArrayTypeRef -> #isArray.
* net/loveruby/cflat/type/ArrayTypeRef.java: ditto.
* net/loveruby/cflat/type/Type.java: #isNumeric removed.
* net/loveruby/cflat/type/IntegerType.java: ditto.
* net/loveruby/cflat/type/Type.java: new method #getComplexType.
* net/loveruby/cflat/type/Type.java: new method #getStructType.
* net/loveruby/cflat/type/Type.java: new method #getUnionType.
* net/loveruby/cflat/type/Type.java: new method #getArrayType.
* net/loveruby/cflat/type/Type.java: new method #getPointerType.
* net/loveruby/cflat/type/Type.java: new method #getFunctionType.
* net/loveruby/cflat/type/UserType.java: override them.
* net/loveruby/cflat/type/PointerType.java (equals): reduce instanceof.
* net/loveruby/cflat/type/TypeTable.java: reduce instanceof/cast.
* test/test.sh: invoke following tests.
* test/defun-semcheck2.cb: test returning value from void function.
* test/defun-semcheck3.cb: test returning nothing from non-void function.
* test/defun-semcheck4.cb: test returning struct.
* test/defun-semcheck5.cb: test returning union.
* test/defun-semcheck6.cb: test returning user type, which is union.
* test/defun-semcheck7.cb: test returning user type, which is struct.
* test/defun-semcheck8.cb: test returning array.


git-svn-id: file:///Users/aamine/c/gitwork/public/cbc/trunk@3771 1b9489fe-b721-0410-924e-b54b9192deb8
This commit is contained in:
Minero Aoki 2008-01-02 10:18:38 +00:00
parent 46109b45b1
commit c2298ffbd2
23 changed files with 243 additions and 42 deletions

View File

@ -1,3 +1,94 @@
Wed Jan 2 19:18:29 2008 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/compiler/TypeChecker.java: check return type.
* net/loveruby/cflat/compiler/JumpResolver.java: set exiting
function to ReturnNode.
* net/loveruby/cflat/ast/ReturnNode.java: new method #setExpr.
* net/loveruby/cflat/ast/ReturnNode.java: new method #function.
* net/loveruby/cflat/ast/ReturnNode.java: new method #setFunction.
* net/loveruby/cflat/ast/Function.java: new method #isVoid.
* net/loveruby/cflat/ast/Function.java: new method #returnType.
* net/loveruby/cflat/ast/Function.java: new method #functionType.
* net/loveruby/cflat/type/TypeRef.java: new method
#getPointerTypeRef.
* net/loveruby/cflat/type/TypeRef.java: new method
#getArrayTypeRef.
* net/loveruby/cflat/type/TypeRef.java: new method
#getStructTypeRef.
* net/loveruby/cflat/type/TypeRef.java: new method
#getUnionTypeRef.
* net/loveruby/cflat/type/TypeRef.java: new method
#getFunctionTypeRef.
* net/loveruby/cflat/type/TypeRef.java: #isFunctionType ->
#isFunction.
* net/loveruby/cflat/type/FunctionTypeRef.java: ditto.
* net/loveruby/cflat/type/TypeRef.java: #isVoidTypeRef -> #isVoid.
* net/loveruby/cflat/type/VoidTypeRef.java: ditto.
* net/loveruby/cflat/type/TypeRef.java: #isArrayTypeRef ->
#isArray.
* net/loveruby/cflat/type/ArrayTypeRef.java: ditto.
* net/loveruby/cflat/type/Type.java: #isNumeric removed.
* net/loveruby/cflat/type/IntegerType.java: ditto.
* net/loveruby/cflat/type/Type.java: new method #getComplexType.
* net/loveruby/cflat/type/Type.java: new method #getStructType.
* net/loveruby/cflat/type/Type.java: new method #getUnionType.
* net/loveruby/cflat/type/Type.java: new method #getArrayType.
* net/loveruby/cflat/type/Type.java: new method #getPointerType.
* net/loveruby/cflat/type/Type.java: new method #getFunctionType.
* net/loveruby/cflat/type/UserType.java: override them.
* net/loveruby/cflat/type/PointerType.java (equals): reduce
instanceof.
* net/loveruby/cflat/type/TypeTable.java: reduce instanceof/cast.
* test/test.sh: invoke following tests.
* test/defun-semcheck2.cb: test returning value from void
function.
* test/defun-semcheck3.cb: test returning nothing from non-void
function.
* test/defun-semcheck4.cb: test returning struct.
* test/defun-semcheck5.cb: test returning union.
* test/defun-semcheck6.cb: test returning user type, which is
union.
* test/defun-semcheck7.cb: test returning user type, which is
struct.
* test/defun-semcheck8.cb: test returning array.
Wed Jan 2 04:03:10 2008 Minero Aoki <aamine@loveruby.net>
* net/loveruby/cflat/compiler/TypeChecker.java: allow ptr + int,

5
ToDo
View File

@ -139,7 +139,7 @@
* their combination
- bare block ({...})
- cast
- semantic check (control)
* semantic check (control)
- reject break from out of loop/switch
- reject continue from out of loop
* reject no return
@ -165,8 +165,9 @@
- validate struct/union member (ct->memb)
- check duplicated struct/union members
- ptr + int; ptr - int
* check return type
- check return type
* check if assignable
* use user type instead of struct/union
- op for various types
- signed char
- signed short

View File

@ -13,4 +13,16 @@ abstract public class Function extends Entity {
abstract public boolean isDefined();
abstract public Iterator parameters();
abstract public AsmEntity address();
public FunctionType functionType() {
return type().getPointerType().base().getFunctionType();
}
public Type returnType() {
return functionType().returnType();
}
public boolean isVoid() {
return returnType().isVoid();
}
}

View File

@ -2,6 +2,7 @@ package net.loveruby.cflat.ast;
public class ReturnNode extends Node {
Node expr;
Function function;
public ReturnNode(Node e) {
super();
@ -13,6 +14,22 @@ public class ReturnNode extends Node {
}
public Node expr() {
return expr;
return this.expr;
}
public void setExpr(Node expr) {
this.expr = expr;
}
public void setFunction(Function f) {
if (this.function != null)
throw new Error("setFunction called twice");
this.function = f;
}
public Function function() {
if (this.function == null)
throw new Error("ReturnNode#function called before setFunction");
return this.function;
}
}

View File

@ -10,13 +10,13 @@ public class JumpResolver extends Visitor {
new JumpResolver(h).resolveAST(ast);
}
protected ErrorHandler handler;
protected ErrorHandler errorHandler;
protected LinkedList breakTargetStack;
protected LinkedList continueTargetStack;
protected DefinedFunction currentFunction;
public JumpResolver(ErrorHandler h) {
handler = h;
errorHandler = h;
}
public void resolveAST(AST ast) throws SemanticException {
@ -26,9 +26,9 @@ public class JumpResolver extends Visitor {
while (funcs.hasNext()) {
currentFunction = (DefinedFunction)funcs.next();
resolve(currentFunction.body());
currentFunction.checkJumpLinks(handler);
currentFunction.checkJumpLinks(errorHandler);
}
if (handler.errorOccured()) {
if (errorHandler.errorOccured()) {
throw new SemanticException("semantic error");
}
}
@ -90,7 +90,7 @@ public class JumpResolver extends Visitor {
node.setTargetLabel(currentBreakTarget().endLabel());
}
catch (SemanticException ex) {
handler.error(ex.getMessage());
errorHandler.error(ex.getMessage());
}
}
@ -99,7 +99,7 @@ public class JumpResolver extends Visitor {
node.setTargetLabel(currentContinueTarget().continueLabel());
}
catch (SemanticException ex) {
handler.error(ex.getMessage());
errorHandler.error(ex.getMessage());
}
}
@ -109,11 +109,15 @@ public class JumpResolver extends Visitor {
node.setLabel(label);
}
catch (SemanticException ex) {
handler.error(ex.getMessage());
errorHandler.error(ex.getMessage());
}
}
public void visit(GotoNode node) {
node.setTargetLabel(currentFunction.referLabel(node.target()));
}
public void visit(ReturnNode node) {
node.setFunction(currentFunction);
}
}

View File

@ -22,10 +22,23 @@ class TypeChecker extends Visitor {
Iterator funcs = ast.functions();
while (funcs.hasNext()) {
DefinedFunction f = (DefinedFunction)funcs.next();
checkReturnType(f);
resolve(f.body());
}
if (errorHandler.errorOccured()) {
throw new SemanticException("compile error");
throw new SemanticException("compile failed.");
}
}
protected void checkReturnType(Function 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());
}
}
@ -130,7 +143,33 @@ class TypeChecker extends Visitor {
public void visit(ReturnNode node) {
super.visit(node);
// FIXME: check return type
if (node.function().isVoid()) {
if (node.expr() != null) {
errorHandler.error("returning value from void function");
}
}
else { // non-void function
if (node.expr() == null) {
errorHandler.error("missing return value");
return;
}
insertImplicitCast(node);
}
}
protected void insertImplicitCast(ReturnNode node) {
Type exprType = node.expr().type();
Type retType = node.function().returnType();
if (exprType.equals(retType)) { // type matches
return;
}
else if (exprType.isCompatible(retType)) {
node.setExpr(newCastNode(retType, node.expr()));
}
else {
errorHandler.error("returning incompatible value: "
+ exprType.textize());
}
}
//

View File

@ -6,16 +6,17 @@ public class ArrayTypeRef extends TypeRef {
static final protected long undefined = -1;
public ArrayTypeRef(TypeRef base) {
this(base, undefined);
this.base = base;
this.length = undefined;
}
public ArrayTypeRef(TypeRef ref, long len) {
if (len < 0) throw new Error("negative array length");
base = ref;
length = len;
public ArrayTypeRef(TypeRef base, long length) {
if (length < 0) throw new Error("negative array length");
this.base = base;
this.length = length;
}
public boolean isArrayTypeRef() {
public boolean isArray() {
return true;
}

View File

@ -11,7 +11,7 @@ public class FunctionTypeRef extends TypeRef {
this.params = params;
}
public boolean isFunctionTypeRef() {
public boolean isFunction() {
return true;
}

View File

@ -19,10 +19,6 @@ public class IntegerType extends Type {
return true;
}
public boolean isNumeric() {
return true;
}
public boolean isSigned() {
return signed;
}

View File

@ -29,18 +29,15 @@ public class PointerType extends Type {
return true;
}
public boolean isNumeric() {
return true;
}
public boolean isPointer() {
return true;
}
public boolean equals(Object other) {
if (! (other instanceof PointerType)) return false;
PointerType otherptr = (PointerType)other;
return this.base.equals(otherptr.base());
if (! (other instanceof Type)) return false;
Type t = (Type)other;
if (! t.isPointer()) return false;
return this.base.equals(t.getPointerType().base());
}
public String textize() {

View File

@ -14,7 +14,6 @@ public abstract class Type {
public boolean isInteger() { return false; }
public boolean isSigned()
{ throw new Error("#isSigned for non-integer type"); }
public boolean isNumeric() { return false; }
public boolean isPointer() { return false; }
public boolean isArray() { return false; }
public boolean isStruct() { return false; }
@ -29,4 +28,11 @@ public abstract class Type {
public boolean isIndexable() { return false; }
public abstract String textize();
public PointerType getPointerType() { return (PointerType)this; }
public FunctionType getFunctionType() { return (FunctionType)this; }
public StructType getStructType() { return (StructType)this; }
public UnionType getUnionType() { return (UnionType)this; }
public ComplexType getComplexType() { return (ComplexType)this; }
public ArrayType getArrayType() { return (ArrayType)this; }
}

View File

@ -1,6 +1,7 @@
package net.loveruby.cflat.type;
public abstract class TypeRef {
public boolean isVoid() { return false; }
public boolean isSignedChar() { return false; }
public boolean isSignedShort() { return false; }
public boolean isSignedInt() { return false; }
@ -14,5 +15,11 @@ public abstract class TypeRef {
public boolean isStruct() { return false; }
public boolean isUnion() { return false; }
public boolean isUserType() { return false; }
public boolean isFunctionType() { return false; }
public boolean isFunction() { return false; }
public PointerTypeRef getPointerTypeRef() { return (PointerTypeRef)this; }
public ArrayTypeRef getArrayTypeRef() { return (ArrayTypeRef)this; }
public StructTypeRef getStructTypeRef() { return (StructTypeRef)this; }
public UnionTypeRef getUnionTypeRef() { return (UnionTypeRef)this; }
public FunctionTypeRef getFunctionTypeRef() { return (FunctionTypeRef)this;}
}

View File

@ -55,20 +55,20 @@ public class TypeTable {
public Type get(TypeRef ref) {
Type type = (Type)table.get(ref);
if (type == null) {
if (ref instanceof PointerTypeRef) {
PointerTypeRef pref = (PointerTypeRef)ref;
if (ref.isPointer()) {
PointerTypeRef pref = ref.getPointerTypeRef();
Type t = new PointerType(pointerSize, get(pref.base()));
table.put(pref, t);
return t;
}
else if (ref instanceof ArrayTypeRef) {
ArrayTypeRef aref = (ArrayTypeRef)ref;
else if (ref.isArray()) {
ArrayTypeRef aref = ref.getArrayTypeRef();
Type t = new ArrayType(get(aref.base()), aref.length());
table.put(aref, t);
return t;
}
else if (ref instanceof FunctionTypeRef) {
FunctionTypeRef fref = (FunctionTypeRef)ref;
else if (ref.isFunction()) {
FunctionTypeRef fref = ref.getFunctionTypeRef();
Type t = new FunctionType(get(fref.returnType()),
fref.params().internTypes(this));
table.put(fref, t);
@ -138,6 +138,9 @@ public class TypeTable {
public void semanticCheck(ErrorHandler errorHandler) {
Iterator types = table.values().iterator();
while (types.hasNext()) {
// We should check true ComplexType.
// We do not need to check UserType because refered
// ComplexType must be kept in this table.
Type t = (Type)types.next();
if (t instanceof ComplexType) {
checkDuplicatedMembers((ComplexType)t, errorHandler);
@ -176,8 +179,8 @@ public class TypeTable {
Iterator membs = t.members();
while (membs.hasNext()) {
Slot slot = (Slot)membs.next();
if (slot.type() instanceof ComplexType) {
checkRecursiveDefinition((ComplexType)slot.type(),
if (slot.type().isComplexType()) {
checkRecursiveDefinition(slot.type().getComplexType(),
seen, errorHandler);
}
}

View File

@ -31,11 +31,18 @@ public class UserType extends Type {
public boolean isReferable() { return real().isReferable(); }
public boolean isInt() { return real().isInt(); }
public boolean isInteger() { return real().isInteger(); }
public boolean isNumeric() { return real().isNumeric(); }
public boolean isPointer() { return real().isPointer(); }
public boolean isArray() { return real().isArray(); }
public boolean isComplexType() { return real().isComplexType(); }
public boolean isStruct() { return real().isStruct(); }
public boolean isUnion() { return real().isUnion(); }
public boolean isUserType() { return true; }
public boolean isFunction() { return real().isFunction(); }
public ComplexType getComplexType() { return real().getComplexType(); }
public StructType getStructType() { return real().getStructType(); }
public UnionType getUnionType() { return real().getUnionType(); }
public ArrayType getArrayType() { return real().getArrayType(); }
public PointerType getPointerType() { return real().getPointerType(); }
public FunctionType getFunctionType() { return real().getFunctionType(); }
}

View File

@ -4,7 +4,7 @@ public class VoidTypeRef extends TypeRef {
public VoidTypeRef() {
}
public boolean isVoidTypeRef() {
public boolean isVoid() {
return true;
}

1
test/defun-semcheck2.cb Normal file
View File

@ -0,0 +1 @@
void f(void) { return 1; }

1
test/defun-semcheck3.cb Normal file
View File

@ -0,0 +1 @@
int f(void) { return; }

2
test/defun-semcheck4.cb Normal file
View File

@ -0,0 +1,2 @@
struct st { int x; };
struct st f(void) { return; }

2
test/defun-semcheck5.cb Normal file
View File

@ -0,0 +1,2 @@
union u { int x; };
union u f(void) { return 1; }

3
test/defun-semcheck6.cb Normal file
View File

@ -0,0 +1,3 @@
union u { int x; };
typedef union u mytype;
mytype g(void) { return 1; }

3
test/defun-semcheck7.cb Normal file
View File

@ -0,0 +1,3 @@
struct s { int x; };
typedef struct s mytype;
mytype f(void) { return 1; }

1
test/defun-semcheck8.cb Normal file
View File

@ -0,0 +1 @@
int[2] f(void) { return 1; }

View File

@ -156,6 +156,13 @@ assert_out "1;2;3" ./defvar
assert_out "OK" ./funcptr
assert_error $CBC defun-semcheck.cb
assert_error $CBC defun-semcheck2.cb
assert_error $CBC defun-semcheck3.cb
assert_error $CBC defun-semcheck4.cb
assert_error $CBC defun-semcheck5.cb
assert_error $CBC defun-semcheck6.cb
assert_error $CBC defun-semcheck7.cb
assert_error $CBC defun-semcheck8.cb
assert_error $CBC funcall-semcheck.cb
assert_error $CBC funcall-semcheck2.cb