编译原理复习笔记-自上而下的语法分析

一般方法

对于输入序列,进行左推导,得到一个合法句子或者非法结构,是一种试探+回溯的方法,自上而下建立输入序列的分析树。

存在的问题

  1. 公共左因子,造成大量回溯。
  2. 左递归,造成死循环。

解决

  1. 消除直接左递归。
方法:首先,整理A产生式为如下形式:
    A→ Aα1|Aα2|...|Aαm|β1|β2|...|βn
    其中αi非空,βj均不以A开始。用下述产生式代替A产生式
    A → β1 A' |β2 A' | ...|βn A'   
    A'→ α1 A' | α2 A' | ... | αm A' |ε
    若αi为空,则形成一个有环的A产生式

  1. 消除左递归。

核心思想:将不是直接左递归的符号右部展开到其他产生式

关键步骤:合理排序非终结符:A1,A2,...,An;
    用Aj→δ1|δ2|...|δk右部替换Ai→Ajγ中的Aj,得到Ai→δ1γ|δ2γ|...|δkγ;
    消除Ai产生式中的直接左递归;
  1. 提取左因子(类似于有限自动机的确定化)
方法  重复过程,直到所有A产生式候选项中不再有公共前缀:
    重排A产生式:A→αβ1|αβ2| ...�|αβn|γ;
    并用 A→αA'|γ 和 A'→β1|β2| ...|βn取代原A产生式。

注意:既有左递归,又含左因子,先消除左递归(左递归可以看作左因子的一部分)。

递归下降分析法

限制:文法不能有左递归和公共左因子,必须先消除。

方法

  1. 构造文法状态图并化简
  2. 将转换图转化为EBNF表示。
  3. 从EBNF构造子程序。

具体操作

  1. 构造状态转换图并化简
    • 为每个非终结符A建立对应的状态转换图,也就是初态到终态的路径。
    • 化简原则
      1. 标记为A的边课等价为标记ε的边转向A转换图的初态;
      2. 可以合并:ε连接的两个状态(FA的确定化思想),标记相同的路径,不可区分的状态(DFA的最小化)
  2. 文法的拓展BNF(EBNF)表示
    • {}:重复任意次数。
    • []:可选择
    • |:或关系
    • ():用于改变优先级。
  3. 构造递归下降子程序
    每一行是一个完整的执行语句。
    1. 循环,包含{}的程序
    语句:E → T { ( + | - ) T }
    procedure E is
    begin
     T;
     while lookahead∈(+|-)
     loop match(lookahead); T;
     end loop;
    end E;
    
    1. 多类匹配,包含或的程序。
    语句:F → ( E ) | id | num 
    procedure F is
    begin
       case lookahead is
        '(' : match('('); E; match(')');
        id  : match(id);
        num : match(num);
        others : error("syntax error2");
       end case;
    end F;
    

预测分析法

核心:预测分析表+驱动器(模拟算法),预测分析表的构建。
LL,符号栈,输入记号流。

方法

  1. 如果已知当前栈顶是非终结符,下一输入终结符,预测分析表指示了下一步动作。
  2. 从初始状态到分析成功或者出错。一个状态(PPT中写作格局)是三元组(栈内容,剩余输入,改变格局的动作)。
    改变格局的动作
    1. 匹配终结符,则前往下一个。
    2. 展开非终结符,逆序放入符号栈。
    3. 成功:栈顶和剩余输入都是#。
    4. 出错:调用错误恢复例程。
  3. 驱动器算法(非递归的预测分析)
  4. 用预测分析器分析句子(及一个三元组(栈,剩余输入,动作)的顺序表示。

关键:构造预测分析表。

  1. 构造fIRST集合与FOLLOW集合,对于每个非终结符而言。
  2. 根据两个集合构造预测分析表。

文法符号序列α的FIRST集合为:
FIRST(α)={ a |α=*>a...,a∈T},若α=*>ε,则ε∈FIRST(α)

非终结符A的FOLLOW集合如下:
FOLLOW(A) = { a |S=*>...Aa...,a∈T}, 若A是某句型的最右符号,则#∈FOLLOW(A)。

通俗理解:FIRST(e)集合就是从e开始可导出的文法序列的开头终结符。Follow(e)集合就是从开始符号可导出的所有含e的文法序列中e之后的终结符。

求这两个集合的算法,需要来理解,first往后多步查看,follow复杂一点。

FIRST集合自下而上计算,FOLLOW集合自上而下计算。

方法 应用下述规则:

1. 加入#到FOLLOW(S),其中S是开始符号,#是输入结束标记
2. 若有产生式A→αBβ,则除ε外,FIRST(β)的全体加入到FOLLOW(B)。
3. 若有产生式A→αB或A→αBβ而ε∈FIRST(β),则FOLLOW(A)的全体加入到FOLLOW(B)。
对3的理解:因为 ε∈FIRST(β),B成为A产生式最右的文法符号,
所以对任何a∈FOLLOW(A),均有a∈FOLLOW(B),
反之不然,因为FIRST(β)不一定只有 ε。

构造预测分析表。

1. 对FIRST(α)的每个终结符a,加入α到M[A,a];
2. 若ε∈FIRST(α),则FOLLOW(A)每个终结符b(包括#),加入α到M[A,b];

你可能感兴趣的:(编译原理复习笔记-自上而下的语法分析)