05语法分析——自下而上分析

2023-10-19 17:50

本文主要是介绍05语法分析——自下而上分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、自下而上分析基本问题
  • 二、算符优先分析
    • 构造FIRSTVT(P)的算法
    • 构造LASTVT(P)的算法
    • 构造优先表的算法
  • 三、LR分析法
    • 1.LR(0)
      • 构造LR(0)项目集规范族
      • 构造识别活前缀的DFA
      • 构造LR(0)分析表
    • 2.SLR
      • SLR解决冲突办法
      • SLR(1)分析表的构造算法
    • 3.LR(1)【规范LR】
      • LR(1)项目集I的闭包
      • 状态转换函数GO
      • LR(1)项目集规范族构造
      • LR(1)分析表的构造算法
    • 4.LALR
      • LALR分析表的构造算法
    • 例题
    • 结论

一、自下而上分析基本问题

归约
本章讨论的自下而上分析法是一种“移进-归约”法。
即:利用一个栈来存放符号,首先把输入符号一个一个移进栈中,当栈顶的若干字符形成某个产生式的候选式时,则把这部分替换成该产生式的左部符号。

“可归约串”的定义有多种方法:
(1) 算符优先分析法: “最左素短语”
(2) 规范归约分析法: “句柄”

自下而上的分析过程也可用一棵语法树来表示,即先建子树,随着归约的完成,连成一棵语法树。

规范归约简述

在这里插入图片描述
一个句型的句柄是这个句型的语法树中最左深度为2的子树的叶子从左到右排列。

在这里插入图片描述
在这里插入图片描述

在形式语言中,最右推导常称为规范推导。由规范推导所得的句型称为规范句型。
若文法是无二义的,则规范推导的逆过程,必是规范归约。

对于规范句型,句柄的后面不会出现非终结符,即只能全是终结符。(原因:对于移进-归约来说,这是由句柄的“最左”特征决定的。)

规范归约的实质:
在移进的过程中,当发现栈顶呈现句柄时,就用相应的产生式的左部符号来替换。

符号栈的使用与语法树的表示
例如5.3 写出输入串i*i+i的规范归约过程:

步骤       栈         输入串               动作
0          #         i*i+i#               预备
1          #i         *i+i#               进栈
2          #F         *i+i#               归约
3          #T         *i+i#               归约
4          #T*         i+i#               进栈
5          #T*i         +i#               进栈
6          #T*F         +i#               归约
….
12         #E+T           #               归约
13         #E             #               归约
14         #E             #               接受

二、算符优先分析

它是一种简单、广为使用的自下而上分析法。特别有利于表达式的分析过程。
算符优先分析法不是一种规范归约法。

算符优先分析(Operator Precedence Parsing)
定义算符之间(即终结符之间)的某种优先关系,借助这种优先关系来寻找“可归约串”和进行归约。

基本思想

算符优先分析法是一种简单、直观、广为使用的自下而上语法分析方法,它是依据算术表达式的四则运算过程而设计的一种方法,也适用于对一般的高级语言程序的分析。

算符优先分析法的基本思想是,首先确定运算符(确切地说是终结符)之间的优先关系和结合性质,然后借助这种关系,比较相邻运算符之间的优先级来确定句型的可归约串,并进行归约。

值得注意的是,算符优先分析过程虽然是自下而上归约过程,但它的可归约串未必是句柄,也就是说,算符优先分析过程不是一种规范归约。

算法优先关系有三种:
a < b a的优先性低于b
a = b a的优先性等于b
a > b a的优先性高于b

注意
a > b 并不意味着 b < a,即不满足对称性

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

构造FIRSTVT§的算法

有两条规则:
(1)若有产生式 P->a……或 P->Qa……则 a∈ FIRSTVT(P)(2) 若有产生式 P->Q…… 则对任意a∈ FIRSTVT(Q),都有a∈ FIRSTVT(P)

构造LASTVT§的算法

有两条规则:(1)若有产生式 P->……b 或 P->……bQ则 b∈ LASTVT(P)(2) 若有产生式 P-> ……Q则对任意 b∈ LASTVT(Q),都有b∈ LASTVT(P)

构造优先表的算法

