语法分析:自上而下分析

概述

本节将介绍编译程序构造中的一些典型的语法分析方法。语法分析器的功能,自上而下分析面临的问题,LL(1)分析法

语法分析器的功能

语法分析是编译过程的核心部分。它的任务是在词法分析识别出单词符号串的基础上,分析并判定程序的语法结构是否符合语法规则。

语言的语法结构是用上下文无关文法描述的。因此,语法分析器的工作本质上就是按文法的产生式,识别输入符号串是否为一个句子。这里所说的输入串是指由单词符号(文法的终结符)组成的有限序列。对一个文法,当给你一串(终结)符号时,怎样知道它是不是该文法的一个句子(“程序”)呢?这就要判断,看是否能从文法的开始符号出发推导出这个输入串,或者,从概念上讲,就是要建立一棵与输入串相匹配的语法分析树。
按照语法分析树的建立方法,我们可以粗略地把语法分析办法分成两类,一类是自上而下分析法,另一类是自下而上分析法。本章主要介绍自上而下分析法,下一章我们将介绍自下而上分析法。

自上而下分析面临的问题

现在来讨论自上而下的语法分析方法。顾名思义,自上而下就是从文法的开始符号出发,向下推导,推出句子。我们首先将简单地介绍自上而下分析的一般方法。这种方法是带“回溯”的。下一节,将着重讨论一种广为使用的不带回溯的递归子程序(递归下降)分析方法。
自上而下分析的主旨是,对任何输入串,试图用一切可能的办法,从文法开始符号(根结)出发,自上而下地为输入串建立一棵语法树。或者说,为输入串寻找一个最左推导。这种分析过程本质上是一种试探过程,是反复使用不同产生式谋求匹配输入串的过程。
实现这种自上而下的带回溯试探法的一个简单途径是让每个非终结符对应一个递归子程序。每个这种子程序可作为一个布尔过程。一旦发现它的某个候选与输入串相匹配,就用这个候选去扩展语法树,并返回“真”值;否则,保持原来的语法树和IP值不变,并返回“假”值。
上述这种自上而下分析法存在许多困难和缺点。
首先是文法的左递归性问题。一个文法是含有左递归的,如果存在非终结符P
PPa
含有左递归的文法将使上述的自上而下的分析过程陷入无限循环。即,当试图用P去匹配输入串时,我们会发现,在没有识别任何输入符号的情况下,又得重新要求P去进行新的匹配。因此,使用自上而下分析法必须消除文法的左递归性。
其次,由于回溯,就碰到一大堆麻烦事情。如果我们走了一大段错路,最后必须回头,那么,就应把已经做的一大堆语义工作(指中间代码产生工作和各种表格的簿记工作)推倒重来。这些事情既麻烦又费时间,所以,最好应设法消除回溯。
第三,在上述的自上而下分析过程中,当一个非终结符用某一候选匹配成功时,这种成功可能仅是暂时的。例如,就文法(4.1)而言,考虑输入串x**y。若对A首先使用第二个候选式,A将成功地把它的唯一子结匹配于输入串的第二个符号。但S的第三个子结y与第三个输入符号不匹配。因而,导致了无法识别输入串x**y是一个句子的事实。然而,若A首先使用它的第一个候选**,则整个输入串即可获得成功分析。这意味着,A首先使用第二个候选所得的成功匹配是虚假的。由于这种虚假现象,我们需要更复杂的回溯技术。一般说,要消除虚假匹配是很困难的。但若从最长的候选开始匹配,虚假匹配的现象就会减少一些。
第四,当最终报告分析不成功时,我们难于知道输入串中出错的确切位置。
最后,由于带回溯的自上而下分析实际上采用了一种穷尽一切可能的试探法,因此,效率很低,代价极高。严重的低效使得这种分析法只有理论意义,而在实践上价值不大。
后面,我们将集中讨论不带回溯的自上而下分析法。

LL(1)分析法

左递归消除

直接消除见诸于产生式中的左递归是比较容易的。假定关于非终结符P的规则为

P→Pa | b

其中b不以P开头。那么,我们可以把P的规则改写为如下的非直接左递归形式:

P→bP¢

P¢→aP¢|e ,e为空字)

这种形式和原来的形式是等价的,也就是说,从P推出的符号串是相同的。
如何消除一个文法的一切左递归呢?虽然困难不少,但仍有可能。如果一个文法不含回路(形如PP的推导),也不含以e为右部的产生式,那么,执行下述算法将保证消除左递归(但改写后的文法可能含有以e为右部的产生式)。
消除左递归算法:

  1. 把文法G的所有非终结符按任一种顺序排列成P1,P2,…,Pn;按此顺序执行;
  2. FOR i:=1 TO n DO
    BEGIN
    FOR j:=1 TO i-1 DO
    把形如Pi→Pjg的规则改写成
    Pi→d1g|d2g|…|dkg。其中Pj→d1|d2|…|dk是关于Pj的所有规则;
    消除关于Pi规则的直接左递归性
    END
  3. 化简由2所得的文法。即去除那些从开始符号出发永远无法到达的非终结符的产生规则。

消除回溯、提左因子

