语法分析

词法分析:

  • 字母是元素,组成字符串,记号的集合,线性结构,以字符流为输入

语法分析:

  • 记号是元素,组成句子, 句子的集合,树结构,以记号流为输入

语法的双重含意:

  1. 语法规则:上下文无关文法(子集-LL文法或LR文法)
  2. 语法分析:下推自动机(LL或LR分析器),自上而下自下而上分析 (这两种都只能处理上下文无关文法的子类)

语法分析器

语法分析器是编译器前端的重要组成部分,中心部件

语法分析器的两个重要作用:

  1. 根据词法分析器提供的记号流,为语法正确的输入构造分析树(或语法树)
  2. 检查输入中的语法(可能包括词法)错误,并调用出错处理器进行适当处理

语法错误处理原则

源程序中可能出现的错误:

  • 语法(包括词法)错误

    • 词法错误非法字符拼写错关键字、标识符
    • 语法错误是指语法结构出错,如少分号、begin/end不配对等
  • 语义错误
    • 静态语义错误(涉及的是编译时可检查出来的错误):如类型不一致、参数不匹配等
    • 动态语义错误(程序运行时的逻辑错误):如死循环、变量为零时作除数等

目标:

  • 清楚而准确地报告错误的出现(地点正确,不漏报、不错报也不多报
  • 迅速从每个错误中恢复过来(以便分析继续进行)
  • 不应对语法正确源程序的分析速度降低太多

基本恢复策略

  1. 紧急方式恢复:抛弃若干输入,直到遇到某个指定的合法记号(称为同步记号)集合为止同步记号一般是定界符,如分号或end等【最简单,但最容易造成错报、漏报和多报语法错误的现象】
  2. 短语级恢复:采用串替换的方式对剩余输入进行局部纠正(抛弃+插入)
  3. 出错产生式:用出错产生式捕捉错误(预测错误),预置型的短语级恢复方式(YACC采用的方式)
  4. 全局纠正:对错误输入序列x,找相近序列y,使得x变换成y所需的修改、插入、删除次数最少【代价太大】

上下文无关文法CFG

CFG:Context Free Grammar

  • CFG是一个四元组G =(N,T,P,S),其中

    • (1) N是非终结符(Nonterminals)的有限集合
    • (2) T是终结符(Terminals)的有限集合,且N∩T=Φ;
    • (3) P是产生式(Productions)的有限集合,
      A→α,其中A∈N(左部),α∈(N∪T)*(右部),
      若α=ε,则称A→ε为空产生式(也可以记为A →);
    • (4) S是非终结符,称为文法的开始符号(Start symbol)
  • 可以将产生式中的记号→读作 “定义为” 或者 “可导出”

    • 如:“E → E + E”可用自然语言表述为“算术表达式定义为两个算术表达式相加”, 或者“一个算术表达式加上另一个算术表达式,仍然是一个算术表达式”

各元素要求

  • 文法开始符号S是第一个产生式的左部;
  • N是可以出现在产生式左边符号的集合;
  • T绝不出现产生式左边符号的集合(记号) ,所以T不一定是一个句子的那种终结符,也可以是一个短语的终结符,如+、-、(、)等等

约定:

  • 大写英文字母A、B、C表示非终结符
  • 小写英文字母a、b、c表示终结符
  • 小写希腊字母α、β、δ表示任意文法符号序列
  • 产生式中,用“|”连接的每个右部称为一个候选项,具有平等的权利

CFG的产生式表示也被称为巴克斯范式BNF,规范的BNF中,->::=来表示

CFG产生语言的基本方法——推导

推导:产生式产生语言的过程是从开始符号S开始,对产生式左部的非终结符反复地使用产生式:将产生式左部的非终结符替换为右部的文法符号序列(展开产生式,用标记=>表示),直到得到一个终结符序列

  • 利用产生式产生句子的过程中,将产生式A→γ的右部代替文法符号序列αAβ中的A得到αγβ的过程,称αAβ直接推导出αγβ,记作:αAβ=>αγβ
  • 若对于任意文法符号序列α1,α2,…αn,均α1=>α2=>…=>αn,则称此过程为零步或多步推导,记为:α1=∗>αnα1=^*>αnα1=∗>αn,其中α1=αn的情况为零步推导;若α1≠αn,即推导过程中至少使用一次产生式,则称此过程为至少一步推导,记为:α1=+>αnα1=^+>αnα1=+>αn
  • 对于所有α,有α=∗>αα=^*>αα=∗>α,即推导具有自反性
  • 若α=∗>βα=^*>βα=∗>β,β=∗>γβ=^*>γβ=∗>γ,则α=∗>γα=^*>γα=∗>γ,即推导具有传递性

CFL上下文无关语言

  • 由CFG G所产生的语言L(G)被定义为:
  • L(G)={ω∣S=+>ωandω∈T∗}L(G)=\{\omega|S=^+>\omega\ and\ \omega\in T^*\}L(G)={ω∣S=+>ω and ω∈T∗}
  • L(G)称为上下文无关语言(Context Free Language, CFL),ω称为句子,若S=*>αα∈(N∪T)*,则称α为G的一个句型

第一个是文法开始符号,最后一个是句子,其他的都是句型,但广义来说,第一个和最后一个也是句型

  • 在推导过程中,若每次直接推导均替换句型中最左边的非终结符,则称为最左推导,由最左推导产生的句型被称为左句型
  • 类似的可以定义最右推导与右句型,最右推导也被称为规范推导

分析树

  • 分析树是推导的图形表示,直观并且同时反映语言结构的实质和推导过程

对CFG G的句型,分析树被定义为具有下述性质的一棵树。

  • (1) 开始符号所标记
  • (2) 每个叶子由一个终结符、非终结符、或ε标记
  • (3) 每个内部结点由一个非终结符标记
  • (4) 若A是某内部节点的标记,且X1,X2,…,Xn是该节点从左到右所有孩子的标记,则A→X1X2…Xn是一个产生式。若A→ε,则标记为A的结点可以仅有一个标记为ε的孩子

分析树与语言和文法的关系:

  1. 每一直接推导(每个产生式),对应一棵仅有父子关系的子树,即产生式左部非终结符“长出”右部的孩子
  2. 分析树的叶子,从左到右构成G的一个句型;若叶子仅由终结符标记,则构成一个句子

语法树

  • 为了仅关注句型,并且忽略推导过程,产生了语法树:

对CFG G的句型,表达式的语法树被定义为具有下述性质的一棵树:

  • (1) 内部节点由表达式中的操作符标记;
  • (2) 叶子由表达式中的操作数标记;
  • (3)用于改变运算优先级和结合性的括弧,被隐含在语法树的结构中

分析树和语法树又被称为具体语法树抽象语法树AST

二义性与二义性的消除

  • 若文法G对同一句子产生不止一棵分析树,则称G是二义的

产生原因:

  • 在产生句子的过程中某些直接推导有多于一种选择
  • 文法中缺少对文法符号优先级和结合性的规定;一个句子有多于一颗分析树,仅与文法和句子有关,与采用的推导方法无关(对于某些文法和句型,无论采用最左推导还是最右推导都会有歧义的)

文法二义性不能说明程序设计语言是二义的

  • 程序设计语言不能二义;
  • 只有当产生一个语言的所有文法都是二义的时,这个语言才被认为是二义的

二义文法不是CFG

消除文法二义的两种方法:

  1. 改写二义文法为非二义文法
  2. 规定二义文法中符号的优先级和结合性,使仅产生一颗分析树

现给出一个二义文法:

E→E+E | E*E|(E) | -E| id

改写二义文法为非二义文法

对于上述二义文法进行改写:

E → E + T  | T
T → T * F  | F
F →(E)    | -F | id

改写二义文法的方法:

  • 通过引入非终结符,使原来分辨不清的结构受到约束,从而使得对任何一个句子,仅能构造一颗分析树

一些结论:

  1. 新引入的非终结符,限制了每一步直接推导均有唯一选择
  2. 最终分析树的形状,仅与文法有关,而与推导方法无关
  3. 非终结符的引入,增加了推导步骤(分析树增高),从而分析树效率降低
  4. 越接近S的文法符号的优先级越低(如E→E+T)
  5. 对于A→αAβ,若a∈βa\in\betaa∈β(A在a的左边),则a具有左结合性质;若a∈αa\in\alphaa∈α(A在a的右边),则a具有右结合性质***【如E->E+T,则+具有左结合性,E->T+E,则+具有右结合性】***

关键步骤:

  1. 引入一个新的非终结符增加一个子结构提高一级优先级
  2. 递归非终结符终结符左边,运算具有左结合性,否则具有右结合性

说明

  • 先列出优先级,比如这里我可以说从低到高是[+] [*] [(), -, id];
  • 然后列出结合性:左结合+,;右结合-;无结合id;因为有三个层次,所以需要再引入两个新变量,首先是优先级最低的,然后是次之,最后是最高的;
  • 在每一个产生式中,又要根据结合性,如果是左结合的则右边应该含有终结符的标号,否则相反,就可以写出来了;当然要注意可以不含有+的问题,所以有个|T的存在*

对于“悬空”问题(即else和最近还是最远if匹配)

  • 因为没有优先级区分,但是结合性应该是右结合,即else与其左边最靠近的then结合,那么只需改写如下:
原来的:
S → if C then S| if C then S else S| id := E
C → E=E | E<E | E>E
E → E+E | -E | id | n改写之后的(MS是完全匹配的意思,即含有if then else;UMS不完全匹配,即含有if then,至于then中是否嵌套,则看如下表示):
S  → MS                | UMS
MS → if C then MS else MS  | id := E
UMS→ if C then S            | if C then MS else UMS
C → E=E | E<E | E>E
E → E + T  | T
T →(E)    | -T | id | n

然后根据一一比对,比如对于if x<3 then if x>0 then x:=5 else x:=-5

比如对于和最远的if匹配的话,

  • 先将S展开,如果是MS,则展开为第一种,但是MS展不开了(这里应该是if x>0 then x:=5这句话);
  • 如果是UMS,则展开为第二种,但是MS也展不开了,所以这种匹配不可行;
  • 而和最近的if匹配的话,是可行的,且唯一确定,首先展开成UMS,S再展开成MS的第一种

规定二义文法中符号的优先级和结合性

但是二义文法具有如下优点:

  1. 比非二义文法容易理解
  2. 分析效率高,分析树低,直接推导步骤少

通过为二义文法规定优先级和结合性(YACC的方法)

修改语言的语法(表现形式被改变)

  1. 明确给出结束标志,如end if
  2. 给表达式加括号

正规式与CFG

正规式到CFG的转换

正规式所描述的语言结构均可用CFG描述,反之不一定

  • 识别正规语言的自动机是有限自动机,它们的特征是没有记忆功能*

  • 识别 CFL 的自动机是下推自动机,在有限自动机的基础上增加了一个下推栈,具有简单的记忆功能*

从正规式到CFG的对应关系:

  1. 构造正规式的NFA
  2. 若0为初态,则A0A_0A0​为开始符号
  3. 对于move(i,a)=j,引入产生式AiA_iAi​→aAjaA_jaAj​
  4. 对于move(i,ε)=j,引入产生式 Ai→AjA_i→A_jAi​→Aj​
  5. 若i是终态,则引入产生式Ai→εA_i →εAi​→ε

为什么用正规式而不用CFG描述词法

  1. 词法规则简单,用正规式描述已足够
  2. 正规式的表示比CFG更直观、简洁、易于理解
  3. 有限自动机的构造比下推自动机简单,且分析效率高
  4. 区分词法和语法,为编译器前端的模块划分提供方便
  • 正规式适合描述线性结构,如标识符、关键字、注释等
  • CFG适合描述具有嵌套(层次)性质的非线性结构,如不同结构的句子if-then-else、while-do等

上下文有关语言CSL

变量的声明与引用、过程调用时形参与实参的一致性检查等无法用CFG描述,所以产生了CSL(Context Sensitive Language)

CFG到CSL的文法所表示的意思都变了

CFG无法表示:
L1={ωcω|ω∈(a|b)*}  (标识符声明与引用一致性的抽象)
L2={a^n b^m c^n d^m|n≥1和m≥1}   (形参ab与实参cd一致性的抽象)
L3={a^nb^nc^n|n≥1}         (输入n个字符,回退n个字符,加n个底线,计数问题的抽象)对文法稍加修改,得到相近的CFL:
【ω^r是ω的逆序】
L1'={ωcω^r|ω∈(a|b)*}          (S→aSa|bSb|c)
L2'={a^n b^m c^m d^n|n≥1, m≥1}      (S→aSd|aAd    A→bAc|bc)
L2''={a^n b^n c^m d^m|n≥1, m≥1}   (S→AB  A→aAb|ab  B→cBd|cd)
L3'={a^m b^m c^n|m, n≥1}        (S→AC  A→aAb|ab   C→cC|c)正规式:
L3''={a^k b^m c^n|k,m,n>=1}      a^+ b^+ c^+

命题:L3’不是正规集,因为构造不出可以识别L3’的DFA

  • 证明:(反证)
  • 假设L3’是正规集,则可构造n个状态的DFA D,它接受L3’;
  • 考察D读完ε,a,aa,…,anε,a,aa,…,a^nε,a,aa,…,an,分别到达S0,S1,…,SnS0,S1,…,SnS0,S1,…,Sn,共有n+1n+1n+1个状态。
  • 根据鸽巢原理,序列中至少有两个状态相同,设Si=Sj(j>i)S_i=S_j(j>i)Si​=Sj​(j>i),因为aibick∈L3’a^ib^ic^k∈L3’aibick∈L3’,所以存在路径aibicka^ib^ic^kaibick,但是D中也有路径ajbicka^jb^ic^kajbick,矛盾;故L3’不是正规集

形式语言与自动机

若文法G=(N,T,P,S)G=(N,T,P,S)G=(N,T,P,S)的每个产生式α→βα→βα→β中,均有α∈(N∪T)∗α∈(N∪T)^*α∈(N∪T)∗,且至少含有一个非终结符,β∈(N∪T)∗β∈(N∪T)^*β∈(N∪T)∗,则称G为0型文法

  • 任何0型语言都是递归可枚举的;反之,递归可枚举集必定是一个0型语言

对0型文法施加以下第i条限制,即得到i型文法。

  1. G的任何产生式α→β(S→ε除外)满足|α|≤|β|
  2. G的任何产生式形如A→β,其中A∈N,β∈(N∪T)∗β∈(N∪T)^*β∈(N∪T)∗【对于αAβ→αγβ\alpha A\beta\to\alpha \gamma\betaαAβ→αγβ,则A只有在左边是α\alphaα,右边是β\betaβ这样的上下文才可能替换成γ\gammaγ
  3. G的任何产生式形如A→a或者A→aB(或者A→Ba),其中A和B∈N,a∈T
文法 语言 自动机
短语文法(0型) 短语结构语言 图灵机
CSG (1型) CSL 线性界线自动机
CFG (2型) CFL 下推自动机
正规文法(3型) 正规集 有限自动机

CSG、CFG、正规式能力递减,但是能力越强的文法,其文法的设计和自动机的构造越苦难。

【编译原理系列】语法分析与上下文无关文法相关推荐

  1. 【编译原理】什么是上下文无关文法?

    上下文无关是指,一句话的含义与其前后的内容没有或者几乎没有关系,只由自己决定,把它剪切到其他任何位置,也还是原有的意思. 例如: ... a = 0; ... 这是一个赋值语句,无论此语句的前后是什么 ...

  2. 编译原理之语法分析(预测分析法)

    编译器之语法分析 自顶向下 上下文无关文法 语法树 NFA→CFG 预测分析法 改写CFG 原因 消除二义性 消除左递归 消除左公因子 消除空产生式 消除回路 自顶向下 上下文无关文法 CFG本质上就 ...

  3. 《编译原理》-3.上下文无关文法及分析

    上下文无关文法及分析 3.1 分析过程 3.2 上下文无关文法 3.2.1 与正则表达式的比较 3.2.2 上下文无关文法规则的说明 3.2.3 推导及由文法定义的语言 3.3 分析树与抽象语法树 3 ...

  4. 上下文无关文法的分析树(Context-Free Grammar, CFG)的分析树--编译原理

    上下文无关文法的分析树(Context-Free Grammar, CFG)的分析树 分析树 根节点的符号为文法开始符号S 每个内部节点都是对某个产生式A→β的应用,该节点的标号就是产生式的左部,子节 ...

  5. 【编译原理】构造产生如下语言的上下文无关文法各一个:

    13.构造产生如下语言的上下文无关文法各一个: (1) (an bm c2m | n,m≥0 } S->AB A->ε|aA B->ε|bBcc (2) w c wR| w∈{a,b ...

  6. 编译原理学习笔记 5.1 翻译文法和语法制导翻译

    前言 参考课上PPT内容. 该学习笔记目前仅打算个人使用. 后续会进一步整理,包括添加笔记内容,标明参考资料. 更新中... 跳过目录 目录 导言 一.翻译文法和语法制导翻译 输入文法 翻译文法 活动 ...

  7. 三万五千字长文!让你懂透编译原理(六)——第六章 属性文法和语法制导翻译

    三万五千字长文!让你懂透编译原理(六)--第六章 属性文法和语法制导翻译 长文预警 系列文章传送门: 万字长文+独家思维导图!让你懂透编译原理(一)--第一章 引论 万字长文!让你懂透编译原理(二)- ...

  8. 编译原理2-Bison语法分析

    ps:补上了图 实验要求 了解 Bison 基础知识和理解 Cminus-f 语法(重在了解如何将⽂法产⽣式转换为 Bison 语句) 阅读 /src/common/SyntaxTree.c ,对应头 ...

  9. 【计算理论】计算理论总结 ( 上下文无关文法 CFG 转为下推自动机 PDA 示例 2 ) ★★

    文章目录 一.上下文无关文法 CFG 转为下推自动机 PDA 流程 二.上下文无关文法 CFG 转为下推自动机 PDA 示例 2 参考博客 : [计算理论]上下文无关语法 ( 语法组成 | 规则 | ...

  10. 【计算理论】计算理论总结 ( 上下文无关文法 CFG 转为下推自动机 PDA 示例 1 ) ★★

    文章目录 一.上下文无关文法 CFG 转为下推自动机 PDA 流程 二.上下文无关文法 CFG 转为下推自动机 PDA 示例 1 参考博客 : [计算理论]上下文无关语法 ( 语法组成 | 规则 | ...

最新文章

  1. python3中的单例模式Singleton
  2. 谁动了我的奶酪?--java实例初始化的顺序问题
  3. 2019ICPC(上海) - Color Graph(二分图+状态压缩)
  4. 互联网岗位也存在鄙视链?我们来康康你喜欢的岗位竞争究竟有多残酷?
  5. Makefile编写详解--项目开发
  6. Polygon Mesh Processing读书笔记——1三角网格Triangle Meshes
  7. SQL Server里面如何检查没有释放的游标
  8. iOS APP中第三方APP调用自己的APP,打开文件
  9. 高通平台SPI驱动框架分析
  10. 2020张宇1000题【好题收集】【第七章:三重积分、曲线曲面积分】
  11. 37--8位级联加法器,并行加法器
  12. 倾斜摄影测量知识基础
  13. python查询12306余票_python自动查询12306余票并发送邮箱提醒脚本
  14. Squid中文权威指南-第10章 与其他Squid会话
  15. Linux安装jdk报错:package jdk-16.0.2-2000:16.0.2-ga.aarch64 is intended for a different architecture
  16. Java 常见设计模式
  17. 终身免费!微软数据恢复工具,界面版体验
  18. ios 多线程gdc_GDC 2019中的Heretic,Megacity版本,实时光线追踪以及更多新闻
  19. c++从零开始---文章导读
  20. ulua中lua代码使用反射调用c#详解

热门文章

  1. 图解机器学习算法 | 从入门到精通系列教程(机器学习通关指南·完结)
  2. 解决VS 2017/2019社区版无法登陆的方法
  3. 使用 SOUI 开发高 DPI 桌面应用程序
  4. win10 动态磁盘 linux,win10 动态磁盘 无效,win10动态磁盘不能识别
  5. Mysql 数据库(一)—— 初识 Mysql
  6. 中控考勤机重置考勤机密码方法
  7. 微观、宏观、精准 多视角估算数据库性能(选型、做预算不求人)
  8. C++ vector 初始化大小
  9. 项目总结 【电商后台管理系统】
  10. win7计算机iis,win7系统如何打开iis管理器|win7系统打开iis管理器的方法