编译原理 第六章 符号表组织
Q : 本章内容是什么 ?
是语义分析的一个部分 , 即符号表相关内容.
6.1 符号表的地位和作用
符号表是标识符的词典 , 用于记录名字 , 类型 , 种类 , 地址四类信息
6.2 符号表的组织和管理
6.2.1 符号表的工作原理
遇到定义性标识符 , 用token指针将语义信息填入表中
遇到应用性标识符 , token指针查符号表的相应项
6.2.2 符号表的查询 , 访问方式
线性表 , 顺序表 , 索引表 , 散列表等
6.2.3 符号表的维护 , 管理方式
每个函数对应一个符号表 , 还有一个公共符号表
6.3 符号表的结构设计
我们首先有一个token串 , 每个token串的唯一标识可以指向符号表的某个项
符号表(SYNBL)有四列 , 分别为NAME , TYPE , CAT , ADDR
其中第一列指向类型表(TYPEL) , 类型表中有两列 , 为TVAL和TPOINT
TVAL记录类型 , TPOINT是指针 , 指向数组表或结构表
而SYNBL中的ADDR指向常量表(CONSL) , 函数表(PFINFL),长度表(LENL),VALL表(活动记录)
6.3.1 符号总表(SYNBL)
Q : 符号表总表的结构是什么 ?
四列 , 为NAME名字 , TYP类型指针 , CAT种类 , ADDR地址
NAME即标识符源码/内部码
TYP为指针 , 指向类型表
CAT为种类 , 分为f(函数) , c(常量) , t(类型) , d(域名)
和v(变量) , 其中vn为换名形参, 相当于(int) , vf为赋值形参 (int &)
ADDR为地址指针 , 根据种类不同 , 分别指向PFINFL(函数表) , CONSL(常量表) , LENL(长度表) , VALL(活动记录)
Q : 赋值形参和换名形参区别 ?
vn不允许修改值 , vf运行修改值
6.3.2 类型表(TAPEL)
类型表的结构是什么 ?
TVAL + TPOINT
TVAL为类型代码 :
\(i \rightarrow\) 整型
\(r \rightarrow\) 实型
\(c \rightarrow\) 字符型
\(b \rightarrow\) 布尔型
\(a \rightarrow\) 数组型
\(d \rightarrow\) 结构型
TPOINT指针 , 根据TVAL不同 , 指向不同地方
- 对$i,r,c,b $ , 指向\(null\)
- 对\(a\) , 指向数组表;
- 对\(d\) , 指向结构表
6.3.3 数组表(AINFL)
Q : 数组表的结构是什么 ?
四列 : LOW ,UP ,CTP ,CLEN
LOW为数组下界
UP为数组上界
CTP , 成分类型指针 , 指向该维数组 成分类型
CLEN , 成分类型的长度 , 即成分类型的数据所占值单元的个数
这里假定值单元个数按照字节为单位计算
6.3.4 结构表(RINF)
Q : 结构表的结构是什么 ?
三列 , ID , OFF , TP
ID为结构的域名
OFF为区距 , 是ID的值单元首址相对于所在记录值区区头位置
TP为域成分类型指针 , 指向\(ID_k\)域成分类型(在类型表中的信息)
6.3.5 函数表(PFINFL)
Q : 函数表的结构是什么 ?
分为五列 , 为LEVEL , OFF , FN , ENTRY , PARAM
LEVEL : 层次号 , 该过函静态层次嵌套号
OFF : 区距 , 该过函自身数据区起始单元相对该过函值区区头位置 , 一般是\(3\)
FN : 参数个数
PARAM : 参数表 , 指针 , 指向形参表
ENTRY : 该函数目标程序首地址 , 在运行时填写
6.3.6 其他表
Q : 常量表CONSL的结构是什么 ?
存放对应常量的初值 , 只有一列 , 就是值
Q : 长度表LENL的结构是什么 ?
一列 , 存放相应数据类型所占值单元的个数
Q : 活动记录表VALL是什么 ?
它是一个过函虚拟的值单元运行存储分配表 , 是过函所定义的数据在运行时刻的内存存储映像
需要注意 , 过函是没有类型的
6.4 运行时刻存储分配
6.4.1 标识符值单元分配
- 静态分配
在编译阶段即可完成真实的地址分配 , 对所有数据对象分配固定的存储单元 , 运行时始终不变 - 动态分配
在运行时刻进行的值单元分配 , 在编译时只能进行相对地址分配
有栈式动态分配和堆式动态分配
6.4.2 活动记录
Q : 什么是过程 , 活动 , 活动记录 ?
过程即可执行模块, 函数 , 过程 , 用于完成特定功能
活动即过函的一次执行 , 每执行一次过函 , 则产生该过函的一个活动
活动记录 : 一个有结构的连续存储块 , 用来存储过函一次执行中所需要的信息
Q : 活动记录的结构 ?
4部分 , 连接数据区 , 形式单元 , 局部数据区 , 栈指针
连接数据区有返回地址 , 动态链 , 静态链
形式单元是用来存放实参的值或地址
局部数据区用来存放局部变量 , 内情向量 , 临时单元
栈指针有SP和TOP , SP指向现行过程活动记录的起点 , 即第一个单元
TOP指向栈顶单元(栈顶已占用) , 即活动记录的最后一个单元
Q : 什么是动态链和静态链 ?
动态链是一个指针 , 根据它能找到调用自己的程序的活动记录
静态链是一个指针 , 指向静态直接外层活动记录
6.4.3 简单的栈式存储分配
比如说调用关系为 : \(main \solve Q \rightarrow qpow\)
那么栈从下到上为main的活动记录 , solve的 , qpow的
Q : 函数调用和返回时 , 四元式如何执行 ?
-
调用的四元式 :
\((param , entry(t_1),_,_)\)
.......
\((call,entry(P),n,_)\)
其中\(entry(t_i)\)为\(t_i\)的地址
\(entry(P)\)为函数\(P\)的入口地址 , \(n\)为参数个数 -
四元式的执行 :
对\((param,entry(t_i),_,_)\) , 执行\([i+3][TOP] = entry(t_i).Addr\)
对\((call,,entry(P),n,_)\) , 执行\(1[TOP] = SP\)
\(3[TOP] = n\)
\(JSP P\)
-
函数\(P\)的工作 :
\(SP = TOP + 1\)
\(1[SP] = 返回地址\)
\(TOP = TOP + L\) -
过程返回的四元式 :
\((ret,_,_,_)\)
指令为 :
\(TOP = SP - 1\)
\(SP = 0[SP]\)
\(X = 2[TOP]\)
这个\(x\)为返回地址
\(UJ 0[X]\)
6.4.4 嵌套过程语言的栈式存储分配
Q : 标识符的范围服从什么 ?
最小作用域原理
Q : 函数Q可能会引用任意外层过程的某些数据 , 怎么解决 ?
在活动记录中增加静态链 , 指向直接外层的最新活动记录的首地址
Q : 如何建立Display表 ?
当前的全局display(SP+3)指向调用者的Display表
当前显示区表从上层拷贝\(l\)个单元 , \(l\)为层次号 , 以及自身的SP
注意最外层为\(0\)层
本章内容需要写题才行 , 熟悉填表方式

浙公网安备 33010602011771号