【问题标题】:Convert regex pattern to LL1 parser将正则表达式模式转换为 LL1 解析器
【发布时间】:2021-12-02 17:38:26
【问题描述】:

背景:我正在尝试解决这个 leetcode 问题:regular-expression-matching。我的方法是实现一个 LL(1) 解析器生成器,对于这个问题可能有点矫枉过正,但这只是脑力锻炼。

我只有解析器理论的入门级知识,如果我问的是一个愚蠢的问题,请原谅。

所以,这个测试用例我失败了。要求是正则表达式模式应该匹配整个字符串

Regex: a*a
Input: aaa

我不知道如何将此模式转换为 LL(1) 解析器。

在我看来,a*a 模式可以转换为生产规则:

S -> Aa      # a*a
A -> aA | ε  # a*

解析表:

a $
S S -> Aa
A A -> aA A -> ε

解析步骤如下:

0: S$    aaa$  # use [S,a]
1: Aa$   aaa$  # use [A,a]
2: aAa$  aaa$  # eat 'a'
3: Aa$   aa$   # use [A,a]
4: aAa$  aa$   # eat 'a'
5: Aa$   a$    # use [A,a]
6: aAa$  a$    # eat 'a'
7: Aa$   $     # use [A,$]
8: a$    $     # Error!

正确的匹配应该是:

a* -> aa
a -> a

但我得到的是:

a* -> aaa
a -> Error!

我不知道我错过了哪一部分????。

【问题讨论】:

  • 您不能为此构造 LL(1) 解析器。您可以使用递归下降解析器或 LL(2) 解析器,因为那是 LL(2) 语法。这是一个或多个aa+可以识别相同的语言。
  • 左重构可能会对您有所帮助,因为您似乎对从正则表达式生成的语法没有限制。
  • 您的 LL(1) 解析器表不正确。尝试使用GrammophoneKocman's LL(k) generator 来检查您的解决方案。在转换为语法之前,您肯定希望将诸如“a*a”之类的模式重写为“a+”。

标签: regex parsing


【解决方案1】:

在解析步骤 5 中,解析器应该使用 [A,$] 而不是 [A,a]。但它只能通过向前看或回溯来做出这个决定。两者都超出 LL(1)。

问题的原因在于您的生产规则。存在 FIRST/FOLLOW 冲突:FIRST(A) 包含 ε,而 FIRST(A) 和 FOLLOW(A) 都包含 一个。这里用一个例子来解释:

https://inst.eecs.berkeley.edu/~cs164/sp18/discussion/04/04-solutions.pdf

更直观地说,您要求解析器向前看,超出S -> Aa 中的a,以便能够决定a 应该使用多少终端A -> aA | ε

基本上,LL(1) 解析器无法解析a*a。它必须首先重写为aa*。可能有一些算法可以成功地重写 a*aaa* 这样简单的东西,但不可能将所有可能的正则表达式都重写为 LL(1) 语法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-17
    • 1970-01-01
    • 2011-10-02
    • 2016-04-02
    相关资源
    最近更新 更多