【Bison學習筆記】1:生成簡易的語法分析程序,使Bsion和Flex協同工作

簡述

Bison是在Yacc上改寫並添加了大量特性後誕生的語法分析生成器,在編譯前端(詞法分析->語法分析->語義分析)中處在中間的位置,它可以用來生成特定的語法分析程序。

安裝Bison:

apt-get install bison

沒有專用於Bison的IDE,可以在VSCode安裝Lex Flex Yacc Bison插件,可以讓Bison語法高亮。

Bsion和Flex協同工作

之前按照課本,用Flex生成了一個簡易計算器的詞法分析程序,這節書寫Bison生成它的語法分析程序,然後讓它們協同工作,來完成這個求解器。

Bison部分

Bison寫在.y文件中,也和Flex一樣由兩個%%分割成了聲明部分、規則部分、例程部分。下面是書寫的Bison文件SimpleCalculator.y(課本程序是錯的,這裏改正了):

/*1 聲明部分*/

%{
#include <stdio.h>
%}

//聲明記號(Token)
%token NUMBER
%token ADD SUB MUL DIV ABS
%token EOL

%%

/*2 規則部分,在這裏寫BNF規則,左部是語法符號(Symbol)*/

//計算列表的語法
calclist: //空,即計算列表::=\epsilon
    | calclist exp EOL { printf("= %d\n", $2); } //或者,計算列表::=計算列表.表達式.文件尾
    ; //分號表示規則結束

//表達式的語法
exp: term { $$ = $1; } //表達式:=項
    | exp ADD term { $$ = $1 + $3; } //或者,表達式::=表達式+項
    | exp SUB term { $$ = $1 - $3; } //或者,表達式::=表達式-項
    ;

//項的語法
term: factor { $$ = $1; } //項::=因子
    | term MUL factor { $$ = $1 * $3; } //或者,項::=項*因子
    | term DIV factor { $$ = $1 / $3; } //或者,項::=項/因子
    ;

//因子的語法
factor: NUMBER { $$ = $1; } //因子::=數字
    | ABS factor { $$ = $2>=0 ? $2 : -$2; } //或者,因子::=絕對值.因子
    ;

%%

/*3 C代碼部分*/

//主函數中調用解析器yyparse()
int main(int argc, char **argv) {
    yyparse();
    return 0;
}

//定義解析出錯時的處理
void yyerror(char *s) {
    fprintf(stderr, "error: %s\n", s);
}

這裏在聲明部分用%token聲明瞭若干記號,這些記號實際上後面會給Flex使用,而Bison會自動爲這些記號編號。

接下來在規則部分,用BNF來書寫了上下文無關文法,這裏用{c代碼}將求解的計算寫在了每條子規則的後面。這裏$$表示規則左部的語法符號(Symbol),$1表示規則右部的第一個語法符號,以此類推。

最後在例程部分,Bison生成的語法分析程序要調用yyparse()進行語法分析。

Flex部分

Flex部分和之前的基本一樣。下面是修改的Flex文件SimpleCalculator.l

%{
//包含Bison翻譯出來的頭文件,文件中就定義了各個記號(Token)的編號,以及yylval記號值
//SimpleCalculator.tab.h是由SimpleCalculator.y這個Bison文件經過`bison -d`命令翻譯得來的
#include "SimpleCalculator.tab.h"
%}

%%

"+"     { return ADD; }
"-"     { return SUB; }
"*"     { return MUL; }
"/"     { return DIV; }
"|"     { return ABS; }
[0-9]+  { yylval = atoi(yytext); return NUMBER; } //匹配到數字時,將其轉爲int寫入記號值的變量中
\n      { return EOL; }
[ \t]   { } //忽略空白符
.       { printf("Mystery charactor %c\n", *yytext); } //其它字符是不合法的,提示錯誤

%%

//這部分例程不寫了,因爲Bison生成的語法分析器會調用這裏Flex生成的詞法分析器

去掉聲明部分,是因爲聲明部分直接使用Bison編譯出的.h文件中對記號(Token)的聲明,直接就統一了。

去掉例程部分,是因爲詞法分析的yylex()要給Bison生成的語法分析器去調用,編譯的時候編譯到一起就可以了。

Makefile

創建Makefile文件:

SimpleCalculator: SimpleCalculator.l SimpleCalculator.y
	bison -d SimpleCalculator.y
	flex SimpleCalculator.l
	gcc -o $@ SimpleCalculator.tab.c lex.yy.c -lfl

clean:
	rm -f SimpleCalculator lex.yy.c SimpleCalculator.tab.c SimpleCalculator.tab.h

第一句是用Bison翻譯SimpleCalculator.y,生成語法分析器SimpleCalculator.tab.c和其頭文件SimpleCalculator.tab.h

第二句是用Flex翻譯SimpleCalculator.l生成詞法分析器lex.yy.c

第三句是用GCC將語法分析器、詞法分析器、Flex庫文件這三者編譯到一起,-o指定輸出的文件名,這裏$@代表所有的目標文件,也就是SimpleCalculator。

編譯:

make SimpleCalculator

運行

lzh@DESKTOP-HCSIG2E:/mnt/e/Compiler/flex_bison$ ./SimpleCalculator
12+34*|0-3
= 9
123-456
= -333
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章