第二章 编译系统设计

来源:互联网 发布:网络成瘾症心理干预 编辑:程序博客网 时间:2024/06/05 18:56
2017年6月1日 22:49:43


1.编译流程:
    词法分析,语法分析,语义分析和代码生成四个阶段。符号表管理和错误处理贯穿整个编译流程。
    如果支持代码优化,那么还需要优化器模块

2.词法分析
    词法分析器通过对源文件的扫描获得高级语言定义的词法记号。
    词法记号:反应在高级语言中就是对应的标识符,关键字,常量,运算符等。

    词法分析器的要求是能正常识别出这些不同形式的词法记号。
    为了识别出词法记号,需要有限自动机。
    有限自动机:解析并识别词法记号。
        例如:识别标识符的有限自动机:自动机从0状态开始,读入一个下划线或者字母进入状态1,
                                      状态1可以接受任意数量的下划线、字母和数字,同时也是结束状态。
                                      一旦读入其他字符便停止自动机的识别,这样就能识别任意一个合法
                                      的标识符。如果在非结束状态读入异常字符,意味着发生了词法错误,
                                      自动机停止。

3.语法分析:
    语法分析器的输入为:词法分许其识别的词法记号序列
                输出为:抽象语法树(不一定是二叉树)

    抽象语法树:所有的词法记号都出现在树的叶子结点上,这种叶子结点称为终结符
                所以的非叶子结点,都是对一串词法记号的抽象概括,称为非终结符
                    整个源程序就是一棵完整的抽象语法树

    文法:高级语言的形式化表示
          文法定义了源程序代码的书写规则,同时也是语法分析器构造抽象语法树的规则
    文法分析算法:
        自顶向下的LL(1)分析,自底向上的算符优先分析,LR分析等
        递归下降子程序作为LL(1)算法的一种便捷的实现方式,费城适合手工实现语法分析器。
        递归下降子程序:将产生式左侧的非终结符转化为函数定义,将产生式右侧的非终结符转化为函数调用,
                        将终结符转化为词法记号匹配。

4.符号表管理
    记录符号信息的数据结构,它使用按名存取的方式记录与符号相关的所有编译信息。
    语法分析需要根据符号检测变量使用是否合法,代码生成需要根据符号产生正确的地址,因此,符号信息的准确
    和完整是进行语义分析和代码生成的前提

    对于变量符号,需要在符号表中记录变量的名称,类型,区分变量的声明和定义的形式,如果是局部变量,还需要
    记录变量在运行时栈帧中的相对位置,考虑代码作用域的变化。

    符号表需要根据作用域的变化动态维护变量的可见性

5.语义分析
    语言的文法分为4中类型:0型,1型,2型,3型。
        3型为正规文法,即词法分析器中有限自动机能处理的语言文法
        2型为上下文无关文法,是目前自算计程序语言所采用的文法,含义:
                程序语言的上下文无关,即程序代码语句之间在文法层次上是没有关联的。
    语法分析只关心程序语言形式的正确性,而不考虑语法模块上下文之间联系的合法性。

    语义分析是编译器处理流程中对源代码正确性的最后一次检查,只要源代码语义上没有问题,编译器就可以正常引导目标代码生成

6.代码生成
    编译器的最后一个处理阶段,根据识别的语法模块翻译出目标机器的指令,比如汇编语言。

7.编译优化
    优化器可以提高生成代码的质量,但会使代码生成过程变得复杂。
    现在编译器结构:
        源代码 ---> 前端 ---> 优化器 ---> 后端 ---> 汇编代码
        前端:
            词法分析 ---> 语法分析 ---> 语义分析
        优化器:
            优化操作 ---> 优化操作 ---> 优化操作
        后端:
            指令选择(选择更“合适”的指令实现中间代码的翻译) ---> 指令调度 ---> 寄存器分配

8. 可以使用 readelf 查看ELF文件

    在文件头之后,是程序头表,记录程序运行时,操作系统如何将文件加载到内存中,所以只有可执行文件有。
    段表,记录每个段的位置和大小等信息。
    符号表段是按照表格形式存储符号信息的。
    重定位表也是按照表格形式存储的。

    可执行文件其实就是按照一定标准将二进制数据和代码等信息包装起来,方便操作系统管理和使用。
    从文件头可以找到程序头表和段表,从段表可以找到其他所以段。
    因此,在汇编语言输出目标文件时,就需要收集这些段的信息,并按照ELF格式组装目标文件。

    在 /usr/include/elf.h中,描述了标准ELF文件的数据结构的定义,在实现汇编器和链接器的代码中都使用了这个头文件。

9.汇编程序的设计
    汇编器和编译器相似,也包含词法分析,语法分析,语义处理,代码生成四个基本流程。

 
10.链接器:
    按照目标文本的输入顺序扫描文件信息,从每个文件的段表中提取出各个文件的代码段和数据段的信息。
    符号解析:
        为段内的符号指定地址。
    重定位:
        目标文件链接时,会重新组织代码段,数据段的位置。这样段内定义的所以符号的地址以及引用符号的数据和指令
        都会产生偏差,这是就重新计算符号的地址,修改原来的地址,即重定位。
        重定位从本质上来说是地址的修正。由于目标文件在链接之前不能获取自己所使用符号的虚拟地址信息,因此导致
        依赖于这些符号的数据定义或者指令信息缺失。汇编器在生成目标文件的时候就记录下所以需要重定位的信息。链接器
        捕获这些重定位的信息,并按照重定位信息的含义修改已经生成的代码,使得最终的代码正确,完整。

    在重定位目标文件内,符号表记录了符号的所以信息。对于本地定义的符号,符号表项记录符号的段内便宜地址。
    对于外部引用的符号,符号表项标识该符号为“未定义的”。当链接器扫描到该符号的目标文件时,就将该外部符
    号的地址修改为正确的符号地址。

    链接器在扫描重定位目标文件的符号表时会动态地维护两个符号集合。一个记录所以定义的全局符号集合Export,该集合内的
    所以符号允许被其他文件引用。还有一个记录所以文件使用的未定义符号的集合Import,该集合内所有符号都来源与其他目标
    文件。文件扫描完毕后,链接器验证Import是否为Export的子集,不是,则说明有未定义符号,报错。