编译器实现(四)

1.自顶向下的分析

参考:https://blog.csdn.net/hjc256/article/details/87949500算法

自顶向下的分析算法经过在最左推导中描述出各个步骤来分析记号串输入。spa

分析树隐含的编号是一个前序编号,顺序是由根到叶。.net

自顶向下的分析程序有两类:回溯分析程序,预测分析程序。code

 

1.1使用递归降低分析算法进行自顶向下的分析

 1.1.1递归降低分析的基本方法

概念:blog

  将一个非终结符A的文法规则看做将识别A的一个过程的定义。递归

 递归降低分析程序由一组过程组成,每一个非终结符号有一个对应的过程。程序的执行从开始符号对应的过程开始,若是这个过程的过程体扫描了整个输入串,他就中止执行并宣布语法分析完成。rem

当非终结符有多个产生式时,可能须要回溯,即重复扫描。

get

产生式:io

  A→a | b | . . .class

若a,b均为非终结符时,须要计算a,b的First集合,来肯定什么时候使用A→a或A→b。

产生式:

  A→ε

须要了解什么记号能够正规地出如今非终结符A以后,这个集合为Follow集合。

进行First集合和Follow集合的计算是为了对早期错误进行探测。

 

1.2 LL(1)分析

1.2.1 LL(1)文法

参考:https://blog.csdn.net/jxch____/article/details/78693775

第一个L表示从左向右扫描输入,第二个L表示产生最左推导,而“1”表示在每一步中只须要向前看一个输入符号来决定语法分析的动做。

文法G是LL(1)的,当且仅当对于G的每一个非终结符Α的任何两个不一样产生式
Α→α,Α→β均知足下面条件(其中α和β不能同时推出ε):
1、FIRST(α)∩FIRST(β)=Φ
2、倘若β=>*ε,那么FIRST(α)∩FOLLOW(A)=Φ

 

LL(1)分析使用显示栈来完成分析。

例:(LL(1))分析的基本方法)

  对文法:S→ (S) S | ε

  

                   自顶向下的分析动做

 

1.2.2 LL(1)分析与算法

构造一个LL(1)分析表表达出可能的自顶向下分析选择,这个表称为M[N,T]。N是文法的非终结符的集合,T是终结符或记号的集合(禁止将ε加入)。

构造规则:

  1) 若是A→α是一个产生式选择,且有推导 α ⇒ *ab成立,其中a 是一个记号,则将A→a添加到表项目M [A, a] 中。

  2) 若是A→α是一个产生式选择,且有推导 α⇒ *ε 和 S $ ⇒*βAaγ成立,其中S是开始符号,α是一个记号(或$),则将A→α添加到表项目M [A, a]中。

例: (LL(1)分析表)

  对文法:S→ (S) S | ε

  

定义:若是文法G相关的LL(1)分析表的每一个项目中至多只有一个产生式,则该文法就是LL(1)文法(LL(1) grammar)。

 

利用LL(1)文法表构造出一个无二义性的分析。

1.2.3 消除左递归和提取左因子

将BNF表示法中的文法重写到LL (1)分析算法所能接受的格式上。应用的两个标准技术是左递归消除(left recursion removal)和提取左因子(left factoring)。这两个技术没法保证可将一个文法变成LL(1)文法,这就同EBNF同样没法保证在编写递归降低程序中能够解决全部的问题。

1.左递归消除

  左递归被广泛地用来运算左结合。

  (1)简单直接左递归

      A→Aα | β

    其中α和β是终结符和非终结符的串,并且β不以A开头。

    重写规则:一个是首先生成β,另外一个是生成α的重复,它不用左递归却用右递归:

      A →βA

      A’ →αA | ε

  (2)广泛的直接左递归

      A → Aα1 | Aα2 | . . . | Aαn| β1 | β2 | . . . | βn

      其中β1 ,β2  . . .  βn均不以A开头。

      重写规则:

        A →β1 A| β2 A | . . . | βm A’

        Aα1A| α2A | . . . | αn A

  (3)通常的左递归

    待写。。。

2.提取左因子

  当两个或更多文法规则选择共享一个通用前缀串时,须要提取左因子。

  A→αβ | αγ

  重写规则:

  A →αA 

  A  → β γ

1.2.4 在LL(1)分析中构造语法树

主要缘由倒是分析栈所表明的仅是预测的结构,而不是已经看到的结构。所以,语法树节点的构造必须推迟到将结构从分析栈中移走时,而不是当它们首次被压入时。通常而言,这就要求使用一个额外的栈来记录语法树节点,并在分析栈中放入“动做”标记来指出什么动做什么时候将在树栈中发生。

例:E → E + n | n

  重写:

  E → n E

  E’ → + n E | ε
   

  

1.2 First集合和Follow集合

1.2.1 First集合

定义:令X为一个文法符号(一个终结符或非终结符)或,则集合First (X) 由终结符组成,此外可能还有ε,它的定义以下:

  1. 若X是终结符或,则First (X) = {X}。

  2. 若X是非终结符,则对于每一个产生式X→X1X2 . . . Xn ,First (X)都包含了First(X1 ) - { ε}。若对于某个i < n,全部的集合First (X1 ), . . . , First   (Xi ) 都包括了ε,则First (X) 也包括了First (Xi + 1) - {ε }。若全部集合First (X1 ), . . . , First (Xn)包括了ε,则First (X)也包括ε。

  

    

 

 

1.2.3 Follow集合

定义:给出一个非终结符A,那么集合Follow (A)则是由终结符组成,此外可能还有$。
集合Follow (A)的定义以下:
  1. 若A是开始符号,则$就在Follow (A)中。
  2. 若存在产生式B→αAγ,则First (γ) - {ε}在Follow (A)中。
  3. 若存在产生式B→αAγ,且ε在First (γ)中,则Follow (A)包括Follow (B)。

 

    

1.2.4 构造LL(1)分析表

参见1.2.2中LL(1)分析表:

  1) 若是A→α是一个产生式选择,且有推导 α ⇒ *αβ成立,其中α 是一个记号,则将A→α添加到表项目M [A, α] 中。

  2) 若是A→ε是ε产生式选择,且有推导 S$ ⇒*αAα β 成立,其中S是开始符号,α是一个记号(或$),则将A→ε 添加到表项目M [A, a]中。

规则1中的记号 α很明显是在First (α) 中,且规则2的记号α 是在Follow (A)中,所以,就可获得LL(1) 分析表的如下算法构造:

LL(1) 分析表M[N, T] 的构造:为每一个非终结符A和产生式A→α重复如下两个步骤:

  1) 对于First (α)中的每一个记号α,都将A→α添加到项目M [A, a]中。

  2) 若ε在First (α)中,则对于Follow (A) 的每一个元素α(记号或是$),都将A→α 添加到M[A, a]中。

 

LL(1)文法的断定规则:

  定理:若知足如下条件,则B N F中的文法就是L L(1)文法(LL(1) grammar)。

    1. 在每一个产生式A→a1 | a2 | . . . |an 中,对于全部的 i 和 j:1≤i,j≤n,i≠j,First (ai ) ∩ First (aj )为空。

    2. 若对于每一个非终结符A都有First (A) 包含了 ε,那么First (A) ∩ Follow (A)为空。

相关文章
相关标签/搜索