编译原理:语法分析(语法制导翻译)、语义分析(类型检查、中间代码生成)

news2024/10/23 2:45:44

编译器在做语法分析的过程中,除了回答程序代码的语法是否合法(LL,LR能否接收)外,还需要完成后续的工作(包括构建语法树、类型检查、中间代码生成、目标代码生成),这些后续工作一般都可以通过语法制导的翻译来完成。

语法制导翻译

在规约时加入相应的动作,完成表达式计算
在这里插入图片描述在这里插入图片描述
左边是产生式,右边是语义规则

语法制导翻译的目的
计算编译所需的额外信息(Additional Information)超出了
上下文无关语法和标准解析算法的能力

语法制导翻译的定义
语法制导是一个上下文无关文法和属性及规则的结合。其中,属性和
文法的符号相关,而规则和产生式相关联。

举例:
在规约时,多加入一个属性值,这样每次需要弹出的数目是3倍的右部长度:
在这里插入图片描述

属性,属性文法

属性:变量的数据类型(int),表达式的值(‘a’),变量在内存中的位置(jvm垃圾回收,内存地址管理),过程或函数或程序的目标代码,数的有效位数(高精度计算用)
属性的存在利于优化

为什么定义这些属性:

  1. 语义分析,作类型检查(程序语言要求的类型匹配规则)
  2. 计算中间结果(例如:解释性语言中)
  3. 内存分配管理、数据溢出管理等
  4. 中间代码生成、代码优化
  5. 抽象语法树的构建

属性的分类:
静态属性与动态属性(根据属性绑定的时机)
① 静态属性:在代码执行前绑定的属性
② 动态属性:在代码执行中绑定的属性
综合属性和继承属性
L属性和S属性
在这里插入图片描述
X的属性不止一个,一个属性可以用多个属性的函数计算
在这里插入图片描述

发现有一些X加了1,2,这是为了区分他们
在这里插入图片描述
可见词法可以融入语法
在这里插入图片描述
从这个例子中发现,有一些属性,是从右向左传递的,但另外一些是从左往右,或者右部里面从左往右传递的。
在这里插入图片描述在这里插入图片描述

在这里插入图片描述在这里插入图片描述

依赖图和求值顺序(考)

依赖图:描述了某个语法分析树中属性实例之间的信息流 (拓扑排序)
在这里插入图片描述
在这里插入图片描述
兄弟结点的传递,分析树用虚线表示,依赖关系用实线表示
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

综合属性和继承属性

综合属性(合成属性):在分析树结点N上的非终结符号A的综合属性是由N上的产生式所关联的语义规则来定义的。(结点N上的综合属性,只能通过N的子结点或者N本身的属性值来定义) (返回值,自底向上,后序遍历)
继承属性:在分析树结点N上的非终结符号B的继承属性是由N的父结点上的产生式所关联的语义规则来定义的。(结点N上的继承属性,只能通过N的父结点、N本身和N的兄弟节点上的属性值来定义) (传参,自顶向下,前序遍历或结合中序)

定理:给定一个属性文法,通过适当地修改文法,而无须改变文法的语言,所有的继承属性可以改变成综合属性。

S属性,L属性

S属性:如果一个语法制导定义中的每个属性都是综合属性,这个语法制导
定义就是S属性的。
L属性:如果一个语法制导定义所产生的依赖图中的边总是从左到右,而不
能从右到左,这个语法制导定义就是L属性的,更准确的讲,所有属性:
① 要么是综合属性
② 要么是继承属性,假设存在X0 -> X1X2…Xn,则
Xi.aj= fij(X0.a1,…,X0.ak, …, X1.al, …, Xi-1.a1, …Xi-1.ak)
也就是Xi依赖于X0~Xi-1,只有前面的算出来,后面的才能用
S属性文法属于L属性文法

在这里插入图片描述
表6.6的语法制导定义不是L-属性定义,因为文法符号Q的继承属性依赖于它右边文法符号R的属性。

代码实现

综合属性算法实现:自底向上或后序遍历分析树或语法树。

procedure PostEval (T : treenode);
begin
	for each child C of T do
		PostEval(C);
		Compute all synthesized attributes of T;
end;

例子:算术表达式

