编译原理第六章

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第6章 语义分析(Semantic Analysis) 和符号表
Semantic:of or relating to meaning, especially meaning in language.
1
语义分析在编译程序中的逻辑位置
表 处 理
源 程 序
词 法 分 析
语 法 分 析
语 义 分 析
中 间 代 码 生 成

动态语义
– 目标程序运行时(run-time)才能检查的
语义 – 例如:除零溢出错误
10
如何描述程序设计语言的语义?

程序设计语言的形式语义
– 属性文法 (用于描述静态语义)
– 操作语义(Operational Semantics)
– 指称语义(Denotational Semantics)
– 代数语义(Algebra Semantics)
程序区 静态存储区 动态存储区
作用域和可视性

标识符在程序中起作用的范围,称为它的作用域。 一般地,定义该标识符的位置及存储类关键字决 定了它的作用域。如:C语言中, 动态存储: 自动变量(本函数内有效) 寄存器变量(本函数内有效) 形式参数(本函数内有效) 静态存储: 静态局部变量(函数内有效) 静态外部变量(本文件内有效) 外部变量(其他文件可引用)
34
类型的内部表示
类型表达式:
typedef float AT[10][100] ;
如: AT = ARRAY[1..10] OF ARRAY[1..100] OF RT = RECORD x : real; a : AT; CASE u : boolean OF false:( k : integer ); true :( y: real; b :boolean ) END
z 1 z z 1
x y x y
6
int i; switch (i){ case 0:printf(“%s\n”,“auto”) ;break;
case 1:printf(“%s\n”,“static”);break; case 2:printf(“%s\n”,“extern”);break; case 1:printf(“%s\n”,“register”);break; }


y+f(....)中的f是不是函数名?形参个数和实参个数是否一致?
p(....)语句中的p是不是过程名?形参个数和实参个数是否一 致?

子界类型中的下界和上界类型是否相容?下界是否小于等 于上界?
16
语义分析的实现
方式一:不作为独立的一遍

类型语义错误检查:可以安排在中间代 码生成时进行

struct RT {float x; AT a; int u; union {int k; struct REAL;{float y; int b; } rt2: }; };
类型的内部表示:表示类型表达式所包含的各种
信息的数据结构。
35
类型的种类属性:
标准、子界、枚举、数组、记录、
集合、文件、指针类型等等。
char a;
31 flaot a;
三种内部表示 值的内部表示 类型的内部表示 标识符的内部表示


值的内部表示
非结构类型值的内部表示:
实型: 指针: 有序类型:整数形式
33
有序类型的常量表示:



整型常量:ord(N) = N 布尔常量:ord(false)=0, ord(true) = 1 字符常量:ord(C) = ASCⅡ(C) 枚举常量:设有枚举类型(D,A,B),则有 ord(D)=0,ord(A)=1,ord(B)=2 子界常量:设有子界类型C1..C2,则值空间 为[ord(C1)...ord(C2)]
中 间 代 码 优 化
目 标 代 码 生 成
目 标 程 序
错 误 处 理
2
6.1 6.2 6.3 6.4
语义分析概述 符号表的数据结构 符号表的管理 程序设计语言符号表的实例
3
主要内容:


语义分析的功能及重要性;
标识符的内部表示; 类型的内部表示; 符号表的组织。
6.1 语义分析概述
24
个变量q对应的内存地址,则称变量p为间接存取变量;
标识符的属性(续3)
存储类别 存储类别是指数据的存储方式,存储方式可 分为两大类:静态存储方式和动态存储方式。 静态存储方式是指在程序运行前即为数据分配好存储空间( 在静态区),在程序运行期间,数据的存储空间仍保持不变; 动态存储方式则是在程序运行期间根据函数调用(函数被激 活)和分程序语句的开始执行(分程序语句被激活)的需要进行 动态存储分配。 标识符的存储类别属性是编译过程语义处理、检查和存储分 配的重要依据。编译程序一般根据变量声明时的存储类别关键 字以及它们声明出现的位置和次序来确定每一个变量应分配的 存储区及在该区中的具体位置。 25
23
来自百度文库
体、联合、枚举、子界、集合、指针等结构类型。
标识符的属性(续2)
存取方式 因为变量标识符代表的是一个内存单元或一段
连续的内存单元,根据这些内存单元中存放信息的类别
又可以把变量分为间接存取变量和直接存取变量。
如果变量标识符p所代表的内存单元中存放的是另一 如果变量标识符p所代表的内存单元中存放的是一个 值,则称变量p为直接存取变量。
静态存储区 int a;
动态存储区float a;
// 引用
„ „ a „ „ }
float a .
int b;
28
为了在函数中也能看 int a,C的新版本中增加了文法记 号“::”,如: int a; // 外部定义的整型变量a int func(a ,b) { float a; // 函数内部定义的局部变量a, 屏闭了外部定义的变量a. int b;
26

通常一个变量的作用域就是该变量可以出现的 场合,也就是说在某个变量作用域范围内该变 量是可以引用的,这就是变量可视性的作用域 规则。 有两种情况也将影响变量的可视性。

27
1、函数的形式参数和函数外部定义的变量重名:函 数的形式参数在函数内可见 。 int a; // 外部定义的整型变量a int func(a ,b) { float a; // 函数内部定义的局部变量a, 屏闭了外部定义的变量a. int b; 程序区
标识符的属性 (续1)
类型 除过程标识符之外,其他标识符都具有类型属 性,函数的数据类型指的是函数返回值的数据类 型。 基本类型有整型、实型、字符型以及布尔型等。
在基本类型的基础上,还可以定义数组、结构 标识符的类型是在程序中该标识符的定义部分
得到的。 变量标识符的类型属性决定了变量所占存储空 间的大小以及能够施于变量上的操作等。
6.1 语义分析概述
语法和语义的区别
语法:
描述一个合法定义的程序结构的规则。
语义:
说明一个合法定义的程序的含义的规则。
5
PASCAL语言的条件语句: if x>y then z := z+1 else z := z -1
C语言的条件语句: if (x>y) { z = z+1; } else { z=z-1; }
常见的语义错误(续1)

