我过去在各种项目中使用了lex和yacc(通常更常用的是bison),通常是用于翻译器(例如将EDIF子集流式传输到EDA应用程序中)。此外,我不得不支持基于lex/yacc语法几十年前编写的代码。因此我知道这些工具的使用方法,但并不是专家。
我曾经在各个论坛中看到过关于Antlr的积极评论,我很好奇我可能错过的东西。所以如果你两者都使用过,请告诉我Antlr的优点或更高级的功能。我的当前限制是我在一个C++商店工作,任何我们发布的产品都不包括Java,因此生成的解析器必须遵循该规则。
我过去在各种项目中使用了lex和yacc(通常更常用的是bison),通常是用于翻译器(例如将EDIF子集流式传输到EDA应用程序中)。此外,我不得不支持基于lex/yacc语法几十年前编写的代码。因此我知道这些工具的使用方法,但并不是专家。
我曾经在各个论坛中看到过关于Antlr的积极评论,我很好奇我可能错过的东西。所以如果你两者都使用过,请告诉我Antlr的优点或更高级的功能。我的当前限制是我在一个C++商店工作,任何我们发布的产品都不包括Java,因此生成的解析器必须遵循该规则。
主要区别之一是ANTLR生成的是LL(*)解析器,而YACC和Bison生成的解析器是LALR。这对于许多应用程序来说是一个重要的区别,最明显的是运算符:
expr ::= expr '+' expr
| expr '-' expr
| '(' expr ')'
| NUM ;
ANTLR无法按原样处理此语法。 要使用ANTLR(或任何其他LL解析器生成器),您需要将此语法转换为不是左递归的内容。 但是,Bison没有问题处理这种形式的语法。 您需要将“+”和“-”声明为左结合运算符,但这不是左递归所必需的。 更好的例子可能是dispatch:
expr ::= expr '.' ID '(' actuals ')' ;
actuals ::= actuals ',' expr | expr ;
请注意,expr
和 actuals
规则都是左递归的。这样做在代码生成时将产生更高效的AST,因为它避免了多个寄存器和不必要的溢出(左倾树可以折叠,而右倾树则不行)。
就个人口味而言,我认为LALR语法更容易构建和调试。缺点是你必须处理一些有点神秘的错误,比如移位-归约和(可怕的)归约-归约。Bison在生成解析器时捕获这些错误,所以它不会影响最终用户的体验,但可能会使开发过程更加有趣。ANTLR通常被认为比YACC/Bison更易于使用,正是因为这个原因。
正如某些人已经指出的那样,ANTLR 的一个很大优点是其图形化 IDE 工具,称为 ANTLRworks。它是一个完整的语法和语言设计实验室。当您输入语法规则时,它会将其可视化,并在发现任何冲突时以图形方式显示冲突及其原因。它甚至可以自动重构和解决冲突,例如左递归。一旦您拥有一个无冲突的语法,您就可以让 ANTLRworks 解析您的语言的输入文件并为您构建解析树和 AST,并在 IDE 中以图形方式显示树。这是一个非常大的优势,因为它可以节省您许多工作时间:在开始编码之前,您将找到语言设计中的概念错误!我没有找到任何 LALR 语法的类似工具,看来没有这样的工具。
即使对于不希望生成解析器而手动编写的人来说,ANTLRworks 也是一个用于语言设计/原型的绝佳工具。可能是目前最好的这样的工具。不幸的是,如果您想构建 LALR 解析器,那么这并不能帮到您。为了利用 ANTLRworks 而从 LALR 切换到 LL 可能是值得的,但对于某些人来说,切换语法类型可能是非常痛苦的经历。换句话说:结果因人而异。
ANTLR的几个优点:
我的.02$
ANTLR 的另一个优点是你可以使用 ANTLRWORKS,虽然我不能说这是一个绝对的优势,因为其他生成器也可能有类似的工具。
另一个 ANTLR 的好处是它可以使用 ANTLRWORKS 工具,尽管我不能说这是一个绝对的优势,因为其他生成器也可能有类似的工具。请注意保留原文中的 HTML 标签。Bison/Flex的内存使用通常为1兆字节左右。与之相比,假设要解析的文件中每个标记令牌使用512字节的内存,则在32位系统上,若有400万标记令牌,就会超出虚拟内存。
如果您要解析的文件很大,antlr可能会耗尽内存,因此如果只想解析配置文件,它将是一种可行的解决方案。否则,如果要解析大量数据的文件,请尝试使用Bison。