1、 预编译:
(1)将所有的”#define”删除,并且展开所有的宏定义。
(2)处理所有条件预编译指令,
比如”#if”,”#ifdef”,”#elif”,”#else”,”#endif”.
(3)处理”#include”预编译指令,将被包含的文件插入到该预编译指令的位置。注意:这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。
(4)删除所有注释”//”和”/**/.
(5)添加行号和文件名标识,比如#2 ”hello.c” 2,以便与变异是编译器产生条使用的行号信息以及用于编译时产生编译错误或警告时能够显示行号。
(6)保留所有的”#pragma”编译器指令,因为编译器需要使用它们。
经过编译后的.i文件不包含任何宏定义,因为所有的宏定义都已经展开,并且包含的文件也已经被插入到.i文件中。
2、编译:
编译过程就是把预处理完的文件进行一系列词法分析,语法分析,语义分析,优化后生成相应的汇编代码文件。
(1)词法分析:
词法分析产生的记号一般可分为以下几类:关键字,标识符,字面量(包含数字,字符串等)和特殊符号(如加号,等号等)。
实现词法扫描的工具是lex,他会按照用户之前描述好的词法规则将输入号的字符串分割成一个个记号。
(2)语法分析:
语法分析器将对由扫描器产生的记号进行语法分析,从而产生语法树(以表达式为节点的树)。实现语法分析的工具是yacc,可以根据用户给定的语法规则对输入的记号序列进行解析,从而构建出一颗语法树。
(3)语义分析:
编译器能进行的语义分析是静态语义分析(指在编译器期间可以确定的语义),静态语义经常包括声明和类型的匹配,类型的转换。
(4)中间语言生成:
源码级优化器在不同编译器中可能有不同的定义或有一些差异,源代码级优化器会在源代码级别进行优化,源代码级优化器往往将整个语法书转换成中间代码,它是语法树的顺序表示。中间代码有多种类型,在不同的编译器中有不同的形式,常见的有:三地址码和P-代码。中间代码将编译器分为前端和后端,编译器前端负责产生机器无关的中间代码,编译器后端将中间代码转换成目标机器代码。
(5)目标代码生成与优化:
编译器后端主要包括代码生成器和目标代码优化器,代码生成器将中间代码转换成目标代码,目标代码优化器将对上述的目标代码进行优化,比如选择合适的寻址方式,使用位移来代替乘法运算,删除多余的指令等等。
3、汇编
汇编器是将汇编代码转变为机器可执行指令
4、链接
生成可执行文件
gcc hello.o - o hello
链接的主要内容:把各个模块之间相互引用的部分都处理好,使得各个模块之间能正确地衔接。t’t处理步骤:
1.合并段和符号表
2.符号解析:在符号引用的地方找到符号定义的地方
3.分配地址和空间
4.符号的重定位(Relocation)
预编译 编译 汇编 链接
最新推荐文章于 2024-02-22 18:46:46 发布