类型相关的语义错误
– 各种条件表达式的类型是不是boolean型? – 运算符的分量的类型是否相容? – 赋值语句的左右部的类型是否相容? – 形参和实参的类型是否相容? – 下标表达式的类型是否为所允许的类型?
常见的语义错误(续2)
– – – –
函数说明中的函数类型和返回值的类型是否一致? V[E]中的V是不是变量,而且是不是数组类型? V.id中的V是不是变量,而且是不是结构体类型? id是不是该 记录类型中的成员? V↑(*V)中的V是不是指针或文件变量?
一般的语义检查:与语法分析相结合
17
方式二 独立一遍的语义分析的功能图示
语法分析树 TokenList 语义定义 自然语言描述的规定
18
语义分析
符号表
判定
类C语言的抽象语法树
程序Root 节点 Node2 …… 常量声明 类型声明 节点 Node 节点 Noden FunNode1 节点 Node1
30
„ {int a; // 第一层头,定义的局部整型变量a „ {char a; // 第二层头,定义的局部字符型变量a „ { // 第三层头 „ {float a; // 第四层头,定义的局部实型变量a ... a ... } // 第四层尾 „a„ // 引用第二层定义的局部字符型变量a } // 第三层尾 程序区 „ } // 第二层尾 静态存储区 .... 动态存储区: } // 第一层尾 int a;
– 公理语义(Axiomatic Semantics)

形式语义描述技术没有形式语法描述技术成熟 硕士研究生的课程-《形式语义学》
11
语义分析的主要任务
根据声明部分建立符号表
符号表(symbol table):是一种供编译器用于保 存有关源程序的各种信息的数据结构。符号表的每 个条目中包含与一个标识符相关的信息,这些信息 全面地反映该名字的属性及它们在编译过程中的特 征。 符号表的作用:
7
1. 2. 3. 4.
5.
int x=10; Main( ) { printf( “%d”,x+x );
符合变量声明的语法、语义
x( );
f = x;
符合函数调用的语法、不符合语义
6.
}
符合赋值语句的语法、不符合语义
7.
8. 9. 10. 11.
float f( )
{int x=20,y; float x; printf( “%d”,x ); }
– 存储标识符的属性;
– 便于检查语义错误;
– 代码生成阶段作为地址分配的依据。
12
语义分析的主要任务(续1)
在整个程序范围内检查常见语义错误
– 声明和使用相关的错误 – 类型相关的语义错误
13
常见的语义错误

声明和使用相关的语义错误 常见的语义错误: – 每个使用性标识符是否都有声明?在同层内有无标识符被声 明多次? – 标号是否有声明?有无重复声明和重复定位错误?有无非法 转入错误? 如何检查? – 每当遇到新声明的标识符,查符号表: 如果当前有效的所有标识符中有相同名字的,则是重复声 明错误; 否则生成它的属性信息,保存到符号表中; – 每当遇到标识符的使用,查符号表 如果没有找到,说明该标识符没有声明; 如果找到,则可获取该标识符的属性,进行进一步分析; 14
符合函数声明的语法、语义 符合变量声明的语法、语义 符合变量声明的语法、不符合语义
8
语义分析的必要性
一个语法正确的程序不能保证它是有意义 的. 程序中容易出现各种语义错误:

– 标识符未声明 – 操作数的类型与操作符的类型不匹配
– ……
9
程序设计语言语义的分类

静态语义
– 编译时(compile-time)可以检查的语义 – 例如:标识符未声明
TypeKind = ( intTy,boolTy,charTy,realTy, enum TypeKind {intTy,boolTy,charTy,realTy, enumTy,subTy,arrayTy, enumTy,subTy,arrayTy,structTy,setTy,fileTy, structTy,setTy,fileTy,pointerTy) pointerTy};
语句
变量声明
函数声明 语句
20
6.2 符号表的数据结构
标识符的属性
名字
类型 存取方式 存储类别
作用域和可视性
21
标识符的属性

名字 在程序语言中,标识符可以作为变量的名字、 函数的名字或过程的名字,是变量、函数或过程的 唯一标志,因此在符号表中标识符的名字一般不允 许重名。 若程序中出现重名标识符: 1.将根据语言的定义,按照该标识符在程序 中的作用域和可视性规则进行相应的处理。 2.在一些允许操作重载(Operator Overload)的语言中,函数名、过程名是可以重名 的,对于这类标识符要通过它们的参数个数和类型、 函数返回值类型来区别,以达到它们在符号表中的 唯一性。 22
程序区
„ „ a „ // „ „ ::a „ }
引用
float a .
int a .
静态存储区 int a; 动态存储区float a;
// 引用
int b;
29
2、分程序结构 :C语言中分程序语句的语法是:
{ 声明 语句 } 分程序的一个特点是它的嵌套结构。 分程序结构的声明作用域由下面的最近嵌套规则给出: (1)分程序B中声明的作用域包括B。 (2)如果名字x没有在B中声明,那么B中x的出现 是在外围分程序B 的x声明的作用域中,且满足: (a)B 有x的声明; (b)B 比其它任何含x声明的分程序更接近被 嵌套的B。
相关文档
最新文档