lcc 原始碼讀書筆記之c語言的語義檢測
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語言的語義檢測暫時介紹到這兒,關於函式呼叫,常量摺疊等比較複雜,下一次繼續,呵呵