04 | 语法分析

04 | 语法分析

  • 语法分析程序(语法分析器)概述
  • 自上而下分析法
    • 前述
    • 递归下降分析法
    • 预测分析法( LL(1)分析法 )
  • 自下而上分析法
    • 前述
    • 算符优先分析法
    • LR分析法
      • LR(0)分析法
      • SLR(1)分析法
      • LR(1)分析法
      • LALR(1)分析法
      • 二义性文法的LR分析

语法分析程序(语法分析器)概述

  • 输入:词法分析器生成的单词符号序列
  • 输出:语法树
  • 详述:语法分析器的功能是以词法分析器生成的单词符号序列作为输入,根据语言的语法规则(描述程序语言语法结构的上下文无关文法),识别出各种语法成分(如表达式、语句、程序段以及整个程序等),并在分析过程中进行语法检查,检查所给单词符号序列是否是该语言的文法的一个句子。若是,则以该句子的某种形式的语法树作为输出;若不是,则表明有错误,并指出错误的性质和位置。
  • 两大类方法:
    (1)自上而下的分析方法:从文法的开始符号出发,根据文法规则正向推导出给定句子的一种方法。即从树根开始,向下构造语法树,直到建立每个树叶。
    (2)自下而上的分析方法:从给定的输入串开始,根据文法规则逐步进行归约,直至归约到文法的开始符号。即从语法树的末端开始,步步向上归约直至根结点。

自上而下分析法

前述

非确定的自上而下分析法的思想:

  • 对任何输入串 W 试图采用一切可能的办法,从文法的开始符号出发,自上而下地为它建立一棵语法树。或者说是为该输入串寻找一个最左推导(由于要对输入串进行自左向右的扫描,因此使用最左推导才能保证自左向右扫描顺序匹配输入串)。如果试探成功,则W是相应文法的一个句子,否则就不是。
  • 本质上该过程是一个穷举试探的过程,反复使用不同规则来谋求匹配的输入串。
  • 存在两个问题,使得效率低、代价高:

左递归: 文法左递归,是指文法中某个非终结符A存在推导A ⇒ +Aα。

分析:自上而下分析法施行最左推导,每次替换当前句型的最左非终结符,当试图用非终结符A去匹配输入串时,结果使当前句型的最左非终结符仍为A。即在没有任何输入符号的情况下,又重新要求A去进行新的匹配,于是造成无穷循环。因此需要消除文法左递归。

消除左递归:

  • 引进一个新的非终结符,将含左递归的规则改成右递归:
    过程中注意空串

  • 采用扩充BNF表示法改写含直接左递归的规则:

04 | 语法分析_第1张图片

回溯: 在文法中某个非终结符A有多个候选式,遇到用 A 去匹配当前输入符号a时,无法确定选用唯一的一个候选式,而只能逐一进行试探,从而引起回溯,具体表现为下面两种情况:

  • 相同左部的规则,其右部左端第一个符号相同引起回溯
  • 相同左部的规则,其中某一右部能退出 ε 串

消除回溯: 要求描述语言的文法是LL(1)文法。

LL(1)文法:

Left to right,left to most。

LL(1)中第一个“L”表明自上而下的分析是从左到右扫描输入串,第二个“L”表明分析过程中使用最左推导,“1”表明分析时每一步只需向前看一个符号即可决定所选用的准确无误的规则。

首先明确3个相关集:

  • FIRST(α):α可推导出的所有首终结符或可能的 ε 。

在这里插入图片描述

  • FOLLOW(A):文法所有句型中紧接在 A 之后出现的终结符或 $ ($为输入串的结束符)。

04 | 语法分析_第2张图片

  • SELECT(A→α):规则的选择集合

04 | 语法分析_第3张图片
LL(1)文法的判断条件: 对于每个非终结符的任何两个不同的规则,满足二者的SELECT集相交为空。

在这里插入图片描述

当一个文法不是LL(1)文法时,对输入串进行自上而下的分析就会发生回溯。因此,首先要消除左递归并将其转换为LL(1)文法。对LL(1)文法,若当前非终结符A面临输入符号a时,可根据a属于哪一个SELECT集,唯一地选择一条相应规则去准确匹配输入符号a。

非LL(1)文法到LL(1)文法的转变:

对一些非LL(1)文法而言,可通过消除左递归和反复提取公共左因子对文法进行等价变换,将其改造为LL(1)文法。
04 | 语法分析_第4张图片
一个例子:

04 | 语法分析_第5张图片

