笔记-编译原理-第14、15章-属性文法和语法制导翻译_设计属性文法-程序员宅基地

技术标签: 笔记  编译器  

第14讲 属性文法和语法制导翻译1

14.1 属性文法

  • 属性文法,也称属性翻译文法
  • Knuth在1968年提出
  • 以上下文无关文法为基础
    • 为每个文法符号(终结符或非终结符)配备若干相 关的“值”(称为 属性 ),代表与文法符号相关信 息,如类型、值、代码序列、符号表内容等
    • 对于文法的每个产生式都配备了一组属性的 语义规则 ,对属性进行计算和传递
    • 文法的属性分为 综合属性继承属性

14.1.1 综合属性

  • 自下而上传递信息
  • 语法规则:根据右 部候选式中的符号的属性计算左部被定义符号的 综合属性
  • 语法树:根据子结点的属性和父结点自身的属性计算父节点的 综合属性

如这样一个文法的,.val就是一个综合属性:每一个节点的综合属性val的值都由其一些子节点的值组成

14.1.2 继承属性

  • 自上而下传递信息
  • 语法规则:根据右部候选式中的符号的属性和左部被定义符号的属性计算右部候选式中的符号的 继承属性
  • 语法树:根据父结点和兄弟节点的属性计算子结点的 继承属性

如下面的文法的type属性,对于id的type的值是由其父节点继承而来的,这样描述了一个声明语句:

14.1.3 属性依赖

  • 对应于每个产生式 A → α A→α Aα 都有一 套与之相关联的 语义规则 ,每条规则的形式为(f是一个函数): b : = f ( c 1 , c 2 , … , c k ) b:=f(c_1,c_2,…,c_k) b:=f(c1,c2,,ck)
  • 属性b 依赖 于属性 c 1 , c 2 , … , c k c_1,c_2,…,c_k c1,c2,,ck
    • b是A的一个 综合属性 并且 c 1 , c 2 , … , c k c_1,c_2,…,c_k c1,c2,,ck 是产生式右边文法符号的属性,或者
    • b是产生式右边某个文法符 号的一个 继承属性 并且 c 1 , c 2 , … , c k c_1,c_2,…,c_k c1,c2,,ck 是A或产生式右边任何文法符号的属性
  • 终结符只有 综合属性 ,由词法分析器提供
  • 非终结符既可有 综合属性 也可有 继承属性 ,文 法开始符号的所有继承属性作为属性计算前的 初始值

14.1.4 语义规则

  • 对出现在 产生式右边的继承属性出现在产生式左边的综合属性 都必须提供一个计算规则。 属性计算规则中只能使用相应 产生式中的文法符号的属性。
  • 出现在 产生式左边的继承属性出现在产生式右边的综合属性 不由所给的产生式的属性计 算规则进行计算,由其它产生 式的属性规则计算或者由属性 计算器的参数提供。
  • 语义规则所描述的工作可以包括属性计算、静态语义检查、符号表操作、代码生成等。

测试:

14.1.5 带注释的语法树

  • 在语法树中,一个结点的 综合属性 的值由 其子结点它本身 的属性值确定
  • 使用自底向上的方法在每一个结点处使用语义规则计算综合属性的值
  • 仅使用综合属性的属性文法称S-属性文法

如:

  • 在语法树中,一个结点的 继承属性其父结点、 其兄弟结点其本身 的某些属性确定
  • 继承属性 来表示程序设计语言结构中的上下 文依赖关系很方便

14.2 属性计算

14.2.1 基于属性文法的处理方法

  • 语义规则的计算:1、产生代码;2、在符号表中存放信息;3、给出错误信息;4、执行任何其它动作
  • 对输入串的 翻译 就是根据 语义规则 进行 计算
  • 由源程序的语法结构所驱动的处理办法就是 语法制导翻译法 输 入 串 → 语 法 树 → 按 照 语 义 规 则 计 算 属 性 输入串 \to 语法树 \to 按照语义规则计算属性
  • 依赖图 、树遍历 、一遍扫描

14.2.2 依赖图

  • 在一棵语法树中的结点的继承属性和综合属性 之间的相互依赖关系可以由依赖图(有向图)来描述。
  • 为每一个包含过程调用的语义规则引入一个 虚综合属性b ,这样把每一个语义规则都写成 b : = f ( c 1 , c 2 , … , c k ) b:=f(c_1,c_2,…,c_k) b:=f(c1,c2,,ck) 的形式。
  • 依赖图中为每一个属性设置一个结点,如果属 性b依赖于属性c,则从属性c的结点有一条有向 边连到属性b的结点。
