使用BNF的编译器编译器

ccl*_*eve 6 java compiler-construction bnf parser-generator

是否有任何理由没有解析器生成器消耗直接BNF?

我熟悉的JavaCCANTLR的,最近碰上了Parse2.似乎每个都有自己的符号.BNF非常容易阅读而其他符号则不然.BNF是明确的.是否有一些固有的原因导致我无法将BNF提供给编译器编译器并获得解析树?

Ira*_*ter 2

有什么原因导致没有直接使用 BNF 的解析器生成器吗?

不,但大多数解析器生成器开始尝试做所有事情。社区花了很长时间才明白有时少即是多

使用 BNF(某些变体)的工具已经存在很长时间了。

一篇描述MetaII的论文早在 1963 年就发表了。MetaII 的基线 BNF 就是你所期望的(左手边加右手边)加上一些现在相对标准的 EBNF 扩展(Kleene Star 和 Plus、分组、替代方案)和非标准嵌入操作(用于生成字面语法指导的翻译输出)。它假定内置令牌词法分析器。MetaII 可以对自己的语法进行元编译,以准确地重现自身(论文展示了这一点,当您了解其工作原理时,这是令人兴奋的时刻),从而能够引导到更复杂的版本。并编译其他简单语言。一个常见的简单扩展是定义词汇标记的语法规则。早在 20 世纪 70 年代,我就构建了各种实现以及使用它的工具,因为它非常酷而且非常有用。

树元添加了用于构建树的操作,以及用于模式匹配树以生成输出的辅助语法。

当您添加所有额外的 EBNF 和生成内容时,MetaII 和 Tree Meta 的最终“BNF”对于新手来说可能相当难以阅读,主要是因为它很密集并且您必须熟悉上下文。否则它看起来就像链式打印机的输出(对于那些年纪大的人来说这是什么)坏了。

大多数现代编译器并没有太大不同。YACC 使用嵌入式(您最喜欢的语言)代码扩展了 BNF 来执行操作,通常用于构建树。JavaCC使用扩展的BNF;使用 JJTree 您可以构建 AST。ANTLR 1/2/3 还具有扩展的 BNF,其中嵌入了用于构建树的操作。这使得它们和 MetaII 一样,呃,丑陋……恕我直言,40 年来没有任何进展。

我们的 DMS Software Reengineering Toolkit(请参阅我的简介)使用您能想象到的最简单的 BNF,用于真正复杂的语法,例如 IBM Enterprise COBOL、Fortran 2005 和 C++14。看起来像:

  LHS = RHS1 RHS2 ...  RHSn ;
Run Code Online (Sandbox Code Playgroud)

对于各种标记 LHS、RHS1 ... RHSn。列表很简单:您使用两种规则,一种用于基本情况,一种用于列表扩展。替代方案很简单:编写另一条规则。从技术上来说,将标记的语法规则简单地编码为终端是实际字符的语法规则是很简单的。(出于解析速度的原因,DMS 提供并且我们通常使用真正的词法分析器)。

这是高中代数的 DMS BNF(以及一些微积分;符号上的一些自由):

equation = sum ;
sum = product ;
sum = sum '+' product ;
sum = sum '-' product ;
product = term ;
product = product '*' term ;
product = product '/' term ;
term = primary ;
term = primary '^' term ;
primary = NUMBER ;
primary = NAME ;
primary = '(' sum ')' ;
primary = '-' primary ;
primary = NAME '(' sum ')' ;
primary = 'D' NAME ':' primary ; -- differentiate primary
primary = 'I' sum 'D' NAME ; -- indefinite integral
primary = 'I' sum ',' sum ':' sum 'D' NAME ; -- definite integral
Run Code Online (Sandbox Code Playgroud)

真正的 DMS 语法文件还有其他用于描述漂亮打印等的内容。在这里您可以看到M6809 汇编代码的 DMS 语法的更大示例

有趣的是,DMS使用语法作为指导来构建 AST;没有额外的建树操作。通过避免在解析时指定操作(构建树节点),生成的语法非常易于阅读。

DMS 大约从 1998 年就开始这样做了;这是我知道的第一个采用这种方法的工具。ANTLR 人员最终发现这是一个好主意,现在 ANTLR4 自 2013 年起将构建一棵没有任何显式嵌入操作的树,尽管它仍然具有用于其他目的的操作。DMS 的树可以是具体的(直接遵循语法),也可以是“抽象的”(许多树节点被删除,因为它们可以由 DMS 按需重建,具有抽象树和语法)。抽象树实际上相当不错。我不知道ANTLR4在这里做什么。

这种方法的真正好处是,人们可以通过简单地修改规则来编写和修改非常复杂、庞大的语法;AST 的构造是“自由的”,并且在语法方面总是“正确的”。这使得 DMS 能够使用它作为基准来提供各种其他相关工具(漂亮打印、源到源级别转换)。(从技术上讲,DMS 是一个“元”编译器,因为它可以使用自己的语法解析自己的语法;我们使用 DMS 的这种功能来生成这些语法隐含的解析器)。

您可以在“代数作为 dms 域”中看到完整的示例,也可以通过我的简历查看。(BNF 是从那里获取的)。我会提供链接,但很多人不喜欢这样做。