以下文法是 LL(1) 吗?

Are the following grammars LL(1)?

S -> Abc|aAcb

A​​ -> b|c|ε

我认为第一个是LL(1)

S -> aAS|b

A​​ -> a|bSA

但问题是第二个。没有冲突问题,但是我觉得不满足右递归。 我不确定这些问题。

第一个语法不是 LL(1),因为有几个冲突,例如输入 bc,LL 解析器将需要 look-ahead 的 2 个标记来解析它:

  • 进入规则S
  • 进入规则A
  • 认字b
  • 加载下一个令牌c
  • 退出规则A
  • 预计还有一个b,但当前令牌是c
  • 回到A
  • 向后移动一个标记,再次移动到 b
  • 退出规则 A 不识别任何东西(因为 epsilon)
  • 识别引用规则 A 后的 b 字符,该字符在未使用任何标记的情况下“跳转”
  • 加载下一个令牌c
  • 认识c
  • 成功

对于输入 acb,您在 S 的第二个备选方案中有类似的情况。语法没有二义性,因为最终只有一种可能的语法树。它不是 LL(1),实际上是 LL(2)。

第二种语法是确定性的——只有一种方法可以解析根据语法有效的任何输入。这意味着它可以被 LL(1) 解析器用于解析。

我制作了一个工具 (Tunnel Grammar Studio),可以检测非确定性语法的语法冲突并生成解析器。 ABNF (RFC 5234) 中的这种语法类似于语法:

S = 'a' A S / 'b'
A = 'a' / 'b' S A

正确的递归本身不会在语法内部产生歧义。产生正确的递归歧义的一种方法是在这个语法中有一些悬空元素:

S = 'c' / 'a' S 0*1 'b'

您可以将其解读为:规则 S 识别字符 c 或字符 a 后跟规则 S 本身并且可能(零次或一次)后跟字符 b.

由于悬垂 b 字符,向上语法具有与右递归相关的歧义。这意味着对于输入 aacb,有不止一种方法来解析它:识别 S 中的第一个 a;再次进入S;认识第二个a;再次进入S并识别c;退出 S 一次;那么有两个选择: 情况一)识别b字符,退出S两次或情况二)先退出S一次,然后识别b字符。两种情况都是这些(来自 TGS 的可视化调试器的屏幕截图):

该文法因此是有歧义的(即不是 LL(1)),因为可以为某些有效输入生成不止一个语法树。对于此输入,可能的树只有两棵,但对于输入 aaacb 有三棵树,因为 aaacbb 有三棵树,因为可能有 3 个地方可以 'attach'两个 b 个字符,其中两个位置将有 b,一个将留空。对于输入 aaacbbb 当然只有一种可能的语法树,但是如果至少有一个输入有不止一种可能的语法树,则语法被定义为有歧义。