【问题标题】:Are regexes an acceptable method for analyzing syntax?正则表达式是分析语法的可接受方法吗?
【发布时间】:2013-09-12 20:39:55
【问题描述】:

如果这个问题对某些人来说很明显,请原谅我,但我正在尝试自学如何编写解释器。我在 python 中执行此操作,我已经编写了 Lexer。

我已经创建了我的令牌列表,但我遇到的问题是构建解析树。我对从这里去哪里有了某种想法,但我不确定我的想法是否正确。

这是我在语法中为使用正则表达式的简单算术表达式定义的语法。

<a_expression> = <identifier | number> <operator> <identifier | number>

但是,如果我的解析器从我的词法分析器接收到与此模式匹配的标记流:

<identifier | number> <operator> <identifier | number> <operator> <identifier | number>

我该如何解析这个,因为它有两个运算符和三个操作数,而不是只有两个操作数?

此外,如何处理 n 个操作数和 n-1 个运算符?我觉得这应该递归地完成,但我不确定是否需要为不同类型的表达式定义更多解析器或从这里开始。我可以将 n 个操作数和 n-1 个运算符的模式与正则表达式匹配吗?

【问题讨论】:

  • 一个正则表达式是否适合解析你的语法,取决于你的语法(即你的语法)是否也是正则的,或者另一个 Chomsky 类的(上下文无关等)。对于 type-0 语法,您需要一台图灵机,对于 type-1 需要一个线性有界自动机,对于 type-2 需要一个下推自动机,并且只有 type-3 可以被正则表达式读取。
  • @Hyperboreus:完美答案;您应该将其作为答案发布(最好通过更多解释、非常规语法示例、一些链接等对其进行扩展)。

标签: python regex parsing interpreter lexer


【解决方案1】:

虽然今天的“常规”表达式并未严格归入Regular Languages 的范畴,但您会发现您需要一个更强大的工具来完成您想做的事情。

上下文无关语法是您想要的,并且有一些工具可以用 Python 编写 CFG。最值得注意的是pyparsing,但是您也可以查看 Haskell 的 Parsec 库的一个端口,称为 Pysec。

【讨论】:

  • pyparsing 特别有趣,因为您可以使用正则表达式和 LL 子集的组合来构建混合解析器。 (许多语言都有大的常规子集,并且更容易用正则表达式来考虑。)我认为 OP 正试图从头开始构建解析器作为学习练习......但它仍然可能值得研究 pyparsing(两者许多解析器示例及其源代码)用于此目的。
  • 但是使用 flex/bison,你不是在学习如何编写递归下降解析器,你只是在学习如何编写一个规范,bison 可以用来为你生成一个。 (此外,即使您确实想使用 bison,也不必使用 C;有几个不同的 Python 包装器可以让您将语义代码插入为 Python 而不是 C。 ) 当然,第一次使用 bison,只是为了了解 CFG 的外观以及 LALR 解析器可以做什么,在尝试从头开始编写自己的 LALR 解析器之前,这可能是一个很好的第一步……
【解决方案2】:

一个正则表达式是否适合解析你的语法,取决于你的语法(即你的语法)是否也是正则的,或者是另一个 Chomsky 类的。

对于 0 型(无限制)语法,您需要一台图灵机。

对于类型 1(上下文相关),您将需要一个线性有界自动机(或上述任何一种)。

对于类型 2(无上下文),您将需要一个下推自动机(或上述任何一种)。

并且只有 type-3 (regular) 可以被正则表达式(或以上任何一个)读取。

您可以找到further readings,例如在维基百科。

【讨论】:

  • 我认为为每种类型取一个简短的名称会很有帮助,因为除非他们已经知道答案,否则没有人会知道“type-2”是什么意思,但“无上下文”可能更有意义。我已经编辑了它们;如果您想恢复它或以不同的方式进行操作,请继续。
【解决方案3】:

具有优先级的中缀算术不是常规语言。正则表达式只适用于解析正则语言。 (现代正则表达式实现不仅仅是正则表达式,它们实际上可以解析大多数上下文无关的语言……但其中一些需要指数级的时间,而且预测哪些语言并非易事。)

但它是一种上下文无关的语言。有关简要说明,请参阅 Context-free grammar 上的 Wikipedia 文章。上下文无关语法适用于解析常规语言和上下文无关语言。

但是,许多非常规语言不需要 CFG 的全部功能。

两个重要的类是LL- 或LR-可解析的(线性时间)。 (这些变体,尤其是 LALR 和 SLR,也很重要。)例如,Python 可以(并且至少在参考实现中)由 LL(1) 解析器解析。

您的语言适合 LR(1) 的一个更具限制性的子集OP。事实上,顾名思义(“OP”是“Operator Precedence”的缩写),它就是范例。并且 OP 解析器比更通用的解析器更容易手工编写。因此,如果您要从头开始构建自定义解析器,那么您可能希望在这里使用它。

【讨论】:

  • 惊人:当我在互联网上搜索 Python 语法所属的语言类时,这个答案(截至今天,世界上任何人每 27 天只查看一次)是唯一有用的结果。所以 LL(1) 它是。 (我猜它的语义分析不是那么简单。)
猜你喜欢
  • 1970-01-01
  • 2017-06-29
  • 2014-02-02
  • 1970-01-01
  • 2012-05-06
  • 2012-07-18
  • 1970-01-01
  • 2020-01-13
  • 2017-11-07
相关资源
最近更新 更多