Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ember.js/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parsing LL(1)解析——使用递归优先选项的优先(A)_Parsing_Compiler Construction_Grammar_Context Free Grammar_Ll - Fatal编程技术网

Parsing LL(1)解析——使用递归优先选项的优先(A)

Parsing LL(1)解析——使用递归优先选项的优先(A),parsing,compiler-construction,grammar,context-free-grammar,ll,Parsing,Compiler Construction,Grammar,Context Free Grammar,Ll,如何将FIRST()规则应用于产品,例如: A->AAb | Ab | s 其中A为非端子,b、s为端子 备选方案1和2的第一(A)也是A,但这将在FIRST的无限应用中结束,因为我需要一个终端来获取第一个集合?要计算第一个集合,通常需要执行定点迭代。也就是说,您从一个小的值集开始,然后迭代地重新计算第一个值集,直到这些值集收敛 在本例中,您将首先注意到生产→ s表示第一个(A)必须包含{s}。因此,首先设置(A)={s} 现在,您将遍历A的每个产品,并根据到目前为止计算的第一个集合的知识首先更

如何将FIRST()规则应用于产品,例如:

A->AAb | Ab | s

其中A为非端子,b、s为端子


备选方案1和2的第一(A)也是A,但这将在FIRST的无限应用中结束,因为我需要一个终端来获取第一个集合?

要计算第一个集合,通常需要执行定点迭代。也就是说,您从一个小的值集开始,然后迭代地重新计算第一个值集,直到这些值集收敛

在本例中,您将首先注意到生产→ s表示第一个(A)必须包含{s}。因此,首先设置(A)={s}

现在,您将遍历A的每个产品,并根据到目前为止计算的第一个集合的知识首先更新。例如,规则

A→ AAb

意味着您应该更新FIRST(A)以包含FIRST(AAb)的所有元素。这不会导致对第一个(A)的更改。然后你去

A→ Ab

您再次更新FIRST(A)以包含FIRST(Ab),这也是一个禁止操作。最后,您访问

A→

因为第一个(A)已经包含s,所以这不会引起任何变化

因为在这个迭代中没有任何变化,所以最终会得到FIRST(A)={s},这确实是正确的,因为从A开始的任何派生最终都会产生一个
s
作为它的第一个字符

要了解更多信息,您可能会发现有用的(这里是)。它们详细描述了自顶向下的解析是如何工作的,以及如何迭代地计算第一个集合

希望这有帮助

您的语法规则与您已经意识到的语法规则相同,并且将使用LL解析器

因此,您需要先摆脱左递归,然后才能计算规则的第一个集合。

我的是西班牙语,但算法是英语的。这是一种先计算的方法:

是字母表(终端),
N
是非终端集,
p
是产品集(规则),
ε
是空字符串,
⋅k
被连接修剪为
k
位置。请注意
∅ ⋅kx=∅,将两个集合串联在一起会产生笛卡尔乘积中元素的串联

手工计算第一组的最简单方法是每次算法迭代使用一个表

F(A) = ∅

F'(A) = F(A) ⋅1 F(A) .1 F(b) U F(A) .1 F(b) U F(s)
F'(A) = ∅  ⋅1 ∅ ⋅1 {b} U ∅  ⋅1 {b} U {s}
F'(A) = ∅ U ∅ U {s} 
F'(A) = {s}

F''(A) = F'(A) ⋅1 F'(A) .1 F'(b) U F'(A) .1 F'(b) U F'(s)  
F''(A) = {s} ⋅1 {s} ⋅1 {b} U {s} ⋅1 {b} U {s}
F''(A) = {s} U {s} U {s}
F''(A) = {s}

我们完成了,因为
F'=F'
,所以
FIRST=F'
,和
FIRST(A)={s}

虽然这是真的,但我认为OP的问题是关于计算第一组,即使语法是左递归的,这也是可能的。问题是关于计算第一组,对于左递归语法也可以这样做。@Apalala-你确定吗?符号
b
肯定不在第一个(A)中。我所知道的计算第一个集合的算法是,在第一个集合中播种所有的结果,从一个终端开始,然后从那里开始。@Apalala-或者,如果你不以这种方式播种所有东西,你就不会通过查看非终端的第一个集合来计算第一个集合,除非非终端可以产生ε。这意味着更新规则会将FIRST(A)添加到FIRST(A)中,这会将空集添加到自身中。您可以首先使用
A->b
形式的规则的终端进行种子设定,但这还不够通用。但我投反对票的原因是,你建议当从
A->AAb
计算第一个时,只需查看第一个
A
,这是错误的,因为,尽管不是在这种情况下,可能是
A=*=>ε
,这将使
第一个(A)
包含
b
。请参阅我关于第一个的一般解决方案的答案。@Apalala-我已经教了两次编译器课程,我很有信心在进行第一个集合计算时不会忽略非终结符,除非您明确发现该非终结符的第一个集合包含ε。你不会乐观地看过去的非终端。这有意义吗?你是对的,第一个[1],但不是第一个[k]。我对你的答案进行了编辑,使之更一般、更正确。我希望你不介意。
F(A) = ∅

F'(A) = F(A) ⋅1 F(A) .1 F(b) U F(A) .1 F(b) U F(s)
F'(A) = ∅  ⋅1 ∅ ⋅1 {b} U ∅  ⋅1 {b} U {s}
F'(A) = ∅ U ∅ U {s} 
F'(A) = {s}

F''(A) = F'(A) ⋅1 F'(A) .1 F'(b) U F'(A) .1 F'(b) U F'(s)  
F''(A) = {s} ⋅1 {s} ⋅1 {b} U {s} ⋅1 {b} U {s}
F''(A) = {s} U {s} U {s}
F''(A) = {s}