而一些公共左因子是隐式的,所以可以用一些规则进行替换后得到显式的左公因子,之后再进行消除。

一个例子:

04 | 语法分析_第6张图片

但是,也并非所有的非LL(1)文法都能被成功改写为LL(1)文法。

一个例子:

在这里插入图片描述

04 | 语法分析_第7张图片

递归下降分析法

  • 确定的自上而下分析法
  • 要求LL(1)文法
  • 基本思想:对文法中的每个非终结符编写一个函数(或子程序),每个函数(或子程序)识别由该非终结符所表示的语法成分。由于描述程序语言的文法常常是递归定义的,因此相应的这组函数(或子程序)必然以相互递归的方式进行调用,因此该分析法为递归下降分析法。
  • 构造:每个函数名是相应的非终结符,函数体根据规则右部的符号串的结构编写

递归下降分析法简单、直观、易于构造分析程序,但文法要求高,另外递归调用多,影响分析器的效率。

预测分析法( LL(1)分析法 )

  • 确定的自上而下分析法
  • 要求文法 LL(1) 文法
  • 预测分析器的组成:预测分析表( LL(1)分析表 )、先进后出分析栈、总控程序。
  • 工作流程:

这里说明一下,选用候选式入栈的时候,实际上就相当于用右部替换栈中的左部。

  • 预测分析表的构造:

    总控程序对于不同的LL(1)文法相同,预测分析表对不同LL(1)文法不同。

  • 错误处理:
    (1)栈顶终结符与当前输入不匹配
    (2)栈顶为非终结符,与当前输入在预测分析表中的对应值为空

自下而上分析法

前述

  • “移进-归约”原理

  • 基本思想:用一个寄存文法符号的先进后出栈,将输入符号一个一个地按从左到右扫描顺序移入栈中,边移入边分析,当栈顶符号串形成某条规则右部时就进行一次归约,即用该规则左部非终结符替换相应规则规则右部符号串,栈顶被归约的这一串符号为可归约串。重复这一过程直到整个输入串分析完毕。最终若栈中剩下句子右界符 “$” 和文法的开始符号,则所分析的输入符号串是文法的正确句子,否则报告错误。

  • 关键问题:定义并识别“可归约串”

