编译原理第五章笔记 -- 自下而上的语法分析

本文中内容整理西安交通大学软件学院吴晓军老师的ppt中,仅供学习使用,请勿转载或他用
参考教材:《程序设计语言 编译原理》(第3版) 陈火旺等 国防工业出版社
里面有排版问题或者图片显示问题及时留言,直接从笔记copy过来的,可能有些格式有问题

语法分析–自下而上分析

本章内容:

  • 自下而上分析的基本问题
  • 直观算符优先分析法
  • 算符优先分析
  • LR分析法

LR分析法篇幅较长

要求输入串w是一个终结符串

自下而上分析法:从输入串W开始,逐步进行“规约”,直到规约到文法的开始符号S

基本问题

归约

利用栈,输入符号移进栈,当栈顶形成P的候选式时,就规约为它的左部P符号

自下而上法即“移进-规约”法

例子:
S → a A c B e A → b A → A b B → d S\to aAcBe\quad\quad A\to b\\ A\to Ab\quad\quad B\to d SaAcBeAbAAbBd
输入串:abbcde

这里的栈漏掉了 # ,最底部应该是 #

在这里插入图片描述

规范归约

  • 短语:令G是一个文法,S是文法的开始符号,若 α β δ \alpha \beta \delta αβδ是文法G的一个句型,如果有 S ⇒ ∗ α A δ 且 A ⇒ + β S\stackrel{*}{\Rightarrow}\alpha A \delta且 A\stackrel{+}{\Rightarrow}\beta SαAδA+β,则称 β \beta β是句型 α β δ \alpha\beta\delta αβδ相对于非终结符A的短语
  • 直接短语:如果有 A → β A\to \beta Aβ,则称 β \beta β是句型 α β δ \alpha\beta\delta αβδ相对于规则 A → β A\to \beta Aβ的直接短语
  • 句柄:一个句型的最左直接短语称为该句型的句柄
  • 规范推导:即最右推导
  • 规范句型:由规范推导所得到的句型称为规范句型
  • 规范归约:是关于句型 α \alpha α的一个最右推导的逆过程,也称最左规约

短语和直接短语

在一个句型对应的语法树中

  • 以某非终结符为根的两代以上的子树的所有末端节点从左到右排列就是相对于该终结符的一个短语
  • 如果子树只有两代,则该短语就是直接短语

image-20220325102115534

符号栈的使用

规范归约用来作语法分析时需要解决的问题:

  • 如果在句型中找出句柄
  • 当相同的右部有不止一个产生式时,选哪一个

栈和输入缓冲区

实现移进-规约分析的一个方便途径是用一个栈和一个输入缓冲区,用#表示栈底和输入的结束

image-20220326163203138

分析程序的动作

  • 移进:下一输入终结符号移进栈顶
  • 规约:把句柄按产生式的左部进行规约
  • 接收:分析程序报告成功
  • 出错:发现了一个语法错误,调用出错处理程序

注意:可规约的串在栈顶,不会在栈的内部!因为在查到可规约的串时候就会直接规约掉而不会把它压入栈的内部

问题:按“移进-规约”方式进行自上而下语法分析时候,可规约串应该是下面哪一个选项?

  • 短语
  • 任意文法符号串
  • 句柄(√)
  • 直接短语

直观算符优先分析法

定义

任两个相继出现的终结符a与b(可能中间有 V N V_N VN),可能有以下优先关系:
a ⋖ b a 的优先性低于 b a ≖ b a 的优先级等于 b a ⋗ b a 的优先级高于 b a\lessdot b \quad a的优先性低于b\\ a\eqcirc b \quad a的优先级等于b\\ a\gtrdot b \quad a的优先级高于b aba的优先性低于baba的优先级等于baba的优先级高于b

优先关系的传递以及逆都不成立

例子

对于文法G: E → E + E ∣ E ∗ E ∣ E ↑ E ∣ ( E ) ∣ i E\to E+E|E*E|E\uparrow E|(E)|i EE+EEEEE(E)i,其终结符的优先关系见下表

空白表示不存在优先关系

读法(例如(0,0)):终结符加号优先性高于终结符加号 先行后列

image-20220325103659069

构造分析算法

#号是特殊的界符

记号使用说明:

  • #:语句符号(栈底和输入串w后)
  • θ \theta θ:运算符栈的栈顶符
  • a:刚读入的终结符号
  • OPTR:运算符栈
  • OPND:操作数栈

调用 θ \theta θ的语义程序是为了完成计算

在第三步是所有优先性高的都做完,直到 θ \theta θ的优先级比a低或等于

算法分析步骤

  1. 下一个输入终结符号读至a中
  2. 若a为i,则a入栈OPED,然后转第一步
  3. θ ⋗ a \theta \gtrdot a θa,则调用关于 θ \theta θ的处理程序(语义程序),处理子表达式: E ( 1 ) θ E ( 2 ) E^{(1)}\theta E^{(2)} E(1)θE(2),(其中, E ( 1 ) , E ( 2 ) E{(1)},E{(2)} E(1),E(2)分别为操作数OPND栈的次栈顶和栈顶);将上述字表达式的结果再填入OPND栈;然后重新进入第3步;
  4. θ ≖ a \theta \eqcirc a θa,则
    • 若$\theta = ( $ 并且 a = ) a=) a=),则去除OPTR栈顶的(并且丢掉a(不处理)中的),然后转第一步
    • θ = a = # \theta = a = \# θ=a=#,则分析成功结束
  5. θ ⋖ a \theta \lessdot a θa,则a入栈OPTR,然后转第一步
  6. θ 与 a \theta 与a θa不存在优先关系,则判输入串错误,调出错处理

image-20220326165129328

例子

image-20220325105131541

完成初始化之后的状态,左#号放在栈底