依赖图的构建算法

依赖图示例

14.2.3 良定义的属性文法

  • 如果一属性文法不存在属性之间的循环依赖关系,则称该文法为良定义的
  • 一个依赖图的任何拓扑排序都给出一个语法树中结点的语义规则计算的有效顺序

14.2.4 属性的计算次序

  • 基础文法用于建立输入符号串的语法分析树
  • 根据语义规则建立依赖图
  • 根据依赖图的拓扑排序,得到计算语义规则的顺序 输 入 串 → 语 法 树 → 依 赖 图 → 语 义 规 则 计 算 次 序 输入串 \to 语法树 \to 依赖图 \to 语义规则计算次序

14.2.5 树遍历

树遍历的属性计算方法

通过树遍历的方法计算属性的值:

  • 假设语法树已建立,且树中已带有开始符号的继承 属性和终结符的综合属性
  • 以某种次序遍历语法树,直至计算出所有属性
  • 深度优先,从左到右的遍历: 输 入 串 → 语 法 树 → 遍 历 语 法 树 计 算 属 性 输入串 \to 语法树 \to \frac{遍历语法树}{计算属性}
树遍历算法

树遍历算法示例

考虑属性的文法G(S),其中:

  • S有继承属性a,综合属性b
  • X有继承属性c、综合属性d
  • Y有继承属性e、综合属性f
  • Z有继承属性h、综合属性g

树遍历示例

不断的用上一规则,检查每一个节点是否有为计算的属性:

14.2.6 一遍扫描

一遍扫描的处理方法
  • 在语法分析的同时计算属性值 :所采用的语法分析方法 会影响 属性的计算次序
  • 所谓 语法制导翻译法 ,直观上说就是为文法中每个 产生式配上一组语义规则,并且在语法分析的同时 执行这些语义规则
  • 语义规则被计算的时机
    • 自上而下分析,一个产生式匹配输入串成功时
    • 自下而上分析,一个产生式被用于进行归约时

14.2.7 抽象语法树

抽象语法树(Abstract Syntax Tree,AST) ,在 语法树中去掉那些对翻译不必要的信息,从而 获得更有效的源程序中间表示

建立表达式的抽象语法树
  • mknode(op,left,right) 建立一个运算符号结点,标号是op,两个域left和right分别指向左子树和右子树
  • mkleaf(id,entry) 建立一个标识符结点,标号为id,一个域entry指向标识符在符号表中的入口
  • mkleaf(num,val) 建立一个数结点,标号为 num,一个域val用于存放数的值
建立抽象语法树的语义规则


第15讲 属性文法和语法制导翻译2

15.1 15.1 S-属性文法

15.1.1 S-属性文法的自下而上计算

  • S-属性文法 :只含有综合属性
  • 在自下而上的分析器分析输入符号串的同时计算 综合属性
    • 分析栈中保存语法符号和有关的综合属性值
    • 每当进行归约时,新的语法符号的属性值就由栈中正在归约的产生式右边符号的属性值来计算
  • 在分析栈中增加附加域存放综合属性值
  • 假设产生式 A → X Y Z \color{red}{A→XYZ} AXYZ 对应的语义规则为 a : = f ( X . x , Y . y , Z . z ) \color{blue}{a:=f(X.x,Y.y,Z.z)} a:=f(X.x,Y.y,Z.z)
    分析栈的变化:

一个例子

15.2 15.2 L-属性文法

15.2.1 一遍扫描的处理方法

  • S-属性文法适合一遍扫描的自下而上分析
  • L-属性文法适合一遍扫描的自上而下分析

15.2.2 L-属性文法和自顶向下翻译

  • 按照深度优先遍历语法树,计算所有属性值
  • 与LL(1) 自上而下分析方法结合
    • 深度优先建立语法树
    • 按照语义规则计算属性

15.2.3 L-属性文法

一个属性文法称为 L-属性文法 ,如果对于每个产生式 A → X 1 X 2 … X n A→X_1X_2…X_n AX1X2Xn ,其每个语义规则中的每个属性或者是 综合属性 ,或者是 X i ( 1 ≤ i ≤ n ) X_i(1≤i≤n) Xi(1in) 的一个 继承属性 且这个继承属性仅依赖于:

  • 产生式中 X i X_i Xi 左边符号 X 1 , X 2 , … , X i − 1 X_1,X_2,…,X_{i-1} X1X2Xi1 的属性
  • A的继承属性

S-属性文法一定是L-属性文法

