编译原理-语法分析-自上而下分析

文章目录

  • 语法分析器的功能
  • 自上而下分析面临的问题
  • LL(1)分析法
    • 左递归的消除
      • 直接左递归
      • 非直接左递归
    • 消除左递归的算法
    • 消除回溯、提左因子
      • FIRST
      • 提左因子
      • FOLLOW集
    • LL(1)的分析条件
      • LL(1)文法
      • 构造FIRST和FOLLOW集合
        • 构造每个文法符号的FIRST集合
        • 构造FOLLOW集合
  • 递归下降分析程序
    • 递归下降分析程序
    • 文法的另一种表示方法和转换图
  • 预测分析程序
    • 预测分析程序的工作过程
    • 预测分析表的构造

语法分析器的功能

语法分析器是编译过程的核心部分。任务是在词法分析识别出的单词符号串的基础上,分析并判定程序的语法结构是否符合语法规则。
image

自上而下分析面临的问题

  1. 左递归: p − > p α ∣ β {p}->{p}{\alpha}|{\beta} p>pαβ:会使程序陷入死循环,导致不可实现
  2. 回溯:试探法就是穷举所有可能,一旦遇到不匹配就进行回溯,尝试下一种可能,这种方法只在理论上有意义,由于回溯穷举时间开销巨大所以不太具有实践意义。

LL(1)分析法

左递归的消除

直接左递归