定义可归约串 { 规 范 归 约 分 析 法 − − − 用 “ 句 柄 ” 刻 画 可 归 约 串 算 符 优 先 分 析 法 − − − 用 “ 最 左 素 短 语 ” 刻 画 可 归 约 串 \left\{\begin{aligned}规范归约分析法---用“句柄”刻画可归约串\\算符优先分析法---用“最左素短语”刻画可归约串\end{aligned}\right. {

根据识别可归约串的不同方法,形成不同的自下而上分析方法,简单优先分析法和LR分析法都是规范归约分析法,但二者识别句柄的方法不同:

识别可归约串 { 简 单 优 先 分 析 法 : 根 据 文 法 符 号 之 间 的 优 先 关 系 确 定 栈 顶 符 号 串 是 否 形 成 句 柄 L R 分 析 法 : 根 据 历 史 、 现 实 、 展 望 的 信 息 确 定 栈 顶 符 号 串 是 否 形 成 句 柄 \left\{\begin{aligned}简单优先分析法:根据文法符号之间的优先关系确定栈顶符号串是否形成句柄\\LR分析法:根据历史、现实、展望 的信息确定栈顶符号串是否形成句柄\end{aligned}\right. {LR

算符优先分析法

要明确算符优先文法,我们首先要明确什么是优先关系,什么是算符文法。

优先关系:
04 | 语法分析_第8张图片
04 | 语法分析_第9张图片

算符文法:

简单来说,即任一规则右部都不存在两个非终结符相邻的情况

04 | 语法分析_第10张图片

算符优先文法:

在这里插入图片描述

一个例子:

04 | 语法分析_第11张图片

算符优先关系表:

在这里插入图片描述
算符优先关系表的构造:

简单来说,FIRSTVT(A)集就是 A 右部从左向右遇到的第一个终结符,LASTVT(A)就是A右部从左向右遇到的最后一个终结符
04 | 语法分析_第12张图片
构造算法如下:


04 | 语法分析_第13张图片

一个例子:

优先关系表中,左侧列为左边的算符,上方的一行为右侧的算符。

素短语: 至少包含一个终结符,并且除自身外,不再包含其他终结符。

最左素短语: 句型最左边的素短语为最左素短语。

识别最左素短语的方法:

算符优先分析算法:



算符优先分析法的局限性:

LR分析法

  • 自下而上规范归约

  • “L”指从左到右扫描输入符号串,“R”指构造最右推导的逆过程

  • LR(k)表示需要向前查看k个输入符号的LR分析法,一般k=0或k=1,当省略(k)时,表示k=1。

  • 关键:如何确定分析栈栈顶的符号串是否已形成句柄

引入状态:
04 | 语法分析_第14张图片

  • 基本思想:在规范归约分析过程中,
    (1)历史:根据分析栈中记录的已移进和归约出的整个符号串
    (2)展望:根据使用的规则推测未来可能遇到的输入符号
    (3)现在:现实读入的输入符号
    由上述3个方面的信息来确定分析栈栈顶的符号串是否构成句柄。

  • LR分析器结构:分析栈、分析表、总控程序
    04 | 语法分析_第15张图片

分析表的结构:
ACTION对应终结符、$,GOTO对应非终结符
04 | 语法分析_第16张图片

04 | 语法分析_第17张图片

  • LR分析法算法:
    04 | 语法分析_第18张图片

  • 在分析的任意时刻,分析栈中已“移进-归约”的全部文法符号与剩余的输入符号串合起来就是文法的一个规范句型。

  • 表格驱动,对文法限制少,大多数无二义性的上下文无关文法描述的语言都可以用LR分析法进行有效的分析,即便对于非LR的上下文无关文法,常见的程序设计语言构造都可以避免使用这样的文法。

  • 分析速度快,采用无回溯的“移进-归约”分析,和其他更原始的“移进-归约”方法一样高效,并能准确及时地指出输入串的语法错误和出错位置

  • { L R ( 0 ) S L R ( I ) L R ( 1 ) L A L R ( 1 ) \left\{\begin{aligned}LR(0)\\SLR(I)\\LR(1)\\LALR(1)\end{aligned}\right. LR(0)SLR(I)LR(1)LALR(1)

LR(0)分析法

LR(0)分析法,就是在分析的每一步,只需根据当前栈顶状态而不必向前查看输入符号就能确定应采取的分析动作。

文法规范句型的活前缀:
(1)字符串的前缀是指字符串的任意首部
(2)规范句型活前缀是指规范句型的前缀。
活前缀可以是一个或若干个规范句型的前缀。

LR(0)项目:

首先理解一下:
04 | 语法分析_第19张图片
具体定义如下:

拓广文法:

04 | 语法分析_第20张图片

后继项目:
04 | 语法分析_第21张图片

构造识别文法活前缀的DFA:

在这里插入图片描述
CLOSURE函数:

04 | 语法分析_第22张图片
04 | 语法分析_第23张图片

GOTO函数:
04 | 语法分析_第24张图片
构造规范LR(0)项集族:
04 | 语法分析_第25张图片

构造LR(0)分析表:
04 | 语法分析_第26张图片

**冲突:**移进-归约冲突、归约-归约冲突

04 | 语法分析_第27张图片

SLR(1)分析法

  • simple LR分析法,简单的LR分析法

  • 向前查看一个输入符号

  • 基本思想:

  • SLR(1)分析表中每一个状态,只有在遇到FOLLOW集中的元素时才会对归约状态采取归约动作,而LR(0)分析法中不论遇到什么输入符号,都会对归约状态采取归约动作

SLR(1)分析表的构造:
04 | 语法分析_第28张图片

冲突: 如下就是一个移进-归约冲突

04 | 语法分析_第29张图片

LR(1)分析法

解决SLR(1)的冲突:
04 | 语法分析_第30张图片
规范LR(1)项目:
04 | 语法分析_第31张图片

等价LR(1)项目:

04 | 语法分析_第32张图片

LR(1)项目集闭包:
04 | 语法分析_第33张图片

GOTO函数:
04 | 语法分析_第34张图片

规范LR(1)项集族:

04 | 语法分析_第35张图片

LR(1)分析表构造算法:
04 | 语法分析_第36张图片

同心项目集:
04 | 语法分析_第37张图片

LALR(1)分析法

对LR(1)合并同心集

04 | 语法分析_第38张图片

冲突:会产生归约-归约冲突,但是不会产生移进-归约冲突

可能会推迟错误的发现
04 | 语法分析_第39张图片
04 | 语法分析_第40张图片

二义性文法的LR分析

利用优选级、结合性,利用LR消除二义性

你可能感兴趣的:(编译原理)