C语言的函数调用要解决以传值方式传递和返回结果,有时还会出现参数中嵌套函数调用的问题。所以必须建立一个正确的树结构,要求嵌套函数的调用在使用参数前计算。函数原型的语义检测由下列片段组成
if (proto && *proto && *proto != voidtype)//表明原型还没比较完全,在此情况下进入循环比较,直到读到')'
if (proto && *proto && *proto != voidtype) //退出循环后,如果此条件还为真,表明参数不够
实参跟形参的比较如下aty = assign(*proto, q);如果返回类型不为空,就表明兼容。
q=cast(q,aty)进行参数转换,将实参转换为正确的形参
建立正确的参数树
r = r ? tree(RIGHT, voidtype, r, q) : q; //有嵌套调用的话就生成右操作树
args = tree(ARG + widen(q->type), q->type, q, args); //参数树,右节点为前一个参数。
t3 = temporary(AUTO, unqual(rty), level); //为结构类型建立临时变量,保存返回值
return calltree(f,rty,args,t3)语义检测结束,生成函数调用树。操作码是call+b
下面再看看C语言对于关系操作符的语义检测,如果操作数都是算术类型的话比较就很简单,返回类型为inttype.
指针类型的话就要判断指针是否满足条件,然后将指针类型转换为无符号数进行比较
if (isarith(l->type) && isarith(r->type)) {
ty = binary(l->type, r->type);
l = cast(l, ty);
r = cast(r, ty);
} else if (compatible(l->type, r->type)) {
ty = unsignedtype;
l = cast(l, ty);
r = cast(r, ty);
} else {
ty = unsignedtype;
typeerror(op, l, r);
}
return simplify(op + ttob(ty), inttype, l, r);
在LCC中NULL指针的定义如下
static int isnullptr(e) Tree e; {
return (isint(e->type) && generic(e->op) == CNST
&& cast(e, unsignedtype)->u.v.u == 0)
|| (isvoidptr(e->type) && e->op == CNST+P
&& e->u.v.p == NULL);
} //NULL指针式为0的整型常量表达式或者将它们转换为VOID*后得到的结果。
不同的编译器对指针操作的要求常常不同,但一般都是转换为无符号数进行比较。