怎樣在bison里構造一組語法產生式,使得C語言的結構體聲明變數時不用加上struct關鍵字?
就像在C++語言中那樣,當我們聲明了一個類class MyClass {…}之後,在使用這個類定義對象x時可以直接寫成MyClass x;
瀉藥。在回答你這個問題的時候,我一直在想把這個問題複雜化回答,還是簡單化回答。其實你看到下面知友說的typedef,你就知道這肯定不止與產生式有關了,也是與類型系統有關了。所以,你要做到C中不使用struct,不僅是產生式的問題,更是類型系統的問題。其實在C++的世界上,struct真的與C很不同,如果你以C++的想法來看,你會覺得很正常,因為在C++的類型系統中,struct與class是同等地位,都是聚合體。在編譯器的產生式中,這兩者其實都被一個統一AggrDeclaration代替(你也可以取其它名字),然後讀到這兩個中的任何一個關鍵字都是統一處理,然後至於為什麼C++可以不需要加struct/class,你讀過C++之父Bjarne的《C++語言設計與演化》你就應該知道C++之父說過要把class做成一等公民,與int等類型地位一樣(int類型變數,我相信你不會使用int i ii,當然這也是不對的)。而在編譯器中,也是這樣設計的。所有的類型其實都保存在了TypeDescriptorPool裡面,然後通過TypeDescriptor掃描變數名字,然後進行解析類型,而編譯器其實也是通過isClassDeclaration()來判定是否是class/struct(方法具體實現我就不說了)。而這樣其實也會造成一些問題,如下面的例子:
#include &
using namespace std;
int a;
class a
{
public:
int c;
};
int main()
{
a = 47;
cout &<&< a &<&< endl;
return 0;
}
// Output: 47
#include &
using namespace std;
int a;
class a
{
public:
int c;
};
int main()
{
a x;
x.c = 47;
cout &<&< x.c &<&< endl;
return 0;
}
// Compile Error
你也會發現第一個例子是沒有錯誤的,是int類型的(當然你也可以說,class看來並沒有達到真正意義上的一等公民地位),而如果我們要修改第二個例子,那就是需要加上struct/class關鍵字。是的,你沒有看錯,我用的是斜杠,就是說可以任意一個。在我看到C++編譯器源代碼之前,我也表示很不解為什麼是這樣,當然我看完後覺得是這麼的自然。
#include &
using namespace std;
int a;
class a
{
public:
int c;
};
int main()
{
struct a x; // No Problem
x.c = 47;
cout &<&< x.c &<&< endl;
return 0;
}
// Output: 47
#include &
using namespace std;
int a;
struct a
{
public:
int c;
};
int main()
{
class a x; // No Problem. It is class keyword!
x.c = 47;
cout &<&< x.c &<&< endl;
return 0;
}
// Output: 47
難道不是一直都用
typedef struct _Fuck
{
} Fuck;這樣的方法來不加上struct關鍵字嗎
這事和上下文無關文法沒關係,文法解決不了這種和「使用前先聲明」類似的問題,因為這已經是上下文相關了。
這個表達式的語義處理要留在語法制導分析階段完成。具體到您問的這個問題,結構作為一個類型變數是需要綁定在一個類型上的,這依靠一個「類型環境」來完成,「類型環境」是一個記錄了類型變數與類型對應關係的數據結構。
在一般的c編譯器中,變數環境和類型環境都對應著符號表
您可以在文法上分別做兩個產生式,一個用於聲明結構,當遇到這個產生式的時候,擴充類型環境。另外一個用於創建結構,當遇到這個產生式的時候,擴充變數環境說句題外話, 個人覺得多寫一個struct不費事, 而且代碼更加清晰.
推薦閱讀:
※如何自學《C++ Primer》和《Thinking in C++》?
※為什麼Delphi的編譯速度如此之快?
※對於以中序表達式為主的編程語言,不實現運算符優先順序,統一求值順序(例如從左往右)會是個好主意嗎?