编译原理:绪论 —— 语义分析
Posted at
# Compiler
语义分析
语义分析的任务
语义分析是编译过程的第三个阶段,高级语言中的语句大多数分为两类,一类是声明语句,一类是可执行语句,在声明语句中会声明一些数据对象或过程,并且为他们分别起一个名字 标识符 (id)
,对于声明语句来说,语义分析的主要任务就是收集标识符的属性信息,一般有这些属性信息
对声明语句语义分析的任务
- 种属 (Kind) : 它说明了这个标识符对应的是简单变量,还是一个复合变量(数组、记录、…),还是过程、…
- 类型 (Type) : 这个我相信都不用说了把
- 储存位置、长度 : 比如说我们写了一个对象或过程,我们都要在内存中给他分配一段空间,这样存储位置和所占用的空间的大小(长度)就成为标识符重要的属性
- 值
- 作用域
关于 3 举个例子:
首先声明了一个实型数组x
,因此 x
的相对地址就是 0
。我们假设一个实型变量占用 8 个字节,因为这个实型数组包含 8 个元素,因此他就占用了 64 个字节,所以接下来声明的变量 i
的相对地址就是 64,我们再假设一个整形变量占用 4 个字节,那么接下来声明的变量 j
的相对地址就是 64 + 4 = 68 ,以此类推。
名字 | 相对地址 |
---|---|
x | 0 |
i | 64 |
j | 68 |
|:-:|:-:| |0|x[0]| |8|x[1]| | | | | |…| |56|x[7]| |64|i| |68|j|
对过程语义分析的任务
对于过程来说,作用有 0. 参数和返回值信息 : 包含了参数个数、参数类型、参数传递方式、返回值类型等等
符号表 (Symbol Table)
NAME | TYPE | KIND | VAL | ADDR |
---|---|---|---|---|
SIMPLE | 整 | 简变 | ||
SYMBLE | 实 | 数组 | ||
TABLE | 字符 | 常数 | ||
. | . | . | . | . |
语义分析中收集的标识符的信息都会存放在符号表里,每一个标识符都对应着一条记录,每个字段对应着一个属性,比如说 类型 (TYPE)
、种属 (KIND)
、值 (VALUE)
和 地址 (ADDRESS)
等等。
符号表中通常带有一个字符串表,用来存放程序中标识符的名称和字符常数,这样的话 NAME
字段就会被分割成两个部分,一个用来存放标识符在字符串表中的起始位置,另一个存放标识符的长度,这里由于 Markdown 的限制不能将其表现出来。符号表中设计字符串表的作用是节省内存空间。
语义分析的另一个任务:语义检查
常见的语义错误有:
- 变量或过程未经声明就使用
- 变量或过程名重复声明
- 运算分量类型不匹配:其中需要判断是否运算无意义(比如将一个数组与数字相加)和是否需要隐式转换
- 操作符与操作数之间类型不匹配
- 数组下标 不是整数
- 对非数组变量使用数组访问操作符
- 对非过程名使用过程调用操作符
- 过程调用的参数类型或数目不匹配
- 函数返回类型有误
graph TD Start-- 字符流 -->词法分析器 词法分析器-- 词法字节流 -->语法分析器 语法分析器-- 语法树 -->语义分析器 语义分析器-- 语法树 -->中间代码生成器 中间代码生成器-- 中间表示形式 -->机器无关代码优化器 机器无关代码优化器-- 中间表示形式 -->目标代码生成器 目标代码生成器-- 目标机器语言 -->机器相关代码优化器 机器相关代码优化器-- 目标机器语言 -->Fin