我毫无理由地实现了LALR解析表的自动构建。这个解析器有两种风格,LALR(0)和LALR(1),其中数字表示预测量。
我对于前瞻意味着什么感到困惑。
如果我的输入流是' abc'我有以下产品,我需要0预测,还是1?
P :== a E
同样的问题,但我只能通过查看' a'而不能提前选择正确的P制作。在输入中。
P :== a b E | a b F
我还有一些困惑,因为我不认为后面的P-productions真的发生在构建LALR解析器生成器时。原因是当我们计算闭包时,语法会自动被左计算。
我是working through this page并且在我到达第一个/后续部分之前一直很好。我的问题是,我不知道为什么我们正在计算这些东西,所以我无法在脑海中抽象出来。
我几乎认为前瞻与转移输入无关,而是决定何时 reduce 。
我一直在阅读龙书,但它与塔伦蒂诺剧本一样线性。对于已经知道如何做的人来说,这似乎是一个很好的参考。
答案 0 :(得分:4)
在学习自下而上解析(例如LALR)时,您需要做的第一件事是要记住它与自上而下的解析完全不同。自上而下的解析以非终结符号(生产的左侧(LHS))开始,并猜测要使用哪个右侧(RHS)。另一方面,自下而上的解析首先确定RHS,然后确定选择哪种LHS。
更具体地说,自下而上的解析器将传入的令牌累积到队列中,直到右侧位于队列的右端。然后通过将RHS替换为相应的LHS来减少该RHS,并检查适当的RHS是否位于修改的累积输入的右边缘。它继续这样做,直到它决定输入中的那个点不会再发生减少,然后读取一个新的令牌(换句话说,取下一个输入令牌并转移它到队列的末尾。)
这一直持续到读取最后一个令牌并执行所有可能的缩减,此时如果剩下的是单个非终端,即“起始符号”,则接受解析。
解析器不一定要因为它出现在当前队列的末尾而减少RHS,但它不能减少不在队列末尾的RHS。这意味着它必须在转移任何其他令牌之前决定是否减少。由于决定并不总是显而易见的,因此它可以检查一个或多个尚未读取的令牌(“超前令牌”,因为它正在向前看输入)以便做出决定。但它只能查看下一个k
令牌,其值为k
,通常为1.
这是一个非常简单的例子;以逗号分隔的列表:
1. Start -> List
2. List -> ELEMENT
3. List -> List ',' ELEMENT
我们假设输入为:
ELEMENT , ELEMENT , ELEMENT
一开始,输入队列为空,由于没有RHS为空,唯一的选择是转移:
queue remaining input action
---------------------- --------------------------- -----
ELEMENT , ELEMENT , ELEMENT SHIFT
在下一步,解析器决定减少使用生产2:
ELEMENT , ELEMENT , ELEMENT REDUCE 2
现在队列末尾有List
,因此解析器可以减少使用生产1,但它决定不基于它看到,的事实传入的输入。这种情况持续了一段时间:
List , ELEMENT , ELEMENT SHIFT
List , ELEMENT , ELEMENT SHIFT
List , ELEMENT , ELEMENT REDUCE 3
List , ELEMENT SHIFT
List , ELEMENT SHIFT
List , ELEMENT -- REDUCE 3
现在,先行标记是“输入结束”伪标记。这次,它决定减少:
List -- REDUCE 1
Start -- ACCEPT
并且解析成功。
这仍然留下一些问题。首先,我们如何使用FIRST和FOLLOW集?
作为一个简单的答案,如果不知道可能跟随非终端的非终端的FIRST集,则无法计算非终端的FOLLOW集。我们可以决定是否应该执行减少的一种方法是查看前瞻是否在减少的目标非终端的FOLLOW集中;如果没有,肯定不应该进行减少。该算法足以满足上述简单语法,例如:,的前瞻不可能减少Start -> List
,因为,不在{ {1}}。可以通过这种方式解决唯一冲突的语法是FOLLOW(Start)
语法(其中SLR
代表“简单”,它当然是)。
对于大多数语法来说,这还不够,还需要进行更多的分析。符号可能位于非终端的FOLLOW集中,但不在导致当前堆栈配置的上下文中。为了确定这一点,我们需要更多地了解我们如何进入当前配置;各种可能的分析会导致S
,LALR
和规范IELR
解析,以及其他可能性。