yacc(Yet Another Compiler Compiler),是一个经典的生成语法分析器的工具。yacc生成的编译器主要是用C语言写成的语法解析器(Parser),需要与词法解析器Lex一起使用,再把两部份产生出来的C程序一并编译。
Bison 基本上与 Yacc 兼容,并且在 Yacc 之上进行了改进。它经常和 Flex (一个自动的词法分析器生成器)一起使用。
BNF
巴科斯范式(BNF: Backus-Naur Form 的缩写)是由 John Backus 和 Peter Naur 首先引入的用来描述计算机语言语法的符号集。
在BNF中,双引号中的字("word")代表着这些字符本身。而double_quote用来代表双引号。
在双引号外的字(有可能有下划线)代表着语法部分。
< > : 内包含的为必选项。
[ ] : 内包含的为可选项。
{ } : 内包含的为可重复0至无数次的项。
| : 表示在其左右两边任选一项,相当于"OR"的意思。
::= : 是“被定义为”的意思 或者单一的冒号
"..." : 术语符号
[...] : 选项,最多出现一次
{...} : 重复项,任意次数,包括 0 次
(...) : 分组
| : 并列选项,只能选一个
下面是是用BNF来定义的Java语言中的For语句的实例:
| 1 2 3 4 |
|
BNF定义如下:
| 1 2 3 4 5 6 |
|
BNF处理1*2 + 3*4 +5简单的算术表达式:
| 1 2 3 4 5 6 7 8 |
|
例子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 |
|
bison程序包括与flex程序相同的三个部分结构:声明部分、规则部分、C代码部分。
1、声明部分:
声明部分包含了会被原样拷贝到目标分析程序开头的C代码,同样也通过%{和%}来声明。
%token记号声明,以便于告诉bison在语法分析程序中的记号的名称。通常,记号总是使用大写。
任何没有声明为记号的语法符号必须出现在至少一条规则的左边(左边表示规则的定义)
2、规则部分:
简单的BNF定义的规则。bison使用单一的冒号而不是::=,分号被用来表示规则的结束。
在flex中每个规则之后,使用花括号括起。
bison会自动分析语法,记住每条被匹配的规则,所以动作代码只需要维护每个语法符号关联的语义值。
bison语法分析器也执行一些额外的动作,例如创建数据结构以便后续使用。
第一条规则左边的语法符号是语法起始符号(start symbol),整个输入必须被它匹配。
每个bison规则中的语法符号都有一个语义值,目标符号(冒号左边的语法符号)的值在动作中代码用$$代替,
右边语法符号的语义值依次为$1,$2,直到这条规则的结束。当词法分析器返回记号时,记号值总是存储在yyval里,
其他语法符号的语义规则在语法分析器的规则里进行设置,例如本例子的 factor、term和exp符号的语义值就是它们所
描述的表达式值。
例子中,头两条规则定义了calclist语法符号,通过循环来读入用换行符结束的表达式并且打印结果。
| 1 2 3 4 |
|
calclist的定义使用一种常见的双规则递归定义来实现一个序列或者列表:
第一个规则为空,不进行任何匹配
第二个规则添加一个项目到列表中,对应的动作是通过$2打印出exp的值
第三个规则实现输入空行
其余的规则实现计算器,带有操作符的规则(exp ADD factor 和ABS term)在语义值上进行相应的算术操作。
右边仅有一个语法符号的规则是组合文法,例如exp:factor,一种表达式exp就是一个因子factor。
如果一个规则缺少现实的动作,语法分析器将把$1赋予$$,这是i一个内部设定。
词法分析器程序
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
1、由于在语法分析中声明了token,故这里使用的话,需要进行引用,在声明部分添加include文件
2、返回记号的时候,记号对应的值是存储在yylval变量中
联合编译flex和bison程序
对应的makefile文件内容为:
| 1 2 3 4 |
|
bison 使用-d选项(用于定义文件)运行,创建fb1-5.tab.c和fb1-5.tab.h文件
flex创建lex.yy.c,然后将两者和flex的库文件编译在一起
测试结果
| 1 2 3 4 5 6 |
|
二义性文法:并不多见
语法分析为什么不写成这样?
| 1 2 3 4 5 6 7 |
|
原因在于优先级和二义性。
分开的term、factor和exp的语法符号可以让bison首先处理ABS,接着是MUL和DIV,然后是ADD和SUB。
通常来说,一旦一种文法有不同的优先级,语法分析器就需要为每种优先级制定一条规则。
下面的文法如何?
| 1 2 3 4 5 |
|
存在二义性。例如1-2+3的输入可能被分析为(1-2)+3,也可能被分析为1-(2+3)
如果一种文法是有歧义的,bison会报告冲突(conflicts),并且标出针对给定输入哪儿会有两种不同的分析。
增加其他规则
支持小括号
词法解析中添加如下:
| 1 2 |
|
语法解析中添加:
| 1 2 3 4 5 |
|
如果想支持如下计算,应该怎么搞呢?
| 1 2 3 4 5 6 7 8 |
|
需要词法分析,重点需要区分正常的加减号以及前缀加减号
| 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 |
|
博客介绍了yacc和Bison这两个生成语法分析器的工具,yacc生成的解析器用C语言写成,需与Lex配合;Bison与Yacc兼容且有改进,常和Flex搭配。还阐述了巴科斯范式(BNF)用于描述计算机语言语法的规则,以及bison程序结构、词法分析器程序、联合编译等内容,提及了二义性文法问题。
370

被折叠的 条评论
为什么被折叠?



