当前位置:
文档之家› 第六章(1)语义分析(Semantic Analysis)
第六章(1)语义分析(Semantic Analysis)
类型的内部表示:表示类型表达式所包含的各种 信息的数据结构。
32
类型的种类属性: 标准、子界、枚举、数组、记录、
集合、文件、指针类型等等。 TypeKind = ( intTy,boolTy,charTy,realTy,
enumTy,subTy,arrayTy, structTy,setTy,fileTy,pointerTy)
…
{ // 第三层头
…
{float a; // 第四层头,定义的局部实型变量a
…
} // 第四层尾
…a… // 引用第二层定义的局部字符型变量a
} // 第三层尾
…
} // 第二层尾
....
} // 第一层尾
28
三种内部表示
标识符的内部表示 类型的内部表示 值的内部表示
值的内部表示
为[ord(C1)...ord(C2)]
31
类型的内部表示
类型表达式:
如: at = ARRAY[1..10] OF ARRAY[1..100] OF integer; rt = RECORD x : real; a : at;
CASE u : boolean OF false:( k : integer ); true :( y: real; b :boolean ) END
14
常见的语义错误(续1)
类型相关的语义错误
– 各种条件表达式的类型是不是boolean型? – 运算符的分量的类型是否相容? – 赋值语句的左右部的类型是否相容? – 形参和实参的类型是否相容? – 下标表达式的类型是否为所允许的类型? – 变体记录中表示情形的常量是否为合法类型?
常见的语义错误(续2)
22
标识符的属性(续3)
存储类别 存储类别是指数据的存储方式,存储方式可分为两大类:静 态和动态。 静态存储方式是指在程序运行前即为数据分配好存储空间( 在静态区),在程序运行期间,数据的存储空间仍保持不变; 动态存储方式则是在程序运行期间根据函数调用(函数被激 活)和分程序语句的开始执行(分程序语句被激活)的需要进行 动态存储分配。 标识符的存储类别属性是编译过程语义处理、检查和存储分 配的重要依据。编译程序一般根据变量的存储类别以及它们出 现的位置和次序来确定每一个变量应分配的存储区及在该区中 的具体位置。
7
1. int x=10; 2. Main( )
符合变量声明的语法、语义
3. { printf( “%d”,x+x );
4. x( );
符合函数调用的语法、不符合语义
5. f = x; 6. }
符合赋值语句的语法、不符合语义
7. float f( ) 8. {int x=20,y;
符合函数声明的语法、语义 符合变量声明的语法、语义
23
作用域和可视性
标识符在程序中起作用的范围,称为它的作用
域。
一般地,定义该标识符的位置及存储类关键字 决定了它的作用域。如:C语言中, 动态存储: 自动变量(本函数内有效) 寄存器变量(本函数内有效) 形式参数(本函数内有效) 静态存储: 静态局部变量(函数内有效) 静态外部变量(本文件内有效) 外部变量(其他文件可引用)
类型 除过程标识符之外,其他标识符都具有类型属 性,函数的数据类型指的是函数返回值的数据类 型。 基本类型有整型、实型、字符型以及布尔型等。 在基本类型的基础上,还可以定义数组、结构 体、联合、枚举、子界、集合、指针等结构类型。 标识符的类型是在程序中该标识符的定义部分 得到的。 变量标识符的类型属性决定了变量所占存储空 间的大小以及能够施于变量上的操作等。 21
标识符的属性(续2)
存取方式 因为变量标识符代表的是一个内存单元或一段 连续的内存单元,根据这些内存单元中存放信息的类别 又可以把变量分为间接存取变量和直接存取变量。
如果变量标识符p所代表的内存单元中存放的是另一 个变量q对应的内存地址,则称变量p为间接存取变量; 如果变量标识符p所代表的内存单元中存放的是一个 值,则称变量p为直接存取变量。
符号表 判定
18
6.2 符号表的数据结构
标识符的属性
名字 类型 存取方式 存储类别 作用域和可视性
19
标识符的属性
名字 在程序语言中,标识符可以作为变量的名字、 函数的名字或过程的名字,是变量、函数或过程的 唯一标志,因此在符号表中标识符的名字一般不允 许重名。
若程序中出现重名标识符:
35
数组类型(方案1):
Size Kind Low Up ElemType SubSize ArrayTy
其中各个域的含义如下:
Size表示数组类型所占空间的大小,是数组所有成分数 据占用空间的和,需要通过计算得到,Size = (UpLow+1)*sizeof(ElemType), 其中sizeof是一个辅助函数 ,用于计算每种类型的size; Kind = arrayTy, 表示是数组类型; Low表示数组下标的下界,在C语言中Low = 0; Up表示数组下标的上界; ElemType 表示数组成分类型的内部表示指针。
类型size属性:表示此种类型数据应该分配的内存空间的大小。 其它属性依类型的不同而不同。
33
内部表示:
标准类型:
Size
Kind
intPtr IntSize intTy
boolPtr BoolSize boolTy
charPtr CharSize charTy
realPtr RealSize realTy
– 编译时(compile-time)可以检查的语义 – 例如:标识符未声明
动态语义
– 目标程序运行时(run-time)才能检查的 语义
– 例如:除零溢出错误
10
如何描述程序设计语言的语义?
程序设计语言的形式语义 – 属性文法 (用于描述静态语义) – 操作语义(Operational Semantics) – 指称语义(Denotational Semantics) – 代数语义(Algebra Semantics) – 公理语义(Axiomatic Semantics)
致? – 子界类型中的下界和上界类型是否相容?下界是否小于等
于上界?
16
语义分析的实现
方式一:不作为独立的一遍 ① 语义错误检查:可以安排在中间代码生
成时进行 。 ② 一般的语义检查:与语法分析相结合
17
方式二、独立一遍的语义分析的功能图示
语法分析树 TokenList 语义定义
语义分析
自然语言描述规定
9. float x; 10. printf( “%d”,x ); 11. }
符合变量声明的语法、不符合语义
8
语义分析的必要性
一个语法正确的程序不能保证它是有意义 的!
程序中容易出现各种语义错误:
– 标识符未声明 – 操作数的类型与操作符的类型不匹配 – ……
9
程序设计语言语义的分类
静态语义
第6章 语义分析(Semantic Analysis) 和符号表
Semantic:of or relating to meaning, especially meaning in language.
1
语义分析在编译程序中的逻辑位置
表处理
中
源
词
语
语
间
程
法
法
义
代
序
分分ຫໍສະໝຸດ 分码析析
析
生
成
中
目
间
标
目
代
代
标
码
码
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; }
程
优
生
序
化
成
错误处理
2
6.1 语义分析概述 6.2 符号表的数据结构 6.3 符号表的管理 6.4 程序设计语言符号表的实例
3
主要内容:
语义分析的功能及重要性; 标识符的内部表示; 类型的内部表示; 符号表的组织。
6.1 语义分析概述
6.1 语义分析概述
语法和语义的区别
语法:
非结构类型值的内部表示: 实型: 指针: 有序类型:整数形式
30
有序类型的常量表示:
整型常量: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,则值空间
34
子界类型:
Size Kind HostType Low Up SubSize SubTy
例:T=1..10;
Size Kind HostType Low Up
1 subTy IntPtr 1
10
TypeIR’ (Size:1, Kind:subTy HostType:intPtr, low:1, up:10)
符号表的作用:
– 存储标识符的属性;
– 便于检查语义错误;
– 代码阶段作为地址分配的依据。
12
语义分析的主要任务(续1)
在整个程序范围内检查语义错误
– 声明和使用相关的错误 – 类型相关的语义错误
13
常见的语义错误
声明和使用相关的语义错误