正在加载图片...
版权所有南京大学计算机科学与技术系许畅等2022春季版 4.2 实验指导 编译器里最核心的数据结构之一就是中间代码(Intermediate Representation或IR)。 中间代码应包含哪些信息,这些信息又应有怎样的内部表示?这些问题会极大地影响编译器代 码的复杂程度、编译器的运行效率、以及编译生成的目标代码的运行效率。 广义地说,编译器中根据输入程序所构造出来的绝大多数数据结构都被称为中间代码(或 可更精确地译为“中间表示”)。例如,我们之前所构造的词法流、语法树、带属性的语法树 等,都可视为中间代码。使用中间代码的主要原因是为了方便编写编译器程序的各种操作。如 果我们在需要有关输入程序的任何信息时都只能去重新读入并处理输入程序源代码的话,编译 器的编写将会变得非常麻烦,同时也会大大降低其运行效率。 狭义地说,中间代码是编译器从源语言到目标语言之间采用的一种过渡性质的代码形式 (这时它常被称作Intermediate Code)。你可能会有疑问:为什么编译器不能把输入程序直 接翻译成目标代码,而是要额外引入中间代码呢?实际上,引入中间代码有两个主要的好处。 一方面,中间代码将编译器自然地分为前端和后端两个部分。当我们需要改变编译器的源语言 或目标语言时,如果采用了中间代码,我们只需要替换原编译器的前端或后端,而不需要重写 整个编译器。另一方面,即使源语言和目标语言是固定的,采用中间代码也有利于编译器的模 块化。人们将编译器设计中那些复杂但相关性不大的任务分别放在前端和后端的各个模块中, 这既简化了模块内部的处理,又使我们能单独对每个模块进行调试与修改而不影响其它模块。 下文中,如果不特别说明,“中间代码”都是指狭义的中间代码。 4.2.1中间代码的分类 中间代码的设计可以说更多的是一门艺术而不是技术。不同编译器所使用的中间代码可能 是千差万别的,即使是同一编译器内部也可以使用多种不同的中间代码:有的中间代码与源语 言更接近,有的中间代码与目标语言更接近。编译器需要在不同的中间代码之间进行转换,有 时为了处理的方便,甚至会在将中间代码1转换为中间代码2之后,对中间代码2进行优化然后 又转换回中间代码1。这些不同的中间代码虽然对应了同一输入程序,但它们却体现了输入程 序不同层次上的细节信息。举个实际的例子:GCC内部首先会将输入程序转换成一棵抽象语 法树,然后将该树转换为另一种被称为GIMPLE的树形结构。在GIMPLE之上它建立静态单赋 值式的中间代码之后,又会将其转换为一种非常底层的RTL(Register Transfer Language) 代码,最后才把RTL转换为汇编代码。 79版权所有 南京大学计算机科学与技术系 许畅等 2022春季版 79 4.2 实验指导 编译器里最核心的数据结构之一就是中间代码(Intermediate Representation或IR)。 中间代码应包含哪些信息,这些信息又应有怎样的内部表示?这些问题会极大地影响编译器代 码的复杂程度、编译器的运行效率、以及编译生成的目标代码的运行效率。 广义地说,编译器中根据输入程序所构造出来的绝大多数数据结构都被称为中间代码(或 可更精确地译为“中间表示”)。例如,我们之前所构造的词法流、语法树、带属性的语法树 等,都可视为中间代码。使用中间代码的主要原因是为了方便编写编译器程序的各种操作。如 果我们在需要有关输入程序的任何信息时都只能去重新读入并处理输入程序源代码的话,编译 器的编写将会变得非常麻烦,同时也会大大降低其运行效率。 狭义地说,中间代码是编译器从源语言到目标语言之间采用的一种过渡性质的代码形式 (这时它常被称作Intermediate Code)。你可能会有疑问:为什么编译器不能把输入程序直 接翻译成目标代码,而是要额外引入中间代码呢?实际上,引入中间代码有两个主要的好处。 一方面,中间代码将编译器自然地分为前端和后端两个部分。当我们需要改变编译器的源语言 或目标语言时,如果采用了中间代码,我们只需要替换原编译器的前端或后端,而不需要重写 整个编译器。另一方面,即使源语言和目标语言是固定的,采用中间代码也有利于编译器的模 块化。人们将编译器设计中那些复杂但相关性不大的任务分别放在前端和后端的各个模块中, 这既简化了模块内部的处理,又使我们能单独对每个模块进行调试与修改而不影响其它模块。 下文中,如果不特别说明,“中间代码”都是指狭义的中间代码。 4.2.1 中间代码的分类 中间代码的设计可以说更多的是一门艺术而不是技术。不同编译器所使用的中间代码可能 是千差万别的,即使是同一编译器内部也可以使用多种不同的中间代码:有的中间代码与源语 言更接近,有的中间代码与目标语言更接近。编译器需要在不同的中间代码之间进行转换,有 时为了处理的方便,甚至会在将中间代码1转换为中间代码2之后,对中间代码2进行优化然后 又转换回中间代码1。这些不同的中间代码虽然对应了同一输入程序,但它们却体现了输入程 序不同层次上的细节信息。举个实际的例子:GCC内部首先会将输入程序转换成一棵抽象语 法树,然后将该树转换为另一种被称为GIMPLE的树形结构。在GIMPLE之上它建立静态单赋 值式的中间代码之后,又会将其转换为一种非常底层的RTL(Register Transfer Language) 代码,最后才把RTL转换为汇编代码
<<向上翻页向下翻页>>
©2008-现在 cucdc.com 高等教育资讯网 版权所有