使用BNF的编译器编译器

时间:2014-10-23 21:36:10

标签: java compiler-construction bnf parser-generator

为什么没有解析器使用直接BNF的解析器生成器?

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

3 个答案:

答案 0 :(得分:2)

有没有理由没有解析器生成器直接消耗BNF?

不,但大多数解析器生成器都开始尝试做所有事情。社区花了很长时间才弄清楚有时 less is more

消耗(某些变化)BNF的工具已经存在了很长时间。

一篇描述MetaII的论文发表于1963年.MetaII的基线BNF是您所期望的(左侧和右侧)加上一些现在相对标准的EBNF扩展(Kleene Star和Plus,分组,替代品)和非标准的嵌入式动作(用于生成字面上的语法指导的转换输出)。它假定内置令牌词法分析器。 MetaII可以对自己的语法进行元编译以完全自我复制[论文显示了这一点,当你理解为什么这样做时,这是令人兴奋的时刻],从而使自举成为更复杂的版本。并编译其他简单语言。一个常见的简单扩展是为词法标记定义语法规则。我在20世纪70年代建立了各种各样的实现和使用它的工具,因为它非常酷且非常有用。

Tree Meta添加了构建树的动作,以及模式匹配树的辅助语法以生成输出。

当您添加所有额外的EBNF和生成内容时,MetaII和Tree Meta的结果“BNF”对于不熟悉的人来说可能相当困难,主要是因为它很密集而且您必须熟悉上下文。否则它看起来像链式打印机的输出(对于你们这些人来说,知道这是什么)破坏了。

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

我们的DMS软件再造工具包(请参阅我的简历)使用您可以想象的最简单的BNF,用于真正复杂的语法,例如IBM Enterprise COBOL,Fortran 2005和C ++ 14。它看起来像:

  LHS = RHS1 RHS2 ...  RHSn ;

用于各种代币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

真正的DMS语法文件还有其他用于描述漂亮印刷等的东西。 在这里,您可以看到a bigger example of a DMS grammar for M6809 assembly code

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

自1998年以来,DMS一直在这样做;这是我所知道的第一个采用这种方法的工具。 ANTLR的人最终发现这是一个好主意,现在ANTLR4截至2013年将构建一个没有任何明确的嵌入式操作的树,尽管它仍然有其他用途的动作。 DMS的树可以是concrete (following the grammar directly) or "abstract"(许多树节点被丢弃,因为它们可以通过DMS按需重建,具有抽象树和语法)。抽象树实际上相当不错。我不知道ANTLR4在这里做了什么。

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

你可以在“代数作为dms域”中看到一个完整的例子,也可以通过我的bio。 (BNF是从那里拿走的)。我提供链接,但很多SO人都不喜欢。

答案 1 :(得分:2)

Marpa::R2Marpa的Perl接口,一般的BNF解析器,接受直接BNF作为语法描述,并在Perl中为它生成解析器。这是一个几乎从BNF grammar tutorial开始的例子。

<tree>  ::= '(' <list> ')'
<list>  ::= <thing> | <list> ',' <thing>
<thing> ::= <tree> | <name>             
<name>  ::= 'ant' | 'bat' | 'cow' | 'dog' | 'cat'

The full code example.

答案 2 :(得分:0)

检查此一项: https://bnfc.digitalgrammars.com/

  

什么是BNF转换器?

     

BNF Converter是一个编译器构造工具,可生成   Labeled BNF语法的编译器前端。目前可以   生成C,C ++,C#,Haskell,Java和OCaml以及XML   表示形式。

     

鉴于该工具生成的标记BNF语法:•抽象语法   实现•同一语法中抽象语法的大小写框架   语言•Alex,JLex或Flex lexer生成器文件•Happy,CUP,   或Bison解析器生成器文件•漂亮打印机   Haskell / Java / C ++ / C模块•包含可读内容的Latex文件   语言规范

这个开放源代码似乎也很有希望: https://github.com/navstev0/nodebnf

  

BNF既是解释器,BNF编译器的框架,也是   语言解析器。它可以使用BNF,ABNF或两者的混合。的   先前版本使用了自定义JavaScript标记,该标记是在   BNF解释脚本文件,此功能已被删除以支持   内联编译。

这里的Ant是一种C ++,也是开源的: https://github.com/chsu16/BNF-Compiler#bnf-compiler

  

BNF-Compiler用C ++编写的上下文无关文法编译器,具有   弯曲/野牛。实现词法分析器,LALR解析器,抽象语法   树,带有类型检查和代码生成的符号表。这个   项目是基于UCSC的Compiler Design类构建的。