LCC在语法分析过程中进行了不少的语义检测,基本集中在一元及二元操作符这里.C语言的语义检查主要包括隐式转换,类型检测和计算顺序。那就让我们从LCC编译器的角度研究C语言的语义规则
转换:
c语言在进行二元计算的时候常常包括返回类型及操作数的类型转换,下面贴出常规算术转换的代码
Type binary(Type ty1,Type ty2) { if(isdouble(ty1)||isdouble(ty2)) return doubletype; if(ty1==floattype||ty2==floattype) return floattype; if(isunsigned(ty1)||isunsinged(ty2)) return unsignedtype; return inttype; }
根据上述代码可以看出来字符类型的算术操作都是返回INT类型
在处理例如char* p for(p)这种语句时。LCC要将这种不是布尔表达式的式子转换为布尔表达式,代码如下
Tree cond(Tree p) { int op=gernic(rightkid(p)->op); if(op==AND||op==布尔操作符..) return p; p=pointer(p); p=cast(p,promote(p->type)); //这个是将P转换为具有目标类型的树,用CV操作符 return (*optree[NEQ])(NE,p,constree(0,inttype)); }
运算符&处理类型为T的操作数,并返回他的地址(类型为(POINTER T))。
if(isarray(p->type)||isfunc(p->type)) return retype(p,ptr(p->type)); //数组或者函数,返回指向数组元素或者函数的指针 else p=lvalue(p); //返回指向本类型的指针,既左值 if(isaddrop(p->op)&&p->u.sym->sclass==REGISTER) error(); else if(isaddrop(p->op)) p->u.sym->addressed=1; //取址运算的操作数不能只保留在寄存器中
运算符*的语义检测如下
p=pointer(p); if (isptr(p->type)&&isfunc(p->type->type)) return retype(p,p->type->type); //函数的取值类型就是函数原来的类型 else{ p=rvalue(p); } //一般指针的取值操作符是INDIR,类型为所指类型
为了方便大家更好的理解LCC各个模块的协作,从软件工程的角度看这个系统,我贴出一张UML顺序图
从软件工程的角度上看,LCC有高内聚,低耦合的特点。各个模块比较易于理解,可重用性也强,而且创建类的职责分配的也不错,有点疑问的是VISITOR直接由解析器创建好了,还是引入一个抽象类。从这图上看C跟C++的差役也没那么大,重构成C++的看起来还是很容易的
扯远了,呵呵。下面看看c语言的[ ]操作。标准C规定e[i]等价于*(e+i);语义函数如下:
Tree q; t=gettok(); q=expr(]); p=(*optree['+'])(ADD,pointer(p),pointer(q)); if(isptr(p->type)&&isarray(p->type->type) p=retype(p,p->type->type) else return p=rvalue(p); //取右操作数
其中执行加法操作的关键处为:
if(isptr(r->type)&&isint(l->type) &&!isfunc(r->type->type) { int n; ty=unqual(r->type); n=type->size; //取出指针所指类型的大小 if(n==0) error(); l=cast(l,promote(l->type)); //短整数类型要提升 if(n>1) l=multree(MUL,consttree(n,inttype),1); //要加的数位指针所指类型的大小×n return simplify(ADD+P,ty,l,r); //返回的类型仍是指针
}
下面再看看->操作符的语义检测,相关的语义检测动作主要包含在field(Tree p,char* name)函数中,放在设计模式中,相当于是一个语义检测Visitor
Tree field(Tree p,char *name) { Field q; Type ty1,ty=p->type; ty1=ty; ty=unqual(ty); if((q=fieldref(name,ty)))!=Null){ //保证是结构的域,否则出错 if(!isarray(q->type)){ ty=q->type; ty=ptr(ty); } p=simply(ADD+P,ty,p,consttree(q->offset,inttype)); //加上偏移量 if (q->lsb) { p = tree(FIELD, ty->type, rvalue(p), NULL); p->u.field = q; } else if (!isarray(q->type)) p = rvalue(p);} //返回右值 else error("unknow field"); }
c语言的语义检测暂时介绍到这儿,关于函数调用,常量折叠等比较复杂,下一次继续,呵呵
|