C詞法分析中的「貪心」法

2021-08-24 17:13:34 字數 2524 閱讀 6063

本章**的是符號和組成符號的字元之間的關係,以及有關符號含義的一些常見的誤解。

當我們閱讀乙個句子時,我們並不去考慮組成這個句子的單詞中單個字母的含義,而是把單詞作為乙個整體來理解。確實,字母本身並沒有什麼意義,我們總是將字母組成單詞,然後給單詞賦予一定的意義。對於c語言或其他語言編寫的程式,道理也是一樣的。

編譯器中負責將程式分解為乙個乙個符號的那部分,一般稱為」詞法分析器」,在c語言中符號之間的空白將被忽略,包括空格符,製表符和換行符。

=和==

一般而言,更為常用的操作用更為簡短的表達,以節省大家的時間。故符號=作為賦值,符號==作為比較運算,因為賦值比使用的更為頻繁。

=的左邊的運算元為左值(lvalue),右邊的為右值(rvalue),關於lvalue和rvalue,詳情請參閱《the c programming language》(k&r/tcpl)的附錄a.5和a.7。

潛在的問題**:

if (x = y)

foo();

程式設計師的本意是判斷(x == y)還是直接的賦值(x = y)呢?現在的gcc編譯器在發現形如e1 = e2的表示式出現在條件判斷的部分時,會給出相關的警告資訊,如果編譯的時候把警告開啟的話。

比如下面這段**:

#include

#include

int main(int argc, char **argv)

不開啟警告的編譯方法和開啟警告的編譯方法分別為:

gcc -o prog prog.c

gcc -wall -o prog prog.c

則可以看到如果開啟警告,編譯器會有提示」warning: suggest parentheses around assignment used as truth value」,如果不開啟警告的話,就沒有任何警告提示了。

作為一種解決方法和一種良好的程式設計習慣,作者建議寫作顯式比較的形式:

if ((x = y) != 0)

foo();

既能去除警告,也使得**的意圖一目了然,只是多了幾個字元,何樂而不為!

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

根據上述說法,我們可以將下述表示式正確解析:a--

-b <==

==> a ---b

而下述表示式寫得時候也應該注意:

y =x/*p (錯誤寫法)

y =x/ *p (正解寫法)

y =x/(*p)(正解寫法)

那麼表示式 "a+++++b" 該如何解析呢?

根據貪心法,我覺得應該這樣解析「(a++)++ + b 」,在gcc 4.1裡面測試了下,發現該表示式根本就是錯誤的,下面是我的測試程式的截圖:

字元與字串

這個相對容易理解多了,單引號和雙引號嘛。下面說說兩者的實質的區別:

單引號:單引號字元本質上是代表乙個整數,其值對應於該字元在編譯器採用的字符集中的序列值。對於普通的採用ascii字符集的編譯器,如gcc,'a'就是97或0141(八進位制)。

雙引號:雙引號的字串代表的是乙個指向無名陣列起始字元的指標,該陣列被雙引號之間的字元以及乙個額外的二進位制值為零的字元'/0'初始化。

下面的語句:

printf("hello world/n");

和char hello =

printf(hello);

兩者是等價的。

這個很好理解,用一種形上學的理解記憶,乙個串相當n多字元的組合,要放在一起使用,當然只能用陣列的形式了,也就是說串就是字元的無名陣列形式了,既然無名,就只能使用指標來引用了,串就是這個指標。而這個陣列最後的'/0'代表串的結束(總得有乙個東西來代表結束吧)。

關於這個結束字串的東西,在《expert c programming: deep c secrets》(《c 專家程式設計》)中的第二章的2.1小節的小啟發中說是nul,而null代表空指標,表示什麼也不指向,而nulll則說明需要檢查一下是不是拼寫錯誤了。這裡的nul其實ascii碼表0值的char字面意思,nul並沒有在標準c中定義,當然如果自己想用的話,#define一下也不錯。

一句話總結就是,單引號的字元代表乙個整數,雙引號的則代表乙個指標,混用的話編譯器的型別檢查功能會檢測到這樣的錯誤的,gcc就可以。

C詞法分析中的「貪心」法

本章 的是符號和組成符號的字元之間的關係,以及有關符號含義的一些常見的誤解。當我們閱讀乙個句子時,我們並不去考慮組成這個句子的單詞中單個字母的含義,而是把單詞作為乙個整體來理解。確實,字母本身並沒有什麼意義,我們總是將字母組成單詞,然後給單詞賦予一定的意義。對於c語言或其他語言編寫的程式,道理也是一...

詞法分析 貪心法

c語言的某些符號,例如 和 只有乙個字元長,稱為單字元符號。而c語言中的其他符號,例如 和 以及識別符號,包括了多個字元,稱為多字元符號 當c編譯器讀入乙個字元 後又跟了乙個字元 那麼編譯器就必須做出判斷 是將其作為兩個分別的符號對待,還是合起來作為乙個符號對待。c語言對這類問題的規則可以歸納為 每...

C 詞法分析器中的「貪心法」

編譯器將程式分解成符號的方法是,從左到右乙個字元乙個字元的讀入,如果該字元可能組成乙個字元,那麼再讀入下乙個字元,判斷已經讀入的兩個字元組成的字串是否可能是乙個符號的組成部分 如果可能,繼續讀入下乙個字元,重複上述判斷,直到讀入的字元組成的字串已不再可能組成乙個有意義的符號。a b這個表示式你要怎麼...