1. BNF定義
雖然不想多提理論知識,但是有些東西還是避免不了。在解析表達式的時候,我們必須知道它的BNF定義,這樣解析起來就非常方便了。所謂的BNF定義,相信大家看一眼就知道了:
exp_additive -> exp_multiplicative ( "+"|"-" ) exp_multiplicative
exp_multiplicative -> exp_cast ( "*"|"/"|"%" ) exp_cast
exp_cast -> ...
意思是:
加法表達式可以表示為 “乘法表達式 + 乘法表達式”
乘法表達式可以表示為 “類型轉換表達式 *或/或% 類型轉換表達式”
...
知道了整個C語言的BNF定義,我們就可以很簡單的按照這個定義來解析了。整個C的BNF定義可以查看以下的鏈接:
http://lists.canonical.org/pipermail/kragen-hacks/1999-October/000201.html
2. 表達式解析
知道了上面的BNF定義,那么我們的解析代碼就可以這么寫:
void exp_additive(){
char op;
exp_multiplicative();
while(
(op = OPERATOR( '+' )) ||
op = OPERATOR( '-' )) ){
get_token();
exp_multiplicative();
...
}
}
void exp_multiplicative(){
char op;
exp_cast();
while(
(op = OPERATOR( '*' )) ||
(op = OPERATOR( '/' )) ||
(op = OPERATOR( '%' )) ){
get_token();
exp_cast();
...
}
}
過程是這樣的:
a. 調用exp_additive時,先調用exp_multiplicative
b. 然后判斷后面是否是 + 或 -,如果是,再次調用exp_multiplicative
這樣就完成了加法表達式的解析。如果非要問為什么這么寫就能解析出表達式,那么我們可以舉個例子:
a = a * b + c * d;
那么,他的語法樹應該是這樣的:
(圖4.2 語法樹)
我們向下遞歸調用的過程,其實就是構造這個語法樹的過程。但是我們不會真的創建出這個語法樹,而是保存了一個與它等價的一種形式--后綴表達式,其實后綴表達式就是語法樹的后續遍歷。
3. 后綴表達式
什么是后綴表達式?我們還是從例子出發,上面的表達式,轉化成后綴表達式就是這樣子的:
a a b * c d * + =
為什么要寫成這種奇怪的形式?我們不是吃飽了撐着,從左往右分別查看這個表達式您就知道原因了。
a
a
b
* 得到*號,那么拿前面的兩個變量a b求和
c
d
* 得到*號,那么拿前面的兩個變量c d求和
+ 的到+號,獲取前面的兩個變量 a*b c*d 的結果,求和
= 得到=號,將前面的結果賦給a
為了生成后綴表達式,我們要改造上面的解析函數。
void exp_additive(){
char op;
exp_multiplicative();
while(
(op = OPERATOR( '+' )) ||
op = OPERATOR( '-' )) ){
get_token();
exp_multiplicative();
EXP_OPR( op ); <--將運算符入棧
}
}
void exp_multiplicative(){
char op;
exp_cast();
while(
(op = OPERATOR( '*' )) ||
(op = OPERATOR( '/' )) ||
(op = OPERATOR( '%' )) ){
get_token();
exp_cast();
EXP_OPR( op ); <--將運算符入棧
}
}
那么解析完成以后,我們的棧中就會形成后綴表達式了。有了表達式的后綴形式,我們就可以很輕松的產生后綴表達式的中間代碼了。
4.后綴表達式到中間代碼
首先我們先說明一下我們的中間代碼是怎樣的一種形式,這里暫且叫它為三元表達式,是因為這個種中間代碼的形式是固定的。例如,緊接上節的例子,表達式 a = a * b + c * d;的中間代碼最終應該是這樣子的:
@1 = a * b;
@2 = c * d;
@3 = @1 + @2;
@4 = a = @3;
其中以@開頭的都是我們為之產生的中間變量。生成上述的中間代碼后,將會對我們后續的解析提供很大的幫助,應為它結構固定,所以我們不用再去解析源程序,而是通過這個中間代碼產生最終的執行代碼。這里先聲明下,我所說的執行代碼,不是真正意義上得可執行代碼,而是能夠被我的軟件解析的命令序列。其實它已經非常接近匯編代碼。但是我們的目標是解析執行,並不產生匯編代碼,所以產生簡單的命令序列已經可以完成目標了。
我們前面解析表達式,產生后綴形式,為的就是生產這種中間表達式。表達式"a = a * b + c * d;"的后綴形式是"a a b * c d * + =;" 我們要根據這個后綴形式產生中間代碼的過程如下:

5.中間代碼的表示
typedef struct _code code_t;
typedef struct _code * pcode_t;
struct _code{
char opr;
struct{
int i, n, t;
}lab;
v_t var[4];
code_t * next;
};
它是一個鏈表,每個節點保存了一個形如"@1 = a * b;"的中間代碼。其中,opr表示運算符"*";lab表示該節點為一個LAB,留到后面章節講解;var表示運算變量,如上面表達式的"@1, a, b"。
這樣子,當一個表達式解析完成后,會生成一個鏈表,表示該表達式的中間代碼。