typedef int a; //a是TypedefNames,作用域?yàn)閍ll the scope
//overload:表示在嵌套作用域中,類型定義名是否作為變量,而不是類型名
int f(char a) //由于之前a已經(jīng)是typedef了,所以這里標(biāo)記為overload,
//那么在函數(shù)f的作用域中只能作為變量,而不是類型名,那么下面用a作為類型來(lái)定義變量都是語(yǔ)法錯(cuò)誤
{
//語(yǔ)法分析時(shí)typedef是聲明,a已經(jīng)被聲明為char了,所以這里報(bào)告a重聲明了
//typedef char a;
printf("%c", a);
return 0;
}
int main()
{
typedef char* a; //在mian的作用域里面,a就是char *類型了
a x = (void*)0;
printf("Hello, World %c\n");
return 0;
}
引用ucc的文檔:
在大多數(shù)情況下,C語(yǔ)言是一個(gè)LL(0)文法,解析器可以根據(jù)當(dāng)前的記號(hào)而決定與什么產(chǎn)生式和非終結(jié)符匹配。但是由于C語(yǔ)言引入了類型定義而破壞了這個(gè)特性。比如說(shuō)在復(fù)合語(yǔ)句中遇到一個(gè)標(biāo)識(shí)符,如果是類型定義名,則應(yīng)該為聲明,否則為語(yǔ)句。為了簡(jiǎn)潔性,ucc將語(yǔ)法分析和語(yǔ)義檢查分成兩個(gè)獨(dú)立的階段,但是類型定義又要求在語(yǔ)法分析中做一定的語(yǔ)義檢查,為此,ucc在語(yǔ)法分析中對(duì)于類型定義做最小的檢查。對(duì)于語(yǔ)法分析器來(lái)說(shuō),只要知道一個(gè)標(biāo)識(shí)符是類型定義名就足夠了,而不需要知道具體的類型。
語(yǔ)法分析中用以進(jìn)行語(yǔ)義檢查的數(shù)據(jù)結(jié)構(gòu)和算法如下:
typedef struct tdname
{
char *id;
int level;
int overload;
} *TDName;
tdname表示一個(gè)類型定義名。
id: 名字
level: 類型定義名被定義點(diǎn)的嵌套層次,文件作用域的嵌套層次為0,復(fù)合語(yǔ)句的起始處嵌套層次加1,復(fù)合語(yǔ)句的結(jié)束處嵌套層次減1。有可能在多個(gè)作用域中定義同一個(gè)類型定義名,level表示這些作用域中嵌套層次最小的。比如說(shuō)對(duì)于如下代碼片段:
typedef int a;
int f(void)
{
typedef int a;
}
其中l(wèi)evel值應(yīng)為0。這樣在其它函數(shù)中a的定義也是可見(jiàn)的。
overload:表示在嵌套作用域中,類型定義名是否作為變量,而不是類型名。比如如下代碼片段:
typedef int a;
int f(int a)
{
}
在f的函數(shù)定義中,a是參數(shù),而不是類型定義名。
ucc使用兩個(gè)向量:TypedefNames記錄了所有定義的類型名。OverloadNames記錄當(dāng)前作用域中被重載了的類型名。
對(duì)于每一個(gè)聲明,調(diào)用CheckTypedefName函數(shù),如果該聲明屬于類型定義,則查看相應(yīng)的類型名是否存在,如果不存在,則加入新的類型定義,如果存在,修改level為最小的嵌套層次。如果該聲明不屬于類型定義并且該聲明所定義的變量已定義為外部作用域的類型名,則標(biāo)記該類型名被重載,并且將其加入OverloadNames中。
每當(dāng)一個(gè)復(fù)合語(yǔ)句結(jié)束時(shí),重置OverloadNames中的所有類型名的重載狀態(tài)。