1、编译原理,第8章 符号表,目录,8.1 符号表的作用和地位 8.2 符号的主要属性及作用 8.3 符号表的组织 8.4 符号表的管理,在编译程序中符号表用来存放语言程序中出现的有关标识符的属性信息,符号表中所登记的信息在编译的不同阶段都要用到。,8.1符号表的作用和地位(1),1、收集符号属性。根据说明语句收集有关标识符的类型属性。 例如,编译程序分析到下述两个说明语句 int A; float B5;,8.1符号表的作用和地位(2),2、上下文语义的合法性检查的依据。如对标识符属性在上下文中的一致性和合法性检查。 例如,在一个C语言程序中出现 int i 3,5; /定义整型数组i floa
2、t i4,2; /定义实型数组i,重定义冲突 int i 3,5; /定义整型数组i,重定义冲突,3、目标代码生成阶段地址分配的依据。 通过存储类别确定分配的区域. 例如,在C语言中首先要确定该符号变量是分配在公共区(extern)、文件静态区(extern static)、函数静态区(函数中static)、还是函数运行时的动态区(auto)等。 根据变量出现的次序决定变量在某个区域中的具体位置。这通常使用在该区域中相对区头的相对位置确定,8.1符号表的作用和地位(3),符号表的构成,一张符号表的每一项(或称入口)包含两大栏(或称区段、字域),即名字栏和信息栏。表的格式: 名字栏(NAME)
3、信息栏(INFORMATION) 第1项(入口1) 第2项(入口2)第n项(入口n) 信息栏包含许多子栏和标志位,用来记录相应名字和种种不同属性; 由于查填符号表一般是通过匹配名字来实现的,因此,名字栏也称主栏。主栏的内容称为关键字(key word)。,符号表的操作,在整个编译期间,对于符号表的操作大致可归纳为五类: 对给定名字,查询名字是否已在表中; 往表中填入一个新的名字; 对给定名字,访问它的某些信息; 对给定名字,填写或更新它的某些信息; 删除一个或一组无用的项。 不同种类的表格所涉及的操作往往也是不同的。上述五个方面只是一些基本的共同操作。,8.2 符号的主要属性(信息)及作用,几
4、种通常都是需要的属性。 1 符号名 作为标识符在表中唯一区别,一般不允许重名。 对于重载可以通过参数类型、个数和返回值类型来区分。 通常把一个标识符在符号表中的位置的整数值称之该标识符的内部代码。,2 类型 标识符中除过程标识符之外函数和变量标识符都具有数据类型(data type)属性。 变量符号的类型属性决定了该变量的数据在存储空间的存储格式,还决定了在该变量上可以施加的运算操作。 定义一个标识符的基本类型或它的组合类型都是符号表中表示标识符属性的重要信息。,3 存储类别 变量存储类别的两种定义方式: 用关键字指定;如static,regist 根据定义变量说明在程序中的位置来决定;如全局
5、,局部 区分符号存储类别属性是编译过程语义处理、检查和存储分配的重要依据。 变量存储类别还决定了变量的作用域、可视性和它的生命期等问题。,4 作用域及可视性 一个符号变量在程序中起作用的范围,称谓它的作用域。一般来说,定义该符号的位置及存储类关键字决定了该符号的作用域。 在变量的作用域中该变量是可以引用的,这就是变量可视性 的作用域规则。 一般来说一个变量的作用域就是该变量可以出现的场合,也就是说在某个变量作用域范围内该变量是可引用的,这就是变量可视性的作用域规则。,除了作用域外,以下两种情况也要影响一个变量的可视性 : 函数的形式参数:影响变量可视性的举例 int a; / 外部定义的整型变
6、量a int func(a,b) float a; / 函数内部定义的局部整型变量a, 屏闭了外部定义的整型变量a int b; a / 引用的是函数内部定义(此处是形参)的局部整型变量a ,分程序结构:影响变量可视性的举例 int a; / 第一层头,定义的局部整型变量a char a; / 第二层头,定义的局部字符型变量a / 第三层头 float a; / 第四层头,定义的局部实型变量a / 第四层尾 a / 引用第二层定义的局部字符型变量a / 第三层尾 / 第二层尾 / 第一层尾,5 存储分配信息 根据存储类别及它们出现的位置和次序来确定每个变量的具体位置。 有静态存储区和动态存储区
7、。 静态存储区:该存储区单元经定义分配后成为静态单元,即在整个语言程序运行过程中是不可改变的。作静态分配的符号变量是具有整个程序运行过程的生命周期。 动态存储区:根据变量的局部定义和分程序结构,编译程序设置动态存储区来适应这些局部变量的生存和消亡。,6 其它属性 数组内情向量 : 内情向量包括数组类型,维数,各维的上、下界及数组首地址; 确定存储分配时数组所占空间的大小和数组元素位置的依据。 记录结构型的成员信息 : 一个记录所占空间大小要由它的全体组成成员来确定; 需要有它所属成员排列次序的属性信息; 这二种信息用来确定结构型变量存储分配时所占空间的尺寸及确定该结构成员的位置。 函数及过程的
8、形参: 函数和过程的形参作为该函数或过程的局部变量; 每个函数或过程的形参个数、形参的排列次序及每个形参的类型,都体现了调用该函数或过程时的属性;,8.3 符号表的组织,一、总体组织 1: 把属性种类完全相同的那些符号组织在一起,构造出表项是分别为等长的多个符号表 。 优点:每个符号表的属性个数和结构完全相同。空间效率高。 缺点:同时管理若干个不同的符号表,增加了总体管理的工作量和复杂性。,总体组织和表项属性信息组织,2、 把语言中的所有符号都组织在一张符号表中。组成一张包括了所有属性的庞大的符号表 。 优点:整体管理集中,单一,管理一致。 缺点:增加了空间开销。,3、折衷方式是根据符号属性相
9、似程度分类组织成若干张表,每张表中记录的符号都有比较多的相同属性。 在管理复杂性和空间效率方面都取得折中的效果。,符号表组织举例,一种组织方法得到三张符号表,第二种组织方法得到一张符号表:,折衷方式组织的符号表,属性复合组织的符号表,二、符号表项的排列,符号表作为一个多元组,表中元组的排列组织是构造符号表的重要成分。 在编译程序的整个工作过程中,符号表被频繁地用来建立表项,找查表项,填充和引用表项的属性。 表项的排列组织对该系统运行的效率起着十分重要的作用。 在编译程序中,符号表项的组织传统上采用三种构造方法。即线性法,二分法及散列法。,三、关键字域的组织,符号表的关键字域(段)就是符号名称
10、可以是保留字,操作符或标识符。可以用以下两种方法组织 等长关键字域(段)符号表 :保证关键字段的等长,但实际上有很多冗余 不等长关键字段符号表-采用关键字池的索引结构。,等长关键字段符号表,关键字池组织的符号表,8.4 符号表的管理,符号表所起的作用反映了符号表的行为特征,符号表的行为通常主要是符号表的初始化、符号的登录、符号的查找和有关分程序结构的符号表层次管理。对符号表的这些管理除初始化之外,都是动态进行的。,一、 符号表的初始化,符号表的初始化,就是在对语言程序开始编译的时刻,定义建立符号表的初始状态。 符号表的不同组织方法,要求不同的初始化方法。两种情况 符号表的表长是渐增变化的情况:
11、线性组织和二分法组织的符号表符号表的表长是确定的情况:散列组织的符号表,二、符号的登录,编译程序从语言程序中获得一个标识符符号并确定该符号在符号表中尚不存在时,就要将此符号登录到符号表中。 登录符号到符号表中,首先要确定登录的位置,组织不同时,登陆位置的确定方法不同; 一个符号表项的登录最基本的是该符号的名字登录。除此之外还有关于该名字的属性的登录。,三、符号的查找,每当编译程序从语言源程序获得一个符号,首先要确定该符号的类别。根据类别分别在相应的符号表中进行查找。 查找符号表的目的是建立或确认该符号的语义属性。 符号表的查找算法,与该符号表的组织方法密切相关。,四、分程序结构的符号表,对于具
12、有分程序型结构的语言程序,不同层次分程序中定义的标识符号具有不同的作用域和不同的可视性规则。 通常对于具有分程序结构的语言可用两种方式组织它们的符号表: 一是对每个分程序建立一个独立的分表结构的符号表; 一是把各分程序符号组织在一张单表结构的符号表中,1、分表结构的组织管理,其基本思想是,每当编译程序扫描到一个分程序结构开始时,为该分程序建立一张符号表,在该分程序中定义的标识符,都被登录在该符号表中。而当编译程序扫描到一个分程序的结束时,编译程序释放为该分程序所建立的符号表。 这种符号表的分表结构与源程序的分程序层次结构一一对应 。,2、单表结构的组织管理,其基本思想是,所有分程序中定义的标识
13、符都集中在单张符号表中。 为了实现分程序构造中标识符的作用域和可视性规则的要求,在符号表中可设立一个属性域用来登录符号所在分程序的层次。 进入分程序时,层次要增加一层.在退出一个分程序时,层次降低一层,且需要把符号表中,所有在退出的分程序中登录的符号项清除。,分程序结构的程序示例,源程序的形式 /第一层分程序 int a; float b,d; /第二层分程序 int c; float a; /第三层分程序 int d; float c; /第四层分程序 float d; a=b+c+d; ,进入分程序第四层时的符号 表层次属性表达,进入分程序第一层时的符号表层次属性表达,例程序说明部分为: CONST A=35,B=49; VAR C,D,E; PROCEDURE P; VAR G ;,举例,名字 类型 层次/值 地址 存储空间,Const(常量),对应名字表,