//算术表达式语法树的结构定义
typedef enum { Plus, Minus, Times } OpKind;
typedef enum { Opkind, ConstKind} ExpKind;
typedef struct streenode {
	ExpKind kind;
	OpKind op;
	struct streenode *lchild,*rchild;
	int val;
} STreeNode;
typedef STreeNode * SyntaxTree;

void postEval( SyntaxTree t )
{
	int temp;
	if ( t->kind == OpKind ) {
		postEval( t->lchild ); /* 遍历左子树 */
		postEval( t_rchild ); /* 遍历右子树 */
		switch ( t->op ) {
		case Plus:
			t->val = t->lchild->val + t->rchild->val;
			break;
		case Minus:
			t->val = t->lchild->val - t->rchild->val;
			break;
		case Times:
			t->val = t->lchild->val * t->rchild->val;
			break;
		} /* end switch */
	} /* end if */
} /* end postEval */

继承属性算法实现:前序(前序中序组合)遍历分析树或语法树

procedure PreEval(T: treenode);
begin
	for each child C of T do
		Compute all inherited attributes of C;
		PreEval(C);
end;

例子:变量申明中的dtype

// 变量申明的语法树的结构定义
typedef enum {decl, type, id} NodeKind;
typedef enum {integer, real} TypeKind;
typedef struct treenode {
	NodeKind kind;
	struct treenode *lchild,*rchild,* sibling;
	TypeKind dtype; /* for type and id nodes */
	char *name; /* for id nodes only */
} *SyntaxTree;

procedure EvalType(T: treenode);
begin
	case nodekind of T of
	decl:
		EvalType( type child of T );
		Assign dtype of type child of T to var-list child of T;
		EvalType( var-list child of T );
	type:
		if child of T = int then T.dtype := integer
		else T.dtype :=real;
	var-list:
		Assign T.dtype to first child of T;
		if third child of T is not nil then
			Assign T.dtype to third child;
			EvalType( third child of T );
	end case;
end EvalType;

void evalType (SyntaxTree t)
{
	switch (t->kind){
		case decl:
			t->rchild->dtype = t->lchild->dtype
			evalType( t->rchild );
			break;
		case id:
			if(t->sibling != NULL) {
				t->sibling->dtype = t->dtype;
				evalType( t->sibling evalType);
			}
			break;
	}
}

或者

void evalType(SyntaxTree t)
{
		if(t->kind == decl){
			SyntaxTree p = t->rchild;
			p->dtype = t->lchlild->dtype;
			while (p->sibling !=NULL){
			p->sibling->dtype = p->dtype;
			p = p->sibling;
		}
	}
}

在组合综合属性和继承属性的文法中,如果
① 综合属性依赖于继承属性(及其它的综合属性),
② 继承属性不依赖于任何综合属性,
那么就可能在分析树或语法树的一遍遍历中计算所有的属性。

综合属性和继承属性组合的文法

procedure CombinedEval(T:treenode);
begin
	for each child C of T do
		Compute all inherited attributes of C;
		CombinedEval( C );
	Compute all synthesized attributes of T. 
end;

存储属性值

作为参数和返回值的属性

在分析过程中,很多属性值都相同,或者只是在计算其他属性时临时使用,此时,并不需要在语法树中存储。那么,对于综合属性和继承属性,有如下的性质:
① 综合属性:可在后序遍历中计算,通常看作是过程的返回值。
② 继承属性:可在前序遍历中计算,通常看作是过程的参数

使用扩展数据结构存储属性值

对于那些不方便用参数或返回值传递的属性,同时,将属性值存储在语法树的结点里也是不合理时。此时,可以考虑扩展数据结构存储属性值。
重新考虑无符号整型数的例子。因为属性一旦设置,在计算过程中就固定了,因此,可以使用一个非局部变量存储它的值,而不是每次作为一个参数进行传递。

翻译模式

翻译模式是语法制导定义的一种便于翻译的书写形式。其中属性与文法符号相对应,语义规则或语义动作用花括号{}括起来,可被插入到产生式右部的任何合适的位置上。
这是一种语法分析和语义动作交错的表示法,它表达在按深度优先遍历分析树的过程中何时执行语义动作。
翻译模式给出了使用语义规则进行计算的顺序。可以看成是分析过程中翻译的注释。
在这里插入图片描述
在这里插入图片描述

设计翻译模式

