3

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

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

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

哪些是最知名/维护的选项?

流行的解析器生成器似乎主要使用我真的不喜欢的混合语法/代码方法。维基百科上的比较列表列出了一些,但我是这方面的新手,不知道该尝试哪个。

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

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

4

2 回答 2

3

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

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

如果您构建的树不是语法的直接功能,则必须有某种方法将树构建机器与语法产生联系起来。将它“靠近”语法产生是一种方法,但会导致您的“混合”符号反对。

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

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

一个反对意见是,这种树是具体的、臃肿的和令人困惑的。如果做得对,那是不对的。我对这个问题的回答是: 抽象语法树和具体语法树有什么区别?讨论我们如何从自动生成的压缩 CST 中获得 AST 的好处。

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

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

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

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

这是我的工具(我是架构师),您不应该将此作为建议,而只是一种偏见。这种偏见得到了 DMS 解析(无需抱怨)C、C++、Java、C#、IBM Enterprise COBOL、Python、F77/F90/F95 以及 column6 continue/F90 continue 和嵌入式 C 预处理器指令在大多数情况下启动的能力的支持), Mumps、PHP4/5 和许多其他语言。

于 2011-05-05T01:37:27.003 回答
1

首先,任何体面的解析器生成器都将足够强大以支持 Python 的缩进。随着语言的发展,这并不是那么奇怪。您应该尝试解析列敏感语言,如 Fortran77 一段时间......

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

第三,您并没有真正说出您不喜欢的语法和代码之间的混合情况。你宁愿它全部用元语言(有点难)实现,还是全部用代码实现?

假设是后者,我知道有几个语言解析器生成器工具包。第一个是Boost 的 Spirit,它是用 C++ 实现的。我用过,效果很好。但是,当我使用它时,您几乎需要“升压学”的研究生学位才能充分理解它的错误消息,以便在合理的时间内完成任何工作。

我知道的另一个是OpenToken,它是在 Ada 中实现的解析器生成工具包。Ada 没有 C++ 模板中的错误新问题,因此 OpenToken 更容易使用。但是,您必须在 Ada 中使用它...

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

于 2011-05-04T16:35:06.827 回答