(二)初識Bison:寫一個簡單計算器

Bison是一種通用的語法分析器生成器,Yacc 的 GNU 版。它將LALR(1)上下文無關文法的描述轉化成分析該文法的C程序
它經常和 Flex一起使用。
基礎:瞭解BNF(可參考: 語法規範:BNF與ABNF)

先來了解一下Bison:

bison程序包括與flex程序相同的三個部分結構:聲明部分、規則部分、C代碼部分,三個部分兩兩之間用%%隔開。
(1) 聲明部分:
%{到%}部分會被拷貝到目標分析程序的開頭。
%token記號我的理解是詞法分析器得到的結果,用於傳入語法分析器進行分析。通常,記號總是使用大寫。
(2) 規則部分:
1、:用於定義規則;表示一個規則的結束
2、在每個規則之後,使用{}括起,表明如何處理。
3、規則按照語法樹從上到下定義規則,第一條規則爲語法起始符號,必須與輸入匹配。
4、目標符號(冒號左邊的語法符號)的在動作中代碼用$$代替,右邊語法符號的語義值依次爲$1,$2,直到這條規則的結束。
5、如果一個規則缺少現實的動作,語法分析器將把$1賦予$$,這是i一個內部設定。
返回記號的時候,記號對應的值是存儲在yylval變量中。
(3) C代碼部分:
主程序,負責調用yyparse(),並輸出結果。

一個實現+-*/|的簡單計算器:

  • 編寫Bison語法分析器:
$ vim SimpleCal.y

寫入以下內容:

%{
#include <stdio.h>
%}

%token NUMBER
%token ADD SUB MUL DIV ABS
%token EOL

%%

calclist: /* 空規則 */
    | calclist exp EOL { printf("= %d\n",$2); }
    ;

exp: factor
   | exp ADD factor { $$ = $1 + $3; }
   | exp SUB factor { $$ = $1 - $3; }
   ;

factor: term
      | factor MUL term { $$ = $1 * $3; }
      | factor DIV term { $$ = $1 / $3; }      
      ;

term: NUMBER
    | ABS term { $$ = $2 >= 0?$2:-$2; }
    ;

%%

main(int argc,char **argv)
{
    yyparse();
}
yyerror(char *s)
{
    fprintf(stderr,"error: %s\n",s);
}
  • 編寫對應Flex詞法分析器:

因爲Bison目標程序是語法分析器,所以還需要寫一個Flex程序來實現詞法分析:

$ vim SimpleCal.l

寫入以下內容:

%{
#include "SimpleCal.tab.h"
%}
%%
"+"     { return ADD; }
"-"     { return SUB; }
"*"     { return MUL; }
"/"     { return DIV; }
 
"|"     {return ABS; }
^[-+][0-9]+ { yylval = atoi(yytext); return NUMBER;}
[0-9]+  { yylval = atoi(yytext); return NUMBER;}
 
\n {return EOL; }
[ \t]   {} 
.       { yyerror("Mystery character: %c!",*yytext);}
        /*這裏輸出有點問題...*/
%%

SimpleCal.tab.hBison生成對應程序的頭文件。

  • 編譯與執行:
$ flex -o SimpleCal.yy.c SimpleCal.l
$ bison -o SimpleCal.tab.c SimpleCal.y 
$ gcc -o SimpleCal SimpleCal.tab.* SimpleCal.yy.c -lfl
$ ./SimpleCal 
1-29*3+50+|30
= -6
q
error: Mystery character: %c!
error: syntax error

沒有()的支持,貌似|取絕對值沒啥用。


寫一個shell腳本方便編譯運行:(我makefile不熟悉)

$ touch SimpleCal.sh
$ chmod u+x SimpleCal.sh
$ vim SimpleCal.sh

然後寫入以下內容:

#!/bin/bash
echo "flex執行開始!"
flex -o SimpleCal.yy.c SimpleCal.l
echo "bison執行開始!"
bison -o SimpleCal.tab.c SimpleCal.y
echo "gcc編譯開始!"
gcc -o SimpleCal SimpleCal.yy.c SimpleCal.tab.* -lfl
echo "刪除中間文件..."
rm SimpleCal.yy.c SimpleCal.tab.*
echo "執行生成最終目標文件..."
./SimpleCal
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章