条件:
语法制导定义是L-属性定义。
保证语义动作不会引用还没有计算的属性值。
方法:分两类讨论
① 只有综合属性的情况
② 既有综合属性,又有继承属性的情况

只有综合属性的情况:为每一个语义规则建立一个包含赋值的动作,并把这个动作放在相应的产生式右边的末尾。
既有综合属性,又有继承属性的情况
① 产生式右边的符号的继承属性必须在这个符号以前的动作中计算出来。
② 一个动作不能引用这个动作右边符号的综合属性。
③ 产生式左边非终结符号的综合属性只有在它所引用的所有属性都计算出来以后才能计算。计算这种属性的动作通常可放在产生式右端的未尾。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

语法制导翻译应用(抽象语法树构建)

利用语法制导翻译,自动构建抽象语法树,即:在语义动作中,加入生成抽象语法树的相关代码,自动生成对应的抽象语法树。
在这里插入图片描述
在这里插入图片描述
return p5 (根节点)

在这里插入图片描述

类型检查(语义分析)

输入:抽象语法树
输出:合法性、中间表示

语义分析也称为类型检查、上下文相关分析。
负责检查程序(抽象语法树表示)的上下文相关属性

符号表:哈希表结构

符号表是编译器的主要继承属性,也是主要的数据结构。用来存储程序中变量的相关信息。符号表的处理必须非常高效(程序中的变量规模会很大)

符号表的接口(数据结构与操作)
操作:新建、查找、插入与删除。
1 新建(New):新建并初始化符号表。
2 查找(Lookup):根据名字查找符号表(名字和结点对应)。
3 插入(Insert):根据结点的名字和内容,将结点加入符号表。
4 删除(Delete):根据结点的名字,删去对应结点(当符号不再有效时) 。

数据结构:(主要目标是实现高效)
A 线性表:

  1. 简洁,方便实现。
  2. 不高效,查找时间是线性时间O(N)。
  3. 适用于对时间要求不高的编译器。
  4. 举例:原型或实验编译器、小规模程序的编译器。

B 各种搜索树结构:

  1. 实现方式:二叉搜索树、平衡树(AVL trees)、B树。
  2. 相对高效,但并不是最高效,查找时间是O(logN)。
  3. 删除节点操作复杂。
  4. 实际中使用相对较少。

C Hash Tables(哈希表、杂凑表、或散列表):

  1. 查找、插入与删除高效,时间是O(1)。
  2. 空间浪费比较严重。
  3. 实际中使用较多

哈希表是一个入口(entries)数组,称为桶(buckets),使用一个索引(index),通常定义在整数范围。同时,需要定义一个哈希函数(hash function),该函数可以直接把搜索键值(key value)转化为哈希值(hash value),该数值对应于索引。
有效性:哈希方法的有效性主要依赖于哈希函数的设定。
冲突:两个键值可能被哈希函数会映射到同一个索引
解决方案: ① 开放地址值法:将冲突的项目放在后续的桶(buckets)中。
问题1:会降低哈希表的性能。
问题2:删除样本时,操作复杂。
② 分离链表:每个桶看作是一个链表,将冲突的项目插入到该链表中。是目前主流的实现方式。

作用域
① 变量使用前说明(没有该条规则,编译器无法单趟完成编译)
② 最近嵌套原则。
块结构:程序语言的一块(block)是能包含说明的任意结构

在这里插入图片描述
方法1:一张Hash表的方法
① 进入作用域时,插入元素
② 退出作用域时,删除元素
方法2:采用符号表构成的栈。
① 进入作用域时,插入新的符号表
② 退出作用域时,删除新的符号表

类型检查

类型推断(type inference)和类型检查(type checking)是编译器的
核心
任务。这两个任务紧密相关,通常也一起执行,统一看作类型检查。
数据类型:显式表示(explicit)与隐式表示(implicit)

数据类型“
简单数据类型:例如 int, double, boolean, char
特殊例子:在C语言中,void这个类型没有值,表示空的集合。用于表示
没有返回值的函数,或表示一个指针指向未知类型。

中间代码生成

现代的编译器的语义分析模块,除了做语义分析外,还要负责生成中间
代码或者目标代码
在这里插入图片描述
在这里插入图片描述
为什么要划分不同的中间表示:高级语言、机器语言的组合

中间代码

定义:中间代码(intermediate representation; IR)是源程序的一种内部表示,
不依赖目标机的结构,易于生成目标代码与优化分析的中间表示。

