解析器生成器(Parser Generator)讀取**文法規格**(Grammar Specification),自動產生語法分析器(Parser)原始碼。開發者專注於文法描述,而非手寫遞歸下降或移進歸約邏輯。
+----------------+ yacc +----------------+ C編譯器 +----------------+
| translate.y | ──────────► | y.tab.c | ────────────► | translate |
| (文法規格+動作) | | (生成的Parser) | | (可執行檔) |
+----------------+ +----------------+ +----------------+
▲ ▲
│ │
│ +----------------+ │
└───────────────────── | 詞法分析器 | ◄─────────────────────┘
| (lex/flex) |
+----------------+
translate.y:包含 **Token 宣告**、**文法規則**、**語義動作 (C 代碼)**。yacc translate.y 產生 y.tab.c(含 yyparse())。lex.yy.c (flex),提供 yylex()。cc y.tab.c lex.yy.c -ly -ll -o translate。%{
/* C 宣告區:#include、全域變數、函數原型 */
#include <stdio.h>
#include "ast.h"
%}
/* Token 宣告區 */
%token NUMBER IDENTIFIER
%token IF ELSE WHILE RETURN
%left '+' '-'
%left '*' '/'
%right UMINUS /* 一元負號優先級最高 */
/* 文法規則區 */
%%
program: declaration_list { $$ = make_program($1); }
;
declaration_list: declaration
| declaration_list declaration { $$ = append_decl($1, $2); }
;
declaration: var_decl
| fun_decl
;
var_decl: type_specifier IDENTIFIER ';' { $$ = make_var_decl($1, $2); }
;
type_specifier: 'int' { $$ = TYPE_INT; }
| 'float' { $$ = TYPE_FLOAT; }
;
/* ... 更多規則 ... */
%%
/* 輔助函數區 */
int yyerror(const char *msg) { fprintf(stderr, "Line %d: %s\n", yylineno, msg); return 0; }
int main() { return yyparse(); }
%token 宣告終結符,可關聯型別:%token <int_val> NUMBER。$$ (左邊)、$1 $2... (右邊符號) 存取。int;複雜型別用 %union 定義:%union {
int int_val;
float float_val;
char *str_val;
ASTNode *node;
}
%token <int_val> NUMBER
%token <str_val> IDENTIFIER
%type <node> program declaration_list
%left:左結合(+ - * /)%right:右結合(= ^ 一元運算子)%nonassoc:不結合(比較運算子 a < b < c 非法)| 衝突類型 | 原因 | Yacc 預設行為 | 解決策略 |
|---|---|---|---|
| 移進/歸約 | 如 if-else 懸空 | **移進** (偏好 shift) | %nonassoc、重寫文法、%expect |
| 歸約/歸約 | 兩條規則同時可歸約 | **第一條規則** (文法順序) | 重寫文法、合併規則 |
| 工具 | 算法 | 語言支援 | 特色 |
|---|---|---|---|
| Yacc/Bison | LALR(1) | C/C++ | 標準、成熟、嵌入 C 代碼 |
| ANTLR 4 | ALL(*) | Java, C#, Python, JS, Go, C++ | 語法圖視覺化、訪問者模式、錯誤恢復強 |
| Menhir | LR(1) | OCaml | 型別安全、參數化模組、增量解析 |
| Tree-sitter | GLR | C, Rust, WASM | 增量解析、錯誤容忍、編輯器整合 |
Yacc 確立了「聲明式文法 + 語義動作」的編譯器前端開發範式。雖然現代專案傾向 ANTLR 或手寫遞歸下降(更易除錯、錯誤訊息更好),但理解 Yacc/LALR 原理對掌握靜態分析、語言設計、工具鏈開發仍具核心價值。