📜  为什么在编译器设计中先行而后行?

📅  最后修改于: 2021-06-28 06:56:21             🧑  作者: Mango

为什么要第一?
在“语法分析简介”的上一篇文章中我们看到了回溯的需要,这实际上是一个复杂的实现过程。有一种更简单的方法来解决此问题:

如果编译器会事先知道“应用生产规则时生成的字符串的第一个字符”是什么,并将其与看到的输入字符串的当前字符或标记进行比较,则可以明智地采用决定要应用哪种生产规则。

让我们采用与上一篇文章相同的语法:

S -> cAd
A -> bc|a 
And the input string is “cad”. 

因此,在上面的示例中,如果知道在读取输入字符串中的字符“ c”并应用S-> cAd之后,输入字符串中的下一个字符为“ a”,则它将忽略生产规则A-> bc(因为’b’是该生产规则产生的字符串的第一个字符,而不是’a’),并直接使用生产规则A-> a(因为’a’是由此生产规则产生的字符串的第一个字符生产规则,并且与输入字符串的当前字符相同,该字符也为’a’ )。
因此,可以验证的是,如果编译器/解析器知道可以通过应用生产规则而获得的字符串的第一个字符,那么它可以明智地应用正确的生产规则来获取给定输入字符串的正确语法树。

为什么要关注?
解析器面临另一个问题。让我们考虑下面的语法来理解这个问题。

A -> aBb
 B -> c | ε
 And suppose the input string is “ab” to parse. 

由于输入中的第一个字符是a,因此解析器将应用规则A-> aBb。

A
        / |  \
      a   B   b

现在的输入字符串的第二个字符是B和非终端导出程序检查是B,但解析器无法获得的B任何字符串推导包含B中第一个字符。
但是语法确实包含一个生成规则B->ε,如果应用该规则,则B将消失,并且解析器将获得输入“ ab”,如下所示。但只有当它知道后面乙方在生产规则中的字符是一样的,在输入当前字符的解析器可以应用它。

在A-> aBb的RHS中,b跟随非终端B,即FOLLOW(B)= {b},并且当前读取的输入字符也是b。因此,解析器将应用此规则。并且能够从给定的语法中获得字符串“ ab”。

A                    A
        /  |  \              /    \                                                
      a    B    b    =>     a      b       
           |
           ε 

因此,如果需要从解析树生成字符串,则FOLLOW可以使Non-terminal消失。

结论是,我们需要找到给定语法的FIRST和FOLLOW集,以便解析器可以在正确的位置正确应用所需的规则。

在下一篇文章中,我们将讨论FIRST和FOLLOW的正式定义,以及一些简单的规则来计算这些集合。

语法分析测验