0x01 參考
我們需要按照bison的要求,書寫bison的源程式(gramma.y),然後由bison把它翻譯為c檔案。因此,bison是編譯程式的翻譯器。bison的原始檔通常由八個部分組成:
一. 自由定義部分:
%
這部分被bison原封不動地複製到輸出的.c檔案中。
二. 語法棧的聯合(union)結構
語法分析程式使用乙個堆疊來存放規約到的各個語法成分,堆疊用乙個陣列表示,這個陣列的每個元素需要能夠描述每乙個語法成分,所以採用乙個union:
%union
union中的每乙個項,都是乙個語法規則的每乙個非終結符;以整數四則表示式為例:
exp : exp 『+』 exp
| exp 『-『 exp
| exp 『*』 exp
| exp 『/』 exp
| 『(『 exp 『)』
| lt_integer
;
lt_integer: lt_integer;
有兩個語法規則,對應了兩個非終結符號:exp是表示式,lt_integer表示整數常量(lt_integer表示詞法分析程式返回的乙個確認為整數的單詞)。 對應的,這個union可以書寫為:
%;
其中par_exp_t用來描述被識別出的exp的資訊,int存放被識別出的整數的值。上面的例子很簡單,所以union只有兩個字段;在dm的語法分析程式中,這個union大約有490個字段,也就是,大概有490個語法規則產生式。
三. 非終結符的型別宣告
上面定義了分析棧的union型別, 還需要把欄位名與語法非終結符號對應起來:
%type
《欄位名》 非終結符號
如上例,這部分應該寫為:
%type
exp%type
lt_integer
看上去似乎有點多餘,每一行都是乙個簡單的重複。但前面乙個表示的是union中對應的欄位名,後乙個是語法符號;如果我們把union改為:
%;
那麼對應的型別宣告需要改為:
%type
exp%type
lt_integer;
這種不一致的寫法,事實上會造成混亂,所以在dm系統中,採用上面一致的寫法。
四: 單詞宣告
語法分析的輸入是連續的有確定意義的單詞。下面需要宣告分析程式支援的單詞:
%token
lt_integer
對於sql語法,關鍵字如:select, from, where等,都可以定義為單詞:
%token
kw_select, kw_from
%token
kw_where
五. 確定運算子的優先順序%left
『-『 『+』
%left
『*』 『/』
%left
『(『 『)』
%left表示是左結合的,表示先規約左邊的產生式,反應到表示式計算中:
1 + 2 + 3 別識別為:((1 + 2) + 3), 而不是 (1 + (2 + 3))
優先順序低的符號列在前面,高有限級的符號列在後面;同一行的表示優先順序相同。所以上面的書寫方式, 符合「先乘除,後加減,括號最優先」的原則。
除了%left以後,還有%right, %nonassoc等用來只是右結合,或者不結合等說明符號,可檢視bison的詳細說明。
六. 宣告語法的開始符號
%start
exp
這是告知bison, 這是語法最終需要規約的非終結符號。
七. 語法規則定義
這是語法分析程式的核心定義部分,用%%開始, 前面已經列出了關於表示式的語法規則:
%%
exp : exp 『+』 exp
| exp 『-『 exp
| exp 『*』
exp | exp 『/』 exp
| 『(『 exp 『)』
| lt_integer
;
lt_integer: lt_integer;
八. 自由新增的c源**
在語法規則定義部分的後面,可以用%%開始,定義c的輔助**。這部分**將被原封不動地複製到輸出的.c檔案中。
給語法規則配上規約動作
規約動作是一段c**,它的作用是每當分析器識別出乙個語法符號時,呼叫該**,完成一定的動作。通常,我們使用這段**,來建立當前語法節點與子節點勾連動作。規約動作應該緊接在語法規則的後面。
如上例:語法分析器 bison
這裡僅列出了其中的兩個子規則, 其中a, b, c, d四個語句構成了第乙個子規則的語句塊:
a:為識別出的exp 生成乙個結構, 用指向它。$$
是乙個bison定義的特殊標記,其意義是當前語法棧的規約元素。如果沒有規約動作**,預設情況下賦予$$
為null。new_node是乙個需要自己編寫的函式,用於生成各個子節點,par_exp是乙個事先定義的常量。顯然,對於不同的規則,需要定義不同的常量型別。象new_node這樣的函式,一般放在.y檔案的最後乙個部分。
b:用來區分是哪個子規則規約的,這裡用tag = 1來表示兩個子表示式『+』運算
c:保留第乙個子表示式;$1表示這個產生式的第1個語法成分所在的語法棧中對應的值
d:保留第二個子表示式;$
3表示這個產生式的第3個語法成分所在的語法棧中對應的值;注意這裡的』+』也佔乙個位置, 用$2,這裡因為有tag=1,已經把相應的資訊儲存到$$
中,所以不需要管它。
e:這是乙個比較特別的語句, 它把$$
賦給了乙個全域性量。因為exp是個開始符號,當分析結束時,這個g_root就是語法樹的根。
f:因為 加了括號的表示式與原表示式等價,所以直接把$
2賦給$$
就可以了,不需要再生成par_exp節點。
最終的函式yyparse()
yyarse()是bison生成的分析器的主函式。 呼叫yyarse(),如果一切順利,那麼上例中的g_root將指向乙個完成的語法樹。
出錯處理
如果輸入的字串有語法錯誤,則分析器將停止分析,在退出yyparse()函式前,會呼叫乙個yyerror(char*s)的函式,這個函式需要使用者自己定義,以便能捕獲一些用意義的資訊,比如:語法錯誤出現的行號,附近的單詞等。
[
前端編譯原理 筆記 BISON
bsion文件,下面是中文的位址 上面的是左遞迴,下面的是右遞迴,推薦的是盡量左遞迴的寫法 使用 left,right或者 nonassoc 可以一次宣告乙個記號並指明它的優先順序和結合性.這些被稱做優先順序宣告 precedence declarations 解決中衝突的方法是比較正在考慮的規則和...
Linux GCC 編譯原始檔
一.常用編譯命令選項 假設源程式檔名為test.c。1.無選項編譯鏈結 用法 gcc test.c 2.選項 o 用法 gcc test.c o test 3.選項 e 用法 gcc e test.c o test.i 作用 將test.c預處理輸出test.i檔案。4.選項 s 用法 gcc s ...
編譯原理 Lex和Bison實現計算器
實現以下步驟,掌握 flex 和 bison 的工作過程 a 在 dos 命令提示符下依次執行以下兩行命令 flex calc.lex bison ocalc.c calc.y b 編譯執行 calc.c 編譯執行完後 題目要求 用 flex 和 bison 實現乙個功能更為強大的計算器,包含以下運...