lcc 源码读书笔记之c语言的语义检测

论坛 期权论坛 脚本     
已经匿名di用户   2022-5-29 19:38   2680   0

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语言的语义检测暂时介绍到这儿,关于函数调用,常量折叠等比较复杂,下一次继续,呵呵

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP