編譯原理之 Bison 原始檔結構原理

2021-08-13 20:46:04 字數 3562 閱讀 7622

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 實現乙個功能更為強大的計算器,包含以下運...