Java 使用BNF的编译器

Java 使用BNF的编译器,java,compiler-construction,bnf,parser-generator,Java,Compiler Construction,Bnf,Parser Generator,为什么没有使用直接BNF的解析器生成器呢 我对和很熟悉,最近遇到过。似乎每个都有自己的符号。BNF真的很容易阅读,而其他符号则不容易阅读。BNF是明确的。是否有一些固有的原因导致我无法将BNF提供给编译器并获得解析树?是否有任何原因导致没有使用直接BNF的解析器生成器? 没有,但是大多数解析器生成器开始尝试做所有事情。社区花了很长时间才明白,有时少就是多 使用BNF(一些变体)的工具已经存在很长时间了 1963年发表了一篇描述这一现象的论文。MetaII的基线BNF是您所期望的(左手边加右手边)

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


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

是否有任何原因导致没有使用直接BNF的解析器生成器?

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

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

1963年发表了一篇描述这一现象的论文。MetaII的基线BNF是您所期望的(左手边加右手边)加上许多现在相对标准的EBNF扩展(Kleene Star和plus、分组、替代)和非标准的嵌入式操作(用于生成语法定向的翻译输出)。它假定内置令牌lexer。MetaII可以通过meta编译自己的语法来精确地复制自己(本文展示了这一点,当你探索这一点的原因时,这是一个令人兴奋的时刻),从而能够引导到更复杂的版本。以及编译其他简单的语言。一个常见的简单扩展是定义词汇标记的语法规则。早在20世纪70年代,我就构建了各种各样的实现和工具来使用它,因为它非常酷,非常有用

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

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

大多数现代编译器没有太大的不同。YACC使用嵌入式(您最喜欢的语言)代码扩展了BNF,以执行操作,通常用于构建树。JavaCC使用扩展的BNF;使用JJTree,您可以构建AST。ANTLR 1/2/3还有一个扩展的BNF,带有用于构建树的嵌入式操作。这使得他们就像,呃,丑陋的梅塔II一样。。。40年来没有任何进展

我们的DMS软件再工程工具包(见我的简历)使用了你能想象到的最简单的BNF,用于真正复杂的语法,如IBM Enterprise COBOL、Fortran 2005和C++14。它看起来像:

  LHS = RHS1 RHS2 ...  RHSn ;
对于各种令牌LHS、RHS1。。。RHSn。列表很简单:使用两个规则,一个用于基本情况,一个用于列表扩展。替代方案很简单:编写另一条规则。从技术上讲,将令牌的语法规则简单地编码为其终端为实际字符的语法规则是很简单的。(出于解析速度的原因,DMS提供并通常使用真正的lexer)

这是一个DMS高中代数BNF(和一点微积分;一些记法自由):

一个真正的DMS语法文件还有其他东西可以用来描述预打印等。 在这里你可以看到

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

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

这种方法的好处在于,只要修改规则,就可以编写和修改非常复杂、庞大的语法;ASTs的构造是“自由”的,并且在语法上总是“正确”的。这使得DMS能够提供各种其他相关工具(预打印、源到源级别转换),并将其作为基线。(DMS在技术上是一个“元”编译器,因为它可以使用自己的语法解析自己的语法;我们使用DMS的这种能力来生成这些语法所隐含的解析器)

你可以在“代数作为dms域”上看到一个完整的例子,也可以通过我的个人简历看到。(BNF是从那里取得的)。我会提供链接,但很多人不喜欢。Perl接口,一个通用的BNF解析器,接受直接的BNF作为语法描述,并用Perl为它生成一个解析器。这是一个几乎是从字面上看的例子

::=”(“”)
::=  |  ',' 
::=  |              
::=“蚂蚁”;“蝙蝠”;“牛”;“狗”;“猫”

请查看此项:

什么是BNF转换器

BNF转换器是一种编译器构造工具,用于生成 从带标签的BNF语法生成编译器前端。它目前可以 生成C、C++、C、Haskell、java和OcAML以及XML 陈述

给定标记的BNF语法,该工具生成:•抽象语法 实现•同一语言中抽象语法的案例框架 语言•Alex、JLex或Flex lexer生成器文件•快乐杯、, 或Bison解析器生成器文件•作为 Haskell/Java/C++/C模块•包含可读 语言规范

这个开源项目似乎也很有希望:

BNF既是解释器、BNF编译器的框架,也是 语言分析器。它可以使用BNF、ABNF或两者的混合。这个 以前的版本使用了自定义JavaScript标记,该标记是在 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
<tree>  ::= '(' <list> ')'
<list>  ::= <thing> | <list> ',' <thing>
<thing> ::= <tree> | <name>             
<name>  ::= 'ant' | 'bat' | 'cow' | 'dog' | 'cat'