问题中的两个示例都不是上下文无关的,因此严格来说,它们不能用上下文无关语法进行解析。但实际上,它们都很容易解析。
Python 算法在 Python参考手册中有很好的描述(尽管您需要在上下文中阅读它。)描述的是一个预处理步骤,其中行开头的空白被系统地替换为INDENT
和DEDENT
标记。
澄清一下:这并不是一个真正的预处理步骤,重要的是要观察它发生在隐式和显式行连接之后。(参考手册中的前面部分描述了这些过程。)特别是,行在括号、大括号和方括号内隐式连接,因此该过程与解析交织在一起。
实际上,行连接和缩进算法都可以通过编程方式完成;通常,这些将在自定义扫描器(标记器)中完成,该扫描器同时维护一堆括号和缩进级别。然后可以使用正常的上下文无关算法解析标记流,但是标记器——尽管它可能使用正则表达式——需要上下文敏感的逻辑(例如计算空格)。[注1]
类似地,包含显式大小的格式(例如大多数序列化格式,包括 PNG 文件、Google protobufs 和 HTTP 分块编码)不是上下文无关的,但显然很容易标记化,因为标记器只需读取长度然后读取那么多字节。
有多种上下文相关的形式,这些肯定有它们的用途,但在实际解析中,最常见的策略是使用图灵等效的形式(例如任何编程语言,可能增加了类似的扫描仪生成器flex
)分词器和解析器的上下文无关形式。[笔记2]
笔记:
Python 缩进不是上下文无关的可能不是很明显,因为上下文无关语法可以接受某些类别的一致。例如,(所有偶数长度回文的语言)是上下文无关的,就像.{ωω-1 | ω∈Σ*}
{anbn}
但是,这些示例无法扩展,因为在上下文无关语言中唯一可能的计数协议是括号。因此,虽然回文是上下文无关的(您可以使用单个堆栈实现检查),但显然非常相似的不是,也不是{ωω | ω∈Σ*}
{anbncn}
一种这样的形式是“常规”表达式中的反向引用,这可能在某些 PEG 实现中可用。反向引用允许表达多种上下文相关语言,但不允许表达所有上下文无关语言。不幸的是,带有反向引用的正则表达式在实践中确实很糟糕,因为确定字符串是否与带有反向引用的正则表达式匹配的问题是 NP 完全的。您可能会在姊妹 SE 网站上发现这个问题很有趣。(并且您可能希望以可以在该网站http://cs.stackexchange.com上提出的方式重新表述您的问题。)