目录

  1. 使用 flexBison
  2. 參考書籍

基礎教學

  1. 撰寫 bas.y (yacc 檔) 和 bas.l (lex 檔)。
  2. yacc 編譯 bas.y 產生定義 token 的 y.tab.h 給 lex.yy.c include; 產生定義 parser 的 y.tab.c,yyparse 是 parser 的入口函式。
  3. lex 編譯 bas.l 產生定義 scanner 的 lex.yy.c,yylex 是 scanner 的入口函式。y.tab.c 的 yyparse 調用 yylex。
  4. cc (C 編譯器) 編譯 y.tab.c 和 lex.yy.c,得到自製編譯器 bas.exe。
  5. bas.exe 編譯 source,得到 compiled output。

BNF

Flex & Bison 應用

Flex

definitions
%%
rules
%%
user code

Bison

Bison 3.0 版之後有較大改變。注意手冊版本。

Each call to yylex() returns an integer value which represents a token type. This tells YACC what kind of token it has read. The token may optionally have a value, which should be placed in the variable yylval.

By default yylval is of type int, but you can override that from the YACC file by re#defining YYSTYPE.

使用 %union 讓 yylval 可以有多種型別。

%union 
{
        int number;
        char *string;
}

%token <number> STATE
%token <number> NUMBER
%token <string> WORD

[0-9]+                  yylval.number=atoi(yytext); return NUMBER;
[a-z0-9]+               yylval.string=strdup(yytext);return WORD;

優先權與結合性

建立符號表

建立語法樹

Bison 中所寫的語法規則,有些僅是用來處理運算子優先順序,和程式無關。抽象語法樹即是將前述語法規則剔除。

Mid-Rule Action

錯誤回報

If you invoke ‘%define parse.error verbose’ in the Bison declarations section (see The Bison Declarations Section), then Bison provides a more verbose and specific error message string instead of just plain "syntax error". However, that message sometimes contains incorrect information if LAC is not enabled (see LAC).

記錄位置

上下文相關語法

錯誤回復

衝突處理

根本原因: 當 Bison 試圖 reduce 時,有其它 shift 或是 reduce 的可能,即為 shift/reduce 或是 reduce/reduce conflict。以下圖來看,"." 出現在規則結尾處時,代表有 reduce 發生。此時,如果有其它 "." 出現,代表衝突發生。

State 14 conflicts: 1 shift/reduce

   ...
   
State 14

   12 input_state_path: T_INPUT_STATE_NO_PATH . T_DIVIDE identifier
   13                 | T_INPUT_STATE_NO_PATH .

    T_DIVIDE  shift, and go to state 19

    T_DIVIDE  [reduce using rule 13 (input_state_path)]
    $default  reduce using rule 13 (input_state_path)
$ grep "State 14" -n Syntax_InputState.output
$ sed -n '211,222p' Syntax_InputState.output > Syntax_InputState.output.new

GLR 剖析器

對於原本文法存在的 shift/reduce 或是 reduce/reduce conflict,GLR parser 於衝突處分成多個 parser 同時並行處理。注意! GLR parser 處理時間隨 conflict 個數增加。

%glr-parser
%expect 2
%expect-rr

Additional syntax error message on GLR parser when syntax is ambiguous

Q & A

處理 INCLUDE

YY_BUFFER_STATE 是 lex 對特定輸入流所產生的句柄。其中包含輸入流的緩衝區,和其它相關變數。

#define YY_STRUCT_YY_BUFFER_STATE
struct yy_buffer_state
    {
    FILE *yy_input_file;
 
    char *yy_ch_buf;        /* input buffer */
    char *yy_buf_pos;       /* current position in input buffer */
 
    /* Size of input buffer in bytes, not including room for EOB
     * characters.
     */
    yy_size_t yy_buf_size;
 
    ...
}
yy_switch_to_buffer (yy_scan_buffer (char *base, yy_size_t size) );

Lex & Yacc Internal

Flex

token 由兩部分組成: token 和 token value。

%x SN_CONDITION_MACRO_DEFINITION    SN_CONDITION_MACRO_CALL  SN_CONDITION_MACRO_CALL_DELIM
%x SN_CONDITION_MACRO_EXPANSION     SN_CONDITION_MACRO_DECL  SN_CONDITION_INCLUDE
%x SN_CONDITION_FALSE
%x SN_CONDITION_COPY                SN_CONDITION_MESSAGE
%x SN_NO_BOUNDARY_TWO_STRING        SN_NO_BOUNDARY_ONE_STRING
%x SN_COMMENT_CONDITION             SN_COMMENT_CONDITION2
%x SN_NO_BOUNDARY_THREE_TOKEN
// 透過 yyscan_t 傳遞 scanner 狀態
//  struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
typedef void* yyscan_t;
 
/* For convenience, these vars (plus the bison vars far below)
   are macros in the reentrant scanner. */
#define yyin yyg->yyin_r
#define yyout yyg->yyout_r
#define yyextra yyg->yyextra_r
#define yyleng yyg->yyleng_r
#define yytext yyg->yytext_r
#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
#define yy_flex_debug yyg->yy_flex_debug_r
 
/* Holds the entire state of the reentrant scanner. */
struct yyguts_t
    {
    /* User-defined. Not touched by flex. */
    YY_EXTRA_TYPE yyextra_r;
 
    /* The rest are the same as the globals declared in the non-reentrant scanner. */
    FILE *yyin_r, *yyout_r;
    size_t yy_buffer_stack_top; /**< index of top of stack. */
    size_t yy_buffer_stack_max; /**< capacity of stack. */
    YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
    char yy_hold_char;
    int yy_n_chars;
    int yyleng_r;
    char *yy_c_buf_p;
    int yy_init;
    int yy_start;
    int yy_did_buffer_switch_on_eof;
    int yy_start_stack_ptr;
    int yy_start_stack_depth;
    int *yy_start_stack;
    yy_state_type yy_last_accepting_state;
    char* yy_last_accepting_cpos;
 
    int yylineno_r;
    int yy_flex_debug_r;
 
    char *yytext_r;
    int yy_more_flag;
    int yy_more_len;
 
    YYSTYPE * yylval_r;
 
    }; /* end struct yyguts_t */

Bison

系列文章

網路教程

進階議題

斷行問題

編碼問題

語法剖析術語

外部連結