GNU Bison

最後更新: 2026-05-19 10:53:04 +0800 +0800
tags: Bison | Gnu | Parsing
原文以英文撰寫。您正在閱讀AI翻譯版本。

GNU Bison 會從上下文無關文法產生剖析器。其與 Yacc 相容的標記法定義 token、非終結符號、語意值與動作;依照慣例,產生的剖析器會從掃描器取得 token。請參閱 GNU Bison 手冊 以了解與骨架及語言相關的介面。

文法區段、值與動作 #

文法包含宣告、產生式以及選用的結尾程式碼,並以 %% 分隔。宣告定義 token、值型別、優先順序、剖析器設定與必要程式碼。產生式定義非終結符號與動作。

bison
%define api.value.type {int}
%token NUMBER
%left '+' '-'
%%
expression:
    NUMBER                 { $$ = $1; }
  | expression '+' expression { $$ = $1 + $3; }
  ;
%%

產生式歸約時會執行動作。$$ 表示結果的語意值,$1、$2 等表示右側的值。當符號攜帶不同值型別時,請搭配 %union 使用 %type 與具型別的 %token 宣告,或使用適當的 %define api.value.type 設定。確保解構函式與擁有權規則涵蓋錯誤復原期間被捨棄的值。

名稱與剖析器介面 #

C 剖析器預設使用 yyparse、yylex 與 yyerror。%define api.prefix {project_} 會為產生的外部名稱設定不同前綴,因此多個產生的剖析器可以連結到同一個程式。使用相符的前綴與標頭契約設定掃描器。

預設的拉取式剖析器會自行呼叫詞法分析器。%define api.push-pull push 會產生由呼叫端提供 token 的推送介面;both 會同時提供拉取與推送介面。%define api.pure full 會從可重入介面移除剖析器全域狀態,但並行設計也需要可重入掃描器與明確的上下文傳遞。使用 %parse-param 與 %lex-param 將該上下文傳遞給剖析器與詞法分析器呼叫。

位置、優先順序與衝突 #

當診斷需要來源範圍時,啟用 %locations。動作可以使用 @$ 與 @1 取得左側與右側的位置。詞法分析器必須一致地填入所有輸入的位置欄位,包括被忽略的空白。

%left、%right、%nonassoc、%precedence 與 %prec 會依宣告的優先順序與結合性解決選定的移進/歸約衝突。否則,Bison 對移進/歸約衝突偏好移進,對歸約/歸約衝突使用較早的規則;這兩種預設都不能建立預期的語言語意。調查每個衝突,在可用時使用 -Wcounterexamples 取得範例,並只在衝突數量已宣告且經審查時保留 %expect。

錯誤復原 #

Bison 保留 error token 供復原產生式使用。發生語法錯誤時,像 statement: error ';' 這樣的產生式可以丟棄輸入直到同步 token,讓後續陳述式繼續剖析。只有在動作刻意結束復原時才使用 yyerrok;只有在已知前瞻 token 不適用時才使用 yyclearin。

復原必須釋放被捨棄的語意值、持續取得進展,並避免將連鎖錯誤回報為獨立根因。將復原點放在穩定的文法邊界,例如陳述式、宣告或結束分隔符,而不是在運算式內接受任意 token。

評論

在 GitHub 上閱讀或評論(發表評論需要登入)