??xml version="1.0" encoding="utf-8" standalone="yes"?>
一个现代编译器的主要工作流E如下:
源程序(source codeQ?#8594;预处理器Q?/span>preprocessorQ?#8594;~译器(compilerQ?#8594;汇编E序Q?/span>assemblerQ?#8594;目标E序Q?/span>object codeQ?#8594;q接器(链接器,LinkerQ?#8594;可执行程序(executablesQ?/span>
工作原理
?
译是从源代码Q通常为高U语aQ到能直接被计算机或虚拟机执行的目标代码Q通常ZU语a或机器言Q。然而,也存在从低语言到高U语a的编译器Q这cȝ
译器中用来从由高U语a生成的低U语a代码重新生成高语言代码的又被叫做反~译器。也有从一U高U语a生成另一U高U语a的编译器Q或者生成一U需要进
一步处理的的中间代码的~译器(又叫U联Q?/span>
典型的编译器输出是由包含入口点的名字和地址以及外部调用的机器代码所l成的目标文件。一l目标文Ӟ不必是同一~译器生,但用的~译器必需采用同样的输出格式,可以链接在一起ƈ生成可以qL接执行的可执行程序?/span>
~译器种c?/span>
~?
译器可以生成用来在与~译器本w所在的计算机和操作pȝQ^収ͼ相同的环境下q行的目标代码,q种~译器又叫做“本地”~译器。另外,~译器也可以生成?
来在其它q_上运行的目标代码Q这U编译器又叫做交叉编译器。交叉编译器在生成新的硬件^台时非常有用?#8220;源码到源码编译器”是指用一U高U语a作ؓ?
入,输出也是高语言的编译器。例?/span>: 自动q行化编译器l常采用一U高U语a作ؓ输入Q{换其中的代码Qƈ用ƈ行代码注释对它进行注释(?/span>OpenMPQ或者用语言构造进行注释(?/span>FORTRAN?/span>DOALL指oQ?/span>
预处理器Q?/span>preprocessorQ?/span>
作用是通过代入预定义等E序D将源程序补充完整?/span>
~译器前端(frontendQ?/span>
前端主要负责解析Q?/span>parseQ输入的源程序,p法分析器和语法分析器协同工作。词法分析器负责把源E序中的‘单词’Q?/span>TokenQ找出来,语法分析器把q些分散的单词按预先定义好的语法l装成有意义的表辑ּQ语?/span>Q函数等{?/span>例如“a = b + c;”前端词法分析器看到的?#8220;a, =, b , +, c;”Q语法分析器按定义的语法Q先把他们组装成表达?#8220;b + c”Q再l装?#8220;a = b + c”的语句?/span>前端q负责语义(semantic checkingQ的查,例如参与运的变量是否是同一cd的,单的错误处理。最l的l果常常是一个抽象的语法树(abstract syntax treeQ或 ASTQ,q样后端可以在此基础上进一步优化,处理?/span>
~译器后端(backendQ?/span>
~译器后端主要负责分析,优化中间代码Q?/span>Intermediate representationQ以及生成机器代码(Code GenerationQ?/span>
一般说来所有的~译器分析,优化Q变型都可以分成两大c:函数内(intraproceduralQ还是函C_interproceduralQ进行。很明显Q函数间的分析,优化更准,但需要更长的旉来完成?/span>
~译器分析(compiler analysisQ的对象是前端生成ƈ传递过来的中间代码Q现代的优化型编译器Q?/span>optimizing compilerQ常常用好几U层ơ的中间代码来表C程序,高层的中间代码(high level IRQ接q输入的源程序的格式Q与输入语言相关Q?/span>language dependentQ,包含更多的全局性的信息Q和源程序的l构Q中层的中间代码Q?/span>middle level IRQ与输入语言无关Q低层的中间代码(Low level IR)与机器语acM?/span>不同的分析,优化发生在最适合的那一层中间代码上?/span>
常见的编译分析有函数调用树(call treeQ,控制程图(Control flow graphQ,以及在此基础上的变量定义Q用,使用Q定义链Q?/span>define-use/use-define or u-d/d-u chainQ,变量别名分析Q?/span>alias analysisQ,指针分析Q?/span>pointer analysisQ,数据依赖分析Q?/span>data dependence analysisQ等{?/span>
上述的程序分析结果是~译器优化(compiler optimizationQ和E序变ŞQ?/span>compiler transformationQ的前提条g。常见的优化和变新有Q函数内嵌(inliningQ,无用代码删除Q?/span>Dead code eliminationQ,标准化@环结构(loop normalizationQ,循环体展开Q?/span>loop unrollingQ,循环体合qӞ分裂Q?/span>loop fusionQ?/span>loop fissionQ,数组填充Q?/span>array paddingQ,{等?/span>优化和变形的目的是减代码的长度Q提高内存(memoryQ,~存Q?/span>cacheQ的使用率,减少d盘Q访问网l数据的频率。更高的优化甚臛_以把序列化的代码Q?/span>serial codeQ变成ƈ行运,多线E的代码Q?/span>parallelizedQ?/span>multi-threaded codeQ?/span>
机器代码的生成是优化变型后的中间代码转换成机器指令的q程。现代编译器主要采用生成汇编代码Q?/span>assembly codeQ的{略Q而不直接生成二进制的目标代码Q?/span>binary object codeQ。即使在代码生成阶段Q高U编译器仍然要做很多分析Q优化,变Ş的工作。例如如何分配寄存器Q?/span>register allocatioinQ,如何选择合适的机器指oQ?/span>instruction selectionQ,如何合ƈ几句代码成一句等{?/span>
~译语言与解释语aҎ
许多人将高E序语言分ؓ两类: ~译型语a?/span>解释型语a。然而,实际上,q些语言中的大多数既可用~译型实C可用解释型实玎ͼ分类实际上反映的是U语a常见的实现方式。(但是Q某些解释型语言Q很隄~译型实现。比如那些允?/span>在线代码更改的解释型语言。)
]]>