你会推荐哪些具有代码分离和语言可扩展性的解析器生成器?

时间:2011-05-04 16:19:57

标签: parser-generator

我正在寻找一种具有语法/代码分离的无上下文语法分析器生成器,并且可以添加对新目标语言的支持。例如,如果我想在Pascal中使用解析器,我可以编写自己的pascal代码生成器,而无需重新实现整个过程。

据我所知,理论上大多数开源解析器生成器都可以扩展,但我更喜欢计划和记录扩展性的东西。

功能方面我需要解析器至少支持Python样式的缩进,可能需要一些额外的工作。对生成的解析器类型没有要求,但我更喜欢快速的东西。

哪些是最知名/最常用的选项?

流行的解析器生成器似乎主要使用混合语法/代码方法,我真的不喜欢。 Comparison list on Wikipedia列出了一些,但我在这方面是新手,无法分辨哪个尝试。

为什么我不喜欢混合语法/代码:因为这种方法看起来很混乱。语法是语法,实现细节是实现细节。它们是用不同语言编写的不同东西,将它们放在不同的位置是直观的。

如果我想在另一个项目中重用部分语法,具有不同的实现细节,该怎么办?如果我想用不同的语言编译解析器怎么办?所有这些都需要将语法分开。

2 个答案:

答案 0 :(得分:3)

大多数解析器生成器都不会处理无上下文的语法。它们处理一些子集(LL(1),LL(k),LL(*),LALR(1),LR(k),......)。如果你选择其中一个,你几乎肯定会破解你的语法以匹配解析器生成器的限制(没有左递归,有限的前瞻,......)。如果你想要一个真正的无上下文解析器生成器,你需要一个早期的解析器生成器(低效),一个GLR解析器生成器(最实用的那个),或者一个PEG解析器生成器(并且最后一个不是上下文的;它需要要排序的规则以确定哪些优先。)

您似乎担心混合用于构建树的语法和解析器操作。

如果你构建的树不是语法的直接函数,那么必须有一些方法将树构建机制与语法产生联系起来。将它置于语法生成“附近”是一种方式,但会导致你的“混合”符号反对。

另一种方法是为每个规则指定一个名称(或一些唯一标识符),并将树构建机制设置为由名称索引的一侧。这样你的语法就不会受到“其他东西”的污染,这似乎是你的反对意见。我所知道的解析器生成器系统都没有这样做。一个尴尬的问题是,你现在必须发明许多规则名称,并且只要你有几百个名称本身不方便而且很难让它们成为助记符。

第三种方法是使语法功能化,并自动生成树构建步骤。这根本不需要额外的东西来产生AST。我所知道的唯一的工具(可能还有其他人,但我一直在寻找20多年而且还没有看到过)是我公司的产品,DMS Software Reengineering Toolkit。 [DMS不仅仅是一个解析器生成器;它是一个完整的生态系统,用于使用GLR解析引擎构建任意语言的程序分析和转换工具;是的,它处理Python样式缩进]。

有一个反对意见是这些树木是混凝土,膨胀和混乱;如果做得对,那不是真的。 我的答案回答了这个问题: What is the difference between an Abstract Syntax Tree and a Concrete Syntax Tree?讨论了我们如何从自动生成的压缩CST中获得AST的好处。

有关DMS方案的好消息是基本语法不会因解析支持而膨胀。不太好的消息是,你会发现很多其他你想要与语法规则相关的东西(漂亮的打印规则,属性计算,树综合......),你会回到同样的选择。 DMS拥有所有这些“其他东西”,并通过多种方式解决了关联问题:

  • 在语法规则旁边放置其他相关的描述性形式(产生你抱怨的混音)。我们容忍这个漂亮的打印规则,因为实际上将语法(解析)规则与漂亮的打印(反解析)规则相邻是很好的。我们还允许将属性计算放在语法规则附近以提供关联。

  • 虽然DMS允许规则具有名称,但这只是为了方便代码访问,而不是将其他机制与规则相关联。

  • DMS提供了第三种方法,通过将规则本身用作一种巨型名称来关联这些机制(尤其是属性语法计算)。因此,您可以在一个地方编写语法和prettyprint规则,在其他地方,您可以使用关联的属性计算再次编写语法规则 。原则上,这就像给每个规则一个名称(好吧,一个签名)并将计算与名称相关联。但它也允许我们定义许多不同的属性计算(用于不同的目的)并将它们与它们的规则相关联,而不会使基本语法混乱。我们的工具检查(规则,关联计算)在基本语法中是否有一个有效的规则,因此它使得相对每一个都可以追踪基语语法发生变化时需要修复的内容。

这是我的工具(我是建筑师)你不应该把它作为推荐,只是偏见。这种偏见得到了DMS的解析能力(没有呜咽)C,C ++,Java,C#,IBM企业COBOL,Python,F77 / F90 / F95,其中column6继续/ F90继续,嵌入式C预处理器指令在大多数情况下启动),流行性腮腺炎,PHP4 / 5和许多其他语言。

答案 1 :(得分:1)

首先,任何体面的解析器生成器都足够强大,可以支持Python的缩进。语言不是那么奇怪。您应该尝试解析像Fortran77这样的列敏感语言......

其次,我认为你真的不需要解析器本身是“可扩展的”吗?你只是希望能够使用它来解释和解析你想到的语言,对吗?同样,任何体面的解析器生成器都可以做到这一点。

第三,你并没有真正说出你不喜欢的语法和代码之间的混合。你是否愿意用元语言(有点强硬)或全部用代码实现它?

假设它是后者,我知道有几种语言解析器生成器工具包。第一个是Boost's Spirit,它是用C ++实现的。我用过它,它的确有效。然而,当我使用它时,你几乎需要一个“升级学”的研究生学位才能够很好地理解它的错误信息,以便在合理的时间内完成任何工作。

我所知道的另一个是OpenToken,它是在Ada中实现的解析器生成工具包。 Ada没有C ++与其模板有关的error-novel问题,因此OpenToken更容易使用。但是,你必须在Ada中使用它......

典型的函数式语言允许您在语言本身内实现您喜欢的任何子语言(主要是),这要归功于它们对lambdas和元编程等方面的非常好的支持。但是,他们的解析器往往更慢。如果你只是解析一两个配置文件,那真的没问题。如果您一次解析数百个文件,这是一个巨大的问题。