Antlr的优势(与lex / yacc / bison相比)

过去我使用lex和yacc(更常见的是bison)来处理各种项目,通常是翻译(例如EDIF的一个子集stream入EDA应用程序)。 另外,我必须支持基于lex / yacc语法的代码。 所以我知道我的工具,虽然我不是专家。

我在过去的各种论坛上看到过关于Antlr的积极评论,我很好奇我可能会错过什么。 所以,如果你使用了两者,请告诉我什么Antlr更好或更先进。 我目前的限制是我在C ++商店工作,任何我们发布的产品都不会包含Java,所以得到的parsing器将不得不遵循这个规则。

一个主要区别是ANTLR生成LL(*)parsing器,而YACC和Bison生成LALRparsing器。 这对于一些应用来说是一个重要的区别,最明显的是运营商:

expr ::= expr '+' expr | expr '-' expr | '(' expr ')' | NUM ; 

ANTLR完全不能按原样处理这个语法。 要使用ANTLR(或任何其他LLparsing器生成器),您需要将此语法转换为不是左recursion的。 不过,Bison对这种forms的语法没有问题。 您需要将“+”和“ – ”声明为左关联运算符,但这对于左recursion并不是严格要求的。 一个更好的例子可能是调度:

 expr ::= expr '.' ID '(' actuals ')' ; actuals ::= actuals ',' expr | expr ; 

请注意, expractuals规则都是左recursion的。 由于它避免了多个寄存器和不必要的溢出(左倾斜树可以折叠而右倾斜树不能),所以这产生了更高效的AST。

就个人的口味而言,我认为LALR语法的构build和debugging要容易得多。 不利的一面是你必须处理一些模糊的错误,如移位减less和(可怕的)减less – 减less。 这是Bison在生成parsing器时捕获的错误,所以它不会影响最终用户的体验,但它可以使开发过程更有趣。 正因为如此,ANTLR通常被认为比YACC / Bison更易于使用。

YACC / Bison和ANTLR最显着的区别在于这些工具可以处理的语法types。 YACC / Bison处理LALR语法,ANTLR处理LL语法。

通常,长期与LALR语法工作的人会发现LL语法的工作更困难,反之亦然。 这并不意味着语法或工具本身就更难以合作。 你发现哪个工具更容易使用,主要归结为熟悉语法的types。

就优点而言,LALR语法比LL语法具有优势,还有其他方面,LL语法比LALR语法具有优势。

YACC / Bison生成表驱动parsing器,这意味着“处理逻辑”包含在parsing器程序的数据中,而不是在parsing器的代码中。 付出的代价是,即使一个非常复杂的语言的parsing器有一个相对较小的代码足迹。 这在20世纪60年代和70年代当硬件非常有限时更为重要。 Table驱动的parsing器生成器可以回溯到这个时代,而当时的小代码是一个主要需求。

ANTLR生成recursion下降parsing器,这意味着parsing器的代码中包含“处理逻辑”,因为语法的每个生成规则都由parsing器代码中的函数表示。 回报是通过阅读代码来理解parsing器在做什么更容易。 此外,recursion下降parsing器通常比表驱动器更快。 但是,对于非常复杂的语言,代码占用空间会更大。 这在二十世纪六七十年代是一个问题。 那时,由于硬件限制,只有像Pascal这样的相对较小的语言才能以这种方式实现。

ANTLR生成的parsing器通常在10.000行代码附近。 手写的recursion下降parsing器通常在同一个球场。 Wirth的Oberon编译器可能是最紧凑的,大约有4000行代码,包括代码生成,但是Oberon是一个非常紧凑的语言,只有大约40条生产规则。

正如有人已经指出,ANTLR的一大优势是graphics化IDE工具,称为ANTLRworks。 这是一个完整的语法和语言devise实验室。 它会在您input语法规则时将您的语法规则可视化,如果发现任何冲突,它将以graphics方式向您显示冲突是什么以及导致冲突的原因。 它甚至可以自动重构和解决诸如左recursion之类的冲突。 一旦你有了无冲突的语法,你可以让ANTLRworksparsing你的语言的input文件,并为你构build一个分析树和AST,并在IDE中以graphics方式显示树。 这是一个非常大的优势,因为它可以为您节省很多工作时间:在开始编码之前,您会在语言devise中发现概念错误! 我还没有find任何这样的LALR语法工具,似乎没有任何这样的工具。

即使对于不希望生成parsing器而是手动编写parsing器的人来说,ANTLRworks也是语言devise/原型devise的绝佳工具。 很可能是最好的这种工具。 不幸的是,如果你想构buildLALRparsing器,这并不能帮助你。 从LALR切换到LL只是为了利用ANTLRworks可能是值得的,但对于一些人来说,切换语法types可能是一个非常痛苦的经历。 换句话说:YMMV。

ANTLR的几个优点:

  • 可以输出各种语言的parsing器 – 运行生成的parsing器不需要Java。
  • 令人敬畏的GUI使语法debugging变得简单(例如,您可以在GUI中看到生成的AST的权限,不需要额外的工具)
  • 生成的代码实际上是人类可读的(这是ANTLR的目标之一),并且它生成LL语法分析器的事实肯定有助于这方面的工作。
  • terminal的定义也是上下文无关的(与(f)lex中的正则expression式相反) – 因此允许例如包含适当closures圆括号的terminal的定义

我的.02 $

ANTRL的另一个优点是可以使用ANTLRWORKS ,但我不能说这是一个严格的优势,因为其他发电机也可能有类似的工具。

  • Bison和Flex导致内存占用更小,但是没有graphics化的IDE。
  • antlr使用更多的内存,但你有antlrworks,一个graphics化的IDE。

野牛/ Flex的内存使用量通常是1兆字节左右。 与antlr相反 – 假设你要parsing的文件中的每个标记都使用512字节的内存。 400万令牌,并且您在32位系统上的虚拟内存不足。

如果你想parsing的文件很大,antlr可能会耗尽内存,所以如果你只是想parsing一个configuration文件,这将是一个可行的解决scheme。 否则,如果你想parsing一个包含大量数据的文件,试试Bison。