实施“*?” (组合GLR解析器中的懒惰“*”)正则表达式模式

时间:2010-12-06 11:26:34

标签: parsing language-agnostic glr

我已经实现了组合GLR解析器。其中有:

  • char(·)解析器,它使用指定的字符或字符范围。
  • many(·)组合子,它从零到无限次重复指定的解析器。

示例:"char('a').many()"将匹配任意数量的"a" - s的字符串。

但是many(·)组合器是贪婪的,所以,例如,char('{') >> char('{') >> char('a'..'z').many() >> char('}') >> char('}')(其中">>"是解析器的顺序链接)将成功使用整个"{{foo}}some{{bar}}"字符串。

我想实现many(·)的延迟版本,在前面的示例中使用它只会消耗"{{foo}}"。我怎么能这样做?

修改

可能我很困惑。在我的程序中,解析器是一个函数(或者就C ++来说是“函子”),它接受“步骤”并返回“步骤”的森林。 “步骤”可以是OK类型(这意味着解析器已成功消耗部分输入)和FAIL类型(这意味着解析器遇到了错误)。有更多类型的步骤,但它们是辅助的。

Parser = f(Step) -> Collection of TreeNodes of Steps.

所以当我解析输入时,我:

  • 编写简单的预定义Parser函数,以获得表示所需语法的复杂Parser函数。

  • 从输入表格初始步骤。

  • 将初始步骤赋予复杂的Parser函数。

  • 使用步骤过滤TreeNodes,只保留OK(如果输入中有错误,则使用最小的FAIL-s)。

  • 从剩下的步骤中收集信息。

4 个答案:

答案 0 :(得分:4)

我已经实施并使用了GLR解析器15年作为程序转换系统的语言前端。

我不知道“组合GLR解析器”是什么,我不熟悉你的符号,所以我不太清楚如何解释它。我假设这是一种curry函数符号?我想象你的组合规则相当于用终端字符来定义一个语法,其中“char('a')。many”对应于语法规则:

 char = "a" ;
 char = char "a" ;
实际上,GLR解析器会生成所有可能的解析。 GLR解析的关键见解是对所有可能的解析的伪并行处理。如果你的“组合器”可以提出多个解析(也就是说,它们产生的语法规则等同于上面的那些),并且你确实将它们连接到GLR解析器,那么它们都将被尝试,并且只有那些瓦片生成的序列文本将存活(意味着所有有效的语法,例如,模糊的解析)将存活。

如果您确实已经实现了GLR解析器,那么您应该非常清楚所有可能的解析集合。事实上它并没有暗示你实现的不是GLR解析器。

使用GLR解析器进行错误恢复是可能的,就像使用任何其他解析技术一样。我们所做的是在错误点之前保留一组实时解析;当发现错误时,我们尝试(在伪并行中,GLR解析机制使其变得容易,如果它正确弯曲)以下所有内容:a)删除违规令牌,b)插入基本上为FOLLOW(x)的所有令牌其中x是实时解析。实质上,删除令牌,或插入实时解析所期望的令牌。然后我们再次松开GLR解析器。只有有效的解析(例如,修复)才能生存。如果无法处理当前令牌,则处理带有已删除令牌的流的解析器仍然存在。在最坏的情况下,GLR解析器错误恢复最终将所有令牌丢弃到EOF。一个严重的缺点是GLR解析器的运行时间在解析错误时变得非常激烈;如果在一个地方有很多,错误恢复时间可以通过屋顶。

答案 1 :(得分:1)

GLR解析器不会产生所有可能的输入解析吗?然后解决歧义就是选择你喜欢的解析。为此,我认为解析林的元素需要根据产生它们的组合符来标记,渴望或懒惰。 (一般来说,在看到所有输入之前,无法逐步解决模糊性。)

(这个答案基于我昏暗的记忆和对GLR解析的模糊可能的误解。希望有专家来这里。)

答案 2 :(得分:0)

考虑正则表达式<.*?>和输入<a>bc<d>ef。这应该找到<a>,没有其他匹配,对吗?

现在考虑具有相同输入的正则表达式<.*?>e。这应该找到<a>bc<d>e,对吧?

这带来了两难境地。为了用户的缘故,我们希望组合器>>的行为可以用它的两个操作数来理解。然而,根据第一个解析器找到的内容,无法生成第二个解析器的行为。

一个答案是每个解析器生成所有解析的序列,按优先级排序,而不是所有解析器的无序集合。贪婪匹配将返回最长到最短的匹配;非贪婪,最短到最长。

答案 3 :(得分:0)

非贪婪功能只不过是一种消歧机制。如果你真的有一个通用的解析器(它不需要消除歧义来产生它的结果),那么&#34;非贪婪的&#34;没有意义;无论操作员是否非贪婪,都会返回相同的结果。

非贪婪的消歧行为可以应用于通用解析器提供的完整结果集。从左到右工作,过滤对应于非贪婪运算符的模糊子组,以使用最短匹配,这仍然导致成功解析剩余输入。