编译原理 第六章 符号表组织

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不同 , 指向不同地方

  1. 对$i,r,c,b $ , 指向\(null\)
  2. \(a\) , 指向数组表;
  3. \(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 标识符值单元分配

  1. 静态分配
    在编译阶段即可完成真实的地址分配 , 对所有数据对象分配固定的存储单元 , 运行时始终不变
  2. 动态分配
    在运行时刻进行的值单元分配 , 在编译时只能进行相对地址分配
    栈式动态分配堆式动态分配

6.4.2 活动记录

Q : 什么是过程 , 活动 , 活动记录 ?

过程即可执行模块, 函数 , 过程 , 用于完成特定功能
活动即过函的一次执行 , 每执行一次过函 , 则产生该过函的一个活动
活动记录 : 一个有结构的连续存储块 , 用来存储过函一次执行中所需要的信息

Q : 活动记录的结构 ?

4部分 , 连接数据区 , 形式单元 , 局部数据区 , 栈指针
连接数据区有返回地址 , 动态链 , 静态链

形式单元是用来存放实参的值或地址

局部数据区用来存放局部变量 , 内情向量 , 临时单元

栈指针有SP和TOP , SP指向现行过程活动记录的起点 , 即第一个单元
TOP指向栈顶单元(栈顶已占用) , 即活动记录的最后一个单元

Q : 什么是动态链和静态链 ?

动态链是一个指针 , 根据它能找到调用自己的程序的活动记录
静态链是一个指针 , 指向静态直接外层活动记录

6.4.3 简单的栈式存储分配

比如说调用关系为 : \(main \solve Q \rightarrow qpow\)
那么栈从下到上为main的活动记录 , solve的 , qpow的

Q : 函数调用和返回时 , 四元式如何执行 ?

  1. 调用的四元式 :
    \((param , entry(t_1),_,_)\)
    .......
    \((call,entry(P),n,_)\)
    其中\(entry(t_i)\)\(t_i\)的地址
    \(entry(P)\)为函数\(P\)的入口地址 , \(n\)为参数个数

  2. 四元式的执行 :
    \((param,entry(t_i),_,_)\) , 执行\([i+3][TOP] = entry(t_i).Addr\)

\((call,,entry(P),n,_)\) , 执行\(1[TOP] = SP\)
\(3[TOP] = n\)
\(JSP P\)

  1. 函数\(P\)的工作 :
    \(SP = TOP + 1\)
    \(1[SP] = 返回地址\)
    \(TOP = TOP + L\)

  2. 过程返回的四元式 :
    \((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\)

本章内容需要写题才行 , 熟悉填表方式

posted @ 2025-05-02 11:21  Guaninf  阅读(107)  评论(0)    收藏  举报