標籤:

C/C++語言有哪些不是上下文無關的語法規則?

比如像函數定義先聲明後使用應該是上下文無關文法描述不了的,還有其他的嗎?


a * b 是乘法還是定義指針?

a b(c); 聲明了一個函數還是定義了一個對對象?

a b(c x); 是合法的嗎?

a &< b &> c 是在使用模板還是比較大小?

函數定義先聲明後使用應這類東西倒是和CFG關係不大。


下課了,來重寫下

我對C++不是很熟悉,所以後面的討論會局限在C語言的範疇內。後面提到的東西放到C++里估計就會錯一堆了。

首先,C語言的文法中確實存在上下文相關的部分。我照著文法看了半天,只找到了typedef會帶來上下文相關的問題,不知道還有沒有別的地方也有……如果有的話歡迎補充。

回歸正題。首先題主說的函數先聲明再使用,這個不是語法層面上的上下文相關。語法的作用是看句子是否符合某些給定的規則。語法層面的上下文相關是指,在判斷一個句子是否符合某個規則時,需要這個句子之外的額外信息來進行判斷。不考慮typedef的話,給一個函數聲明的句子,我們總是能根據規則和輸入的句子本身是不是一個合法的函數聲明而不需要知道額外的信息,那麼這樣就算是上下文無關。題主所認為的上下文相關實際上是語義的上下文相關。

再說說C文法里上下文相關的事。再次強調,這裡的上下文相關是語法上的上下文相關,即判斷一個句子是否符合某規則時需要額外的信息。有了typedef的話,c的類型和標識符就可能一樣了,這就是衝突的根源。比如,a*b這個,在上文是typedef struct {} a的情況下,這個句子就會符合指針定義的規則。如果上文是int a, b,那麼這個句子就是一個語句了。

最後放上一個不太確定的猜測,歡迎討論:如果去除了typedef,那麼C的文法應該是上下文無關的


C/C++能用上下文無關法描述。但是*一旦*使用上下文無關法,很多原屬於語法層面的特性被迫*推遲*到語法分析之後(語義分析階段)實現。

例如 a * b,上下文無關法分析器只能將它標記為「帶歧義的星號語句」,交給之後的程序處理。這會導致語法規則混亂,以及使語義分析器承擔語法分析器的部分職責,所以少有項目用這樣的方法實現。


所有自然語言和編程語言都可以用上下文無關語法(CFG)描述。

另外,你說得這個問題不屬於語法範疇,而是句法分析(parsing)。

編譯原理而言,一段程序要經歷如下幾個過程:

1. 詞法分析(Lexical Analysis)&<-就是把字元變成詞

比如,

int x = 1;

x = x + 1;

會被轉化為 (int)(x)(=)(1)(;)(x)(=)(x)(+)(1)(;)這些標記(Token)

2. 語法分析(Syntax Analysis)&<-保證詞符合語句結構。&<-CFG屬於這個層面的工具

這個作用是

比如上邊的標記,會被對應到如下兩個語法樹中

S = (variable_type) (variable_name) = (expression)

| =(variable_name) = (expression) + (expression)

| = (expression)

(expression) = (variable_name)

| = (int_value)

3. 語義分析(Semantic Analysis)&<- 保證詞的上下文意思合理。&<-你問的問題在這個層面

這個時候會有一些對各種value進行檢查的機制。比如下邊使用的變數名應該在之前被定義過,之類。

這是個基本的編譯器的原理。現在新的編譯器還有很多別的功能(特別是在IDE中的語法提示之類),那就是另外一碼事了。


推薦閱讀:

應該如何理解「上下文無關文法」?
為什麼Objective-C 和 Swift 語言在其他平台上沒有相應的編譯器?
Visual Studio能否避免感染類似XcodeGhost的病毒?
世界上存在「與規範完全一致」的 C++ 編譯器/解釋器嗎?
編譯器內部是如何處理 C 語言 typedef 關鍵字的?

TAG:CC | 編譯器 |