符号表贯穿词法分析到语义处理的全过程,是用来存放在程序中出现的符号标识符(变量、函数、过程等)的语义属性在词法分析及语法分析阶段不断积累和更新符号表中的信息,并在词法分析到代码生成甚至动态链接的各个阶段,按照各阶段的需求获取不同的属性信息进行处理。
1. 在编译翻译各阶段不断的收集和加工符号属性;
2. 为语义分析阶段的合法性检查提供数据支持( 比如变量可见性、类型匹配与否);
3. 作为目标代码生成阶段地址分配的依据( 无论是静态链接还是动态链接,符号表提供的标识符空间位置都是很重要的依据)
关于第三点的地址分配依据需要额外说明:以前说过,对于常量以及全局变量,以及局部静态变量都是存在在.data段的,而其他局部变量则是出现的在临时栈上的。故而符号位置属性的首要任务便是确定该符号应该分配的区域,例如,在C语言中首先要确定该符号变量是分配在公共区(extern)、文件静态区(extern static)、函数静态区(函数中static)、还是函数运行时的动态区(auto)等。其次是根据变量出现的次序,决定该变量在某个区中所处的具体位置,这通常使用在该区域中相对区头的相对位置确定。而有关区域的标志及相对位置都是作为该变量的语义信息被收集在该变量的符号表属性中。
符号的属性有很多,下面给出常见的符号属性
关于上述重要的符号属性的说明如下
数据类型有语言默认的基本数据类型,如果是符合数据类型如数组、结构体等,显然还需要设置额外的扩展成分,来存放复合类型的完整的类型属性。
(1) 数组内情向量:数组是一种重要的数据类型。编译程序处理数组说明的主要工作是,把描述数组属性信息的内情向量登录到符号表中。内情向量包括数组类型,维数,各维的上、下界及数组首地址,这些属性信息是确定存储分配时数组所占空间的大小和数组元素位置的依据。
(2) 记录结构型的成员信息: 一个记录结构型的变量,在存储分配时所占空间大小要由它的全体组成成员来确定,另外对于记录结构型变量还需要有它所属成员排列次序的属性信息。这二种信息用来确定结构型变量存储分配时所占空间的尺寸及确定该结构成员的位置。
(3) 函数及过程的形参: 函数和过程的形参作为该函数或过程的局部变量,但它又是该函数或过程对外的接口。每个函数或过程的形参个数、形参的排列次序及每个形参的类型,都体现了调用该函数或过程时的属性,它们都应该反映在符号表的函数或过程标识符的项中。有关函数及过程的形参属性信息用来作调用过程的匹配处理和语义检查。
根据符号变量的存储类别定义及它们出现的位置和次序来确定每一个变量应分配的存储区及在该区中的具体位置,用相对区头的位移量表示。通常一个编译程序有两类存储区,即静态存储区和动态存储区;
(1) 静态存储区
该存储区单元经定义分配后成为静态单元,即在整个语言程序运行过程中是不可改变的。作静态分配的符号变量是具有整个程序运行过程的生命周期。因此编译程序可以设置一个固定的空间作为静态存储区。但由于不同的静态变量具有不同的可视性,编译程序也可以设置几个不同的固定空间作为静态区。根据变量存储类别及作用域规则,这类静态存储区通常又可分为公共静态区(全局)和若干个局部静态区(为不同层次的程序结构,如文件、函数、段)。
编译程序为局部静态量可设立若干个局部静态区。对外部静态量,为每个程序文件建立一个局部静态区,对内部静态量,则为每个具有内部静态量定义的函数或过程,建立一个局部静态区。在C语言中被Static所定义的符号变量具有的生命周期也是该程序运行的全过程。但被Static定义的变量若在函数之外则为所在之文件中所有函数可视。而若变量在函数内被定义为Static,则它仅为所在函数可视。
(2) 动态存储区
根据变量的局部定义和分程序结构,编译程序设置动态存储区来适应这些局部变量的生存和消亡。局部动态变量的生存期是定义该变量的局部范围,即在该定义范围之外此变量已经没存在的必要。及时撤销时这些单元的分配可以回收,从而提高程序运行时的空间效率。
对变量存储分配的属性除了存储类别之外还要确定其在所在存储区的具体位置的属性信息。通常在符号表中存放具体位置的信息是按该变量的存储区类分别依出现先后的次序(扫描源程序的次序)排列下相对该存储区表头的相对位移量来表示的。
int a; // 外部定义的整型变量a
…
float b; // 外部定义的实型变量b
…
struct cc{
int d; // 外部定义的结构类型cc, cc的第一个结构分量d
float e; // cc的第二个结构分量t
…
}c; // 外部定义的结构型变量c
…
/* *其中a,b,c是三个外部量,d,e是结构分量,在符号表中,对于外部量a,b,c依次相对公共静态区头的相对位置分别是0,4,8。 *1.这儿虽然a是整形量只需要2个字节,但因为b是实形量,它本身需要4个字节, *2.b作为float型变量,它存在地址对齐的需求,b的地址也必须是4的倍数的字节号。 *3.对于c来说它是一个结构变量,其中占最大字节数的结构分量是e,需要4个字节, *因此c必须亦是依4的倍数的字节号作为它的地址(根据存储器所遵循的Alignment规则)。 */
//至于d和e是cc的结构分量,其位置的主属性由结构c来决定,但是d,e的相对位移量分别是0,4。
//这儿cc是一个结构标记,作为标识符它要登入到符号表中,但它只是一个类型标识符,因此没有地址分配的问题。