# 《程序员的自我修养》读书笔记
高级语言使得程序员们能够更加关注程序逻辑的本身,而尽量少考虑计算机本身的限制,如字长、内存大小、通信方式、存储方式等。
编译过程一般可分为6步:扫描、语法分析、语义分析、源代码优化、目标代码优化。
如下所示:
Source Code --Scanner--> Tokens --Parser--> Syntax Tree --Semantic-Analyzer--> Commented Syntax Tree --Source-Code-Optimizer--> Intermediate Representation --Code-Generator--> Target Code --Code-Optimizer--> Final Target Code
# Tokens:记号
# Parser:语法分析器
# Syntax:语法
# Semantic:语义的
# Commented:注释的
# Optimizer:优化器
# Intermediate Representation:中间表示
# Generator:生成器
目录
词法分析
首先源代码程序被输入到扫描器(Scanner),扫描器的任务很简单,只是简单地进行词法分析,运用一种类似于有限状态机(Finite State Machine)的算法可以很轻松地将源代码的字符序列分割成一系列的记号(Token)。
有限状态机:有限状态机是一种用来进行对象行为建模的工具,主要作用是描述对象在它的生命周期内所经历的状态序列,以及如何相应来自外界的各种事件。在计算机科学中,有限状态机被广泛用于建模应用行为、硬件电路系统设计、软件工程、编译器、网络协议和计算机语言的研究。
词法分析产生的记号一般可分为:关键字、标识符、字面量(包含数字、字符串等)和特殊符号(如加号、等号)。在识别记号的同时,扫描器也完成了其他工作,如将标识符放到符号表,将数字、字符串常量存放到文字表等。
标识符:如变量名称、函数名称、数据类型等都属于标识符。
对于一些有预处理的语言,如C,它的宏替换和文件包含等工作一般不归入编译器的范围而交给一个独立的预处理器。
语法分析
语法分析器(Grammer Parser)对扫描器产生的Tokens进行语法分析,从而产生语法树(Syntax Tree)。整个分析过程采用了上下文无关语法(Context-free Grammer)的分析手段。由语法分析器产生的语法树就是以表达式(Expression)为节点的树,一个节点代表一棵树,一棵树就是一个表达式。C语言的一个语句就是一个表达式,复杂的语句是很多表达式的组合。符号和数字是最小的表达式。在语法分析的同时,很多运算符号的优先级和含义也被确定下来。如果出现了表达式不合法,比如各种括号不匹配、表达式中缺少操作符等,编译器就会报告语法分析阶段的错误。
语义分析
由语义分析器(Semantic Analyzer)来完成。语法分析仅仅完成了对表达式语法层面的分析,但它并不了解这个语句是否真正有意义。编译器所能分析的语义是静态语义(Static Semantic),所谓静态语义是指在编译期可以确定的语义,与之对应的动态语义(Dynamic Semantic)就是只有在运行期间才能确定的语义,比如将0作为除数。静态语义通常包括声明、类型的匹配和类型的转换。经过语义分析阶段以后,整个语法树的表达式都被标识了类型,如果有些类型需要做隐式转换,语义分析程序会在语法树中插入相应的转换节点。
中间语言生成
现代的编译器有着很多层次的优化,往往在源代码级别会有一个优化的过程。由于直接在语法树上作优化比较困难,源码级优化器(Source Code Optimizer)往往将整个语法树转换成中间代码(Intermediate Code),它是语法树的顺序表示。其实它已经非常接近目标代码了,只是它一般跟目标机器和运行时环境是无关的,比如它不包含数据的尺寸、变量地址和寄存器的名字等。中间代码有很多类型,在不同编译器中有不同的形式,常见的有:三地址码(Three-Address Code)和P-代码(P-Code)。
中间代码使得编译器可以被分为前端和后端。编译器前端负责产生机器无关的中间代码,编译器后端将中间代码转换成目标机器代码。这样对于一些可以跨平台的编译器而言,可以针对不同平台使用同一个前端和针对不同平台的数个后端。
目标代码生成与优化
编译器后端主要包括代码生成器(Code Generator)和目标代码优化器(Target Code Optimizer)。代码生成器将中间代码转换成目标机器代码,这个过程十分依赖于目标机器,因为不同的机器有着不同的字长、寄存器、整数数据类型和浮点数据类型等。最后目标代码优化器对目标代码进行优化,比如选择合适的寻址方式、使用位移来代替乘法运算、删除多余的指令等。
链接器
目标代码中有变量定义在其他模块该怎么办?事实上,定义在其他模块的全局变量和函数在最终运行时的绝对地址都要在最终链接的时候才能确定。所以现代编译器可以将一个源代码文件编译成一个未链接的目标文件,然后由链接器最终将这些目标文件链接起来形成可执行文件。

编译器将高级语言转化为机器可执行代码,主要过程包括词法分析、语法分析、语义分析、中间代码生成、目标代码优化及链接器的工作。词法分析将源代码拆分成记号;语法分析构建语法树;语义分析确保语义正确;中间代码生成方便优化;目标代码生成考虑目标机器特性;链接器处理跨模块引用,生成可执行文件。
1188

被折叠的 条评论
为什么被折叠?