例如这样一个文法就不是L-属性文法:

15.3 翻译模式

15.3.1 翻译模式

  • 语义规则 :给出了属性计算的定义,没有属性计算的次序等实现细节
  • 翻译模式 :给出使用语义规则进行计算的次序,把实现细节表示出来
  • 在翻译模式中,和文法符号相关的属性和语义规则(也称 语义动作 ),用花括号{ }括起来,插入到产生式右部的合适位置上

15.3.2 翻译模式示例

如把带加号和减号的中缀表达式翻译成相应的后缀表达式,对输入串使用上面的文法的处理:9-5+2
分析如下:

15.3.3 设计翻译模式的原则

  • 设计翻译模式时,必须保证当某个动作引用一个属性时它必须是有定义的
  • L-属性文法 本身就能确保每个动作不会引用尚未计算出来的属性

15.3.4 建立翻译模式

  • 当只需要 综合属性 时:为每一个语义规则建立 一个包含赋值的动作,并把 这个动作放在相应的产生式右边的末尾
  • 如果既有 综合属性 又有 继承属性 ,在建立翻译模式时就必须保证:
    • 1.产生式右边的符号的继承属性必须在这个符号以前的动作中计算出来
    • 2.一个动作不能引用这个动作右边的符号的综合属性
    • 3.产生式左边非终结符的 综合属性 只有在它所引用的所有属性都计算出来以后才能计算。计算这种属性的动作通常可放在产生式右端的 末尾

15.3.5 数学格式语言EQN


15.3.6 语义动作执行时机统一

  • 把所有的语义动作都放在产生式的末尾 :语义动作的执行时机统一
  • 转换方法:
    • 加入新产生式 M → ε M→ε Mε
    • 把嵌入在产生式中的每个语义动作用不同的非终结 符M代替,并把这个动作放在产生式 M → ε M→ε Mε 的末尾

15.3.7 消除翻译模式中的左递归

  • 语义动作是在相同位置上的符号被展开(匹配 成功)时执行的
  • 为了构造不带回溯的自顶向下语法分析,必须消除文法中的左递归
  • 当消除一个翻译模式的基本文法的左递归时同时考虑属性计算 :适合带综合属性的翻译模式

一个消除左递归同时构造出新的翻译模式的例子:
此时进行分析时,语法分析和语义分析即可同时进行:

假设有翻译模式: A → A 1 Y { A . a : = g ( A 1 . a , Y . y ) } A → X { A . a : = f ( X . x ) } A → A_1Y\{A.a:=\color{blue}{g(A_1.a, Y.y)}\color{black}{\}}\\ A → X\{A.a:=\color{red}{f(X.x)}\} AA1Y{ A.a:=g(A1.a,Y.y)}AX{ A.a:=f(X.x)} 它的每个文法符号都有一个综合属性,用小写字母表示, g和f是任意函数。

在语法的左递归消除中,添加语义的步骤,为R添加两个属性,连接上下文的属性:

例如:左为没有消除左递归的翻译模式,右为消除左递归的翻译模式:

另一个消除的例子:

15.4 递归下降翻译器的设计

  • 对每个非终结符A构造一个函数过程

  • A的属性实现为参数和变量

    • 继承属性 :对A的每个 继承属性 设置为函数的一个 形式参数
    • 综合属性 :实现为函数的返回值 (若有多个综合属性,打包成作为结构或记录记录返回 为了简单,我们假设每个非终结只有一个综合属性)
    • A的产生式中的每一个文法符号的每一个 属性 :实现为A对应的函数过程中的 局部变量
  • 按照产生式右部从左到右的,对于 单词符号 (终结符)非终结符语义动作 ,分别实现

    • 对于带有综合属性x的 终结符X ,把x的值存入为X.x 设置的变量中。然后产生一个匹配X的调用,并继续 读入一个输入符号。
    • 对于每个 非终结符B ,产生一个右边带有函数调用的 赋值语句 c = B ( b 1 , b 2 , … , b k ) c=B(b_1,b_2,…,b_k) c=B(b1,b2,,bk) ,其中, b 1 , b 2 , … , b k b_1,b_2,…,b_k b1,b2,,bk 是为B的 继承属性 设置的变量,c是为B的 综合属性 设置的变量。
    • 对于 语义动作 ,把动作的代码抄进分析器中,用代 表属性的变量来代替对属性的每一次引用。

一个例子:

R → a d d o p T R ∣ ε R→addopTR|ε RaddopTRε 的递归下降分析过程:

(end)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/pi31415926535x/article/details/105487436

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签