编译原理-4(2)-语法分析

目录

8 自底向上分析概述

9 LR分析法概述

(1)LR 分析法的基本原理

(2)LR 分析器(自动机)的总体结构

(3)LR 分析表的结构

(4)LR 分析器的工作过程及LR 分析算法

(5)如何构造给定文法的LR分析表

10 LR(0)分析

(1)LR(0) 项目

(2)增广文法 (Augmented Grammar)

(3)文法中的项目

(4)LR(0)自动机

11 LR(0)分析表构造算法

12 SLR分析

13 LR(1)分析

(1)LR(1)分析法的提出

(2)规范LR(1)项目

(3)等价LR(1)项目

(4)例:LR(1)自动机

(5)LR(1)项目集闭包及GOTO函数

(6)LR(1)自动机的形式化定义

(7)LR分析表构造算法

14 LALR分析法

15 二义性文法的LR分析

16 LR分析中的错误处理


8 自底向上分析概述

  • 从分析树的底部(叶节点)向顶部(根节点)方向构造分析树
  • 可以看成是将输入串w归约为文法开始符号S的过程
  • 的语法分析采用最左推导方式,的语法分析采用最左归约方式反向构造最右推导
  • 最左归约是最右推导的逆过程
  • 自底向上语法分析的通用框架 — 移入-归约分析(Shift-Reduce Parsing)
移入-归约分析的工作过程
①在对 输入 串的一次从左到右扫描过程中,语法分析 器将零个或多个输入符号 移入 的顶端,直到它 可以对栈顶的一个文法符号串 β 进行 归约 为止
②然后,它将β 归约 为某个产生式的左部
③语法分析器不断地重复这个循环,直到它检测到一个语法 错误 ,或者栈中包含了开始符号且输入缓冲 区为空 ( 当进入这样的格局时,语法分析器停止运行, 并宣称 成功 完成了语法分析)为止
移入-归约分析器可采取的4种动作
移入:将下一个输入符号移到栈的顶端
归约:被归约的符号串的 右端 必然处于栈顶。语法 分析器在栈中确定这个串的 左端 ,并决定用哪个非终结符来替换这个串
接收:宣布语法分析过程成功完成
报错:发现一个语法错误,并调用错误恢复子例程
移入-归约分析中存在的问题

9 LR分析法概述

LR文法 ( Knuth, 1963) 是最大的、可以构造出相应 移入-归约语法分析器 的文法类
   L: 对输入进行从 到右的扫描
   R: 反向构造出一个最 推导序列
LR(k)分析
需要向前查看k个输入符号的LR分析
k = 0 k = 1 这两种情况具有实践意义,当省略(k ) 时,表示 k =1

(1)LR 分析法的基本原理

自底向上分析的关键问题是什么? ——如何正确地识别句柄
句柄是逐步形成的,用“状态”表示句柄识别的进展程度
 

(2)LR 分析器(自动机)的总体结构

(3)LR 分析表的结构

(4)LR 分析器的工作过程及LR 分析算法

(5)如何构造给定文法的LR分析表

         LR(0)分析
         SLR分析
         LR(1)分析
         LALR分析

10 LR(0)分析

(1)LR(0) 项目

(2)增广文法 (Augmented Grammar)

(3)文法中的项目

(4)LR(0)自动机

11 LR(0)分析表构造算法

LR(0)自动机的每一个状态是一个项目集闭包

12 SLR分析

LR(0)分析在构造项目时向前查看0个符号,即没有考虑文法符号的上下文环境。

LR(0)文法要求文法的每一个LR(0)项目都不含有冲突的项目,这个条件比较苛刻。对于大多数程序设计语言来说,一般都不能满足LR(0)文法的条件。
不难看出在状态I2中既存在规约项目,又存在移进项目,因而这个文法不是LR(0)文法。
为了对语言句子进行确定性的分析,需要解决冲突。可以采用对含有冲突的项目集向前查看一个输入符号的办法来解决冲突,这种分析法称为简单的LR分析法,即SLR(1)分析法。

SLR分析法只需向前查看一个符号,因此也称SLR(1)分析法,k=1时可省略
S:simple
仅需FOLLOW集便可化解冲突

LR(0)分析表中每一个归约状态遇到任何输入符号时都采取归约动作
SLR分析表中归约状态只有遇到FOLLOW集中的元素时才采取归约动作

这种用来解决分析动作冲突的方法称为SLR(1)方法。如果对于一个文法的某些LR(0)项目集或LR(0)分析表中所含有的动作冲突都能用SLR(1)方法解决,则称这个文法是SLR(1)文法

和LR(0)分析表构造仅有一处不同。

13 LR(1)分析

(1)LR(1)分析法的提出

SLR 分析存在的问题
SLR 只是简单地考察 下一个输入符号 b 是否属于与 归约 项目 A α 相关联的 FOLLOW ( A ) b FOLLOW ( A ) 只是归约 α 的一个 必要条件 ,而非 充分条件
对于产生式 A α 的归约,在 不同的使用位置 A 会要求 不同的后继符号
在特定位置,A 的后继符集合是 FOLLOW ( A ) 子集
而SLR分析法利用FOLLOW集作为判定是否可以归约的条件,显然 扩大了可以归约的范围

(2)规范LR(1)项目

(3)等价LR(1)项目

(4)例:LR(1)自动机

(5)LR(1)项目集闭包及GOTO函数

(6)LR(1)自动机的形式化定义

(7)LR分析表构造算法

14 LALR分析法

LR(1)分析法根据展望符集合的不同将原始的LR(0)项目进行分裂分裂成不同的LR(1)项目使LR(1)自动机中的状态数比LR(0)多很多

而把没有动作冲突的状态进行合并可以大大减少自动机的状态数,有利于节省空间。

