日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

关于bison

發(fā)布時(shí)間:2024/3/26 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 关于bison 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

yacc(Yet Another Compiler Compiler),是一個(gè)經(jīng)典的生成語法分析器的工具。yacc生成的編譯器主要是用C語言寫成的語法解析器(Parser),需要與詞法解析器Lex一起使用,再把兩部份產(chǎn)生出來的C程序一并編譯。

Bison 基本上與?Yacc?兼容,并且在 Yacc 之上進(jìn)行了改進(jìn)。它經(jīng)常和?Flex?(一個(gè)自動(dòng)的詞法分析器生成器)一起使用。

此軟件的源代碼是可自由獲得的,在?GPL?下發(fā)布。

?

BNF

巴科斯范式(BNF: Backus-Naur Form 的縮寫)是由 John Backus 和 Peter Naur 首先引入的用來描述計(jì)算機(jī)語言語法的符號(hào)集。

在BNF中,雙引號(hào)中的字("word")代表著這些字符本身。而double_quote用來代表雙引號(hào)。

在雙引號(hào)外的字(有可能有下劃線)代表著語法部分。

< > : 內(nèi)包含的為必選項(xiàng)。?
[ ] : 內(nèi)包含的為可選項(xiàng)。?
{ } : 內(nèi)包含的為可重復(fù)0至無數(shù)次的項(xiàng)。?
|? : 表示在其左右兩邊任選一項(xiàng),相當(dāng)于"OR"的意思。?
::= :?是“被定義為”的意思 或者單一的冒號(hào)
"..." : 術(shù)語符號(hào)?
[...] : 選項(xiàng),最多出現(xiàn)一次?
{...} : 重復(fù)項(xiàng),任意次數(shù),包括 0 次?
(...) : 分組

|?? : 并列選項(xiàng),只能選一個(gè)

?

下面是是用BNF來定義的Java語言中的For語句的實(shí)例:

1

2

3

4

for?(initialization; termination;

?????increment) {

????statement(s)

}

BNF定義如下:

1

2

3

4

5

6

FOR_STATEMENT ::=

????"for"?"("?( variable_declaration? |

??( expression?";"?)? |??";"??)

??????[ expression ]?";"

??????[ expression ]??";"

?????")"?( statement |?"{"?statement?"}"?)

BNF處理1*2 + 3*4 +5簡單的算術(shù)表達(dá)式:

1

2

3

4

5

6

7

8

<exp> ::= <factor>

????| <exp> + <factor>

<factor> ::= NUMBER

????| <factor> * NUMBER

?

exp被定義為是一個(gè)factor或者factor+exp

?

factor被定義是NUMBER或者factor*NUMBER

?

例子1:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

%{??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

#include <stdio.h>

%}

?

/*聲明token*/

%token NUMBER

%token ADD SUB DIV MUL ABS

%token EOL

?

%%

calclist:?/*空規(guī)則*/

????| 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; }

????|?"+"?term { $$ = $2; }

????;

?

%%

int?main(int?argc,?char?** argv)

{

????printf(">");

????yyparse();

????return?0;

}

?

yyerror(char?*s)

{

????fprintf(stderr,"error:%s\n",s);

}

bison程序包括與flex程序相同的三個(gè)部分結(jié)構(gòu):聲明部分、規(guī)則部分、C代碼部分。

1、聲明部分:

聲明部分包含了會(huì)被原樣拷貝到目標(biāo)分析程序開頭的C代碼,同樣也通過%{和%}來聲明。

%token記號(hào)聲明,以便于告訴bison在語法分析程序中的記號(hào)的名稱。通常,記號(hào)總是使用大寫。

任何沒有聲明為記號(hào)的語法符號(hào)必須出現(xiàn)在至少一條規(guī)則的左邊(左邊表示規(guī)則的定義)

2、規(guī)則部分:

簡單的BNF定義的規(guī)則。bison使用單一的冒號(hào)而不是::=,分號(hào)被用來表示規(guī)則的結(jié)束。

在flex中每個(gè)規(guī)則之后,使用花括號(hào)括起。

?

bison會(huì)自動(dòng)分析語法,記住每條被匹配的規(guī)則,所以動(dòng)作代碼只需要維護(hù)每個(gè)語法符號(hào)關(guān)聯(lián)的語義值。

bison語法分析器也執(zhí)行一些額外的動(dòng)作,例如創(chuàng)建數(shù)據(jù)結(jié)構(gòu)以便后續(xù)使用。

?

第一條規(guī)則左邊的語法符號(hào)是語法起始符號(hào)(start symbol),整個(gè)輸入必須被它匹配。

每個(gè)bison規(guī)則中的語法符號(hào)都有一個(gè)語義值,目標(biāo)符號(hào)(冒號(hào)左邊的語法符號(hào))的值在動(dòng)作中代碼用$$代替,

右邊語法符號(hào)的語義值依次為$1,$2,直到這條規(guī)則的結(jié)束。當(dāng)詞法分析器返回記號(hào)時(shí),記號(hào)值總是存儲(chǔ)在yyval里,

其他語法符號(hào)的語義規(guī)則在語法分析器的規(guī)則里進(jìn)行設(shè)置,例如本例子的 factor、term和exp符號(hào)的語義值就是它們所

描述的表達(dá)式值。

?

例子中,頭兩條規(guī)則定義了calclist語法符號(hào),通過循環(huán)來讀入用換行符結(jié)束的表達(dá)式并且打印結(jié)果。

1

2

3

4

calclist: /*空規(guī)則*/

????| calclist exp EOL { printf("= %d\n",$2); }

????| calclist EOL { printf("> "); } /* blank line or a comment */??????????????????????????????????????????????????????????

