理解了BNF,就能实现代码解析了吗?还有点早,因为理解了BNF,还要会写BNF。实际上,BNF实现有固定的模式,也有现成的工具,比如可以使用yacc、bison等工具自动化进行。所以把实现先放一放,看一看BNF是怎么写的。

编写BNF

上一篇文章中,我们介绍了如何编写四则运算的BNF,我们需要遵循几个原则:

  • 优先级越高的产生式越接近终端节点;
  • 有左递归要消除左递归。

是否所有的BNF都可以这么来写呢?下面我们尝试对其他语法的BNF进行编写。

如C语言中枚举类型的定义:

enum EnumName
	A, B, C

枚举类型的定义语法,用语言描述出来是:

以一个enum开头,后面可以跟一个标识符,也可以省略不写。
接着是一个左大括号;
接着是枚举值列表,枚举值列表可以为空,不为空时,枚举值之间用逗号隔开。
枚举值可以只写出标识符名称,也可以给它赋值,如A和A=1都是正确的;
接着是一个右大括号和一个分号。

其BNF可以尝试写出来:

enum_decl=‘enum’ + option_identifier + ‘{’ + value_list + ‘};’
option_identifier=identifier | ‘’
value_list=’’ | value_list + ‘,’ + indentifier | value_list + ‘,’ + indentifier + ‘=’ + Num

写到最后的value_list会发现,不管怎么写都会多出一个逗号。
因为BNF里面的控制命令太少了,想要表达出我们想要表达的规则,我们得求助于EBNF。

EBNF介绍

下面是EBNF的介绍:

EBNF,E即Extended,EBNF即扩展BNF范式。
它最初由尼古拉斯·沃斯开发,最常用的 EBNF 变体由标准,特别是 ISO-14977 所定义。 ——来自维基百科
更详细的介绍可以参考维基百科:
扩展巴科斯范式(可能需要翻墙)
ISO-14977标准文档获取方法,参考文章:去哪查阅ISO国际标准?

下图列举了EBNF包含的符号:
EBNF包含的公式符号
可见EBNF中包含了更多的控制命令。相对于BNF来说,它的描述能力更为强大。

我们现在使用EBNF重写上面的枚举声明语法。

enum_decl = 'enum'[id]'{'[id'='num]{','id'='num}'}';

可见上面用一个EBNF语句即描述BNF很多条语句才能描述的内容。
以此类推,可以自己尝试编写。

欢迎专注【编译原理】专栏!

这里的 符号> 是非终结符,而表达式由一个符号序列,或用指示选择的竖杠 '|' 分隔的多个符号序列构成,每个符号序列整体都是左端的符号的一种可能的替代。从未在左端出现的符号叫做终结符。       BNF类似一种数学游戏:从一个符号开始(叫做起始标志,实例中常用S表示),然后给出替换前面符号的规则。BNFBison是在Yacc上改写并添加了大量特性后诞生的语法分析生成器,在编译前端(词法分析->语法分析->语义分析)中处在中间的位置,它可以用来生成特定的语法分析程序。 安装Bison: apt-get install bison 没有专用于Bison的IDE,可以在VSCode安装Lex Flex Yacc Bison插件,可以让Bison语法高亮。 Bsion和Flex协同工... 巴科斯范式(BNF: Backus-Naur Form 的缩写)是由 John Backus 和 Peter Naur 首先引入的用来描述计算机语言语法的符号集。 在BNF中,双引号中的字("word")代表着这些字符本身。而double_quote用来代表双引号。 在双引号外的字(有可能有下划线)代表着语法部分。 < > : 内包含的为必选项。 [ ] : 内包含的为...
之前一直想创造一门新的语言,于是便花了一些精力研究这些相关的工具和技术现在我把我总结的一些经验分享给大家 Flex & Bison 是比较有名而且易用的parser组合,今后的工作大体都用到了这两个工具。他们可以在gnu官网下载,windows用户要么去下载winflexbison,要么自己编译一份(推荐),这里不详细介绍获取方法 本教程所有代码都在Android平台和windows平台的g+
你也可以通过我的独立博客 —— www.huliujia.com 获取本篇文章 简易编译器实现(一)使用Flex创建词法分析器一文介绍了编译器的概念和七个阶段,并说明了如何使用Flex创建词法分析器。本篇文章介绍如何使用Bison创建语法分析器,并实现基本的运算能力。本文继续使用简易编译器实现(一)使用Flex创建词法分析器中提出的集合运算语言AlphaGun作为演示的例子。 语法分析器使用词法分析器输出的token流作为输入,把token流转换成树状的中间表示,通常会转换成语法树,本文中使用.
BNF范式 BNF范式本质上就是树形分解,很简单嘛。 前端代码解析的难点就在于BNF,对于对数学不敏感的人来说,看到公式就很烦(像我一样)。那么我们就从计算机专业的角度来掌握它。 产生式就是将语法的分解规则表达出来的等式。如 句子 = 主 + 谓 + 宾 将语法规则描述出来是为了便于代码实现,便于计算,所以产生式可以看做 BNF 是最原始,最简单的方法,主要用于理论背景的学术论文中,以与人类进行交流。(与在编译器/解析器中使用相反)。BNF 没有确切的规范。 EBNF 是 Extended BNF (扩展的BNF)的缩写。没有一个标准的 EBNF,因为每个作者或程序都定义了自己的稍有不同的 EBNF 变体。 ABNF 是 augmented BNF(增强型BNF)的缩写,ABNF 的语法 与 BNF 完全不同,但是更加标准化,利于解析器的翻译,但不利于阅读; BNF、EBNF、ABNF 这三者的表达能力是等效
当我们的文法设计的有问题的时候,就需要开启bison的调试方式来检测文法错在哪里,那么如何开启bison的调试方式呢? bison调式需要做的事情如下: 1 )在语法文件*.y定义段开启yydebug,最终如下: #include #include #include int yydebug=1; 2)在编译语法文件*.y的时候,使用-v参数,生成output文件,这
    3. 编写错误报告函数 yyerror()     4. 在 main() 中调用分析器函数 yyparse()     5. 执行 bison -d,由 .y 文件 产生 .tab.c 和 .tab.h 文件     6. 执... 程序中遇到这种单个点的问题,一般的排故方法是: 1. 代码注释排查,让程序简单越好,最好只剩下出问题的那块代码。然后再运行测试看看到底出问题的代码在哪一块。 2. 代码提取排查,如果注释导致很难编译,那就把可能出问题的模块代码提取出来,写个demo单独测试,排查问题模块。 你问的两个问题我只能提供做法思路。因为出现bug的原因太多,也不要轻易下断言说哪个模块没问题,查出来问题前,每个模块都可能有问题。 windeployqt.exe的使用与避坑(windows平台) 屁屁rtq: 你好,请问一下就是我的程序打包后运行没问题,但是程序中使用了一个ini文件来保存设置内容的,每次运行完程序ini会被改回原来的内容,比如文件中原来有个数据100,我把他改成50后,运行程序,数据又被改回100了,但是在程序中并没有修改ini文件的语句。然后就是我使用了一个动态库来读取传感器数据,这个库是32位的,读取传感器读数时没有问题,但是一旦停止读数,程序就会闪退。大佬看到后请回复一下,感谢