LALR ( lookahead-LR )分析的基本思想
①寻找具有 相同核心 LR (1) 项集,并将这些项集合并为一个项集。 所谓项集的核心就是其第一分量的集合
②然后根据合并后得到的项集族构造语法分析表
③如果分析表中 没有 语法分析动作 冲突 ,给定的文法就称为 LALR (1) 文法 ,就可以根据该分析表进行语法分析
实际合并的是对应项的展望符集合,展望符仅在归约时起作用,在移入时不起作用,所以在合并前各个同心项目集不存在移入-归约冲突的话,合并后也不会有移入-归约冲突
 

状态4&9、6&10同心项目
但是当遇到错误的输入d$(因为至少输入dcd)  合并前状态4遇到$报错;合并后不会报错执行归约,将栈顶d连同状态4一起出栈,露出了压在状态4下的状态0,状态0遇到刚刚归约的A进入状态2,此时遇到$是非法符号报错

LALR (1) 的特点
形式上与LR (1)相同
大小上与 LR (0)/ SLR相当
分析能力介于 SLR LR (1)二者之间   SLR<LALR (1)< LR(1)
合并后的展望符集合仍为 FOLLOW 集的 子集

15 二义性文法的LR分析

二义性文法的使用
  应该保守地使用二义性文法,并且必须在严格控制之下使用,因为稍有不慎就会导致语法分析器所识别的语言出现偏差

16 LR分析中的错误处理

LR 分析中的错误处理
    语法错误的检测     当 LR 分析器在查询分析表并发现一个报错条目时,就检测到了一个语法错误
错误恢复策略
    恐慌模式错误恢复
    短语层次错误恢复
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
附录c 编译程序实验 实验目的:用c语言对一个简单语言的子集编制一个一遍扫描的编译程序,以加深对编译原理的理解,掌握编译程序的实现方法和技术。 语法分析 C2.1 实验目的 编制一个递归下降分析程序,实现对词法分析程序所提供单词序列的语法检查和结构分析. C2.2 实验要求 利用C语言编制递归下降分析程序,并对简单语言进行语法分析. C2.2.1待分析的简单语言的语法 实验目的 通过上机实习,加深对语法制导翻译原理的理解,掌握将语法分析所识别的语法成分变换为中间代码的语义翻译方法. 实验要求 采用递归下降语法制导翻译法,对算术表达、赋值语句进行语义分析并生成四元序列。 实验的输入输出 输入语法分析提供正确单词输出地址指令形式四元序列。 例如:对于语句 begin a:=2+3*4;x:=(a+b)/c end# 输出地址指令如下: (1) t1=3*4 (2) t2=2+t1 (3) a=t2 (4) t3=a+b (5) t4=t3/c (6) x=t4 算法思想 1设置语义过程 (1) emit(char *result,char *arg1,char *op,char *ag2) 该函数功能是生成一个地址语句送到四元表中。 四元表的结构如下: struct {char result[8]; char ag1[8]; char op[8]; char ag2[8]; }quad[20]; (2)char *newtemp() 该函数回送一个新的临时变量名,临时变量名产生的顺序为T1,T2,…. Char *newtemp(void) { char *p; char m[8]; p=(char *)malloc(8); k++; itoa(k,m,10); strcpy(p+1,m); p[0]=’t’; return(p); } (2)主程序示意图如图c.10所示。 (2) 函数lrparser在原来语法分析的基础上插入相应的语义动作:将输入翻译成四元序列。在实验中我们只对表达、赋值语句进行翻译。 语义分析程序的C语言程序框架 int lrparser() { int schain=0; kk=0; if(syn=1) { 读下一个单词符号; schain=yucu; /调用语句分析函数进行分析/ if(syn=6) { 读下一个单词符号; if(syn=0 && (kk==0)) 输出(“success”); } else { if(kk!=1 ) 输出 ‘缺end’ 错误;kk=1;} else{输出’begin’错误;kk=1;} } return(schain); int yucu() { int schain=0; schain=statement();/调用语句分析函数进行分析/ while(syn=26) {读下一个单词符号; schain=statement(); /调用语句分析函数进行分析/ } return(schain); } int statement() { char tt[8],eplace[8]; int schain=0; {switch(syn) {case 10: strcpy(tt,token); scanner(); if(syn=18) {读下一个单词符号; strcpy(eplace,expression()); emit(tt,eplace,””,””); schain=0; } else {输出’缺少赋值号’的错误;kk=1; } return(schain); break; } } char *expression(void) {char *tp,*ep2,*eplace,*tt; tp=(char *)malloc(12);/分配空间/ ep2=(char *)malloc(12); eplace=(char *)malloc(12); tt =(char )malloc(12); strcpy(eplace,term ());/调用term分析产生表达计算的第一项eplace/ while(syn=13 or 14) { 操作符 tt= ‘+’或者‘—’; 读下一个单词符号; strcpy(ep2,term());/调用term分析产生表达计算的第二项ep2/ strcpy(tp,newtemp());/调用newtemp产生临时变量tp存储计算结果/ emit(tp,eplace,tt,ep2);/生成四元送入四元表/ strcpy(eplace,tp); } return(eplace); } char *term(void)/仿照函数expression编写/ char *factor(void) {char *fplace; fplace=(char *)malloc(12); strcpy(fplace, “ ”); if(syn=10) {strcpy(fplace,,token);/将标识符token的值赋给fplace/ 读下一个单词符号; } else if(syn=11) {itoa(sum,fplace,10); 读下一个单词符号; } else if (syn=27) {读下一个单词符号; fplace=expression();/调用expression分析返回表达的值/ if(syn=28) 读下一个单词符号; else{输出‘}’错误;kk=1; } } else{输出‘(’错误;kk=1; } return(fplace); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值