理论:LLk解析器与LLk语法解析器

问题描述

我关注的是Therms之间非常重要的区别:“ LL(k)解析器”和“ LL(k)语法解析器”。遇到LL(1)回溯解析器时,它可以{strong>是一个用于LL(k)语法的解析器,因为它可以解析它们,但是它的不能 {{ 1}}解析器,因为它不使用LL(k)标记从语法中的单个位置向前看,而是通过回溯可能的情况进行探索,而不管它仍使用k标记进行探索。 我说的对吗?

该问题可能会分解为执行预见的方式。如果前瞻实际上仍在使用回溯处理语法,则不会使其成为k解析器。要成为LL(k)解析器,解析器不得使用带有回溯机制的语法,因为那样的话,它将是“ LL(k)带有回溯的解析器,可以解析LL(1)语法”。 我又对吗?

我认为差异与以下期望有关:LL(k)解析器每个令牌使用LL(1)时间,而constant解析器最多使用LL(k)(线性每个令牌的前瞻时间),不是 k * constant,就像在回溯解析器中一样。

更新1:为简化起见-每个令牌,解析exponential time相对于LL(k)是指数运行还是相对于k线性运行?

更新2:我将其更改为k,因为问题与LL(k)的范围(整数或无穷大)无关。

解决方法

LL(k)解析器需要在内循环中的每个点执行以下操作:

  • 收集下一个 k 输入符号。由于这是在输入的每个点上完成的,因此可以通过将超前向量保持在循环缓冲区中,从而在恒定时间内完成此操作。

  • 如果预测堆栈的顶部是终端,则将其与下一个输入符号进行比较;要么两者都被丢弃,要么发出错误信号。显然,这是恒定的时间。

  • 如果预测堆栈的顶部是非终结符,则使用非终结符,当前状态和当前超前向量作为键来查询动作表。 (并不是所有的LL(k)解析器都需要维护一个状态;这是最通用的表示形式。但这并不会影响复杂性。)此查找也可以在恒定时间内完成,再次利用增量超前向量的性质。

  • 通常通过将所选产品的右侧推入堆栈来完成预测动作。天真的实现将花费与右侧长度成正比的时间,该长度与前瞻k或输入N的长度均不相关,而与语法本身。只需将引用推到右侧,就可以避免这项工作的可变性,因为引用可以像符号列表一样使用(因为在解析期间该列表不能更改)。

    但是,这还不是全部。执行预测动作不会消耗输入,并且有可能甚至可能为单个输入符号进行多个预测。同样,预测的最大数目仅与语法本身有关,与kN都不相关。

    更具体地,由于不能在不违反LL属性的情况下在同一位置两次预测相同的非终结点,因此预测的总数不能超过语法中的非终结点的数量。因此,即使您确实将整个右手侧压入堆栈,在连续的移位操作之间压入的符号总数也不能超过语法的大小。 (每个右侧最多可以推一次。实际上,一个给定非终端的只能推一个右侧,但是几乎每个非终端都可能只有一个右侧,所以如果仅将一个引用压入堆栈,则连续移位动作之间被压入的对象数(即,两个连续移位动作之间的预测动作数)不能超过该大小非终结字母的形式。 (但是,|V|可能是O(|G|)

我相信,Lewis and Stearns(1968)建立了LL(k)解析的线性,但是我现在手边没有该论文,所以我将向您介绍Sippu&Soisalon中的证明-Soininen的解析理论(1988),在第5章中针对强LL(K)(由Rosenkrantz & Stearns 1970定义)进行了证明,在第八章中对规范LL(K)进行了证明。

简而言之,LL(k)算法在转移两个连续的输入符号之间花费的时间预计为O(|G|),这与kN无关(并且,当然,对于给定的语法来说是恒定的。

这实际上与LL(*)解析器没有任何关系,因为LL(*)解析器不仅会尝试连续的LL(k)解析(无论如何都不可能)。对于Terence Parr提出的LL(*)算法(这是我所知的唯一参考文献,它定义了LL(*)的含义),在两次连续换档之间可以花费的时间没有限制。解析器可能会将前瞻性扩展到整个其余输入(因此,时间复杂度取决于输入的总大小),或者它可能会故障转移到回溯算法,在这种情况下,定义起来会更加复杂什么是“处理输入符号”。

,

建议您阅读 Aho Ullman Volume 1 的第 5.1 章。

https://dl.acm.org/doi/book/10.5555/578789

  1. LL(k) 解析器是一种 k 预测算法(k 是前瞻整数 >= 1)。
  2. LL(k) 解析器可以解析任何 LL(k) 文法。 (第 5.1.2 章)
  3. 对于所有 a,b 你有一个 LL(b) 语法也是一个 LL(a) 语法。但反过来就不是这样了。
  4. LL(k) 解析器是预测性的。所以没有回溯。
  5. 所有 LL(k) 解析器都是 O(n) n 是解析句子的长度。
  6. 了解 LL(3) 解析器的解析速度并不比 LL(1) 快,这一点很重要。但是 LL(3) 解析器可以比 LL(1) 解析更多的语法。 (见第 2 点和第 3 点)