编译原理(4):语法分析(自上而下)
上一篇说了词法分析这次说语法分析,这两部分是一脉相承的。(上一篇在这)
- 要进行语法分析,必须对语言的语法结构进行描述。
- 采用正规式和有限自动机可以描述和识别语言的单词符号;
- 用上下文无关文法(前面已经说过了)来描述语法规则。
一、语法分析的任务
语法分析的任务:分析一个文法的句子结构。
语法分析器的功能(不深入探究):按照文法的产生式(语言的语法规则),识别输入符号串是否为一个句子(合式程序)。
二、语法分析的方法:
1. 自下而上分析法(Bottom-up):“了解”
基本思想:从输入串开始,逐步进行“归约”,直到文法的开始符号。即从树末端开始,构造语法树。所谓归约,是指根据文法的产生式规则,把产生式的右部替换成左部符号。
算符优先分析法:按照算符的优先关系和结合性质进行语法分析。适合分析表达式。
LR分析法:规范归约
2.自上而下分析法(Top-down)
基本思想:它从文法的开始符号出发,反复使用各种产生式,寻找"匹配"的推导。
递归下降分析法:对每一语法变量(非终结符)构造一个相应的子程序,每个子程序识别一定的语法单位,通过子程序间的信息反馈和联合作用实现对输入串的识别。
预测分析程序 优点:直观、简单和宜于手工实现。
三、自上而下分析的问题
自上而下就是从文法的开始符号出发,向下推导,推出句子。
- 带“回溯”的
- 不带回溯的递归子程序(递归下降)分析方法。
自上而下分析的主旨:对任何输入串,试图用一切可能的办法,从文法开始符号(根结点)出发,自上而下地为输入串建立一棵语法树。或者说,为输入串寻找一个最左推导。
例 : 假定有文法G(S): (1) S→xAy
(2) A→**|* 分析输入串x*y(记为α)。
则推导过程为:
由上图给出的的一种过程以及A的产生式集合可以看出该推导过程是不唯一的,也就是说A既可以用*来表示也可以用**来表示
上例的说明就带来了以下问题:
当某个非终结符有多个产生式候选时,可能带来如下问题:
- 1. 分析过程中,当一个非终结符用某一个候选匹配成功时,这种匹配可能是暂时的。出错时,不得不“回溯”。
- 2. 文法左递归问题。一个文法是含有左递归的,如果存在非终结符P
ps:含有左递归的文法将使自上而下的分析陷入无限循环。
四、LL(1)分析法
- 构造不带回溯的自上而下分析算法
- 要消除文法的左递归性
- 克服回溯
1.左递归的消除
直接消除见诸于产生式中的左递归:假定关于非终结符P的规则为 P→Pα|β,其中β不以P开头。 我们可以把P的规则等价地改写为如下的非直接左递归形式: P→βP' , P'→αP' |ε,即将上述的左递归文法改为了右递归文法。
一般而言,假定P关于的全部产生式是 P→Pα1 | Pα2 | … | Pαm | β1 | β2|…|βn 其中,每个β都不等于ε,每个β都不以P开头 那么,消除P的直接左递归性就是把这些规则改写成:
- P→β1P'| β2P' | … | βnP'
- P'→α1P' | α2P' |… | αmP' | ε
例 文法G(E):
E→E+T | T
T→T*F | F
F→(E) | i
经消去直接左递归后变成:
E→TE'
E'→+TE' | ε
T→FT'
T'→*FT' | ε
F→(E) | i
该例就是用了将左递归的文法改成右递归,这样一来就不含有右递归了
2.消除回溯、提左因子
消除回溯
为了消除回溯就必须保证:对文法的任何非终结符,当要它去匹配输入串时,能够根据它所面临的输入符号准确地指派它的一个候选去执行任务,并且此候选的工作结果应是确信无疑的。
这个地方要用到First集跟Follow集,不懂得可以看这篇
(点这里:first、Follow)
令G是一个不含左递归的文法,对G的所有非终结符的每个候选α定义它的终结首符集FIRST(α)为:
特别是,若α=*> ε ,则规定ε ∈ FIRST(α)。
如果非终结符A的所有候选首符集两两不相交,即A的任何两个不同候选α i和α j FIRST(αi)∩FIRST(α j)=∅
当要求A匹配输入串时,A就能根据它所面临的第一个输入符号a,准确地指派某一个候选前去执行任务。这个候选就是那个终结首符集含a的α。
提取公共左因子:
假定关于A的规则是 A→ δβ1 | δβ2 | …| δβn | γ1 | γ2 | … |γm
(其中,每个γ不以δ开头)
那么,可以把这些规则改写成 A→δA' | γ1 |γ2 | … | γm
A'→β1 | β2 | … | βn
经过反复提取左因子,就能够把每个非终结符(包括新引进者)的所有候选首符集变成为两两不相交。
五、LL(1)分析条件
假定S是文法G的开始符号,对于G的任何非终结符A,我们定义
特别是,若S=*>......A 则规定 #∈FOLLOW(A)
构造不带回溯的自上而下分析的文法条件
1. 文法不含左递归,
2. 对于文法中每一个非终结符A的各个产生式的候选首符集两两不相交。
即,若 A→α1|α2|…|αn 则 FIRST(α i)∩FIRST(αj)=∅ (i ≠ j)
3. 对文法中的每个非终结符A,若它存在某个候选首符集包含 ε,
则 FIRST(αi)∩FOLLOW(A)=∅ i=1,2,...,n
如果一个文法G满足以上条件,则称该文法G为LL(1)文法。
对于一个满足上述条件的文法,可以对其输入串进行有效的无回溯的自上而下分析。假设要用非终结符A进行匹配,面临的输入符号为a,A的所有产生式为
A→α1 |α2 | … | αn
1. 若aFIRST(αi),则指派αi执行匹配任务;
2. 若a不属于任何一个候选首符集,则:
(1) 若ε 属于某个FIRST(αi )且 a∈FOLLOW(A), 则让A与α自动匹配。
(2) 否则,a的出现是一种语法错误。
六、First集与Follow集(详细的解释看这篇)
1.First集的构造
对每一文法符号X∈Vt∪Vn构造FIRST(X)
连续使用下面的规则,直至每个集合FIRST不再增大为止:
1. 若X∈Vt,则FIRST(X)={X}。
2. 若X∈Vn,且有产生式X→a…,则把a加入到FIRST(X)中;若X→ε也是一条产生式,则把ε也加到FIRST(X)中。
3. 若X→Y…是一个产生式且Y∈Vn,则把FIRST(Y)中的所有非ε-元素都加到FIRST(X)中;
4. 若X→Y1Y2…Yk是一个产生式,Y1,…,Yi-1都是非终结符,而且,对于任何j,1≤j≤i-1,FIRST(Yj)都含有ε(即Y1…Yi-1 =*>ε), 则把FIRST(Yi)中的所有非ε-元素都加到FIRST(X)中;
5. 特别是,若所有的FIRST(Yj)均含有ε,j=1,2,…,k,则把ε加到FIRST(X)中。
对文法G的任何符号串α=X1X2…Xn构造集合FIRST(α)。
1. 置FIRST(α)=FIRST(X1)\{ε};
2. 若对任何1≤j≤i-1,ε∈FIRST(Xj),则把FIRST(Xi)\{ε}加至FIRST(α)中;特别是,若所有的FIRST(Xj)均含有ε,1≤j≤i-1,则把ε也加至FIRST(α)中。显然,若α=ε则FIRST(α)={ε}。
2.Follow集的构造
对于文法G的每个非终结符A构造FOLLOW(A)的办法
连续使用下面的规则,直至每个FOLLOW不再增大为止:
1. 对于文法的开始符号S,置#于FOLLOW(S)中;
2. 若A→αBβ是一个产生式,则把FIRST(β)\{ε}加至FOLLOW(B)中;
3. 若A→αB是一个产生式,或A→αBβ是一个产生式而β=*> ε(即ε∈FIRST(β)), 则把FOLLOW(A)加至FOLLOW(B)中。
例 文法: S→ABc
A→a|ε
B→b|ε
FIRST(S)={a,b,c} FIRST(A)={a,ε}; FIRST(B)={b,ε};
Follow(S)={#} Follow(A)={b,c} Follow(B)={c}
First集合求法:能由非终结符号推出的所有的开头符号或可能的ε,但要求这个开头符号是终结符号。如此题A可以推导出a和ε,所以FIRST(A)={a,ε};同理FIRST(B)={b,ε};S可以推导出aBc,还可以推导出bc,还可以推导出c,所以FIRST(S)={a,b,c}
Follow集合的求法:紧跟随其后面的终结符号或#。但文法的识别符号包含#,在求的时候还要考虑到ε。 具体做法是把所有包含你要求的符号的产生式都找出来,再看哪个有用。 Follow(S)={#}如求A的,产生式:S→ABc A→a|ε ,但只有S→ABc 有用。跟随在A后年的终结符号是FIRST(B)={b,ε},当FIRST(B)的元素为ε时,跟随在A后的符号就是c,所以 Follow(A)={b,c} 同理Follow(B)={c}
七、预测分析表
在对文法G的每个非终结符A及其任意候选α都构造出FIRST(α)和FOLLOW(A)之后,现在可以用它们来构造G的分析表M[A,a]。
1. 对文法G的每个产生式A→α执行第2步和第3步;
2. 对每个终结符a ∈FIRST(α),把A→α加至M[A,a]中;
3. 若ε ∈ FIRST(α),则对任何b∈ FOLLOW(A)把A→α 加至M[A,b]中。
4. 把所有无定义的M[A,a]标上“出错标志”。
对于文法G(E) E→TE'
E'→+TE' | ε
T→FT'
T'→*FT' | ε
F→(E) | i 构造每个非终结符的FIRST和FOLLOW集合如下
First集 Follow集
E {(,i} {),#} E' {+, ε} {),#} T {(,i} {+,),#} T' {*, ε} {+,),#} F {(,i} {*,+,),#} 根据First集跟Follow集构建预测分析表如下:
i + * ( ) # E E→TE' E→TE' E' E'→+TE' E'→ε E'→ε T T→FT' T→FT' T' T'→ε T'→*FT' T'→ε T'→ε F F→ i F→(E) 如果G是左递归或二义的,那么,M至少含有一个多重定义入口。因此,消除左递归和提取左因子将有助于获得无多重定义的分析表M。 可以证明,一个文法G的预测分析表M不含多重定义入口,当且仅当该文法为LL(1)的。
小结
暂时写到了语法分析的部分,细节后面会补充,写到这可能会停一段时间,要忙一些事情。明白语法分析的过程是构建语法分析器的基础,大家可以好好看看。感谢大家的观看,如有错误还请指正。可以留言,会回复的。
编译原理(4):语法分析(自上而下)相关推荐
- 编译原理实验:自上而下语法分析
编译原理实验:自上而下语法分析 1. 实验题目:自上而下语法分析 实验目的 实验内容 实验要求 输入输出 2. 设计思想 3. 算法流程 4. 源程序 5. 调试数据 1. 实验题目:自上而下语法分析 ...
- 编译原理实验二 自上而下语法分析
自上而下 语法分析实验 一.实验目的 (1)给出 PL/0 文法规范,要求编写 PL/0语言的语法分析程序. (2)通过设计.编制.调试一个典型的自上而下语法分析程序,实现对词法分析程序所提供的单词序 ...
- 编译原理2-Bison语法分析
ps:补上了图 实验要求 了解 Bison 基础知识和理解 Cminus-f 语法(重在了解如何将⽂法产⽣式转换为 Bison 语句) 阅读 /src/common/SyntaxTree.c ,对应头 ...
- 编译原理之语法分析(自底向上)(包含源码)
编译器之语法分析 自底向上 基本概念 算符优先 SLR 规范LR LALR 自底向上 基本概念 自底向上形成语法树的过程就是及逆行归约,将一堆单词串放在一起,形成某个产生式的样子,然后规约成某个产生式 ...
- 编译原理之语法分析(预测分析法)
编译器之语法分析 自顶向下 上下文无关文法 语法树 NFA→CFG 预测分析法 改写CFG 原因 消除二义性 消除左递归 消除左公因子 消除空产生式 消除回路 自顶向下 上下文无关文法 CFG本质上就 ...
- 编译原理实验二 自上而下的语法分析器(算术表达式)
1.语法分析器比之前的词法分析器简单一些,要做语法分析,首先我们需要词法分析器将输入的算术表达式进行分解,将其变为一个String数组,这样我们可以依次对每一个词进行匹配. 2.在执行匹配的时候,思想 ...
- 编译原理词/语法分析
效果: 代码: 1: using System; 2: using System.Collections.Generic; 3: using System.ComponentModel; 4: usi ...
- 计算机语法分析,电子科技大学-计算机学院-编译原理实验-语法分析.pdf
// SyntaxAnalyzer.cpp : 定义控制台应用程序的入口点. // #include #include #include #define MAX_COUNT 1024 #define ...
- 【编译原理】Python语法分析LL(1)、LR(1)
目录 一.实验目的 二.实验任务 三.实验原理 1 LL(1)文法 2 LR文法 四.实验过程 1 LL(1)文法 2 LR文法 五.实验结果 1 LL(1)文法 2 LR(0)文法 3 ...
- [编译原理]DO-WHILE循环语句的翻译程序设计(LR(1)方法、输出四元式)C++实现
题目: DO-WHILE循环语句的翻译程序设计(LR(1)方法.输出四元式) 1 课设任务概述 初始条件: 理论:完成编译原理,数据结构.高级编程语言.汇编语言等相关课程的学习,基于计算机专业知识 ...
最新文章
- 终于有人把计算机视觉讲明白了 。。。
- python使用matplotlib可视化线图(line plot)、将可视化图像的图例(legend)放置在图像外部、底部区域
- Map存值问题的研究
- DaVinci Resolve 16中文版
- php artisan 命令
- Linux下安装oracle的过程
- android onitemclicklistener 参数,android – 对listview中的项使用setOnItemClickListener
- python自动发送邮件_Python自动发送邮件
- 使用no-gui 模式执行分布式测试
- vmware-tools安装失败
- java颠倒字符串_Java经典实例:按字符颠倒字符串
- 基于深度学习的银行卡号识别 卡号识别和分割
- 手写原笔迹输入_手写原笔迹
- svn status详解
- python布尔类型的两个值_布尔人有两个可能的值。是否有三种可能值的类型?
- SQL编程-组队学习打卡task06-秋招秘籍ABC
- TIOBE编程语言排行榜,使用前二十语言实现HelloWorld程序
- DevOps落地实践:普元:PRIMETON DEVOPS
- JAVA interrupt、interrupted和isInterrupted的区别
- 微软面试程序题100道