在令牌流

时间:2017-01-08 10:22:08

标签: algorithm parsing compiler-construction antlr ll

我试图理解LL解析算法中最左边的派生。这个link生成视角解释了它。即它显示了如何遵循最左边的派生以从一组规则生成特定的标记序列。

但我正在考虑相反的方向。给定一个令牌流和一组语法规则,如何找到 正确的步骤以通过最左边的推导应用一组规则?

让我们继续使用上述链接中的以下语法:

enter image description here

给定的令牌序列是:1 2 3

一种方法是:

1 2 3
-> D D D 
-> N D D (rewrite the *left-most* D to N according to the rule N->D.)
-> N D (rewrite the *left-most* N D to N according to the rule N->N D.)
-> N  (same as above.)

但是还有其他方法可以应用语法规则:

1 2 3 - > D D D - > N D D - > N N D - > N N N

OR

1 2 3 - > D D D - > N D D - > N N D - > N N

但只有第一个推导最终会出现在一个非终端中。

随着令牌序列长度的增加,可以有更多方法。我认为推断出正确的推导步骤,需要2个先决条件:

  • 起始/根规则
  • 令牌序列

在给出这两个之后,找到导出步骤的算法是什么?我们是否必须将最终结果设为非终端?

1 个答案:

答案 0 :(得分:1)

LL解析的一般过程包括:

  • 预测堆栈顶部语法符号的生成(如果该符号是非终端),并将该符号替换为生产的右侧。

  • 使用下一个输入符号匹配堆栈顶部语法符号,同时丢弃它们。

匹配操作没有问题,但预测可能需要一个oracle。然而,出于解释的目的,只要其起作用,进行预测的机制是无关紧要的。例如,对于某个小整数k,每个可能的k输入符号序列只与最多一个可能的生成一致,在这种情况下,您可以使用查找表。在这种情况下,我们说语法是LL(k)。但你可以使用任何机制,包括魔法。只需要预测总是准确的。

在此算法的任何步骤中,部分派生的字符串是附加堆栈的消耗输入。最初没有消耗输入,并且堆栈仅由起始符号组成,因此部分派生的字符串(已应用0个派生)。由于消耗的输入仅由终端组成,并且算法只修改了堆栈的顶部(第一个)元素,因此很明显,部分派生的字符串系列构成了最左边的派生。

如果解析成功,将消耗整个输入并且堆栈将为空,因此解析将导致从起始符号输入的最左侧。

以下是您的示例的完整解析:

Consumed           Unconsumed   Partial      Production
Input      Stack   input        derivation   or other action
--------   -----   ----------   ----------   --------------- 
           N       1 2 3        N            N → N D
           N D     1 2 3        N D          N → N D
           N D D   1 2 3        N D D        N → D
           D D D   1 2 3        D D D        D → 1
           1 D D   1 2 3        1 D D        -- match --
1          D D       2 3        1 D D        D → 2
1          2 D       2 3        1 2 D        -- match --
1 2        D           3        1 2 D        D → 3
1 2        3           3        1 2 3        -- match --
1 2 3      --         --        1 2 3        -- success --

如果您阅读了最后两列,则可以看到从N开始到1 2 3结束的派生过程。在此示例中,只能使用魔法进行预测,因为任何 k 的规则N → N D不是LL( k );使用右递归规则N → D N将允许LL(2)决策过程(例如,如果至少有两个未消耗的输入令牌,则使用N → D N;否则N → D“。 )

您尝试制作的图表(以1 2 3开头,以N结尾)是自下而上解析。使用LR算法的自下而上解析对应于最右边的派生,但是需要向后读取派生,因为它以起始符号结束。