中间代码的常见类型
1 三地址码(Three-address Code)
2 波兰式
3 P-代码(P-code)

三地址码(Three-address Code)

基本形式:x = y op z。该定义表示:对y和z的值进行op操作,并将值赋给x。
p:既可以是算术运算符,也可以是其他能操作y和z的操作符
为什么叫三地址码:基本形式包含x,y和z,代表了内存中的三个地址
注意:x的地址和y与z的使用不同。y和z可以代表常量等。

在这里插入图片描述
后序遍历
在这里插入图片描述
分支和循环都用跳转实现
实现方式:四元式(Quadruple)和三元式(Triple)
四元式:1个操作符以及三个地址。(对于少于3个地址的指令,将一个或更多的域设置成null或“empty”)
三元式:用自己的指令来代表临时变量。即:三地址码指令中的目标地址总是一个临时变量,供后续引用。
在这里插入图片描述
在这里插入图片描述
注意:取消了label指令,用三元式的引用代替。

//四元式的数据结构
	typedef enum { rd, gt, if_f, asn, lab, mul, sub, eq, wri, halt,} OpKind;
	typedef enum { Empty, IntConst, String } AddrKind;
	typedef struct {
	AddrKind kind;
	Union {
		int val;
		char * name;
	} contents;
}Address;

typedef struct {
	OpKind op;
	Address addr1, addr2,addr3;
} Quad;

中间代码生成

在这里插入图片描述
在这里插入图片描述

代码优化

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国产芯片方案/血氧仪方案SIC88336

血氧仪是用来测量脉率、血氧浓度以及灌注指数的仪器设备,血氧浓度是临床医疗上重要的基础数据之一。如果有条件,人们应该时刻监测自己的血氧饱和度,对自己的健康更加有利。下面是详细知识说明。 一、血氧仪方案开发原理 该方案一种检测方式是…

SOFTS: Efficient Multivariate Time Series Forecasting with Series-Core Fusion

SOFTS: Efficient Multivariate Time Series Forecasting with Series-Core Fusion 文章目录 SOFTS: Efficient Multivariate Time Series Forecasting with Series-Core Fusion1. 论文背景1.1 通道独立-通道依赖的区别1.2 论文贡献 2. 模型架构2.1 SOFTS的主要架构2.2 STAR 模…

家用洗地机哪个牌子的好用性价比高?热销品牌型号推荐

洗地机在市场上越来越受到人们的欢迎,它能够一次性完成吸尘、拖地和清洗的所有步骤,极大地提高了清洁效率,是减轻人们日常清洁负担的优秀家电,为了避免大家盲信挑选机器,我整理了一份洗地机选购指南,帮助大…

基于MATLAB的误码率与信噪比(附完整代码与分析)

目录 一. 写在前面 二. 如何计算误码率 三. 带噪声的误码率分析 3.1 代码思路 3.2 MATLAB源代码及分析 四. 总结 4.1 输入参数 4.2 规定比特长度 4.3 特殊形式比较 一. 写在前面 (1)本文章主要讨论如何仿真误码率随着信噪比变化的图像 &#…

原子性(juc编程)

原子性 概述:所谓的原子性是指在一次操作或者多次操作中,要么所有的操作全部都得到了执行并且不会受到任何因素的干扰而中断,要么所有的操作都不执行,多个操作是一个不可以分割的整体。 //比如说:你喂你女朋友吃冰淇…

户外LED显示屏的发展历程

户外LED显示屏自其问世以来,经历了显著的发展与变革。其技术不断进步,应用场景逐步扩大,并在广告、信息传播等领域发挥了重要作用。本文将梳理户外LED显示屏的发展历程,重点介绍其技术演进和应用拓展。 早期发展:直插式…

一文带你理清同源和跨域

1、概述 前后端数据交互经常会碰到请求跨域,什么是跨域,为什么需要跨域,以及常用有哪几种跨域方式,这是本文要探讨的内容。 同源策略(英文全称 Same origin policy)是浏览器提供的一个安全功能。同源策略限制了从同一个源加载的…

海外盲盒小程序搭建过程的最大挑战:文化差异与本地化

