【问题标题】:Is there a general way to convert an unambiguous context-free-grammar into a LALR(1) grammar?有没有一种通用的方法可以将明确的上下文无关语法转换为 LALR(1) 语法?
【发布时间】:2013-08-28 21:41:31
【问题描述】:

我正在尝试为以下语法创建一个 LALR(1) 解析器并发现一些移位/减少冲突。

S := expr
expr := lval | ID '[' expr ']' OF expr
lval := ID | lval '[' expr ']'

因此解析器无法正确解析字符串“ID[ID]”。 我的问题是,

  1. 是否有任何通用方法可以将此类非 LALR(1) 语法转换为 LALR(1) 语法?
  2. 如果两个语法生成完全相同的语言,并且我们知道其中一个不是 LALR(1),我们能否知道另一个是否是 LALR(1)?

上面提到的语法只是一个例子,我真正想知道的是解决这些语法问题的一般方法。欢迎任何建议或阅读建议。

提前致谢。

【问题讨论】:

    标签: algorithm parsing context-free-grammar lalr lr


    【解决方案1】:

    1 .有没有什么通用的方法可以将这种非 LALR(1) 文法转换为 LALR(1) 文法?

    没有。将任意上下文无关文法 (CFG) 转换为 LALR(1) 文法可能会也可能不会。此外,如果您有 CFG 和 LALR(1) 语法,您无法判断它们是否识别相同的语言。 (更糟糕的是,没有算法可以告诉您任意 CFG 是否能够识别其字母表中所有可能的字符串。)

    2 。如果两个文法生成完全相同的语言,并且我们知道一个不是 LALR(1),我们能知道另一个是否是 LALR(1)?

    再次,不。如上所述,没有算法可以验证两种语法是否生成相同的语言,但即使假设您知道两种语法生成相同的语言,其中一个不是 LALR(1) 的事实并不能告诉您另一个一个。

    但是,有一个有用的结果。如果你有一个有限 k > 1 的 LALR(k) 文法,那么你可以生成一个 LALR(1) 文法。换句话说,对于 k > 1,不存在 LALR(k) language 这样的东西;如果一种语言有 LALR(k) 文法,那么它对任何 k' 都有一个 LALR(k') 文法,满足 1 ≤ k'

    但是,这对您的语法没有帮助,因为无法通过增加对任何有限值的前瞻来消除冲突。

    不过,有一种简单的方法可以消除这种特殊的班次减少冲突,而且这种技术通常很有效。考虑两个相互冲突的规则:

    lval := lval '[' expr ']'
    expr := ID   '[' expr ']' OF expr
    

    问题在于,在第一种情况下,ID 必须立即减少为lval(或至少在以下expr 减少之前),但在第二种情况下它可能不会减少为@ 987654326@。但是在我们减少expr 并遇到OF(或没有)之前,我们无法判断我们处于哪种情况。

    如果我们可以在不进行内部 lval 归约的情况下完成 lval 产生式,那么我们就不会有问题,因为当 ] 后面的标记可见时,实际的归约就会发生。

    这可能有一个技术术语,但我不知道。我一直把它描述为“减少延迟”,而且在很多情况下并不是很困难:

    lval' := ID `[` expr `]`
          |  lval' `[` expr `]`
    lval  := ID
          |  lval'
    expr  := lval
          |  ID '[' expr ']' OF expr
    

    【讨论】:

    • 一个非常有用的答案。关于您在答案中使用的技术的问题,我如何才能找到这些语法转换的常用技术?非常感谢。
    • @MingyanGuo:我希望我有一个参考。我敢肯定我自己没有想到那个,但我无法用谷歌搜索引文,而且我已经使用了很长时间,以至于我不记得它来自哪里。对不起。不可判定性结果简单且众所周知;它基于构建表示图灵机计算的语法。我很确定它在 Hopcroft&Ullman 中。我从 Sippu&Soisalon-Soinenen (Parsing Theory) 得到了 LALR(k>1) 减少,但我认为您可以在任何好的参考资料中找到它。
    • 其实现在想想,我使用的技术和S&S-S描述的LR(k)覆盖算法很相似。假设你为一个文法构造了一个 LR(k) 解析器;实际上,您已经为每个产品计算了一组可能的前瞻。因此,您可以用一组非终结符 (N,L1,L2...Lk-1) 替换每个非终结符 N,计算 RHS 中每个非终结符的替换。这显然给了你一个 LR(1) 语法。有时你可以用非规范的前瞻(即包括非终端)做类似的事情。我认为这就是我所做的。
    • 我明白了,我需要了解一些更通用的语法和解析技术。谢谢。
    • 有更简单的方法。使用 GLR 解析器;他们将解析任何上下文无关的语法。众所周知,C++ 很难使用 LALR(1) 进行解析,例如,您可以做到这一点,但只能通过将词法分析器/解析器/符号表模块破解为错综复杂的耦合。对比见stackoverflow.com/a/6320330/120163
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-28
    • 1970-01-01
    • 2020-01-12
    • 2018-07-13
    • 2022-01-03
    • 2014-04-26
    相关资源
    最近更新 更多