欲构造行之有效的自上而下分析器,必须消除回溯。为了消除回溯就必须保证:对文法的任何非终结符,当要它去匹配输入串时,能够根据它所面临的输入符号准确地指派它的一个候选去执行任务,并且此候选的工作结果应是确信无疑的。也就是说,若此候选获得成功匹配,那么,这种匹配决不会是虚假的;若此候选无法完成匹配任务,则任何其它候选也肯定无法完成。换句话说,假定现在轮到非终结符A去执行匹配(或称识别)任务,A共有n个候选a1,a2,…,an,即A→a1 | a2 | … |an。A所面临的第一个输入符号为a,如果A能够根据不同的输入符号指派相应的候选ai作为全权代表去执行任务,那就肯定无需回溯了。在这里A已不再是让某个候选去试探性地执行任务,而是根据所面临的输入符号a准确地指派唯一的一个候选。其次,被指派候选的工作成败完全代表了A。

前面已经说过,欲实行自上而下分析,文法不得含有左递归。令G是一个不含左递归的文法,对G的所有非终结符的每个候选a定义它的终结首符集FIRST(a)为:

FIRST(a)={a | aa…, aÎV T}

特别是,若ae,则规定eÎFIRST(a)。换句话说,FIRST(a)是a的所有可能推导的开头终结符或可能的e。如果非终结符A的所有候选首符集两两不相交,即A的任何两个不同候选a i和a j

FIRST(ai)∩FIRST(a j)=f

那么,当要求A匹配输入串时,A就能根据它所面临的第一个输入符号a,准确地指派某一个候选前去执行任务。这个候选就是那个终结首符集含a的a。
应该指出,许多文法都存在那样的非终结符,它的所有候选的终结首符集并非两两不相交的。例如,通常关于条件句的产生式

语句®if 条件 then 语句 else 语句
     | if 条件 then 语句

就是这样一种情形。

如何把一个文法改造成任何非终结符的所有候选首符集两两不相交呢?其办法是,提取公共左因子。例如,假定关于A的规则是

A→db 1 | db 2 | …| db n | g 1 | g 2 | … g m (其中,每个g 不以d开头)

那么,可以把这些规则改写成

A→dA¢ | g 1 | g 2 | … | g m

A¢→b 1 | b 2 | … | b n

经过反复提取左因子,就能够把每个非终结符(包括新引进者)的所有候选首符集变成为两两不相交。我们为此付出的代价是,大量引进新的非终结符和e-产生式。

LL(1)分析条件

当一个文法不含左递归,并且满足每个非终结的所有候选首符集两两不相交的条件,我们可以找出满足构造不带回溯的自上而下分析的文法条件:

  1. 文法不含左递归,
  2. 对于文法中每一个非终结符A的各个产生式的候选首符集两两不相交。即,若
    A→a 1|a 2|…|an

    FIRST(a i)∩FIRST(a j)=f(i¹j)
  3. 对文法中的每个非终结符A,若它存在某个候选首符集包含e,则
    FIRST(A)∩FOLLOW(A)=f

    如果一个文法G满足以上条件,则称该文法G为LL(1)文法

这里,LL(1)中的第一个L表示从左到右扫描输入串,第二个L表示最左推导,1表示分析时每一步只需向前查看一个符号。
对于一个LL(1)文法,可以对其输入串进行有效的无回溯的自上而下分析。假设要用非终结符A进行匹配,面临的输入符号为a,A的所有产生式为

A→a 1 | a 2 | … | an

1. 若aÎFIRST(a i),则指派a i去执行匹配任务;
2. 若a不属于任何一个候选首符集,则:
(1) 若e属于某个FIRST(ai )且aÎFOLLOW(A),则让A与e自动匹配。
(2) 否则,a的出现是一种语法错误。
根据LL(1)文法的条件,每一步这样的工作都是确信无疑的。

递归下降分析程序构造

当一个文法满足LL(1)条件时,我们就可以为它构造一个不带回溯的自上而下分析程序,这个分析程序是由一组递归过程组成的,每个过程对应文法的一个非终结符。这样的一个分析程序称为递归下降分析器。如果用某种高级语言写出所有递归过程,那就可以用这个语言的编译系统来产生整个的分析程序。例如,考虑文法,它的每个非终结符所对应的递归过程列于如下图1。其中,ADVANCE是指把输入串指示器IP调至指向下一个输入符号;SYM是指IP当前所指的那个输入符号;ERROR为出错诊察处理程序。
对于图1的递归子程序,我们假定在开始工作前,输入串指示器IP指向第一个输入符号。当每个子程序工作完毕之后,IP总是指向下一个未处理的符号。请注意递归子程序E¢,我们知道,关于E¢的规则是

E¢→+TE¢|e

即E¢只有两个候选。第一个候选的开头终结符为+,第二个候选为e。这就是说,当E¢面临输入符号+时就令第一个候选进入工作,当面临任何其它输入符号时,E¢就自动认为获得了匹配(这时,更精确的做法是判断该输入符号是否属于FOLLOW(E¢))。递归过程E¢就是根据这一原则设计的。同理,关于T¢的过程也是如此。

     PROCEDURE  E;             PROCEDURE  T;
     BEGIN                                   BEGIN
       T;E¢                                    F;T¢
         END;                                    END
         PROCEDURE  E¢;            PROCEDURE  T¢;
         IF SYM=‘&#
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值