一、引言 随着全球化的深入发展,跨境电商和海外市场的拓展成为许多企业的重要战略方向。盲盒小程序作为一种新兴的消费模式,也在海外市场展现出巨大的潜力。然而,在海外搭建盲盒小程序并非易事,文化差异与本地化问题是其搭建过程…

计算最大数位-第13届蓝桥杯省赛Python真题精选

[导读]:超平老师的Scratch蓝桥杯真题解读系列在推出之后,受到了广大老师和家长的好评,非常感谢各位的认可和厚爱。作为回馈,超平老师计划推出《Python蓝桥杯真题解析100讲》,这是解读系列的第87讲。 计算最大数位&…

Qwen2大模型微调入门实战-命名实体识别(NER)任务(完整代码)

Qwen2是通义千问团队最近开源的大语言模型,由阿里云通义实验室研发。 以Qwen2作为基座大模型,通过指令微调的方式做高精度的命名实体识别(NER),是学习入门LLM微调、建立大模型认知的非常好的任务。 使用LoRA方法训练&…

MySQL快速安装(mysql8.0.30区别之前yum安装)

目录 一.初始化环境并解压 二.创建程序用户管理 三.修改mysql目录和配置文件的权限 四.修改配置文件 五.设置环境变量,申明/宣告mysql命令便于系统识别 六.初始化数据库 七.设置系统识别,进行操作 八.初始化数据库密码 九.用户并设置密码 十.赋…

机器学习模型评估之校准曲线

模型校准曲线(Calibration Curve),也称为可靠性曲线(Reliability Curve)或概率校准曲线(Probability Calibration Curve),是一种评估分类模型输出概率准确性的图形工具。它可以帮助我…

STM32 串口通讯

使用STM32的串口通讯,接收串口助手的数据,并且将接收到的数据返回串口,重定义printf功能。 配置引脚信息 由于每次新建工程都需要配置信息,比较麻烦,好在STM32CubeIDE提供了导入.ioc文件的功能,可以帮我们…

达梦8 兼容MySQL语法支持非分组项作为查询列

MySQL 数据库迁移到达梦后,部分GROUP BY语句执行失败,报错如下: 问题原因: 对于Oracle数据库,使用GROUP BY时,SELECT中的非聚合列必须出现在GROUP BY后面,否则就会报上面的错误,达梦…

基于python+tkinter(Gui)的学生信息管理系统

博主介绍: 大家好,本人精通Java、Python、C#、C、C编程语言,同时也熟练掌握微信小程序、Php和Android等技术,能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验,能够为学生提供各类…

[创业之路-119] :制造业企业的必备管理神器-ERP-主要功能模块说明与系统架构

目录 一、ERP功能的标准化 二、常见的ERP标准化功能 2.1 基础档案 2.2 供应链 2.3 人力资源管理 2.4 资产管理 2.5 生产制造 2.6 财务会计 2.7 管理会计 2.8 CRM客户管理管理 2.9 商业智能分析 三、常见的ERP软件供应商 国内ERP软件供应商 国外ERP软件供应商 四…

2024考古之还在用原始JDBC开发 手搓 案例 实现一个模块的增删改

JDBC案例 将来如果完成的话 就代表对JDBC里面的知识点全部融会贯通了 其实就是对数据的增删改查 我们入门做不出来前端的内容 很正常 准备环境 建表 use mybatis;create table tbl_brand (id int primary key auto_increment,brand_name varchar(20),company_name varcha…

在hue中使用ooize调度ssh任务无法执行成功,无法查看错误

ssh执行失败,但是hue没有给出明确的错误原因: 经过经验分析,原来是服务器上的sh文件用的是doc/window格式,需要使用notepad将格式改为unix之后就可以正常执行。 特此记录,避免遗忘知识点

图标设计新手手册:应用图标尺寸比例全解析

通常我们在App Store中寻找新的应用程序时,首先会快速扫描搜索栏中的一些关键词,然后选择感兴趣的应用程序,在选定的应用页面中查看具体信息,最后决定是否下载。在这一系列操作中,APP图标的大小比例是影响用户体验的关…

大腾智能,基于云原生的国产工业协同平台

大腾智能是一家基于云原生的国产工业软件与数字化协同平台,专注于推动企业数字化转型与升级,为企业提供一系列专业、高效的云原生数字化软件及方案,推动产品设计、生产及营销展示的革新,实现可持续发展。 大腾智能旗下产品 3D模型…