御敌之策,成竹在胸
1 概述
Import *Note
2 文法
Import Automata.Note
符号约定
- 终结符:前几位小写字母
- 非终结符:前几位大写字母
- 文法符号:后几位大写字母
- 终结符号串:后几位小写字母(包括空串)
- 文法符号串:小写希腊字母
3 词法分析
- 词法分析器读入表示源程序的字符流,按照程序功能要求,转换为对应的单词序列,并剔除注释和空字符
- 词素/单词/token:程序设计语言中具有独立意义的最小语法单位
- 编译的第一步即是利用词法分析器将源程序切分为单词
- 单词在编译过程中不会被继续切分
- token序列二元组:(种别,属性值)
词法分析例题
例3.1 分词
- 写出token序列
- 哪些token具有关联的属性值?
- 应该具有什么值?
例3.2 符号表的名称字段为什么要设计成字符串表这种数据结构?
不同标识符的NAME字段长度往往不同,如果以变长存储,就会使得符号表的查询效率降低,增大符号表管理的难度; 而若是以定长存储,很显然必须为该字段按照最大长度分配空间,而造成空间的严重浪费.
4 语法分析
语法分析-概念
- 根据文法,识别成分然后构造语法树
- 以token作为终结符
- 寻求无二义性
- 对任意CFG,不存在算法判定其二义性
- 但是能给出一组充分条件,满足充分条件的文法是无二义性的
- 推导:自顶向下;规约:自底向上
最左推导&最右推导
最左推导总是选择每个句型的最左非终结符进行替换;如果则是当前文法的最左句型。
相同地,有最右推导和最右句型。最右句型又叫规范句型,从而最左规约=规范规约,最右推导=规范推导。
最左推导&最右推导都是唯一的。
预测分析
- 预测分析是递归下降分析技术的一个 特例,通过在输入中向前看固定个数符号来选择正确的产生式。
- 对某些文法构造出向前看k个输入符号的预测分析器,该类文法有时也称为LL(k)文法类
- 预测分析不需要回溯,是确定的自顶向下的分析方法
Follow集合
非终结符后继符号集合记作,表示在某个句型中紧跟在后边的终结符的集合; 如果可能是某个句型的的最右符号,则将结束符\$$添加到Follow(A)$中;
Select集合
产生式的可选集是指可以选用该产生式进行推导时对应的输入符号的集合
- 如果
- 否则
挺好理解的,当读到特定符号可以选定(Select)特定产生式的集合,正是如此
First集合
文法符号串的串首终结符集是指可以它推导出的所有串首终结符构成的集合。如果,则
计算算法:
- 不断应用以下规则,直到没有新的终结符或可以被加入到任何First集合中为止
- 如果X是一个终结符,则
- 否则,,则
- 如果,则
- 如果,
- 如果,
一些文法
- S文法:简单确定性文法,要求每个产生式的右部都以终结符开始,同一非终结符的各个候选式的首终结符都不同,不含空产生式
- q文法:每个产生式右部或为空,或以终结符开始;具有相同左部的产生式有不相交的可选集(Select)
LL(1)
文法G是LL(1)的,当且仅当G的任意两个具有相同左部的产生式满足下面的条件:
- 不存在终结符a,是的均能推导出a开头的串
- 至多一个能推导出空
- 如果则;反之亦然。
第一个L表示从左向右扫描,第二个L表示最左推导;1表示每一步中只需要向前看一个输入符号来决定语法分析动作
递归与非递归方法
递归方法 | 非递归方法 | |
---|---|---|
程序规模 | 大 | 主控程序规模小 |
分析表需求 | 不需要 | 需要 |
直观性 | 好 | 差 |
效率 | 低下 | 正比于长度 |
自动生成 | 难 | 容易 |
实现步骤
- 构造文法
- 改造文法:消除二义性、左递归、回溯
- 求First和Follow集合,从而求Select集合
- 检查是否为LL(1)文法,如果是,构造预测分析表
- 对于递归的预测分析,根据预测分析表为每一个非终结符编写一个过程;对于非递归的预测分析,实现表驱动的预测分析算法
错误预测
两种情况下可以检测到错误
- 栈顶的终结符和当前输入符号不匹配
- 栈顶非终结符与当前输入符号在预测分析表对应项中的信息为空
恐慌模式是指,忽略输入中的一些符号,直到输入中出现由设计者选定的同步词法单元集合中的某个词法单元;synch是指,如果终结符在栈顶而不能匹配,一个简单的办法就是弹出此终结符,则可根据相应非终结符的Follow集得到的同步词法单元
移入-归约分析
自底向上的分析,利用最左归约,反向构建最右推导
- 栈内符号串+剩余输入=规范句型
- 移入:将下一个输入符号移到栈的顶端
- 规约:被归约的符号串的右端必然处于栈顶。语法分析器在栈中确定这个串的左端,并决定用哪个非终结符来替换这个串
- 每次归约的符号串称为"句柄"
- 接收:宣布语法分析过程成功完成
- 报错:发现一个语法错误,并调用错误恢复子例程
- LR文法是最大的、可以构造出相应移入-归约语法分析器的文法类,L表示从左到右扫描,R表示反向构造最右推导
- LR(k)文法表示需要向前查看k个输入符号的LR分析
- k=0和k=1两种有实践意义,默认k=1
- LR分析器基于一些状态来构造自动机进行句柄的识别
- 有动作表和转移表
LR(0)分析
- 右部某位置标有圆点的产生式称为相应文法的一个LR(0)项目(简称为项目),描述句柄识别的状态
- 空产生式只生成一个项目
- 同属于一个产生式的项目,但圆点的位置只相差一个符号,则称后者是前者的后继项目(如的后继项目为)
- 如果G是一个以S为开始符号的文法,则G的增广文法G'就是在G中加上新开始符号S'和产生式而得到的文法
- 增广文法使得文法开始符号仅出现在一个产生式的左边,从而使得分析器只有一个接受状态
- 规范句型的活前缀:不含句柄右侧任意符号的规范句型的前缀
- LR自动机中从初始状态开始的每一条路径对应一个规范句型活前缀
- 如果LR(0)分析表中没有语法分析动作冲突,那么给定的文法就称为LR(0)文法
- 不是所有CFG都能用LR(0)方法进行分析,也就是说,CFG不总是LR(0)文法
LR(0)的Closure
可以把等价的项目组成一个项目集(I),Closure(I)称为项目集闭包,每个项目集闭包对应着自动机的一个状态
算法:
- do
- for ()
- for ()
- if ()
- if ()
- for ()
- for ()
- until // 没有新项目加入
- return
LR(0)的Goto
项目集对应于文法符号的后继项目集闭包记作
⭐ LR(0)规范项集族
LR(0)分析表的构造
- 求规范项目项集族 // C为自动机状态集合
- foreach
- if()
- 如有 // 表示将符号状态入栈
- if()
- 如有
- if()
- if()
- Action[i,\]=accacc$表示接受
- if()
- foreach a\in V_T\cup\{\}$
- // 表示用第j个产生式进行归约,是产生式编号
- foreach a\in V_T\cup\{\}$
- if()
- if()
SLR分析
- LR(0)考虑了A的上文(规范句型的前缀),但未考虑A的下文,因此消解冲突能力有限
- 如果给定文法的SLR分析表中不存在有冲突的动作,那么该文法称为SLR文法
- SLR只是简单地考察下一个输入符号是否属于与归约项目相关联的Follow,但只是归约的一个必要条件,而非充分条件
SLR基本思想
如果已知项目集合,是移进项目的句柄中,点后第一个元素,是规约项目中的产生式左部;如果和两两不相交,则项目中的冲突可以按照以下原则解决:
设a是下一个输入符号
- if,则移入a
- if,则用产生式归约
- else error
SLR分析表的构造
- 求规范项目项集族 // C为自动机状态集合
- foreach
- if()
- 如有 // 表示将符号状态入栈
- if()
- 如有
- if()
- if()
- Action[i,\]=accacc$表示接受
- if() // 注意此处和LR(0)的区别
- foreach
- // 表示用第j个产生式进行归约,是产生式编号
- foreach
- if()
- if()