《C陷阱與缺陷》一1 3 詞法分析中的「貪心法」

2021-09-23 16:10:57 字數 1601 閱讀 1135

c語言的某些符號,例如/ 、、和=,只有乙個字元長,稱為單字元符號。而c語言中的其他符號,例如/和 = = ,以及識別符號,包括了多個字元,稱為多字元符號。當c編譯器讀入乙個字元'/'後又跟了乙個字元'*',那麼編譯器就必須做出判斷:是將其作為兩個分別的符號對待,還是合起來作為乙個符號對待。c語言對這個問題的解決方案可以歸納為乙個很簡單的規則:每乙個符號應該包含盡可能多的字元。也就是說,編譯器將程式分解成符號的方法是,從左到右乙個字元乙個字元地讀入,如果該字元可能組成乙個符號,那麼再讀入下乙個字元,判斷已經讀入的兩個字元組成的字串是否可能是乙個符號的組成部分;如果可能,繼續讀入下乙個字元,重複上述判斷,直到讀入的字元組成的字串已不再可能組成乙個有意義的符號。這個處理策略有時被稱為「貪心法」,或者,更口語化一點,稱為「大嘴法」。kernighan與ritchie對這個方法的表述如下,「如果(編譯器的)輸入流截止至某個字元之前都已經被分解為乙個個符號,那麼下乙個符號將包括從該字元之後可能組成乙個符號的最長字串。」

需要注意的是,除了字串與字元常量,符號的中間不能嵌有空白(空格符、製表符和換行符)。例如,= =是單個符號,而= = 則是兩個符號,下面的表示式

a---b
與表示式

a -- - b
的含義相同,而與

a - -- b
的含義不同。同樣地,如果/是為判斷下乙個符號而讀入的第乙個字元,而/之後緊接著,那麼無論上下文如何,這兩個字元都將被當作乙個符號/,表示一段注釋的開始。

根據**中注釋的意思,下面的語句的本意似乎是用x除以p所指向的值,把所得的商再賦給y:

y = x/*p    /* p指向除數*/;
而實際上,/被編譯器理解為一段注釋的開始,編譯器將不斷地讀入字元,直到/出現為止。也就是說,該語句直接將x的值賦給y,根本不會顧及到後面出現的p。將上面的語句重寫如下:

y = x / *p   /* p指向除數 */;
或者更加清楚一點,寫作:

y = x/(*p)   /* p指向除數 */;
這樣得到的實際效果才是語句注釋所表示的原意。

諸如此類的準二義性(near-ambiguity)問題,在有的上下文環境中還有可能招致麻煩。例如,老版本的c語言中允許使用=+來代表現在+=的含義。這種老版本的c編譯器會將

a=-1;
理解為下面的語句

a =- 1;
亦即

a = a - 1;
因此,如果程式設計師的原意是

a = -1;
那麼所得結果將使其大吃一驚。

另一方面,儘管/*看上去像一段注釋的開始,在下例中這種老版本的編譯器會將

a=/*b;
當作

a =/ *b ;
這種老版本的編譯器還會將復合賦值視為兩個符號,因而可以毫無疑問地處理

a >> = 1;
而乙個嚴格的ansi c編譯器則會報錯。

C缺陷與陷阱 詞法陷阱

從較低的層面考察,程式是由符號 token 序列組成的,將程式分解成符號的過程,稱為詞法分析。這節主要分析在程式被詞法分析器分解成各個符號的過程中可能出現的問題。編譯器中負責將程式分解成乙個乙個符號的部分,一般稱之為詞法分析器。c語言中符號之間的空白 包括空格符,製表符和換行符 將被忽略。術語符號 ...

C陷阱與缺陷(一)詞法 陷阱

第一章 詞法 陷阱 1 不同於 1 while c c t c n 賦值運算子 的優先順序低於邏輯運算子 相當於 c t c n 賦給了c,條件永遠為真 2 if x y 應該寫成if x y 0 對變數進行賦值並檢查該變數的新值是否為0 2 和 不同於 和 按位運算子 和 邏輯運算子 和 3 詞法...

C 陷阱與缺陷 (一)詞法陷阱

碼字不易,對你有幫助點讚 關注支援一下作者 看更多乾貨,獲取第一時間更新 練習上傳至 0.不同於 當程式設計師本意是作比較運算時,卻可能無意中誤寫成了賦值運算。1.本意是檢查 x 與 y 是否相等 if x y break 實際上是將 y 的值賦值給了 x 然後再檢查該值是否為 0 2.本意是跳過檔...