????;

calclist的定義使用一種常見的雙規(guī)則遞歸定義來實(shí)現(xiàn)一個(gè)序列或者列表:

第一個(gè)規(guī)則為空,不進(jìn)行任何匹配

第二個(gè)規(guī)則添加一個(gè)項(xiàng)目到列表中,對(duì)應(yīng)的動(dòng)作是通過$2打印出exp的值

第三個(gè)規(guī)則實(shí)現(xiàn)輸入空行

?

其余的規(guī)則實(shí)現(xiàn)計(jì)算器,帶有操作符的規(guī)則(exp ADD factor? 和ABS term)在語義值上進(jìn)行相應(yīng)的算術(shù)操作。

右邊僅有一個(gè)語法符號(hào)的規(guī)則是組合文法,例如exp:factor,一種表達(dá)式exp就是一個(gè)因子factor。

如果一個(gè)規(guī)則缺少現(xiàn)實(shí)的動(dòng)作,語法分析器將把$1賦予$$,這是i一個(gè)內(nèi)部設(shè)定。

?

詞法分析器程序

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

%option noyywrap

%{

#include "fb1-5.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);}

%%

?

1、由于在語法分析中聲明了token,故這里使用的話,需要進(jìn)行引用,在聲明部分添加include文件

2、返回記號(hào)的時(shí)候,記號(hào)對(duì)應(yīng)的值是存儲(chǔ)在yylval變量中

?

聯(lián)合編譯flex和bison程序

對(duì)應(yīng)的makefile文件內(nèi)容為:

1

2

3

4

fb1-5: fb1-5.l fb1-5.y

????????bison -d fb1-5.y

????????flex fb1-5.l

????????gcc -o $@ fb1-5.tab.c lex.yy.c -lfl

bison 使用-d選項(xiàng)(用于定義文件)運(yùn)行,創(chuàng)建fb1-5.tab.c和fb1-5.tab.h文件

flex創(chuàng)建lex.yy.c,然后將兩者和flex的庫文件編譯在一起

?

測(cè)試結(jié)果

1

2

3

4

5

6

[root@typhoeus79 bison]# ./fb1-5

>

> -5+10

= 5

-5*4+20

= 0

二義性文法:并不多見

語法分析為什么不寫成這樣?

1

2

3

4

5

6

7

exp:exp ADD exp

??????| exp SUB exp

??????| exp MUL exp

??????| exp DIV exp

??????| ABS exp

??????| NUMBER

??????;

原因在于優(yōu)先級(jí)和二義性。

分開的term、factor和exp的語法符號(hào)可以讓bison首先處理ABS,接著是MUL和DIV,然后是ADD和SUB。

通常來說,一旦一種文法有不同的優(yōu)先級(jí),語法分析器就需要為每種優(yōu)先級(jí)制定一條規(guī)則。

?

下面的文法如何?

1

2

3

4

5

exp: exp ADD exp

??????|?? exp SUB exp

??????| factor;

?

factor和term部分相似

存在二義性。例如1-2+3的輸入可能被分析為(1-2)+3,也可能被分析為1-(2+3)

如果一種文法是有歧義的,bison會(huì)報(bào)告沖突(conflicts),并且標(biāo)出針對(duì)給定輸入哪兒會(huì)有兩種不同的分析。

?

增加其他規(guī)則

支持小括號(hào)

詞法解析中添加如下:

1

2

"("???? { return OP; }

")"???? { return CP; }

語法解析中添加:

1

2

3

4

5

term:NUMBER

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

????| "+" term { $$ = $2; }

????| "-" term { $$ = -$2; }

????| OP exp CP { $$ = $2;}

?如果想支持如下計(jì)算,應(yīng)該怎么搞呢?

1

2

3

4

5

6

7

8

>(10-2)+(-10+2)

= 0

>(100-2)*2

= 196

>(+10-2)

= 8

>10-(-10+10)?

= 10

需要詞法分析,重點(diǎn)需要區(qū)分正常的加減號(hào)以及前綴加減號(hào)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

%option noyywrap

%{

#include "fb1-5.tab.h"

int?flag=1;

int?flag2 = 1;

?

%}

?

%%

"+"?????{

????????????if(flag){

????????????????flag = 1;

????????????????//printf("ADD\n");

????????????????return?ADD;

????????????}else

????????????{

????????????????flag2 = 1;

????????????}

????????}

"-"?????{

????????????if(flag){

????????????????//printf("SUB\n");

????????????????flag = 1;

????????????????return?SUB;

????????????}else

????????????{

????????????????//printf("Flag=%d,Here\n",flag);

????????????????flag2 = -1;

????????????}

????????}

"*"?????{?return?MUL; }

"/"?????{?return?DIV; }

"("?????{?? flag = 0;

????????????//printf("OP\n");

????????????return?OP; }

")"?????{

????????????flag =1;

????????????flag2 = 1;

????????????//printf("CP\n");

????????????return?CP; }

?

?

"|"?????{return?ABS; }

^[-+][0-9]+ { yylval = atoi(yytext);?return?NUMBER;}

[0-9]+? {

????????????if(flag)

????????????????yylval = atoi(yytext);

????????????else{

????????????????yylval = flag2*atoi(yytext);

????????????????flag = 1;

????????????}

????????????//printf("NUMBER2=%d\n",yylval);

????????????return?NUMBER;}

?

\n????? {return?EOL; }??????????????????????????????????????????????????????????????????????????????????????????????????????

[ \t]?? {}?

.?????? { yyerror("Mystery character=%c!",*yytext);}

%%

總結(jié)

以上是生活随笔為你收集整理的关于bison的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。