编译原理-中间代码的生成

一、中间代码简介

  1. 中间代码应具备的特性:
    1)便于语法制导翻译
    2)既与机器指令的结构相近,又与具体机器无关

  2. 使用中间代码的好处:
    1)一是便于编译器程序的开发和移植
    2)二是代码进行优化处理

  3. 中间代码的主要形式:后缀式、树、三地址码

最基本的中间代码形式是树;
最常用的中间代码形式是三地址码,它的实现形式常采用四元式形式

符号表是帮助声明语句实现存储空间分配的重要数据结构


1.1 后缀式

操作数在前,操作符紧随其后,无需用括号限制运算的优先级和结合性;便于求值

1.2 三地址码

① 三元式 形式: (i) (op, arg1, arg2)

三地址码:(i):= arg1 op arg2

序号的双重含义:既代表此三元式,又代表三元式存放的结果

存放方式:数组结构,三元式在数组中的位置由下标决定

弱点:给代码的优化带来困难

② 四元式 形式: ( i ) (op,arg1,arg2,result)

所表示的计算: result:= arg1 op arg2

四元式与三元式的唯一区别:将由序号所表示的运算结果改为:用(临时)变量来表示。

此改变使得四元式的运算结果与其在四元式序列中的位置无关.为代码的优化提供了极大方便,因为这样可以删除或移动四元式而不会影响运算结果.

③ 树形表示

1> 语法树真实反映句子结构,对语法树稍加修改(加入语义信息),即可以作为中间代码的一种形式(注释语法树)
2> 树的优化表示-DAG
3> 树与其他中间代码的关系

表示的中间代码与后缀式和三地址码之间有内在联系

  1. 树 → 后缀式
    ​方法:对树进行深度优先后序遍历,得到的线性序列就是后缀式,或者说后缀式是树的一个线性化序列;
  2. 树 → 三元式/四元式
    特点:树的每个非叶子节点和它的儿子对应一个三元式或四元式;
    方法:对树的非叶子节点进行深度优先后序遍历,即得到一个三元式或四元式序列。

二、符号表简介

  • 符号表的作用:连接声明与引用的桥梁,记住每个符号的相关信息,如作用域和类型等,帮助编译的各个阶段正确有效地工作。
  • 符号表的基本目标:有效记录信息、快速准确查找。
  • 符号表设计的基本要求:
    • 正确存储各类信息;
    • 适应不同阶段的需求;
    • 便于有效地进行查找、插入、删除和修改等操作;
    • 空间可以动态扩充.

(1)构成名字的字符串

构成名字的字符串的存储方式:直接存储—定长数据(直接将构成名字的字符串放在符号表条目中)和间接存储—变长数据(将构成名字的字符串统一存放在一个大的连续空间内,字符串与字符串之间采用特殊的分隔符隔开,符号表条目中仅存放指向该字符串首字符的指针).

(2)名字的作用域

☆ 程序语言范围的划分可以有两种划分范围的方式:并列和嵌套

☆ 名字的作用域规则:规定一个名字在什么样的范围内应该表示什么意义

<1> 静态作用域规则(static-scope rule):编译时就可以确定名字的作用域,即仅从静态读程序就可确定名字的作用域
<2> 最近嵌套规则(most closely nested):名字的声明在离其最近的内层起作用

(3)线性表

符号表以(线性表)的方式组织.

线性表上的操作:查找、插入、删除、修改

查找:从表头(栈顶)开始,遇到的第一个符合条件的名字;插入:先查找,再加入在表头(栈顶);

关键字 = 名字+作用域;

(4)散列表

名字挂在两个链上(便于删除操作):
操作:查找、插入、删除

散列链(hash link): 链接所有具有相同hash值的元素,表头在表头数组中;

作用域链(scope link):链接所有在同一作用域中的元素,表头在作用域表中.


三、声明语句的翻译

(1)变量的声明

一个变量的声明应该由两部分来完成:类型的定义变量的声明

  • 类型定义:为编译器提供存储空间大小的信息
  • 变量声明:为变量分配存储空间
  • 组合数据的类型定义和变量声明:定义与声明在一起,定义与声明分离.
1> 简单数据类型的存储空间是预先确定的,如int可以占4个字节,double可以占8个字节,char可以占1个字节等
2> 组合数据类型变量的存储空间,需要编译器根据程序员提供的信息计算而定.

(2) 过程

1.过程(procedure):过程头(做什么) +  过程体(怎么做)- 函数:  有返回值的过程
   - 主程序:  被操作系统调用的过程/函数

2.过程的三种形式:过程定义、过程声明和过程调用。
   过程定义:过程头+过程体;
   过程声明:过程头;

3. 左值与右值 
   1> 直观上,出现在赋值号左边和右边的量分别称为左值和右值;
   2> 实质上,左值必须具有存储空间,右值可以仅是一个值,而没有存储空间.
   3> 形象地讲,左值是容器,右值是内容.
   
4. 参数传递
   1> 形参与实参
        - 声明时的参数称为形参(parameter或formal parameter)
        - 引用时的参数称为实参(argument或actual parameter)
   2> 常见的参数传递形式:(不同的语言提供不同的形式)
        - 值调用(call by value)---过程内部对参数的修改,不影响作为实参的变量原来的值.
        - 引用调用(call by reference)--- 过程内部对形参的修改,实质上是对实参的修改.
        - 复写-恢复(copy-in/copy-out)--- ① 过程内对参数的修改不直接影响实参,避免了副作用;
                                          ② 返回时将形参内容恢复给实参,实现参数值的返回.
        - 换名调用(call by name)--- 宏调换
   3> 参数传递方法的本质区别: 实参是代表左值、右值、还是实参本身的正文.
   
5. 作用域信息的保存
☆ 能够画出嵌套过程的嵌套关系树,根据语法制导翻译画出分析树,写出推导步骤,构造的符号表

四、简单算术表达式与赋值句

主要是变量类型的转换


五、数组元素的引用

(1)数组元素的地址计算:注意是行主存储还是列主存储
(2)数组元素引用的语法制导翻译


六、布尔表达式

布尔表达式的计算有两种方法:数值表示的直接计算和逻辑表示的短路计算


七、控制语句

控制语句的分类:①无条件转移、②条件转移、③循环语句、④分支语句


参考文章:编译原理知识汇总

你可能感兴趣的:(关于考研,编译原理)