2

如果我理解正确,解析会将一系列符号变成一棵树。我的问题是,是否可以使用一些标准程序(LR、LL、PEG、..?)来解析以下两个示例,或者是否有必要手动编写专门的解析器?

  1. Python 源代码,即空格缩进的块

我想我在某处读到解析器跟踪前导空格的数量,并假装用大括号替换它们来分隔块。是因为标准解析技术不够强大还是出于性能原因而从根本上需要它?

  1. PNG图像格式,块以标头和块大小开头,之后是块的内容

内容可能包含类似于某些标头的字节,因此有必要“知道”接下来的 x 个字节不会被“解析”,即应该跳过它们。比如说,如何用 PEG 来表达这一点?换句话说,“右括号”由内容的长度表示。

4

2 回答 2

0

实际上,几乎所有的解析器构造都需要一些巧妙的技巧来克服解析器的局限性。

纯上下文无关的解析器不能做 Python;您列出的所有解析器技术都弱于纯上下文无关,因此它们也无法做到。词法分析器中用于跟踪缩进并生成 INDENT/DEDENT 标记的 hack 将缩进问题转化为显式的“括号”,这很容易被上下文无关的解析器处理。

大多数二进制文件也无法处理,因为它们通常在某处包含长度为 N 的列表,其中 N 在遇到列表主体之前提供(这是您给出的示例)。同样,您可以通过更复杂的 hack 解决此问题;有些东西必须保留一堆嵌套列表长度,并且解析器必须在它从一个列表元素移动到下一个列表元素时发出信号。最上面的长度计数器递减,解析器返回一个信号“减少”或“移位”。其他更复杂的链接结构通常很难以这种方式解析。让解析器以这种方式合作并不总是那么容易。

于 2014-09-18T17:05:58.780 回答
0

问题中的两个示例都不是上下文无关的,因此严格来说,它们不能用上下文无关语法进行解析。但实际上,它们都很容易解析。

Python 算法在 Python参考手册中有很好的描述(尽管您需要在上下文中阅读它。)描述的是一个预处理步骤,其中行开头的空白被系统地替换为INDENTDEDENT标记。

澄清一下:这并不是一个真正的预处理步骤,重要的是要观察它发生隐式和显式行连接之后。(参考手册中的前面部分描述了这些过程。)特别是,行在括号、大括号和方括号内隐式连接,因此该过程与解析交织在一起。

实际上,行连接和缩进算法都可以通过编程方式完成;通常,这些将在自定义扫描器(标记器)中完成,该扫描器同时维护一堆括号和缩进级别。然后可以使用正常的上下文无关算法解析标记流,但是标记器——尽管它可能使用正则表达式——需要上下文敏感的逻辑(例如计算空格)。[注1]

类似地,包含显式大小的格式(例如大多数序列化格式,包括 PNG 文件、Google protobufs 和 HTTP 分块编码)不是上下文无关的,但显然很容易标记化,因为标记器只需读取长度然后读取那么多字节。

有多种上下文相关的形式,这些肯定有它们的用途,但在实际解析中,最常见的策略是使用图灵等效的形式(例如任何编程语言,可能增加了类似的扫描仪生成器flex)分词器和解析器的上下文无关形式。[笔记2]


笔记:

  1. Python 缩进不是上下文无关的可能不是很明显,因为上下文无关语法可以接受某些类别的一致。例如,(所有偶数长度回文的语言)是上下文无关的,就像.{ωω-1 | ω∈Σ*}{anbn}

    但是,这些示例无法扩展,因为在上下文无关语言中唯一可能的计数协议是括号。因此,虽然回文是上下文无关的(您可以使用单个堆栈实现检查),但显然非常相似的不是,也不是{ωω | ω∈Σ*}{anbncn}

  2. 一种这样的形式是“常规”表达式中的反向引用,这可能在某些 PEG 实现中可用。反向引用允许表达多种上下文相关语言,但不允许表达所有上下文无关语言。不幸的是,带有反向引用的正则表达式在实践中确实很糟糕,因为确定字符串是否与带有反向引用的正则表达式匹配的问题是 NP 完全的。您可能会在姊妹 SE 网站上发现这个问题很有趣。(并且您可能希望以可以在该网站http://cs.stackexchange.com上提出的方式重新表述您的问题。)

于 2014-09-18T17:07:12.187 回答