For  每个P->x1X2 …Xn    dofor  i:=1 to n  do  beginif Xi和Xi+1都是终结符 then Xi = Xi+1if Xi和Xi+2都是终结符,且Xi+1是非终结符,then  Xi = Xi+2 ;  (i<=n-2if Xi是终结符,Xi+1是非终结符 thenfor FirstVT(Xi+1)的每个a  do Xi < a ;  if Xi是非终结符,Xi+1是终结符 thenfor LastVT(Xi)的每个a  do a > Xi+1 ;  end.

在这里插入图片描述
在这里插入图片描述
素短语:至少含有一个终结符的短语,且除它自身外不再含有任何更小的素短语。
最左素短语:句型中最左边的素短语。
在算符优先文法中,用“最左素短语”来刻画可归约串。

在这里插入图片描述

算符优先分析算法

   k=1;     S[k]=‘#’;Repeat读一个输入字符aif  S[k] ∈VT    then   j:=k   else   j:=k-1 ;while    S[j] > a   do{   从栈中取出最左素短语->归约到某个N;N进栈  }if  S[j] < a  or  S[j] = a   then    {   a进栈   }     else   error;Until    a=‘#’                   

算法工作完毕后,符号栈S呈现#N#
某个非终结符号N是指那样一个产生式的左部符号,此产生式的右部和S[j+1]…S[k]构成如下一 一对应关系:自左向右,终结符对终结符,非终结符对非终结符,而且对应的终结符相同。

例5.4:对 P90 文法(5.3),
(1)E->E+T|T
(2)T->T*F|F
(3)F->P↑F|P
(4)P->(E)|i
分析句子 i+i

0    #         i+i#     预备
1    #i         +i#     进栈 (∵ # < i )
2    #P         +i#     归约 (∵ i > + )
3    #P+         i#     进栈 (∵ # < + ) 
4    #P+i         #     进栈 (+ < i )
5    #P+P         #     归约 (∵ i > # )
6    #E           #     归约 (+ > # )
7    #E#                接受 (∵ # = # )

若输入串正确,则符号栈里为#S#;
比规范归约分析要快得多( 跳过所有的单非产生式所对应的归约步骤,单非产生式:右部仅含一个非终结符的产生式,例如P->Q)
可能把不是句子的输入串误认为是句子(忽略了非终结符的作用) 适用于分析各类表达式的正确性。

优先函数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

优先函数:
优点: 便于作比较运算,且节约存储空间(n^2->2n);
缺点: 原来不存在优先关系的两个终结符,由于与自然数相对应,变成可比较了。

注意 一个优先关系表的优先函数不是唯一的; 有的优先关系表可能不存在其对应的优先函数。

三、LR分析法

LR分析法是一种有效的自下而上的分析技术,可用于很大一类上下文无关文法(包括LL(1))的语法分析。
L:表示从左到右扫描输入串;
R:表示构造一个最右推导的逆过程。

本章讨论四种LR分析表的构造方法:
LR(0) SLR
规范LR LALR

LR分析法的优缺点
1.能识别几乎所有能用CFG描述的程序设计语言的结构;
2.目前最一般的无回溯移进规约语法分析法,可以有效的实现;
3.是LL文法类的真超集;
4.在自左向右扫描输入串时,能准确发现出错位置;
5.用手工构造分析程序时,工作量太大,主要体现在分析表的构造。

1.LR(0)

LR(0)项目:在文法的每个产生式的右部添加一个点就称为一个LR(0)项目。
例如:产生式 A->XYZ 对应四个项目:

 A->. XYZA->X .YZA->XY. Z A->XYZ. 

一个项目指明了在分析过程中的某时刻,我们看到了产生式的多大部分。

注意:对于A->ε,只对应一个项目  A-> .

LR(0)文法
对文法G的拓广文法G’,若识别所有活前缀的DFA的每个状态不含有冲突,则称G是一个LR(0)文法
即:它的LR(0) 规范族C中的每个项目集都不是冲突项目集。
在这里插入图片描述

构造LR(0)项目集规范族

LR(0)项目集规范族:
构成识别一个文法所有活前缀的DFA的状态(项目集)的全体,称为这个文法的LR(0)项目集规范族。

项目集I的闭包closure(I)定义和构造
在这里插入图片描述
在这里插入图片描述
状态转换函数GO的定义
在这里插入图片描述
在这里插入图片描述

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

Procedure   itemset(G’)begin  C:={   Closure(S’.S)  };repeat   for  I ∈ C and x∈Vt∪VN  doif GO(I , x) not in C then 把 GO(I , x)加入到C until  C不再增大
End;

冲突项目集
若一个项目集里,既含有移进项目又含有归约项目,或含有多个不同的归约项目,则说该项目集含有冲突。
在这里插入图片描述

构造识别活前缀的DFA

在这里插入图片描述
在这里插入图片描述

构造LR(0)分析表

在这里插入图片描述
在这里插入图片描述
LR(0)分析表:按上述算法构造的分析表,若没有多重定义入口,则称为LR(0)分析表。
LR(0)文法:具有LR(0)分析表的文法。
LR(0)分析器:使用LR(0)分析表的分析器。

例如 对文法(5.7),
S’->.E
E->aB|bB
A->cA|d
B->cB|d
写出输入串 accd 的LR(0)分析过程。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.SLR

SLR(1)分析表:按上述算法构造的分析表若没有多重定义入口,则称为SLR分析表。 SLR(1)文法:具有SLR分析表的文法。
SLR(1)分析器:使用SLR(1)分析表的分析器。

在这里插入图片描述

SLR解决冲突办法

在这里插入图片描述
在这里插入图片描述

SLR(1)分析表的构造算法

在这里插入图片描述
在这里插入图片描述
若一个文法是LR(0)的,则一定是SLR(1)的;
每个SLR(1)文法都是无二义的。
当然,无二义的文法未必是SLR(1)的。

3.LR(1)【规范LR】

在SLR方法中,可能会存在无效的归约。
解决办法:
希望每个状态含更多的“展望”信息,以便能消除动作冲突 或 排除无效归约。
必要时,将状态进行分裂,使得LR分析器的每个状态能确切指出,当一个归约项目后跟哪些终结符时,才允许归约。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

LR(1)项目集I的闭包

在这里插入图片描述
在这里插入图片描述

状态转换函数GO

在这里插入图片描述

LR(1)项目集规范族构造

Procedure   itemset(G’)begin   C:={   I0=Closure(  [S’.S , #] )  };repeat   for  I∈ C and X∈Vt∪VN     doif   GO(I , X) not in C   then 把 GO(I , X)加入到C until  C不再增大
End;

在这里插入图片描述

LR(1)分析表的构造算法

在这里插入图片描述
在这里插入图片描述

规范LR分析表:按上述算法构造的分析表,若没有多重定义入口,则称为规范的LR(1)分析表。
LR(1)文法:具有规范LR(1)分析表的文法。
LR(1)分析器:使用规范LR(1)分析表的分析器。

4.LALR

LALR方法,是一种折中方法。
它的分析表比LR(1)分析表要小,能力也差一点,但它能解决一些SLR所不能对付的情形。
对同一个文法而言,LALR分析表和SLR分析表的状态个数相同。

两个LR(1)项目集是同心的:若除了搜索符外,这两个集合是相同的。

我们试图将所有同心的LR(1)项目集,合并为一个项目集。目的是希望能减少些状态个数。
但可能会存在这种现象:有一个LR(1)文法,它的所有LR(1)项目集都不存在冲突,但同心集合并后会存在“归约-归约”冲突 。
在这里插入图片描述
合并同心集后对某些错误发现的时间会产生推迟现象;
当输入串有误时,LR(1)能够及时发现错误,而 LALR 则可能还继续执行一些多余的归约动作,但决不会执行新的移进。
这意味着 LALR(1) 分析表比 LR(1) 分析表对同一输入串的分析可能会有多余归约
但错误的出现位置仍是准确的。

LALR分析表的构造算法

在这里插入图片描述
在这里插入图片描述

LALR分析表:按上述算法构造的分析表,若没有多重定义入口,则称为LALR分析表。
LALR(1)文法:具有LALR分析表的文法。

例题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

结论

●若文法是LR(0)的,则一定是SLR(1)的。反之不一定
●若文法是LALR(1)的,则一定是LR(1)的。反之不一定
●所有LR文法都是无二义的。

四种 LR 文法的判别方法:

首先判别文法是否为二义性文法,任何二义性文法都不是 LR 类文法。然后根据项目集中是否含冲突项目或相应分析表中是否含多重定义元素进行判断:
(a)LR(0) 文法是所有 LR(0) 项目集中没有“移进-归约”或“归约-归约”冲突(或 LR(0)分析表中不含多重定义)。
(b)SLR(0) 文法是 **LR(0) 项目集中含有冲突的项目都能用 SLR 规则解决(**或 SLR(0)分析表中不含多重定义)。
(c)LR(1) 文法是所有 LR(1) 项目集中 没有移进-归约”或“归约-归约”冲突(或LR(1)分析表中不含多重定义)。
(d)LALR(1) 项目集中 无“归约-归约”冲突(或LALR(1)分析表中不含多重定义)。注意搜索符只对归约项目起作用。

四种文法的关系:
一个文法是 LR(0) 文法,一定也是 SLR(1) 文法,也是 LR(1) 文法和 LALR(1) 文法。
在这里插入图片描述

这篇关于05语法分析——自下而上分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/241386

相关文章

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

找不到Anaconda prompt终端的原因分析及解决方案

《找不到Anacondaprompt终端的原因分析及解决方案》因为anaconda还没有初始化,在安装anaconda的过程中,有一行是否要添加anaconda到菜单目录中,由于没有勾选,导致没有菜... 目录问题原因问http://www.chinasem.cn题解决安装了 Anaconda 却找不到 An

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

C++ 各种map特点对比分析

《C++各种map特点对比分析》文章比较了C++中不同类型的map(如std::map,std::unordered_map,std::multimap,std::unordered_multima... 目录特点比较C++ 示例代码 ​​​​​​代码解释特点比较1. std::map底层实现:基于红黑

Spring、Spring Boot、Spring Cloud 的区别与联系分析

《Spring、SpringBoot、SpringCloud的区别与联系分析》Spring、SpringBoot和SpringCloud是Java开发中常用的框架,分别针对企业级应用开发、快速开... 目录1. Spring 框架2. Spring Boot3. Spring Cloud总结1. Sprin

Spring 中 BeanFactoryPostProcessor 的作用和示例源码分析

《Spring中BeanFactoryPostProcessor的作用和示例源码分析》Spring的BeanFactoryPostProcessor是容器初始化的扩展接口,允许在Bean实例化前... 目录一、概览1. 核心定位2. 核心功能详解3. 关键特性二、Spring 内置的 BeanFactory

MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析

《MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析》本文将详细讲解MyBatis-Plus中的lambdaUpdate用法,并提供丰富的案例来帮助读者更好地理解和应... 目录深入探索MyBATis-Plus中Service接口的lambdaUpdate用法及示例案例背景

MyBatis-Plus中静态工具Db的多种用法及实例分析

《MyBatis-Plus中静态工具Db的多种用法及实例分析》本文将详细讲解MyBatis-Plus中静态工具Db的各种用法,并结合具体案例进行演示和说明,具有很好的参考价值,希望对大家有所帮助,如有... 目录MyBATis-Plus中静态工具Db的多种用法及实例案例背景使用静态工具Db进行数据库操作插入

Go使用pprof进行CPU,内存和阻塞情况分析

《Go使用pprof进行CPU,内存和阻塞情况分析》Go语言提供了强大的pprof工具,用于分析CPU、内存、Goroutine阻塞等性能问题,帮助开发者优化程序,提高运行效率,下面我们就来深入了解下... 目录1. pprof 介绍2. 快速上手:启用 pprof3. CPU Profiling:分析 C

MySQL表锁、页面锁和行锁的作用及其优缺点对比分析

《MySQL表锁、页面锁和行锁的作用及其优缺点对比分析》MySQL中的表锁、页面锁和行锁各有特点,适用于不同的场景,表锁锁定整个表,适用于批量操作和MyISAM存储引擎,页面锁锁定数据页,适用于旧版本... 目录1. 表锁(Table Lock)2. 页面锁(Page Lock)3. 行锁(Row Lock