读入操作数之后直接就压栈了,然后再读入下一个,发现是运算符,然后和栈顶元素进行优先级比较,根据后面四个规则进行判断操作,完了之后再把第二个操作数入栈

问题:直观算法优先分析法中,如果 a ⋗ b , b ⋗ c , a ≖ e , a ≖ f a\gtrdot b,b\gtrdot c,a\eqcirc e,a\eqcirc f ab,bc,ae,af,那么下列哪些选项不正确?

  • a ⋗ c a \gtrdot c ac
  • b ⋖ a b \lessdot a ba
  • e ≖ f e \eqcirc f ef
  • c ⋗ b c \gtrdot b cb

答案:ABCD

算符优先分析

所谓算符优先分析就是定义算符之间(确切的说,是终结符之间)的某种优先关系,借助这种优先关系寻找“可规约串”和进行规约。

算符优先分析法不是一种规范规约法

算符优先文法

算符文法定义

如果一个文法的任何产生式右部都不含两个相继(并列)的非终结符,即不含有如下形式的产生式右部: ⋯ Q R ⋯ \cdots QR \cdots QR,则我们称该文法为算符文法

假定G是一个不含 ε \varepsilon ε产生式的算符文法,对于任何一对终结符a,b,我们说:

  • a ≖ b a\eqcirc b ab,当且仅当文法G中有含有形如 P → ⋯ a b ⋯ P\to \cdots ab \cdots Pab P → ⋯ a Q b ⋯ P\to \cdots aQb \cdots PaQb的产生式(如有(E),则( ≖ \eqcirc )
  • a ⋖ b a\lessdot b ab,当且仅当G中含有形如 P → ⋯ a R ⋯ P\to \cdots aR \cdots PaR的产生式,而 R ⇒ + b ⋯ R\stackrel{+}{\Rightarrow}b\cdots R+b R ⇒ + Q b ⋯ R\stackrel{+}{\Rightarrow}Qb\cdots R+Qb
  • a ⋗ b a\gtrdot b ab,当且仅当G中含有形如 P → ⋯ R b ⋯ P\to \cdots Rb \cdots PRb的产生式,而 R ⇒ + ⋯ a R\stackrel{+}{\Rightarrow}\cdots a R+a R ⇒ + ⋯ a Q R\stackrel{+}{\Rightarrow}\cdots aQ R+aQ

算符优先文法定义

如果一个算符文法G中的任何终结符对(a,b)至多只满足下述三种关系之一:
a ≖ b , a ⋖ b , a ⋗ b a\eqcirc b,a\lessdot b, a\gtrdot b ab,ab,ab
则称G是一个算符优先文法

从算符优先文法构造优先关系表

首终结符集,尾终结符集

构造步骤:

  1. 构造优先关系表,就是要找出所有 V T V_T VT偶对之间的三种关系;对于 ≖ \eqcirc 可以直接检查G中多有的P来得到,而 ⋖ , ⋗ \lessdot,\gtrdot ,关系不易检查,故要定义两个集合
  2. F I R S T V T ( P ) = { a ∣ P ⇒ + a ⋯ 或 P ⇒ + Q a ⋯   , a ∈ V T 而 Q ∈ V N } FIRSTVT(P)=\{a|P\stackrel{+}{\Rightarrow}a\cdots或P\stackrel{+}{\Rightarrow}Qa\cdots,a\in V_T 而 Q\in V_N\} FIRSTVT(P)={ aP+aP+Qa,aVTQVN} 第一个位置或第二个位置出现的
  3. $LASTVT§={a|P\stackrel{+}{\Rightarrow}\cdots a或P\stackrel{+}{\Rightarrow}\cdots aQ,a\in V_T 而 Q\in V_N} $ 最后一个或倒数第二个位置出现的
  4. 如两个集合构造好,检查P就可确定满足 ⋖ \lessdot ⋗ \gtrdot 的(a,b)对
  5. 这是因为,假定有个产生式候选式:
    • ⋯ a P ⋯ \cdots aP \cdots aP,那么对于任何 b ∈ F I R S T V T ( P ) b\in FIRSTVT(P) bFIRSTVT(P),有 a ⋖ b a\lessdot b ab
    • ⋯ P b ⋯ \cdots Pb \cdots Pb,那么对于任何 a ∈ L A S T V T ( P ) a\in LASTVT(P) aLASTVT(P),有 a ⋗ b a\gtrdot b ab

因此,问题归结为:

  • 构造该两个集合的算法,即对每个非终结符P构造其 F I R S T V T ( P ) FIRSTVT(P) FIRSTVT(P) L A S T V T ( P ) LASTVT(P) LASTVT(P)
  • 使用每个非终结符P的 F I R S T V T ( P ) , L A S T V T ( P ) FIRSTVT(P),LASTVT(P) FIRSTVT(P),LASTVT(P),检查每一个产生式,找出所有(a,b)的关系,最终完成优先关系表的构造

构造集合首终结符集的算法

  1. $P\to a\cdots 或 或 P\to Qa\cdots ,则 ,则 ,则a\in FIRSTVT§$
  2. a ∈ F I R S T V T ( Q ) a\in FIRSTVT(Q) aFIRSTVT(Q),且有产生式 P → Q ⋯ P\to Q\cdots PQ,则 a ∈ F I R S T V T ( P ) a\in FIRSTVT(P) aFIRSTVT(P) Q的首终结符也是P的首终结符

算法的一种实现

  • 布尔数组F[P,a],使得F[P,a]为真的条件是,当且仅当 a ∈ F I R S T V T ( P ) a\in FIRSTVT(P) aFIRSTVT(P)。开始时,按上述的规则1对每个数组元素F[P,a]赋初值

  • 栈STACK,把所有初值为真的数组元素F[P,a]的符号对(P,a)全都放在STACK之中

  • 若栈STACK不空,就将栈顶弹出,记此项为(Q,a)。对于每个形如 P → Q ⋯ P\to Q\cdots PQ的产生式,若F[P,a]为假,则变其值为真且将(P,a)推进STACK栈

  • 上述过程一直重复,直到栈STACK为空为止

  • 算法的工作结果得到一个二维数组F,从他可以得到任何非终结符P的FIRSTVT:
    F I R S T V T ( P ) = { a ∣ F [ P , a ] = T R U E } FIRSTVT(P) = \{a|F[P,a]=TRUE\} FIRSTVT(P)={ aF[P,a]=TRUE}

FIRSTVT§的自动构造

第一个循环是赋初值,全部设置为false

第二个循环是检查右部第一个或者第二个终结符

第三个循环是检查右部第一个非终结符

构造集合尾终结符的算法

  1. P → ⋯ a P \to \cdots a Pa P → ⋯ a Q P\to \cdots aQ PaQ ,则 a ∈ L A S T V T ( P ) a\in LASTVT(P) aLASTVT(P)
  2. a ∈ L A S T V T ( Q ) a\in LASTVT(Q) aLASTVT(Q),且有产生式 P → ⋯ Q P\to \cdots Q PQ,则 a ∈ L A S T V T ( P ) a\in LASTVT(P) aLASTVT(P)

image-20220326235521289

image-20220326235858539

构造优先表方法

4这个点注意不能漏掉,着重理解一下

  1. 对于形如 P → ⋯ a b ⋯ P\to \cdots ab \cdots Pab和形如 P → ⋯ a Q b ⋯ P\to \cdots aQb \cdots PaQb,有 a ≖ b a\eqcirc b ab
  2. 对于形如 P → ⋯ a R ⋯ P\to \cdots aR \cdots PaR,而 b ∈ F I R S T V T ( R ) b\in FIRSTVT(R) bFIRSTVT(R),有 a ⋖ b a\lessdot b ab
  3. 对于形如 P → ⋯ R b ⋯ P\to \cdots Rb \cdots PRb,而 a ∈ L A S T V T ( R ) a\in LASTVT(R) aLASTVT(R),有 a ⋗ b a\gtrdot b ab
  4. 对于S和终结符#,有 # ⋖ F I R S T V T ( S ) , L A S T V T ( S ) ⋗ # \# \lessdot FIRSTVT(S),LASTVT(S)\gtrdot \# #FIRSTVT(S),LASTVT(S)#,且对 # S # \#S\# #S#,有 # ≖ # \#\eqcirc \# ##

image-20220326180546115

问题:对于算符优先文法,如果有产生式 P → ⋯ Q P\to \cdots Q PQ,请问下列哪些关系成立?

  • L A S T V T ( Q ) ⊂ L A S T V T ( P ) LASTVT(Q)\subset LASTVT(P) LASTVT(Q)LASTVT(P)
  • L A S T V T ( P ) ⊂ L A S T V T ( Q ) LASTVT(P)\subset LASTVT(Q) LASTVT(P)LASTVT(Q)
  • F O L L O W ( Q ) ⊂ F O L L O W ( P ) FOLLOW(Q)\subset FOLLOW(P) FOLLOW(Q)FOLLOW(P)
  • F O L L O W ( P ) ⊂ F O L L O W ( Q ) FOLLOW(P)\subset FOLLOW(Q) FOLLOW(P)FOLLOW(Q)

答案:AD

例子:

如果在优先关系表中有多个入口说明对于这一个终结符对有多种优先关系(那如果还是只满足一种优先关系怎么办?

考试时候优先关系表中的终结符的顺序都会给定

先找优先关系相等的(注意#S#中两个#也相等)

然后再判断 # 和开始字符的优先关系 #S#,即 # ⋖ F I R S T V T ( E ) , L A S T V T ( E ) ⋗ # \#\lessdot FIRSTVT(E),LASTVT(E)\gtrdot \# #FIRSTVT(E),LASTVT(E)#

然后再看产生式集合本身

image-20220328083333414

算符优先分析算法的设计

这里和前面短语,直接短语,最左直接短语对比一下

第二条中至少要有一个终结符是为了消除 P → Q P\to Q PQ的情况

定义

  • 文法G,开始符号S,如果 S ⇒ ∗ α A δ S\stackrel{*}{\Rightarrow}\alpha A \delta SαAδ A ⇒ + β A\stackrel{+}{\Rightarrow}\beta A+β,则称 β \beta β是句型 α β δ \alpha \beta \delta αβδ的一个短语
  • 所谓素短语是指这样一个短语,它至少含有一个终结符,并且除自身之外不再含任何更小的素短语
  • 句型最左边的那个素短语叫最左素短语

定理

算符优先文法的句型具有如下一般形式: # N 1 a 1 N 2 a 2 ⋯ N n a n N n + 1 # \#N_1a_1N_2a_2\cdots N_na_nN_{n+1}\# #N1a1N2a2NnanNn+1#,其中, a i ∈ V T , N i ∈ V N ∣ ε a_i\in V_T,N_i\in V_N|\varepsilon aiVT,NiVNε

最左素短语是满足以下条件的最左子串 N j a j ⋯ N i a i N i + 1 N_ja_j\cdots N_ia_iN_{i+1} NjajNiaiNi+1

image-20220401185711430
# N 1 a 1 N 2 a 2 ⋯ a j − 1 N j a j ⋯ N i a i N i + 1 a i + 1 ⋯ N n a n N n + 1 # \#N_1a_1N_2a_2\cdots a_{j-1} N_ja_j\cdots N_ia_iN_{i+1}a_{i+1}\cdots N_na_nN_{n+1}\# #N1a1N2a2aj1NjajNiaiNi+1ai+1NnanNn+1#
也即:

image-20220401190223209

例子

image-20220401190243443

算法分析

image-20220328084746968

优先函数

定义

我们把每个终结符 θ \theta θ与两个自然数 f ( θ ) f(\theta) f(θ) g ( θ ) g(\theta) g(θ)相对应,使得:

  • θ 1 ⋖ θ 2 \theta_1\lessdot \theta_2 θ1θ2,则 f ( θ 1 ) < g ( θ 2 ) f(\theta_1)< g(\theta_2) f(θ1)<g(θ2)
  • θ 1 ≖ θ 2 \theta_1\eqcirc \theta_2 θ1θ2,则 f ( θ 1 ) = g ( θ 2 ) f(\theta_1)= g(\theta_2) f(θ1)=g(θ2)
  • θ 1 ⋗ θ 2 \theta_1\gtrdot \theta_2 θ1θ2,则 f ( θ 1 ) > g ( θ 2 ) f(\theta_1)> g(\theta_2) f(θ1)>g(θ2)

函数 f f f称为入栈优先函数 g g g称为比较优先函数

使用优先函数的优缺点

优点:便于比较运算;节省存储空间

缺点:对不存在优先关系的两个终结符,由于与自然数相对应,变成可比较

优先函数的性质

  1. 正确性

    优先函数掩盖了矩阵中出错元素对,若 f ( i d ) < g ( i d ) f(id)< g(id) f(id)<g(id),暗示 i d ⋖ i d id \lessdot id idid,但id之间无优先关系,因此失去发现错误能力,但并未严重到妨碍在可解地方使用优先函数

  2. 存在性

    并非总能把表映射到优先函数

    image-20220401190802085

  3. 惟一性

    如果存在一个优先函数,则有无数多对,原因在于:加任一常数,不等式仍成立

构造优先函数的方法

(如果优先函数存在的话)

  • 对每个a(包括#) ∈ V T \in V_T VT,对应两个符号 f a , g a f_a,g_a fa,ga

  • 把所建立的符号应尽可能划分为许多组:

    • a ≖ b a\eqcirc b ab,则 f a , g b f_a,g_b fa,gb就在一组
    • a ≖ b , c ≖ b a\eqcirc b,c\eqcirc b ab,cb,则 f a , f c f_a,f_c fa,fc同组
  • 建立一个有向图,其结点是上一步中找出的组

    • 对于任何a和b,
    • a ⋗ b a\gtrdot b ab,画 f a → g b f_a\to g_b fagb弧,意味着 f ( a ) > g ( b ) f(a)> g(b) f(a)>g(b)
    • a ⋖ b a\lessdot b ab,画 g b → f a g_b\to f_a gbfa弧,意味着 f ( a ) < g ( b ) f(a)< g(b) f(a)<g(b)
  • 如果上一步结果构成环,则 f , g f,g f,g不存在

    • 否则 f ( a ) = f(a)= f(a)= f a f_a fa组开始的路径和

      image-20220401191438573

image-20220328092744088

LR分析法

L:从左到右扫描输入串

R:自下而上进行规约

语法分析概述

image-20220328093013857

  • LR分析程序(器):自左向右扫描,识别句柄,自下而上规约的语法分析程序

  • LR分析程序生成器:自动生成LR分析程序的程序

LR分析程序:

image-20220328093233312

问题:某些语法分析方法的核心构件是总控程序和分析表。请问,下列哪些分析法采用这样的设计思路

  • LR分析法
  • 算符优先分析法
  • 预测分析法
  • 递归下降分析法

答案:ABC

规范归约的关键问题是寻找句柄

  • 历史:已移入符号栈的内容
  • 展望:根据产生式推测未来可能遇到的输入符号
  • 现实:当前的输入符号

LR1意味着在构造时候会看展望符号,但是只看了一个符号

image-20220328093801428

包含两个字表:动作子表和转移子表

LR分析程序

LR分析程序的实质:分析栈+DFA

image-20220401194401690

LR分析过程

image-20220401194424529

LR分析的核心–分析表

分析表由ACTION表和GOTO表两部分组成

  • ACTION(s,a):表示当状态s面临输入a时的动作
  • GOTO(s,x):表示面对文法符号x的下一状态

ACTION[s,a]表中的动作类型:

  • 移进
  • 归约
  • 接受
  • 报错

例子

考试时自下而上的几个算法都会考到

image-20220402225432032

把候选式都分开写,然后给每个候选式一个唯一的编号

空白情况都表示是出错了

image-20220402225445730

读输入的时候查Actions表中状态栈栈顶和当前输入字符

碰到r时候首选先根据产生式右部的字符数量从从状态栈和符号栈弹出对应数量的字符,规约后压回符号栈,然后在GOTO表中查看当前状态栈和符号栈的栈顶对应的状态,并压入状态栈

(7)到(8)时由于 T*F 三个符号出栈,所以移出三个状态2 7 10

image-20220402225506036

image-20220402225515241

s:状态栈

X:符号栈

a:输入串

红色框表示按照某个产生式规约的时候两个栈的实际变化过程

  • 首先先把符号栈和状态栈可以规约的字符以及状态出栈
  • 然后将字符规约为A压入符号栈
  • 将GOTO( s m − r s_{m-r} smr,A)对应的状态压入状态栈中

image-20220402225539941

LR文法

定义:对于一个文法,如果能够构造一张分析表,使得它的每个入口均是唯一确定的,则我们把这个文法称为LR文法

LR(k)文法:一个文法,如果能用一个每步顶多向前检查K个输入符号的LR分析器进行分析,则这个文法称为LR(k)文法

一般k只取0和1,当k为0时候,不进行超前搜索,当k为1的时候,后续会有n种状态,当k为2时候,后续就会有 n 2 n^2 n2种状态,状态太多,不便于处理

问题:LR文法要求它的分析表中每个入口均是唯一确定的。请问,这里的入口属于哪些表

  • ACTION表
  • 优先关系表
  • 预测分析表
  • GOTO表

答案:AD

LR(0)分析表的构造

LR(0)分析表的构造步骤

这里的项目是item,不是project

  1. 确定G的LR(0)项目
  2. 以LR(0)项目为状态,构造一个能识别文法G的所有活前缀的NFA
  3. 利用子集法将NFA确定化,成为以项目集合为状态的DFA
  4. 根据上述DFA可直接构造出LR(0)分析表

LR(0)项目

LR(0)项目简称为项目

定义:文法G的每一个产生式的右部添加一个圆点,称为G的一个LR(0)项目

image-20220401202417937

项目的意义:指明在分析过程的某时刻我们看到产生式多大一部分

项目在计算机中的表示:(m, n)

image-20220401202506907

字的前缀

指该字的任意首部

如:abc的前缀包括 ε , a , a b , a b c \varepsilon,a,ab,abc ε,a,ab,abc

**活前缀:**规范句型的一个前缀,该前缀不含句柄之后的任何符号。

活前缀包含的句柄并不完整,完整了就会直接规约了

构造NFA

对文法G,构造能识别G的所有活前缀的NFA

NFA的状态:所有LR(0)项目

构造方法

S‘是新引入的开始符号,也就是额外有产生式 S ′ → S S'\to S SS

  • 开始符号S’的形如 S ′ → ⋅ S S'\to \cdot S SS的项目为NFA的唯一初态
  • 若状态 i i i j j j出自同一个产生式,而且 j j j的圆点只落后于 i i i的圆点一个位置,则从 i i i画一条标志位 X i Xi Xi的弧到 j j j;即:
    • $i:X\to X1\cdots Xi-1\ \cdot\ Xi\cdots Xn $
    • $j:X\to X1\cdots Xi-1\ Xi \bold{\cdot} \cdots Xn $
  • 若状态 i i i的圆点之后的符号为非终结符,如 i i i X → α ⋅ A β X\to \alpha \cdot A\beta XαAβ,其中A属于 V N V_N VN,则从状态 i i i ε \varepsilon ε弧到所有 A → ⋅ γ A\to \cdot \gamma Aγ状态

例子

image-20220402225547987

image-20220402225555755

image-20220402225606397

终态是可以做规约,也就是圆点在最右边的项目

将NFA确定化

使用子集法将NFA确定化,使之成为一个以项目集合为状态的DFA

① 相关定义:

  • LR(0)项目集规范族:构成识别一个文法活前缀的DFA的项目集(状态)的全体
  • 规约项目: A → α ⋅ A\to \alpha \cdot Aα
  • 接受项目: S ′ → α ⋅ S'\to \alpha \cdot Sα(s‘–文法的开始符号)
  • 移进项目: A → α ⋅ a β A\to \alpha \cdot a\beta Aαaβ a a a–终结符)
  • 待约项目: A → α ⋅ B β A\to \alpha \cdot B \beta Aα(B–非终结符)

② 利用CLOSURE方法构造LR(0)项目集规范族

  • 拓广文法
  • C L O S U R E ( I ) CLOSURE(I) CLOSURE(I)算法(其中 I I I G G G的任一项目集)
    • I的任何项目都属于 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I)
    • A → α ⋅ B β A\to \alpha \cdot B \beta Aα属于 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I),那么,对任何关于B的产生式 B → γ B\to \gamma Bγ,项目 B → ⋅ γ B\to \cdot \gamma Bγ也属于 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I)
    • 重复执行上述两步骤直至 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I)不再增大为止
  • 构造项目集规范族的方法
    • 令NFA的初态为 I I I,求其 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I),得到初态项目集。即:求 C L O S U R E ( { S ′ → ⋅ S } ) CLOSURE(\{S'\to \cdot S\}) CLOSURE({ SS})
    • 对所得项目集 I I I和文法 G G G的每个文法符号 X X X(包括 V T 和 V N V_T和V_N VTVN)计算 G O ( I , X ) = C L O S U R E ( J ) GO(I, X)=CLOSURE(J) GO(I,X)=CLOSURE(J),得到新的项目集,其中: J = { 任何形如 A → α X ⋅ β 的项目 ∣ A → α ⋅ X β 属于 I } J=\{任何形如A\to \alpha X\cdot \beta的项目|A\to \alpha \cdot X \beta属于I\} J={ 任何形如AαXβ的项目Aα属于I}
    • 重复步骤二,直至没有新的项目集出现

LR(0)分析表的构造

① 相关定义

L R ( 0 ) LR(0) LR(0)文法:不存在以下两种冲突的文法

  • 移进与规约冲突
  • 归约与归约冲突

L R ( 0 ) LR(0) LR(0)表:由 L R ( 0 ) LR(0) LR(0)文法得到的分析表

L R ( 0 ) LR(0) LR(0)分析器:使用 L R ( 0 ) LR(0) LR(0)表的分析器

② 分析表的构造方法

  • 若项目 A → α ⋅ a β A\to \alpha \cdot a\beta Aαaβ属于 I k I_k Ik G O ( I k , a ) = I j GO(I_k,a)=I_j GO(Ik,a)=Ij a a a为终结符,则置 A C T I O N [ k , a ] ACTION[k, a] ACTION[k,a]为“把 ( j , a ) 移进栈 (j,a)移进栈 (j,a)移进栈”,简记为“ s j sj sj
  • 若项目 A → α ⋅ A\to \alpha \cdot Aα属于 I k I_k Ik,那么,对任何输入符号 a a a(或者终结符#)置 A C T I O N [ k , a ] ACTION[k,a] ACTION[k,a]为"用产生式 A → α A\to \alpha Aα进行归约",简记为" r j rj rj":其中,假定 A → α A\to \alpha Aα为文法 G ’ G’ G的第 j j j个产生式
  • 若项目 S ′ → S ⋅ S'\to S\cdot SS属于 I k I_k Ik,则置 A C T I O N [ k . # ] ACTION[k.\#] ACTION[k.#]为”接受“,简记为" a c c acc acc"
  • G O ( I k , A ) = I j , A GO(I_k,A)=I_j,A GO(Ik,A)=Ij,A为非终结符,则置 G O T O [ k , A ] = j GOTO[k,A]=j GOTO[k,A]=j
  • 分析表中凡不能使用规则1至4填入信息的空白格均置上“出错标志”

问题:对于一个 L R ( 0 ) LR(0) LR(0)文法,如果项目 A → α ⋅ A\to \alpha \cdot Aα属于 I k I_k Ik,请问 A C T I O N ACTION ACTION表中国 I k I_k Ik行哪些终结符列应填入 r j rj rj(假设$A\to \alpha 为第 为第 为第j$个产生式)

  • 文法的所有终结符(不含#)
  • 文法的所有终结符(含#)
  • F O L L O W ( A ) FOLLOW(A) FOLLOW(A)中的所有终结符
  • F I R S T ( α ) FIRST(\alpha) FIRST(α)中除空串之外的所有终结符

答案:B

image-20220402225614930 image-20220402225628245

image-20220402225649461

完整的步骤在书上有

image-20220402225707120

6-11所有都是相同的,这是LR(0)最显著的特征

image-20220402225722876

image-20220410221126914

SLR表的构造方法

SLR和SLR(1)是一个意思

是为了解决移进与归约冲突和归约与规约冲突

向前展望方法解决冲突

若LR(0)规范族中含有冲突项目,采用向前展望方法解决

例:若 I = { X → α ⋅ b β , A → α ⋅ , B → α ⋅ } I=\{X\to \alpha \cdot b \beta,A\to \alpha \cdot, B\to \alpha \cdot\} I={ Xαbβ,Aα,Bα}

若当前输入符号位b,则含有移进–归约冲突,而A和B,又有归约–归约冲突。

解决方法:

考察FOLLOW(A)和FOLLOW(B)

F O L L O W ( A ) ∩ F O L L O W ( B ) FOLLOW(A)\cap FOLLOW(B) FOLLOW(A)FOLLOW(B)为空,且均不含b,则当 I I I面临任何输入符号a时,可以做出如下“移进–归约”决策:

  • 如果a=b,移进;
  • 如果a属于FOLLOW(A),则用 A → α A\to \alpha Aα归约
  • 如果a属于FOLLOW(B),则用 B → α B\to \alpha Bα归约
  • 此外,报错

回顾FOLLOW(A)的计算

其中A是非终结符

注:FIRST集是针对终结符、非终结符和产生式构造的,FOLLOW集仅对非终结符构造

SLR表的构造方法

  • 若项目 A → α ⋅ a β A\to \alpha\cdot a\beta Aαaβ属于 I k I_k Ik G O ( I k , a ) = I , a GO(I_k,a)=I,a GO(Ik,a)=I,a为终结符,则置 A C T I O N k , a ACTION{k,a} ACTIONk,a为“把状态j和顾浩a移进栈”,简记为“ s j sj sj

  • 若项目 A → α ⋅ A\to \alpha \cdot Aα属于 I k I_k Ik,那么,对任何输入符号 a , a ∈ F O L L O W ( A ) a,a\in FOLLOW(A) a,aFOLLOW(A),则置 A C T I O N [ k , a ] ACTION[k,a] ACTION[k,a]为“用产生式 A → α A\to \alpha Aα进行规约”,简记为“ r j rj rj”;其中,假定 A → α A\to \alpha Aα为文法 G ′ G' G的第j个产生式

    只在规约时才向前展望,即 ⋅ \cdot 已到产生式末尾,则去判断 F O L L O W ( A ) FOLLOW(A) FOLLOW(A)

  • 若项目 S ′ → S ⋅ S'\to S\cdot SS属于 I k I_k Ik,则置 A C T I O N [ k , # ] ACTION[k,\#] ACTION[k,#]为“接受”,简记为“acc”

  • G O ( I k , A ) = I j GO(I_k,A)=I_j GO(Ik,A)=Ij,A为非终结符,则置 G O T O [ k , A ] = j GOTO[k,A]=j GOTO[k,A]=j

  • 分析表中凡不能使用规则1至4填入信息的空白格置上“出错标志”

问题:对于一个SLR(1)文法,如果项目 A → α ⋅ A\to \alpha\cdot Aα属于 I k I_k Ik,请问 A C T I O N ACTION ACTION表中 I k I_k Ik行哪些终结符列应填入 r j r_j rj(假设 A → α A\to \alpha Aα为第 j j j个产生式)?

  • 文法的所有终结符(不含#)
  • 文法的所有终结符(含#)
  • F O L L O W ( A ) FOLLOW(A) FOLLOW(A)中的所有终结符
  • F I R S T ( α ) FIRST(\alpha) FIRST(α)中除空串之外的所有终结符

答案:C

image-20220402225735535

千万不要忘了首先把#加入FOLLOW(S’)中,然后再根据求FOLLOW集的规则去求FOLLOW

image-20220402225742906

⑤:构造SLR分析表

image-20220402225755333

规范LR分析表的构造

  • 问题:有些无二义文法会产生“移进/归约”冲突或“归约/归约”冲突
  • 产生原因:SLR分析表中未包含足够多的“展望信息”
  • 解决办法:让每个状态含有更多的“展望信息”

方法:重新定义项目,使得每个项目都附带有k个终结符,即每个项目的形式为: [ A → α ⋅ β , a 1 a 2 ⋯ a k ] [A\to \alpha\cdot\beta,a_1a_2\cdots a_k] [Aαβ,a1a2ak]

定义:如上形式的项目称为一个LR(k)项目

说明:

  • 向前搜索符串仅对规约项目 [ A → α ⋅ , a 1 a 2 ⋯ a k ] [A\to\alpha\cdot,a_1a_2\cdots a_k] [Aα,a1a2ak]有意义
  • 归约项目 [ A → α ⋅ , a 1 a 2 ⋯ a k ] [A\to \alpha\cdot,a_1a_2\cdots a_k] [Aα,a1a2ak]意味着:当它所属的状态呈现在栈顶且后续的k个输入符号位 a 1 a 2 ⋯ a k a_1a_2\cdots a_k a1a2ak时,才可以把栈顶上的 α \alpha α规约为A
  • 一般只研究 k ≤ 1 k\le 1 k1的情况

规范LR就是LR(1),二者是一个意思

构造规范LR分析表的步骤

  • 确定LR(1)项目
  • 根据与LR(1)项目构造NFA
  • 利用函数CLOSURE和GO求DFA
  • 根据DFA构造规范LR分析表

确定LR(1)项目

对文法做拓广需要先加入 S ′ S' S,同时需要对文法编号

确定LR(1)项目的方法:

  • S ′ 和 S S'和S SS,只向前搜索#
  • 其他产生式,对每个 V T V_T VT(含#)均向前搜索

image-20220402192722368

这里是所有的候选式

image-20220402192737310

定义:

我们说一个LR(1)项目 [ A → α ⋅ β , a ] [A\to \alpha\cdot \beta,a] [Aαβ,a]对于活前缀 γ \gamma γ是有效的,如果存在规范推导
S ⇒ ∗ δ A ω → δ α β ω S\stackrel{*}{\Rightarrow}\delta A\omega \to \delta \alpha \beta \omega SδAωδαβω
其中

  • γ = δ α \gamma = \delta \alpha γ=δα

  • a是 ω \omega ω的第一个符号,或者a为#而 ω \omega ω ε \varepsilon ε

这里的 ω \omega ω是一个全为终结符的串,是因为在归约时是按照最左规约进行的,如果前面没有被归约,那么后面是不可能被归约的,也就是不可能含有非终结符,所以a直接去 ω \omega ω的第一个字符就可以了

构造NFA

构造方法:与LR(0)构造识别活前缀的NFA方法相同

构造有效的LR(1)项目集族

即求DFA

  • 项目集 I I I的闭包 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I)构造方式

    假定 I I I G ′ G' G的任一项目集,定义和构造 I I I的闭包 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I)如下:

    • I的任何项目都属于 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I)

    • 若项目 [ A → α ⋅ B β , a ] [A\to \alpha\cdot B\beta,a] [Aα,a]属于 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I) B → ξ B\to \xi Bξ是一个产生式,那么,对于 F I R S T ( β a ) FIRST(\beta a) FIRST(βa)中的每个终结符 b b b,如果 [ B → ⋅ ξ , b ] [B\to \cdot \xi,b] [Bξ,b]原来不在 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I)中,则把他加进去

    • 重复执行步骤2,直至 C L O S U R E ( I ) CLOSURE(I) CLOSURE(I)不再增大为止

  • 函数 G O ( I , X ) GO(I,X) GO(I,X)的定义

    I I I是一个项目集, X X X是一个文法符号,函数 G O ( I , X ) GO(I,X) GO(I,X)定义为: G O ( I , X ) = C L O S U R E ( J ) GO(I,X)=CLOSURE(J) GO(I,X)=CLOSURE(J)

    其中 J = { 任何形如 [ A → α X ⋅ β , a ] 的项目 ∣ [ A → α ⋅ X β , a ] ∈ I } J=\{任何形如[A\to \alpha X \cdot \beta ,a]的项目|[A\to \alpha\cdot X\beta ,a]\in I\} J={ 任何形如[AαXβ,a]的项目[Aα,a]I}

  • LR(1)项目集规范族C的构造算法

    • G G G拓广为 G ‘ G‘ G
    • G ’ G’ G构造 L R ( 1 ) LR(1) LR(1)项目集规范族 C C C和活前缀识别自动机的状态转换函数 G O GO GO
    • 使用 C C C G O GO GO,构造 L R ( 1 ) LR(1) LR(1)分析表
      • 令每个 I k I_k Ik的下标 k k k为分析表的状态,令含有 [ S ′ → ⋅ S , # ] [S'\to \cdot S,\#] [SS,#] I k I_k Ik的k为分析器的初态
      • 构造 L R ( 1 ) LR(1) LR(1) 分析表的 A C T I O N ACTION ACTION G O T O GOTO GOTO字表

    image-20220402221356374

项目集是啥

根据DFA构造规范LR分析表

  • 若项目 [ A → α ⋅ a β , b ] [A\to \alpha \cdot a\beta,b] [Aαaβ,b]属于 I k I_k Ik G O ( I k , a ) = I j GO(I_k,a)=I_j GO(Ik,a)=Ij a a a为终结符,则置 A C T I O N [ k , a ] ACTION[k,a] ACTION[k,a]为“把 ( j , a ) (j,a) (j,a)移进栈”,简记为“ s j sj sj
  • 若项目 [ A → α ⋅ , a ] [A\to \alpha\cdot,a] [Aα,a]属于 I k I_k Ik,则置 A C T I O N [ k , a ] ACTION[k,a] ACTION[k,a]为“用产生式 A → α A\to \alpha Aα归约”,简记为“ r j rj rj”,其中,假定 A → α A\to \alpha Aα为文法 G ′ G' G的第 j j j个产生式
  • 若项目 [ S ′ → S ⋅ , # ] [S'\to S\cdot ,\#] [SS,#]属于 I k I_k Ik,则置 A C T I O N [ k . # ] ACTION[k.\#] ACTION[k.#]为“接受”,简记为“ a c c acc acc
  • G O ( I k , A ) = I j GO(I_k,A)=I_j GO(Ik,A)=Ij,A为非终结符,则置 G O T O [ k , A ] = j GOTO[k,A]=j GOTO[k,A]=j
  • 分析表中凡不能使用规则1至4填入信息的空白格均置上“出错标志”

问题:项目具有如下形式: [ A → α ⋅ β , a 1 a 2 ⋯ a k ] [A\to \alpha\cdot\beta,a_1a_2\cdots a_k] [Aαβ,a1a2ak]。请问,该项目的中文名称是什么

  • LR(1)项目
  • LR(0)项目
  • LR(k)项目
  • LR项目

答案:C

问题:在规范句型 α β δ \alpha\beta\delta αβδ中,若 β \beta β为句柄,且 α β = u 1 u 2 ⋯ u r \alpha\beta=u_1u_2\cdots u_r αβ=u1u2ur,请问,下列哪个符号串是 α β δ \alpha\beta\delta αβδ的活前缀?

  • u 1 u 2 ⋯ u r u_1u_2\cdots u_r u1u2ur α \alpha α必为终结符串)
  • u 1 u 2 ⋯ u i ( 1 ≤ i ≤ r ) u_1u_2\cdots u_i(1\le i \le r) u1u2ui(1ir) δ \delta δ必为终结符串)
  • u 1 u 2 ⋯ u r u_1u_2\cdots u_r u1u2ur δ \delta δ必为终结符串)
  • u 1 u 2 ⋯ u i ( 1 ≤ i ≤ r ) u_1u_2\cdots u_i(1\le i\le r) u1u2ui(1ir) α \alpha α必为终结符串)

按最左规约进行,如果 β \beta β没有被规约,则 δ \delta δ中不可能被规约,也就是不可能有非终结符

image-20220402225902301

image-20220402225918842

LALR分析表的构造

问题:对于一般的语言,规范LR分析表要用几千个状态,无法实际应用

分析:由例6中可以看到,有些状态集除了搜索符不同外是两两相同的

解决办法:合并同心集,构造LALR分析表

说明:如果除去搜索符之后,这两个集合是相同的,我们称两个LR(1)项目集具有相同的心

将所有同心的LR(1)项目集合合并后,得到一个心就是一个LR(0)项目集

合并项目集时不用修改转换函数,即 G O ( I , X ) GO(I,X) GO(I,X);动作 A C T I O N ACTION ACTION应进行修改,使得能够反映各被合并的集合的既定动作

合并同心集不会产生新的移进-归约冲突,但有可能产生新的“归约-归约”冲突

对于同一个文法,LALR分析表和SLR分析表永远具有相同数目的状态,却能处理一些SLR所不能对付的事情

构造LALR分析表的第一个算法

步骤:

  • 构造文法G的LR(1)项目集族 C = { I 0 , I 1 , ⋯   , I n } C=\{I_0,I_1,\cdots,I_n\} C={ I0,I1,,In}
  • 把所有的同心集合并在一起,记 C ′ = { J 0 , J 1 , ⋯   , J m } C'=\{J_0,J_1,\cdots,J_m\} C={ J0,J1,,Jm}为合并后的新族。那个含有项目 [ S ′ → ⋅ S , # ] [S'\to \cdot S,\#] [SS,#] J k J_k Jk为分析表的初态
  • C ′ C' C构造 A C T I O N ACTION ACTION
    • 若项目 [ A → α ⋅ a β , b ] [A\to \alpha \cdot a \beta ,b] [Aαaβ,b]属于 J k J_k Jk G O ( J k , a ) = J i GO(J_k,a)=J_i GO(Jk,a)=Ji a a a为终结符,则置 A C T I O N [ k , a ] ACTION[k,a] ACTION[k,a]为“ s j sj sj
    • 若项目 [ A → α ⋅ , a ] [A\to \alpha \cdot ,a] [Aα,a]属于 J k J_k Jk,则置 A C T I O N [ k , a ] ACTION[k,a] ACTION[k,a]为“用产生式 A → α A\to \alpha Aα归约”,简记为" r j rj rj";其中,假定 A → α A\to \alpha Aα为文法 G ′ G' G的第 j j j个产生式
    • 若项目 [ S ′ → S ⋅ , # ] [S'\to S\cdot ,\#] [SS,#]属于 J k J_k Jk,则置 A C T I O N [ k , # ] ACTION[k,\#] ACTION[k,#]为"接受",简记为“ a c c acc acc
  • 构造 G O T O GOTO GOTO
  • 分析表中凡不能用步骤3、4填入信息的空白格均填上“出错标志”

image-20220402225936522

可以看到行数明显减少,减少了三行,因为做了三次同心集合并

image-20220402230033871

考试真题

算符优先分析

2021春-A

image-20220402230052515

image-20220402230115902

image-20220402230130381

2021春-B

image-20220402230204108

这例的LASTVT(w)错了,没有c

image-20220402230224330

image-20220402230241394

LR分析

2021-春-A

image-20220402230256600

image-20220402230303873

image-20220402230312412

image-20220402230325612

image-20220402230333213

2021-春-B

image-20220408101823919

image-20220408102001585

image-20220408102014781

在之前出现过得也要写在后面(倒数三四行)

image-20220408102100707

image-20220408102144757

猜你喜欢

转载自blog.csdn.net/qq_46311811/article/details/129430276