如何扩展此语法的项目集?

问题描述

我有这个语法

E -> E + i
E -> i

增强语法

E' -> E
E -> E + i
E -> i

现在,我尝试扩展项目集0

I0)
 E' -> .E
+E  -> .E + i
+E  -> .i

然后,由于我在.E中有I0,所以我将其扩展,但是随后我将得到另一个E规则,依此类推,这是我的第一个疑问。

假设没问题,下一个项目集是

I0)
 E' -> .E
+E  -> .E + i
+E  -> .i

I1) (I moved the dot from I0,no variables at rhs of dot)
E' -> E.
E -> E. + i
E -> i.

I2) (I moved the dot from I1,no vars at rhs of dot)
E -> E +. i

I3) (I moved the dot from I2,also no vars)
E -> E + i.

然后我将拥有这个DFA

I0 -(E,i)-> I1 -(+)-> I2 -(i)-> I3
              |                   |
              +-(∅)-> acpt <-(∅)--+

我丢失了一些内容,因为E -> E + i必须接受i + i + ..,但是DFA不会返回I0,所以对我来说似乎是错误的。我的猜测是它应该具有从I0到I0的过渡,但是我不知道该与点有关。

解决方法

您所说的项目集的“扩展”实际上是一个闭包。这就是我所见过的所有算法描述中所描述的方式(至少在教科书中)。像任何关闭操作一样,您只需继续进行转换,直到达到固定点为止。包括E的作品后,它们也会被包括在内。

但重要的一点是,您不是要构建DFA。您正在构建下推式自动机,而DFA只是其中的一部分。 DFA用于班次操作;转移新终端时(因为当前的解析堆栈不是句柄),您将根据DFA进行状态转换。但是您还可以将当前状态推送到PDA的堆栈中。

有趣的部分是当自动机决定执行归约时,它将生产的右侧替换为左侧的非终端,这会发生什么。 (位于堆栈顶部的右侧称为“句柄”。)要进行缩小,请展开堆栈,弹出每个右侧符号(以及相应的DFA状态),直到到达起始位置为止。生产。这样做是将DFA倒回到从右侧移出第一个符号之前的状态。 (请注意,只有在这一点上您才能确定使用了哪种生产方式。)如此重置DFA之后,您现在可以移动遇到的非终端,进行相应的DFA转换,然后继续进行解析。

此过程的基础是以下事实:解析器堆栈始终是“可行前缀”;也就是说,是一系列符号,它们是可以从起始符号中得出的某种右义形式的前缀。与上下文无关的语法的可行前缀集有趣的是,它是一种常规语言,因此可以被DFA识别。当“修剪”句柄(使用Knuth的原始词汇)时,上面给出的归约过程恰好表示该识别过程。

从这个意义上讲,使用什么过程来确定要修剪哪个句柄并不重要,只要它提供了有效的答案即可。例如,您可以在每次发现堆栈顶部有潜在的句柄时就派发解析,并与两个派生并行进行。使用聪明的堆栈管理,可以在最坏情况的O(n 3 )时间内对任何无上下文无关的语法进行并行搜索(如果语法不明确,则可以减少并行搜索)。这是对Earley解析器的非常粗略的描述。

但是在LR(k)解析器的情况下,我们要求语法是明确的,并且我们还需要通过从输入流中查看不超过k个符号来识别归约,因为k是固定的,所以是O(1)操作。如果在解析的每个点我们都知道是否减少,以及如果选择减少,那么可以按照我上面概述的方法来减少。对于固定的语法,每个缩减都可以在O(1)时间内执行(因为特定语法中右侧的最大大小是固定的),并且由于解析的缩减次数在线性的大小上是线性的输入,整个解析可以在线性时间内完成。

这有点非正式,但是我希望它可以作为一种直观的解释。如果您对正式证明感兴趣,那么Donald Knuth最初的1965年论文(从左向右的语言翻译)很容易找到,并且随着这些事情的发展而具有很高的可读性。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...