Home 自上而下分析
自上而下分析
取消

自上而下分析

一、开始

        从根部开始构建语法树

二、两大问题

    1、消除左递归

        (1)问题:无限递归

                根源是无限递归让编译器陷入死循环

        (2)分类

                a、直接左递归

                    A —> A+B | B

                    B —> int | (A)

                    修改为

                    A —> BA’

                    A’—> +BA’|ε

                b、非直接左递归

                    S —> Aa | b

                    A —> Sd | ε

                    v先变换成直接左递归

                    S —> Aa | b    

                    A —> Aad | bd | ε  (这里注意改的是A,而不是S)

                    v再消除左递归

                    S —> Aa | b

                    A —> bdA’| A’

                    A’ —> adA’| ε

        复杂一点的例子

            

    2、提取左因子

        (1)问题:一步推导存在多个产生式选择(推导不唯一)

                    根源是编译器不想回溯,即需要确定的知道下一步要干什么

        (2)解决方法

                A —>ab1 | ab2

                修改为

                A —> a A’ 

                A’—> b1 | b2

        复杂一点的例子

            

 

三、LL(1)文法

1、说明

    a、通过对文法加限制来保证没有回溯

    b、必须要先消除左递归,提取左因子,不然很容易发现得到的文法不是LL(1)的

    c、第一个L是从左向右读入数据,第二个L是最左推导,采用1的前看符号

2、FIRST集合

    (1)计算方法

        a、X—>a...    将终结符a加入集合中

        b、X—>ε      将ε加入集合中

        c、X—>Y...    剔除FIRST(Y)中的ε后加入集合中

        d、X—>Y1Y2...Yk(注意都是非终结符

                如果前k-1的FIRST中都有ε,就把所有FIRST(Y)剔除ε加入集合

                如果前k    的FIRST中都有ε,就把所有FIRST(Y)加入集合(包括ε)

3、FOLLOW集合

    (1)计算方法

        a、开始符号S    将$加入集合

        b、A—>αBβ    将FIRST(β)/ε加入B的集合中

        c、A—>αB       将FOLLOW(A)加入FOLLOW(B)中

        d、A—>αBβ,且ε属于FIRST(β),将FOLLOW(A)加入FOLLOW(B)中

    尤其注意这里的α,β都是文法的符号串

4、LL(1)文法要求

(1)A—> α | β,则要求FIRST(α) ∩ FIRST(β) = Φ

(2)若ε属于FIRST(β),则要求FIRST(α) ∩ FOLLOW(A) = Φ

5、LL(1)文法的特征

    没有左递归

    没有左因子

    不是二义的

6、递归下降的分析法

    从文法的起始符号开始 

    为每一个非终结符写一个函数

    这些函数可能是递归的

 

    每个函数的设计规则

        1、匹配FIRST集合:如果是非终结符匹配到的,转到该非终结符,如果是终结符匹配到的,成功匹配要删减输入串

        2、如果FIRST有ε,则按照FOLLOW集合匹配

        3、错误处理:对于FIRST没有ε的,匹配FOLLOW集合内容的,输出SYN错误,越过该函数

                                空白项的删除一个输入流符号

7、非递归下降的分析法

    借助栈和预测分析表

    预测分析表

        行:非终结符

        列:终结符(包括$)

        表项:推导式右部(按照FIRST集合加)

                    如果ε在FIRST集合中,把A->α加入每个FOLLOW(A)中

        空白项:错误

错误处理

        同步错误(FOLLOW记录的):弹栈

        空白错误:移除首部输入流记号

    举例

8、错误处理

    (1)同步:词法分析器和记号流良匹配的状态

            在出现不匹配错误时,可以放弃一些记号,直到达到同步状态,然后弹出非终结符,所以以下是出现错误情况下的选择走法

            同步集合的选择

                1、FOLLOW集合记录

                2、高层的开始符号加入到底层的同步集合中(如;避免遗漏错过一大段程序)

                3、也可以放置FIRST(A),但是注意这是在出错之后才去选择的

                4、推导式有空串,将该产生式作为优先考虑的推导式(会延迟错误的发现,但不会遗漏,可以减少错误恢复的非终结符)

            遇到同步记号,则将非终结符弹栈

    (2)空白:紧急恢复:抛弃一个输入记号

    (3)栈顶的终结符和指针指向的终结符不匹配:终结符弹栈


注意除了空白是抛弃输入符号,其他都是弹栈操作


预测分析器动作

 栈                    输入                    动作

$E                  id*id+id$            

$E_T               id*id+id$            输出E->TE_

.......................

 

 

 四元组

一组终结符,一组非终结符,开始符号,一组产生式

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

该博客文章由作者通过 CC BY 4.0进行授权。