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

来源:互联网 发布:java音乐网站源码 编辑:程序博客网 时间:2024/06/04 08:14

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

                 

 

 

     

原创粉丝点击