直接左递归的形式: p − > p α ∣ β {p}->{p\alpha}|{\beta} p>pαβ β {\beta} β不以 p {p} p开头
这个推导:
p = > p α = > p α α = > . . . = > β α . . . . α {p => p\alpha => p\alpha\alpha => ... => \beta\alpha....\alpha} p=>pα=>pαα=>...=>βα....α
从这个推到我们可以看出 p {p} p推出的串是以 β {\beta} β后面跟着若干个 α {\alpha} α组成的串
这样我没对这个串做等价变换:
p − > β p ′ {p->\beta p'} p>βp
p ′ − > α p ′ ∣ ϵ {p'->\alpha p'|\epsilon} p>αpϵ
我们可以验证这个文法是不是和上面左递归形式的文法等价,我们对这个文法做推导看看会推导出哪些串
p = > β p ′ = > β α p ′ = > . . . = > β α . . . α {p => \beta p' => \beta \alpha p' => ... => \beta \alpha ...\alpha} p=>βp=>βαp=>...=>βα...α
我们得到的串同样是以 β {\beta} β开头后面接跟着若干个 α {\alpha} α的串
我们对上面的结论进行推广:
对于P的全部产生式是
P − > P α 1 ∣ P α 2 ∣ . . . ∣ P α m ∣ β 1 ∣ β 2 ∣ . . . ∣ β n , 其中每个 α 都不以 ϵ 开头 , 每个 β 都不以 P 开头 {P -> P\alpha_1|P\alpha_2|...|P\alpha_m|\beta_1|\beta_2|...|\beta_n},其中每个{\alpha}都不以{\epsilon}开头,每个\beta都不以P开头 P>Pα1Pα2∣...∣Pαmβ1β2∣...∣βn,其中每个α都不以ϵ开头,每个β都不以P开头
我们直接进行右递归改造:
P − > β 1 P ’ ∣ β 2 P ’ ∥ . . . ∣ b e t a n P ’ {P -> \beta_1P’|\beta_2P’\|...|beta_nP’} P>β1P’∣β2P’∥...∣betanP
P ’ − > α 1 P ’ ∣ α 2 P ’ ∣ . . . ∣ α m P ′ {P’->\alpha_1P’|\alpha_2P’|...|\alpha_mP'} P>α1P’∣α2P’∣...∣αmP

例子:
E − > E + T ∣ T {E->E+T|T} E>E+TT
T − > T ∗ F ∣ F {T->T*F|F} T>TFF
F − > ( E ) ∣ i {F->(E)|i} F>(E)i
对于第一个式子有直接左递归我们进行消除,首先第一个式子最终的推导串是以 T {T} T开头后面若干个{+T}我们进行等价变换: E − > T E ′ {E->TE'} E>TE E ′ − > + T E ′ ∣ ϵ {E'->+TE'|\epsilon} E>+TEϵ
对于第二个式子也是直接左递归的我们也需要进行消除,首先第二个式子最终推导出的串的形式下以 F {F} F开头后面若干个*F,我们根据这个进行等价变换
T − > F T ′ {T->FT'} T>FT
T ′ ∗ F T ′ ∣ ϵ {T'*FT'|\epsilon} TFTϵ
最后一个式子没有直接左递归不用进行处理

非直接左递归

文法 G ( S ) 文法G(S) 文法G(S)
S − > Q c ∣ c {S -> Qc|c} S>Qcc
Q − > R b ∣ b {Q -> Rb|b} Q>Rbb
R − > S a ∣ a {R -> Sa|a} R>Saa
形式上这个文法并没有直接左递归,但是实际上这个文法是左递归的,进行如下推导就可以看出
S = > Q c = > R b c = > S a b c {S => Qc => Rbc => Sabc} S=>Qc=>Rbc=>Sabc
经过推导我们发现S实际上是左递归的
我们从上面的文法可以看出S是由Q定义的,Q是由R定义的,R是由S定义的,那么我们可以得到下图
image
S − > Q c ∣ c {S -> Qc|c} S>Qcc
Q − > R b ∣ b {Q -> Rb|b} Q>Rbb
R − > S a ∣ a {R -> Sa|a} R>Saa
我们将Q中的R替换掉
image
S − > Q c ∣ c {S -> Qc|c} S>Qcc
Q − > S a b ∣ a b ∣ b {Q -> Sab|ab|b} Q>Sababb
R − > S a ∣ a {R -> Sa|a} R>Saa
再将S中的Q替换掉
image
S − > S a b c ∣ a b c ∣ b c ∣ c {S ->Sabc|abc|bc|c} S>Sabcabcbcc
Q − > S a b ∣ a b ∣ b {Q -> Sab|ab|b} Q>Sababb
R − > S a ∣ a {R -> Sa|a} R>Saa

消除左递归的算法

1.把文法G的所有非终结符按任意一种顺序排列成 P 1 P 2 , . . . , P n {P_1 P_2, ... ,P_n} P1P2,...,Pn按此顺序执行
2.
F O R i : = 1 T O n D O FOR\quad i:=1\quad TO\quad n\quad DO FORi:=1TOnDO
B E G I N BEGIN BEGIN
F O R j : = 1 T O i − 1 D O \quad \quad FOR \quad j:=1 \quad TO \quad i-1\quad DO FORj:=1TOi1DO
$ \quad \quad 把形如P_i->P_j \gamma 的规则改写成,P_i-> \delta_1 \gamma|\delta_2 \gamma|…|\delta_k \gamma (其中P_j -> \delta_1|\delta_2|…|\delta_k是关于P_j的所有规则) $

消除回溯、提左因子

FIRST

为了消除回溯,我们首先需要引入两个概念一个是FIRST集一个是FOLLW集
FIRST:
零G是一个不含左递归的文法,对G的所有非终结符的每一个候选 α \alpha α定义它的终结首符集 F I R S T ( α ) FIRST(\alpha) FIRST(α)
image
那么当要求A匹配输入串时,A就能根据它所面临的第一个输入符号a,准确地指派某一个候选前去。这个候选就是那个首符集含 a a a α \alpha α

提左因子

很多文法都存在不满足所有候选式的终结首符集不两两相交的。我们采用提取公共左因子的办法
假设关于A的规则是:
A → δ β 1 ∣ δ β 2 ∣ . . . ∣ δ β n ∣ γ 1 ∣ γ 2 ∣ . . . ∣ γ m , ( 其中 , 每个 γ 不以 δ 开头 ) {A\rightarrow \delta \beta_1 | \delta \beta_2 | ... |\delta \beta_n| \gamma_1 | \gamma_2| ... | \gamma_m} \quad ,(其中,每个 \gamma 不以 \delta 开头) Aδβ1δβ2∣...∣δβnγ1γ2∣...∣γm,(其中,每个γ不以δ开头)
那么可以把这些规则改写成
A → δ A ′ ∣ γ 1 ∣ γ 2 ∣ . . . ∣ γ m {A \rightarrow \delta A' | \gamma_1 | \gamma_2| ... | \gamma_m} AδAγ1γ2∣...∣γm
A ′ → β 1 ∣ β 2 ∣ . . . ∣ β n {A' \rightarrow \beta_1 | \beta_2 | ... | \beta_n} Aβ1β2∣...∣βn

经过上面反复提取左因子,我们一定可以将一个非终结符的所有候选式的FIRST集两两不相交

FOLLOW集

消除左递归后的文法
E → T E ′ {E \rightarrow TE'} ETE
E ′ → + T E ′ ∣ ϵ {E' \rightarrow +TE'|\epsilon} E+TEϵ
T → F T ′ {T \rightarrow FT'} TFT
T ′ → ∗ F T ′ ∣ ϵ {T' \rightarrow * FT'|\epsilon} TFTϵ
F → ( E ) ∣ i {F \rightarrow (E)|i} F(E)i
我们对$ i + i $进行至上而下的语法分析

image
当我们进行到这个地方的时候我们发现 T ′ 有两个候选式 T ′ → ∗ F T ′ ∣ ϵ ,但是 ∗ 不能和 + 匹配,另一个候选式是 ϵ , 这时我们不能选择 ∗ F T ′ 去扩展,只能选择 ϵ T'有两个候选式{T' \rightarrow * FT'|\epsilon},但是 * 不能和 + 匹配,另一个候选式是{\epsilon} ,这时我们不能选择 * FT' 去扩展,只能选择 {\epsilon} T有两个候选式TFTϵ,但是不能和+匹配,另一个候选式是ϵ,这时我们不能选择FT去扩展,只能选择ϵ
可以看到当候选式有 ϵ {\epsilon} ϵ时,会对我们的分析产生困难,如何消除这个困难呢?什么时候才能用 ϵ {\epsilon} ϵ去扩展呢?
这里我们就引入了 F O L L O W 集 FOLLOW集 FOLLOW
image

LL(1)的分析条件

LL(1)文法

image

  1. 文法不含左递归
  2. 对文法中每一个非终结符A的各个产生式的候选终结首符集两两不相交,
    A → α 1 ∣ α 2 ∣ . . . ∣ α n A \rightarrow \alpha_1 | \alpha_2 | ... | \alpha_n Aα1α2∣...∣αn
    则 F I R S T ( α i ) ∩ F I R S T ( α j ) = ∅ 则 FIRST( \alpha_i ) \cap FIRST( \alpha_j ) = \varnothing FIRST(αi)FIRST(αj)=
  3. 对文法中的每个非终结符A,若它存在某个候选首符集包含 $ { \epsilon }$
    F I R S T ( A ) ∩ F O L L W O ( A ) { FIRST(A) \cap FOLLWO(A)} FIRST(A)FOLLWO(A)

对于一个LL(1)文法,我们可以对输入串进行有效的无回溯的至上而下分析,假设我们要用非终结符 A 做匹配,面临的输入符号为 α , A A做匹配,面临的输入符号为 \alpha, A A做匹配,面临的输入符号为α,A的所有产生式为:
A → α 1 ∣ α 2 ∣ . . . ∣ α n A \rightarrow \alpha_1 | \alpha_2 | ... | \alpha_n Aα1α2∣...∣αn

  1. a ∈ F I R S T ( α i ) 则指派 α i a \in FIRST(\alpha_i)则指派 \alpha_i aFIRST(αi)则指派αi匹配

  2. 若$ a $不属于任何一个候选首符集,则:

    1. ϵ ∈ F I R S T ( α i ) 并且 a ∈ F O L L O W ( A ) 则让 A 与 ϵ 自动匹配 \epsilon \in FIRST(\alpha_i)并且a \in FOLLOW(A)则让A与 \epsilon自动匹配 ϵFIRST(αi)并且aFOLLOW(A)则让Aϵ自动匹配
    2. 否则a的出现是一种语法错误

构造FIRST和FOLLOW集合

构造每个文法符号的FIRST集合

对每一文法符号 $ X \in V_T \cup V_N构造FIRST(X) $
连续使用下面几条规则,直到每个FIRST集合不再增大为止

  1. 若 $ X \in V_T 则FIRST(X) = {X} $
  2. 若$ X \in V_N 且有产生式 X \rightarrow a …,则把a加入到FIRST(X)中;若 X \rightarrow \epsilon 也是一条产生式,则把\epsilon也加入FIRST(X) $
  3. 若 $ X \rightarrow Y 且Y \in V_N,则把FIRST(Y)中的所有非 \epsilon 元素加入到FIRST(X)中 $
    image
构造FOLLOW集合

再回顾一遍FOLLOW集合的定义:
F O L L O W ( A ) = { a ∣ S ⇒ . . . A a . . . , a ∈ V T } FOLLOW(A) = \{ a| S \Rightarrow ...Aa...,a \in V_T\} FOLLOW(A)={aS...Aa...,aVT}
对于文法G的每个非终结符A构造FOLLOW(A),连续使用下面的规则,直至每个FOLLOW不再增大为止

  1. 对于文法的开始符号 S , 置 # 于 F O L L O W ( S ) 中 S ,置 \# 于FOLLOW(S)中 S,#FOLLOW(S)
  2. A → α B β 是一个产生式,则把 F I R S T ( B )   { β } 加至 F O L L O W ( B ) 中 A \rightarrow \alpha B \beta 是一个产生式,则把FIRST(B)\ \{ \beta \}加至 FOLLOW(B)中 Aα是一个产生式,则把FIRST(B) {β}加至FOLLOW(B)
  3. A → α B 是一个产生式,或 A → α B β 是一个产生式,但 β ⇒ ϵ A \rightarrow \alpha B 是一个产生式,或 A \rightarrow \alpha B \beta是一个产生式,但 \beta \Rightarrow \epsilon AαB是一个产生式,或Aα是一个产生式,但βϵ则把 F O L L O W ( A ) 加入到 F O L L O W ( B ) FOLLOW(A)加入到FOLLOW(B) FOLLOW(A)加入到FOLLOW(B)

递归下降分析程序

递归下降分析程序

image
image
image
文法 G ( E ) : 文法G(E): 文法G(E)
E → T E ′ {E \rightarrow TE'} ETE
E ′ → + T E ′ ∣ ϵ {E' \rightarrow +TE'|\epsilon} E+TEϵ
T → F T ′ {T \rightarrow FT'} TFT
T ′ → ∗ F T ′ ∣ ϵ {T' \rightarrow * FT'|\epsilon} TFTϵ
F → ( E ) ∣ i {F \rightarrow (E)|i} F(E)i
image
image

文法的另一种表示方法和转换图

image
image

文法
E → T ∣ E + T E \rightarrow T | E + T ETE+T
T → F ∣ T ∗ F T \rightarrow F | T * F TFTF
F → i ∣ ( E ) F \rightarrow i | (E) Fi(E)
用巴克斯范式可以表示为:
E → T { + T } E \rightarrow T \{ +T \} ET{+T}
T → F { ∗ F } T \rightarrow F \{ * F \} TF{F}
F → i ∣ ( E ) F \rightarrow i | (E) Fi(E)

我们还可以用语法图来表示,这种图的每一个子图是一个非终结符,子图和子图之间可以相互引用
image
根据语法图和上面的巴克斯范式我们可以写出递归下降程序
image

预测分析程序

预测分析程序的工作过程

image
image
预测分析的总控程序:
image

预测分析表的构造

image
image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/141295.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

windows安装nginx

一、下载安装Nginx 1、官网下载地址:nginx: download 2、下载教程:选择最新的Stable version(稳定版本)下载到本地 3、下载完成后,解压放入本地非中文的文件夹中: 4、启动nginx:切勿直接双击n…

Django路由层

路由层(urls) Django的路由层是负责将用户请求映射到相应的视图函数的一层。在Django的MVT架构中,路由层负责处理用户的请求,然后将请求交给相应的视图函数进行处理,最后将处理结果返回给用户。 在Django中&#xff0c…

Redhat7设置国内可用yum源

问题: 因为最近安装了redhat7,在使用的时候提示系统未注册订阅,无法使用官方的yum源进行安装软件。为此,我使用centos7国内的yum源替换redhat的官方的yum源实现软件安装。 “This system is not registered with an entitlement …

机器学习算法实战实战案例代码详解

文章目录 1.问题建模数据预处理 结果分析数据探索特征工程特征选择模型融合 1.问题建模 导入库 import numpy as np import pandas as pd from sklearn.model_selection import KFold from sklearn.metrics import mean_squared_error from sklearn.preprocessing import One…

EtherCAT转Modbus网关的 EtherCAT从站配置案例

兴达易控EtherCAT转Modbus网关(XD-MDEC20 )是一款具备ETHERCAT从站功能的通讯网关,其主要作用是将ETHERCAT网络和MODBUS-RTU网络连接起来。该网关可作为ETHERCAT总线中的从站使用,同时也能够连接到MODBUS-RTU总线中,作…

Topk问题!(面试高频常考)

🎥 屿小夏 : 个人主页 🔥个人专栏 : 剑指offer 🌄 莫道桑榆晚,为霞尚满天! 文章目录 📑前言🌤️什么是Top-k问题?🌤️常见的Top-K问题类型☁️寻找…

Halcon 练习(1):模板匹配

文章目录 前言相关视频链接模板匹配介绍Halcon平台使用动态区域截取代码优化固定选取位置添加打印信息添加匹配个数 个人能力不足 前言 Halcon平台的使用需要学习新的知识,这里专门开个新的专栏用来练习Halcon平台使用。 相关视频链接 WPF/HALCON机器视觉合集 模板…

Java16新增特性

前言 前面的文章,我们对Java9、Java10、Java11、Java12 、Java13、Java14、Java15 的特性进行了介绍,对应的文章如下 Java9新增特性 Java10新增特性 Java11新增特性 Java12新增特性 Java13新增特性 Java14新增特性 Java15新增特性 今天我们来一起看一下…

​软考-高级-系统架构设计师教程(清华第2版)【第4章 信息安全技术基础知识(P160~189)-思维导图】​

软考-高级-系统架构设计师教程(清华第2版)【第4章 信息安全技术基础知识(P160~189)-思维导图】 课本里章节里所有蓝色字体的思维导图

2023最新版本 从零基础入门C++与QT(学习笔记) -2- 命名空间的使用

🎏在不同的命名空间变量名可相同 创建(如下方代码块) 🎄分析一下构成 🎈-1- namespace 关键字命名空间 🎈-2- wm9 空间名称 🎈-3-括号里边正常定义变量即可 namespace wm9 {int a 99;char b A;float c 9.99;char…

C语言——计算n的阶乘

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int i;int n 0;int s1;scanf("%d",&n);for(i1; i<n; i){s*i;}printf("s%d\n",s);return 0; }

JVM:卡表元素如何维护?(写屏障)

写屏障 上面使用记忆集解决了缩减GC Roots扫描范围的问题&#xff0c;现在又抛出来一个新的问题&#xff0c;卡表元素如何维护的呢&#xff1f;&#xff0c;例如它们何时变脏、谁来把它们变脏等。 何时变脏这个问题应该很明确的&#xff0c;原则上应该发生在引用类型字段赋值…

032-从零搭建微服务-定时服务(一)

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff08;后端&#xff09;&#xff1a;mingyue: &#x1f389; 基于 Spring Boot、Spring Cloud & Alibaba 的分布式微服务架构基础服务中心 源…

Python 列表 pop()函数使用详解

pop函数使用详解 目录 pop函数使用详解 1、按照索引删除元素 1.1、正数索引 1.2、负数索引 1.3、不指定索引 2、返回被删除的元素 3、不同类型的元素 4、常见错误 pop() 可以「删除」列表中的元素&#xff08;默认最后一个&#xff09;。 语法 list.pop( index ) 参…

Java多线程编程秘籍:各种方案一网打尽,不要错过!

一、多线程实现方式 Java 中实现多线程的方式主要有四种&#xff1a; 继承 Thread 类&#xff1a;这是一种最简单的实现方式&#xff0c;直接继承 Thread 类&#xff0c;重写 run() 方法即可。实现 Runnable 接口&#xff1a;这是一种更加灵活的实现方式&#xff0c;不需要继承…

Zigbee智能家居方案设计

背景 目前智能家居物联网中最流行的三种通信协议&#xff0c;Zigbee、WiFi以及BLE&#xff08;蓝牙&#xff09;。这三种协议各有各的优势和劣势。本方案基于CC2530芯片来设计&#xff0c;CC2530是TI的Zigbee芯片。 网关使用了ESP8266CC2530。 硬件实物 节点板子上带有继电器…

Git精讲(一)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、Git初识1、提出问题2、如何解决--版本控制器3、注意事项 二、Git 安装1、Linux-centos2、…

目标检测问题总结

目标检测问题总结 目标检测二阶段和一阶段的核心区别目标检测二阶段比一阶段的算法精度高的原因1. 正负样本不平衡2.样本的不一致性 如何解决目标检测中遮挡问题如何解决动态目标检测FPN的作用如何解决训练数据样本过少的问题IOU代码实现NMS代码实现NMS的改进思路 目标检测二阶…

数据结构-堆排序及其复杂度计算

目录 1.堆排序 1.1 向上调整建堆 1.2 向下调整建堆 2. 两种建堆方式的时间复杂度比较 2.1 向下调整建堆的时间复杂度 2.2 向上调整建堆的时间复杂度 Topk问题 上节内容&#xff0c;我们讲了堆的实现&#xff0c;同时还包含了向上调整法和向下调整法&#xff0c;最后我们…

Linux_磁盘管理_df命令

1、df命令是用来干什么的 df的全称是disk free&#xff0c;意为“磁盘空间”。 使用df命令可以查看系统中磁盘的占用情况&#xff0c;有哪些文件系统&#xff0c;在什么位置&#xff08;挂载点&#xff09;&#xff0c;总空间&#xff0c;已使用空间&#xff0c;剩余空间等。…