精华内容
下载资源
问答
  • 编译原理(三)类型检查

    千次阅读 2018-01-24 20:52:54
    静态检查中最典型的部分——类型检查: 类型系统、类型检查、多态函数、重载 忽略其它的静态检查:控制流检查、唯一性检查、关联名字检查 上面不能在不该出现continue的地方出现continue。 C语言: ...
    • 静态检查中最典型的部分——类型检查:

    类型系统、类型检查、多态函数、重载

    • 忽略其它的静态检查:控制流检查、唯一性检查、关联名字检查


    上面不能在不该出现continue的地方出现continue。

    C语言:

    • 称&为地址运算符,&a为变量a的地址
    • 数组名代表数组第一个元素的地址

    问题:

    如果a是一个数组名,那么表达式a和&a的值都是数组a第一个元素的地址,它们的使用是否有区别?

     用四个C文件的编译报错或运行结果来提示

    上面报错,返回的a不能作为二位数组的指针

    返回a的指针时,是正确的

    二维数组的第一个元素,可以看作是一个一维数组,所以返回a时,表示二位数组的第一个元素,与B类型相同,没有报错

    a+1加了80,因为A的第二元有20个int类型的数组,&a+1加了800,因为A占用了800字节内存。

    类型在编程语言中的作用

    执行错误和安全语言

    1、程序运行时的执行错误分成两类

    • 会被捕获的错误(trapped error)

     例:非法指令错误、非法内存访问、除数为0

     引起计算立即停止

    • 不会被捕获的错误(untrapped error)

      例如:跳到一个错误的地址,该地址开始的内存正好代表一个指令序列

     错误可能会有一段时间未引起注意

    安全语言

    • 任何合法程序都是良行为的
    • 通常是设计一个类型系统,通过静态的类型检查来拒绝不会被捕获的错误
    • 但是,设计一个类型系统,正好拒绝不会被捕获错误是非常困难的

    禁止错误

    • 不会被捕获错误集合+会被捕获错误的一个子集
    • 为语言设计类型系统的目标是在排除禁止错误

    良行为程序和安全语言也可基于禁止错误来编译

    类型化的语言

    • 变量都被给定类型的语言
    • 表达式、语句等程序构造的类型都可以静态确定
    • 例如,类型boolean的变量x在程序每次运行时的值只能时布尔值,not(x)总有意义

    类型系统

    • 语言的组成部分,它由一组定型规则(typeing rule)构成,这组规则用来给各种程序构造指派类型
    • 设计类型系统的根本目的是用静态检查的方式来保证合法程序运行时的良行为
    • 类型系统的形式化
    • ----类型表达式(描述类型的表达式)、定型断言(根据语言跟早实例判断类型)、定型规则
    • 类型检查算法
    • ----通常是静态地完成类型检查

    良类型的程序

    • 没有类型错误的程序

    类型可靠的语言

    • 所有良类型程序(合法程序)都是良行为的
    • 类型可靠的语言一定是安全的语言

    类型检查:类型化语言

    • 类型检查也可以放在运行时完成,但影响效率
    • 一般都是静态检查,类型系统被用来支持静态检查
    • 静态检查语言通常也需要一些运行时的检查
    • ----数组访问越界检查

    实际使用的一些语言并不安全

    C语言
    • 还有很多不安全的并且被广泛使用的特性,如:指针算数运算、类型强制、参数个数可变
    • 在语言的设计历史上,安全性考虑不足时因为当时强调代码的执行效率。

    在现代语言设计上,安全性越来越重要

    • C语言的一些问题已经在C++中得到缓和
    • 更多一些问题在Java中已得到解决

    类型化语言的优点

     从工程的观点看,类型化语言有下面一些优点

    • 开发的实惠
    • ----较早发现错误
    • ----类型信息还具有文档左右
    • 编译的实惠
    • ----程序模块可以相互独立地编译
    • 运行的实惠
    • ----可得到更有效的空间安排和访问方式






     



      




    展开全文
  • 编译原理编译原理简单介绍

    万次阅读 多人点赞 2017-05-07 13:27:20
    编译原理简单介绍编译原理简单介绍 什么叫编译程序 翻译程序 编译程序 翻译和编译的区别 编译的过程 词法分析 语法分析 语义分析和中间代码的产生 优化 目标代码生成 编译程序的结构 编译程序总框 表格与表格的管理 ...

    编译原理简单介绍



    什么叫编译程序

    翻译程序

    翻译程序(Translator)是一种程序,其输入是某种语言的一系列语句,而其输出则是另一种语言的一系列语句,二者在逻辑上是等价的。就类似生活中的翻译官一样,把英语翻译成汉语,二者在意思上也是等价的。
    这里写图片描述

    编译程序

    编译程序(Compiler)是一种程序。它把用高级语言写的源程序作为数据接收,经过翻译转换,产生面向机器的代码作为输出。
    这当中代码还可能要由汇编程序或装配程序作进一步加工,得出目标程序,交给计算机执行。
    这里写图片描述

    翻译和编译的区别

    这里写图片描述

    编译的过程

    编译程序的工作过程一般可以分为5个阶段:
    1. 词法分析
    2. 语法分析
    3. 语义分析和中间代码的产生
    4. 优化
    5. 目标代码生成

    词法分析

    词法分析的任务是:输入源程序,对构成源程序的字符串进行扫描和分解,识别出一个个单词(定义符、标识符、运算符、界符、常数)。

    在词法分析阶段的工作中所依循的是语言的语法规则(或称构词规则)。
    描述语法规则的有效工具是正规式有限自动机

    语法分析

    语法分析的任务是:在词法分析的基础上,根据语言的语法规则,把单词符号串分解成各类语法单元(语法范畴)(短语、子句、句子、程序段、程序),并确定整个输入串是否构成语法上正确的程序。

    语法分析所依循的是语言的语法规则。
    语法规则通常用上下文无关文法描述。
    词法分析是一种线性分析,而语法分析是一种层次结构分析。

    语义分析和中间代码的产生

    这一阶段的任务是:对语法分析所识别出的各类语法范畴,分析其含义,并进行初步翻译(产生中间代码)。这一阶段通常包含两个方面的工作。
    1. 对每种语法范畴进行静态语义的检查,例如,变量是否定义、类型是否正确等等。
    2. 如果语义正确则进行中间代码的翻译。

    这一阶段所依循的是语言的语义规则,通常使用属性文法描述语义规则。

    优化

    对于代码(主要是中间代码)进行加工变换,以期能够产生更为高效(省时间和空间)的目标代码 。
    优化的主要方面有:公共子表达式的提取、循环优化、删除无用代码等等。

    优化所依循的是程序的等价变换规则。

    目标代码生成

    这一阶段的任务是:把中间代码(经过优化处理之后的)变换成特定机器上的低级语言代码(绝对指令、可重定位指令、汇编指令
    )。

    编译程序的结构

    编译程序总框

    这里写图片描述

    表格与表格的管理

    编译程序在工作过程中需要保持一系列的表格,以登记源程序的各类信息和编译各阶段的进展状况
    最重要的是符号表,用来等级源程序中出现的每个名字以及名字的各种属性。例如,一个名字是常量名还是变量名,还是过程名;如果是变量名,类型是什么,占多大内存,地址是多少等等。

    编译各阶段均须维持表格并进行表格管理,建表的技术支持是数据结构,表格的分类、结构、处理方法决定于语言及机器,还有优化措施。

    出错处理

    如果源程序有错误,编译程序应设法发现错误,并把有关错误的信息报告给用户。一个好的编译程序:
    1. 全
    最大限度发现错误
    2. 准
    准确指出错误的性质和发生地点
    3. 局部化
    将错误的影响限制在尽可能小的范围内
    4. 自动校正
    若能自动校正错误则更好,但其代价非常高

    源程序中的错误一般分为语法错误和语义错误。
    1. 语法错误
    指源程序中不符合不符合语法(或词法)规则的错误,例如:单词拼写错误、括号不匹配等等。
    2. 语义错误
    指源程序中不符合语义规则的错误,例如:说明错误、作用域错误、类型不匹配等等。
    一般在语义分析时检出来,有的语义错误要在运行时才能检测出来。

    遍 是对源程序或源程序的中间结果从头到尾扫描一次,并作有关的加工处理,生成新的中间结果或目标程序。遍数多了,整个编译程序的逻辑结构就比较清晰,但是会增加输入和输出所消耗的时间。因此,在主存可能的前提下,一般还是遍数少的好。
    分遍的依据:
    1. 源程序的结构
    2. 选用机型的内存大小
    3. 设计目标的技术指标
    4. 参加编译程序人员的数量、素质

    好的编译程序的指标:
    1. 符合语法规则的程序都可执行。
    2. 任何非法的错误都有可能识别,并尽量少的产生连锁反应。
    3. 错误不至于导致系统崩溃。
    4. 可维护和可读性。
    5. 模块化和结构化。

    编译的前端与后端

    概念上我们有时候把编译程序分成编译前端和编译后端。

    编译前端

    前端主要由源语言有关但与目标机无关的那些部分组成,通常包括词法分析、语法分析、语义分析与中间代码的产生,有的代码优化工作也可以包括在前端。

    编译后端

    后端包括编译程序中与目标机有关的那些部分,如与目标机有关的代码优化和目标代码生成等。
    通常后端不依赖源语言而仅仅依赖于中间语言。

    编译程序的生成

    编译程序的构造工具

    以前人们构造编译程序大多数采用的是机器语言或汇编语言,现在只有为了充分发挥各种不同硬件系统的效率,为了满足各种不同的具体要求,才会采用这种工具来构造编译程序(或编译程序的“核心”部分)。现在越来越多采用高级语言来构造编译程序。

    T型图

    为了便于说明,我们常采用T型图来表示源语言S、目标语言T、和比编译程序实现语言I之间的关系。
    每个T型图相当于一个编译程序。
    这里写图片描述

    用高级语言L1构造编译程序

    如果A机器上有一个使用A机器代码实现的某高级语言L1的编译程序(黄色),则我们可以使用L1语言编写另外一种高级语言L2的编译程序(橙色)。把写好的L2编译程序经过L1编译程序编译后就可以得到A机器码实习的L2编译程序(绿色)。
    这里写图片描述

    编译程序的移植

    通过上面用高级语言L1构造编译程序的原理,我们可以实现编译程序的“移植”。首先我们有一个可以在A机器上编译的高级语言L,
    这里写图片描述
    接下来我们使用L去写一个能够在B机器上运行的编译程序,
    这里写图片描述
    然后通过L的编译程序就可以生成在A机器上可以运行的产生B机器代码的编译程序(3)。
    这里写图片描述
    使用这个编译程序(3)去编译一遍(2)就可以得到能在B机器上运行的B机器代码的编译程序(4).
    这里写图片描述

    自编译方式

    先对语言的核心部分构造一个小小的编译程序(可用低级语言实现),再以它为工具构造能编译更多语言成分的较大编译程序,如此不断扩展,最后形成整个编译程序(滚雪球),这种通过一系列自展途径而形成的编译程序的过程叫做自编译过程。

    构造工具

    现在人们已经建立了多种编制部分编译程序或者整个编译程序的有效工具。构造编译程序的工具称为编译程序-编译程序、编译程序产生器或翻译程序书写系统。
    例如:
    自动产生扫描器:LEX FLEX
    自动产生语法分析器:YACC BISON

    展开全文
  • sparse静态编译检查工具

    千次阅读 2018-04-24 20:20:28
    sparse是由Linux之父开发,主要的功能就是静态的检查代码中可能出现的错误,从而减少Linux内核的隐患,这个工具的好处就是能够静态检查代码,尽量在代码编写的最前期发现bug,避免了系统在running状态下才暴露问题,...

    sparse是由Linux之父开发,主要的功能就是静态的检查代码中可能出现的错误,从而减少Linux内核的隐患,这个工具的好处就是能够静态检查代码,尽量在代码编写的最前期发现bug,避免了系统在running状态下才暴露问题,从而提高了debug的效率。

    使用方法:

    在使用该工具之前,我们需要先安装sparse工具:

    sudo apt-get install sparse
    

    当我们在kernel源码环境中执行make help时会发现有如下的提示:

    make C=1   [targets] Check all c source with $CHECK (sparse by default)
    make C=2   [targets] Force check of all c source with $CHECK
    

    从上面的help提示可知:

    当用”make C=1”命令来编译内核,会对所有重新编译的 C 文件使用 sparse 工具进行检查。

    当使用”make C=2”命令,无论文件是否被重新编译都会对其使用 sparse 工具进行检查。

    (如果你已经编译了内核,用后一种方式可以很快地检查整个源码树)

    make C=2 CHECKFLAGS="-D__CHECK_ENDIAN__"
    

    make 的可选变量 CHECKFLAGS 可以用来向 sparse 工具传递参数。编译系统会自动向 sparse 工具传递 -Wbitwise 参数。你可以定义 __CHECK_ENDIAN__ 来进行大小尾检查。这些检查默认都是被关闭的,因为他们通常会产生大量的警告。

    运行原理:

    想要sparse能够正常功能,必须要在kernel代码中加上对应的处理,也就是gcc attribute属性。

    首先看在linux/compiler.h中的定义:

    #ifdef __CHECKER__
    # define __user     __attribute__((noderef, address_space(1)))
    # define __kernel   __attribute__((address_space(0)))
    # define __safe     __attribute__((safe))
    # define __force    __attribute__((force))
    # define __nocast   __attribute__((nocast))
    # define __iomem    __attribute__((noderef, address_space(2)))
    # define __must_hold(x) __attribute__((context(x,1,1)))
    # define __acquires(x)  __attribute__((context(x,0,1)))
    # define __releases(x)  __attribute__((context(x,1,0)))
    # define __acquire(x)   __context__(x,1)
    # define __release(x)   __context__(x,-1)
    # define __cond_lock(x,c)   ((c) ? ({ __acquire(x); 1; }) : 0)
    # define __percpu   __attribute__((noderef, address_space(3)))
    # define __pmem     __attribute__((noderef, address_space(5)))
    #ifdef CONFIG_SPARSE_RCU_POINTER
    # define __rcu      __attribute__((noderef, address_space(4)))
    #else
    # define __rcu
    #endif
    extern void __chk_user_ptr(const volatile void __user *);
    extern void __chk_io_ptr(const volatile void __iomem *);
    #else
    # define __user
    # define __kernel
    # define __safe
    # define __force
    # define __nocast
    # define __iomem
    # define __chk_user_ptr(x) (void)0
    # define __chk_io_ptr(x) (void)0
    # define __builtin_warning(x, y...) (1)
    # define __must_hold(x)
    # define __acquires(x)
    # define __releases(x)
    # define __acquire(x) (void)0
    # define __release(x) (void)0
    # define __cond_lock(x,c) (c)
    # define __percpu
    # define __rcu
    # define __pmem
    #endif

    include/uapi/linux/types.h中也有定义如下:

     /*
      * Below are truly Linux-specific types that should never collide with
      * any application/library that wants linux/types.h.
      */
    
     #ifdef __CHECKER__
     #define __bitwise__ __attribute__((bitwise))
     #else
     #define __bitwise__
     #endif
     #ifdef __CHECK_ENDIAN__
     #define __bitwise __bitwise__
     #else    
     #define __bitwise
     #endif   
    
     typedef __u16 __bitwise __le16;
     typedef __u16 __bitwise __be16;
     typedef __u32 __bitwise __le32;
     typedef __u32 __bitwise __be32;
     typedef __u64 __bitwise __le64;
     typedef __u64 __bitwise __be64;
    
     typedef __u16 __bitwise __sum16;
     typedef __u32 __bitwise __wsum;

    可以看出,上面的代码,如果有定义CHECKER宏的话(也就是使能了sparse后),那么很多类型都会加上gcc attribut属性。用到的属性如下:

    • address_space(num)
    • bitwise
    • force
    • context

    我们以bitwise为例做一个介绍,bitwise传给gcc后,在编译过程中会做一个big endian/little endian的类型检查。比如上面定义的:

    typedef __u32 __bitwise     __le32;
    typedef __u32 __bitwise     __be32;

    这两条语句代表的是不同的endian,两种类型是不能够混用的,比如把__le32类型的数据强制转换为__be32就会上报WARNING。

    另外最后一条,如果在某些场景,我们确实要进行上述类型的转换,为了避免编译时继续上报WARNING,可以使用__force attribute来标识这次转换,由此可以避免编译上报WARNING。

    参考:
    https://en.wikipedia.org/wiki/Sparse
    Documentation/sparse.txt 内核文档

    展开全文
  • 编译原理

    千次阅读 2016-07-07 16:49:22
    编译原理 编辑词条 B 添加义项  ? 编译原理是计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法。内容包括语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成...

    编译原理 编辑词条

    编译原理计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法。内容包括语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成、存储管理、代码优化和目标代码生成。 编译原理是计算机专业设置的一门重要的专业课程。虽然只有少数人从事编译方面的工作,但是这门课在理论、技术、方法上都对学生提供了系统而有效的训练,有利于提高软件人员的素质和能力。 目前各个大学使用的教材机械工业出版社、国防工业出版社出版的《编译原理》。

    基本信息

    • 书名

      编译原理

    • 装帧

      平装

     
    • 开本

      16

    • 页数

      542

    编译原理计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法。内容包括语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成、存储管理、代码优化和目标代码生成。 编译原理是计算机专业设置的一门重要的专业课程。虽然只有少数人从事编译方面的工作,但是这门课在理论、技术、方法上都对学生提供了系统而有效的训练,有利于提高软件人员的素质和能力。 目前各个大学使用的教材机械工业出版社、国防工业出版社出版的《编译原理》。

    折叠编辑本段基本概念

    编译器 是将汇编或高级计算机语言翻译为二进制机器语言代码的计算机程序。编译器将源程序(source language) 编写的程序作为输入,翻译产生目标语言(target language )机器代码的等价程序。通常地,源程序为高级语言(high-level language ),像C或C + +、汉语语言程序等,而目标则是机器语言的目标代码 (object code,有时也称作机器代码(machine code )),也就是可以在计算机硬件中运行的机器代码软件程序。这一过程可以表示为:

    源程序→编译器 →目标机器代码程序

    折叠编辑本段编译原理课程

    这门课程关注的是编译器方面的产生原理和技术问题,似乎和计算机的基础领域不沾边,可是编译原理却一直作为大学本科的 必修课程,同时也成为了研究生入学考试的必考内容。编译原理及技术从本质上来讲就是一个算法问题而已,当然由于这个问题十分复杂,其解决算法也相对复杂。 我们学的数据结构与算法分析也是讲算法的,不过讲的基础算法,换句话说讲的是算法导论,而编译原理这门课程讲的就是比较专注解决一种的算法了。在20世纪 50年代,编译器的编写一直被认为是十分困难的事情,第一Fortran的编译器据说花了18年的时间才完成。在人们尝试编写编译器的同时,诞生了许多跟 编译相关的理论和技术,而这些理论和技术比一个实际的编译器本身价值更大。就犹如数学家们在解决著名的哥德巴赫猜想一样,虽然没有最终解决问题,但是其间 诞生不少名著的相关数论。

    折叠编辑本段发展历程

    在20世纪40年代,由于冯·诺伊曼在存储-程序编译原理实验程序编译原理实验程序计算机方面的先锋作用,编写一串代码或程序已成必要,这样计算机就可以执行所需的计算。开始时,这些程序都是用机器语言 (machine language )编写的。机器语言就是表示机器实际操作的数字代码,例如:

    C7 06 0000 0002 表示在IBM PC 上使用的Intel 8x86处理器将数字2移至地址0 0 0 0 (16进制)的指令。

    但编写这样的代码是十分费时和乏味的,这种代码形式很快就被汇编语言(assembly language )代替了。在汇编语言中,都是以符号形式给出指令和存储地址的。例如,汇编语言指令 MOV X,2 就与前面的机器指令等价(假设符号存储地址X是0 0 0 0 )。汇编程序(assembler )将汇编语言的符号代码和存储地址翻译成与机器语言相对应的数字代码。

    汇编语言大大提高了编程的速度和准确度,人们至今仍在使用着它,在编码需要极快的速度和极高的简洁程度时尤为如此。但是,汇编语言也有许多缺点:编写起来也不容易,阅读和理解很难;而且汇编语言的编写严格依赖于特定的机器,所以为一台计算机编写的代码在应用于另一台计算机时必须完全重写。

    发展编程技术的下一个重要步骤就是以一个更类似于数学定义或自然语言的简洁形式来编写程序的操作,它应与任何机器都无关,而且也可由一个程序翻译为可执行的代码。例如,前面的汇编语言代码可以写成一个简洁的与机器无关的形式 x = 2。

    在1954年至1957年期间,IBM的John Backus带领的一个研究小组对FORTRAN语言及其编译器的开发,使得上面的担忧不必要了。但是,由于当时处理中所涉及到的大多数程序设计语言的翻译并不为人所掌握,所以这个项目的成功也伴随着巨大的辛劳。几乎与此同时,人们也在开发着第一个编译器, Noam Chomsky开始了他的自然语言结构的研究。他的发现最终使得编译器结构异常简单,甚至还带有了一些自动化。Chomsky的研究导致了根据语言文法(grammar ,指定其结构的规则)的难易程度以及识别它们所需的算法来为语言分类。正如现在所称的-与乔姆斯基分类结构(Chomsky hierarchy )一样-包括了文法的4个层次:0型、1型、2型和3型文法,且其中的每一个都是其前者的专门化。2型(或上下文无关文法(context-free grammar ))被证明是程序设计语言中最有用的,而且今天它已代表着程序设计语言结构的标准方式。

    分析问题( parsing problem ,用于限定上下文无关语言的识别的有效算法)的研究是在20世纪60年代和70年代,它相当完善地解决了这一问题, 现在它已是编译理论的一个标准部分。它们与乔姆斯基的3型文法相对应。对它们的研究与乔姆斯基的研究几乎同时开始,并且引出了表示程序设计语言的单词(或称为记号)的符号方式。

    人们接着又深化了生成有效的目标代码的方法,这就是最初的编译器,它们被一直使用至今。人们通常将其误称为优化技术(optimization technique ),但因其从未真正地得到过被优化了的目标代码而仅仅改进了它的有效性,因此实际上应称作代码改进技术(code improvement technique )。

    这些程序最初被称为编译程序-编译器,但更确切地应称为分析程序生成器 (parser generator ),这是因为它们仅仅能够自动处理编译的一部分。这些程序中最著名的是 Yacc (yet another compiler- compiler),它是由Steve Johnson在1975年为Unix系统编写的。

    类似地,有穷自动机的研究也发展了另一种称为扫描程序生成器 (scanner generator )的工具,Lex (与Yacc同时,由Mike Lesk为Unix系统开发的)是这其中的佼佼者。在20世纪70年代后期和80年代早期,大量的项目都关注于编译器其他部分的生成自动化,这其中就包括代码生成。这些尝试并未取得多少成功,这大概是因为操作太复杂而人们又对其不甚了解。

    编译器设计最近的发展包括:首先,编译器包括了更为复杂的算法的应用程序,它用于推断或简化程序中的信息;这又与更为复杂的程序设计语言(可允许此类分析)的发展结合在一起。其中典型的有用于函数语言编译的Hindle y - Milner类型检查的统一算法。

    其次,编译器已越来越成为基于窗口的交互开发环境(interactive development environment,IDE )的一部 分,它包括了编辑器、链接程序、调试程序以及项目管理程序。这样的IDE的标准并没有多少, 但是已沿着这一方向对标准的窗口环境进行开发了。

    折叠编辑本段相关程序

    折叠解释程序

    解释程序(interpreter):解释程序是如同编译器的一种语言翻译程序。它与编译器的不同之处在于:它立即执行源程序而不是生成在翻译完成之后才执行的目标代码。从原理上讲,任何程序设计语言都可被解释或被编译,但是根据所使用的语言和翻译情况,很可能会选用解释程序而不用编译器。例如, 我们经常解释BASIC语言而不是去编译它。类似地,诸如LISP 的函数语言也常常是被解释的。

    解释程序也经常用于教育和软件的开发,此处的程序很有可能被翻译若干次。而另一方面,当执行的速度是最为重要的因素时就使用编译器,这是因为被编译的目标代码比被解释的源代码要快得多,有时要快10倍或更多。但是,解释程序具有许多与编译器共享的操作,而两者之间也有一些混合之处。

    折叠汇编程序

    汇编程序(assembler):汇编程序是用于特定计算机上的汇编语言的翻译程序。正如前面所提到的,汇编语言是计算机的机器语言的符号形式,它极易翻译。有时,编译器会生成汇编语言以作为其目标语言, 然后再由一个汇编程序将它翻译成目标代码。

    折叠连接程序

    连接程序(linker):编译器和汇编程序都经常依赖于连接程序,它将分别在不同的目标文件中编译或汇编的代码收集到一个可直接执行的文件中。在这种情况下,目标代码,即还未被连接的机器代码,与可执行的机器代码之间就有了区别。连接程序还连接目标程序和用于标准库函数的代码,以及连接目标程序和由计算机的操作系统提供的资源(例如,存储分配程序及输入与输出设备)。连接程序现在正在完成编译器最早的一个主要活动(这也是"编译"一词的用法, 即通过收集不同的来源来构造)。连接过程对操作系统和处理器有极大的依赖性。

    折叠装入程序

    装入程序(loader):编译器、汇编程序或连接程序生成的代码经常还不完全适用或不能执行,但是它们的主要存储器访问却可以在存储器的任何位置中且与一个不确定的起始位置相关。这样的代码被称为是可重定位的(relocatable ),而装入程序可处理所有的与指定的基地址或起始地址有关的可重定位的地址。装入程序使得可执行代码更加灵活,但是装入处理通常是在后台(作为操作环境的一部分)或与连接相联合时才发生,装入程序极少会是实际的独立程序。

    折叠预处理器

    预处理器(preprocessor ):预处理器是在真正的翻译开始之前由编译器调用的独立程序。预处理器可以删除注释、包含其他文件以及执行宏(宏macro是一段重复文字的简短描写)替代。预处理器可由语言(如 C )要求或以后作为提供额外功能(诸如为FORTRAN提供Ratfor预处理器)的附加软件。

    折叠编辑器

    编辑器(editor):编译器通常接受由任何生成标准文件(例如ASCII文件)的编辑器编写的源程序。现在, 编译器已与另一个编辑器和其他程序捆绑进一个交互的开发环境-IDE中。此时,尽管编辑器仍然生成标准文件,但会转向正被讨论的程序设计语言的格式或结构。这样的编辑器称为基于结构的(structure based ),且它早已包括了编译器的某些操作;因此,程序员就会在程序的编写时而不是在编译时就得知错误了。从编辑器中也可调用编译器以及与它共用的程序,这样程序员无需离开编辑器就可执行程序

    折叠调试程序

    调试程序(debugger ):调试程序是可在被编译了的程序中判定执行错误的程序,它也经常与编译器一起放在IDE 中。运行一个带有调试程序的程序与直接执行不同,这是因为调试程序保存着所有的或大多数源代码信息(诸如行数、变量名和过程)。它还可以在预先指定的位置(称为断点(breakpoint )) 暂停执行,并提供有关已调用的函数以及变量的当前值的信息。为了执行这些函数,编译器必须为调试程序提供恰当的符号信息,而这有时却相当困难,尤其是在一个要优化目标代码的编译器中。因此,调试又变成了一个编译问题。

    折叠描述器

    描述器(profiler):描述器是在执行中搜集目标程序行为统计的程序。程序员特别感兴趣的统计是每一个过程的调用次数和每一个过程执行时间所占的百分比。这样的统计对于帮助程序员提高程序的执行速度极为有用。有时编译器也甚至无需程序员的干涉就可利用描述器的输出来自动改进目标代码。

    折叠项目管理程序

    项目管理程序(project manager):软件项目通常大到需要由一组程序员来完成,这时对那些由不同人员操作的文件进行整理就非常重要了,而这正是项目管理程序的任务。例如,项目管理程序应将由不同的程序员制作的文件的各个独立版本整理在一起,它还应保存一组文件的更改历史,这样就能维持一个正在开发的程序的连贯版本了(这对那些由单个程序员管理的项目也很有用)。项目管理程序的编写可与语言无关,但当其与编译器捆绑在一起时,它就可以保持有关特定的编译器和建立一个完整的可执行程序的链接程序操作的信息。在Unix系统中有两个流行的项目管理程序:sccs (source code control system )和rcs (revision control system )。

    折叠编辑本段步骤

    编译器内部包括了许多步骤或称为阶段源代码(phase),它们执行不同的逻辑操作。将这些阶段设想为编译器中一个个单独的片断是很有用的, 尽管在应用中它们是经常组合在一起的,但它们扫描程序确实是作为单独的代码操作来编写的。

    折叠扫描程序

    扫描程序(scanner):在这个阶段编译器实际阅读源程序(通常以分析程序字符流的形式表示)。扫描程序执行词法分析注释树符号表 (Lexical analysis ):它将字符序列收集到称作记号错误处 (token )的有意义单元中,记号同自然语言,如英源代码理器语中的字词相似。因此可以认为扫描程序执行与优化程序拼写相似的任务。中间代码例如在下面的代码行(它可以是C程序的一部分)中:代码生成器 a [index] = 4 + 2 这个代码包括了1 2个非空字符,但只有 8个目标代码记号:a 标识符目标代码优化程序 [ 左括号 i n d e x 标识符 ] 右括号 = 赋值目标代码 4 数字编译器的阶段 + 加号 2 数字 每一个记号均由一个或多个字符组成,在进一步处理之前它已被收集在一个单元中。扫描程序还可完成与识别记号一起执行的其他操作。例如,它可将标识符输入到符号表中, 将文字(litral)输入到文字表中(文字包括诸如3 . 1415926535的数字常量,以及诸如"Hello,world ! "的引用字符串)。

    折叠语法分析

    语法分析(parser ):语法分析程序从扫描程序中获取记号形式的源代码,并完成定义程序结构的语法分析 (syntax analysis ),这与自然语言中句子的语法分析类似。语法分析定义了程序的结构元素及其关系。通常将语法分析的结果表示为分析树(parse tree)或语法树(syntax tree)。例如,还是那行C代码,它表示一个称为表达式的结构元素,该表达式是一个由左边为下标表达式、右边为整型表达式的赋值表达式组成。这个结构可按下面的形式表示为一个分析树:请注意,分析树的内部节点均由其表示的结构名标示出,而分析树的叶子则表示输入中的记号序列(结构名以不同字体表示以示与记号的区别)。分析树对于显示程序的语法或程序元素很有帮助,但是对于表示该结构却显得力不从心了。分析程序更趋向于生成语法树,语法树是分析树中所含信息的浓缩(有时因为语法树表示从分析树中的进一步抽取,所以也被称为抽象的语法树(abstract syntax tree ))。下面是一个C赋值语句的抽象语法树的例子:请注意,在语法树中,许多节点(包括记号节点在内)已经消失。例如,如果知道表达式是一个下标运算,则不再需要用括号"["和"]"来表示该操作是在原始输入中。

    折叠语义分析

    语义分析(semantic analyzer ):程序的语义就是它的"意思",它与语法或结构不同。程序的语义确定程序的运行,但是大多数的程序设计语言都具有在执行之前被确定而不易由语法表示和由分析程序分析的特征。这些特征被称作静态语义(static semantic),而语义分析程序的任务就是分析这样的语义(程序的"动态"语义具有只有在程序执行时才能确定的特性,由于编译器不能执行程序,所以它不能由编译器来确定)。一般的程序设计语言的典型静态语义包括声明和类型检查。由语义分析程序计算的额外信息(诸如数据类型)被称为属性(attribute),它们通常是作为注释或"装 饰"增加到树中(还可将属性添加到符号表中)。在正运行的C表达式 a [index] = 4 + 2 中,该行分析之前收集的典型类型信息可能是:a是一个整型值的数组,它带有来自整型子范围的下标;index则是一个整型变量。接着,语义分析程序将用所有的子表达式类型来标注语法树,并检查赋值是否使这些类型有意义了,如若没有,则声明一个类型匹配错误。在上例中, 所有的类型均有意义,有关语法树的语义分析结果可用以下注释了的树来表示。

    折叠优化程序

    优化程序(source code optimizer):编译器通常包括许多代码改进或优化步骤。绝大多数最早的优化步骤是在语义分析之后完 成的,而此时代码改进可能只依赖于源代码。这种可能性是通过将这一操作提供为编译过程中的单独阶段指出的。每个编译器不论在已完成的优化种类方面还是在优化阶段的定位中都有很大的差异。在上例中,我们包括了一个源代码层次的优化机会,也就是:表达式4 + 2可由编译器计算先得到结果6 (这种优化称为常量合并(constant folding ))。当然,还会有更复杂的情况。还是在上例中,通过将根节点右面的子树合并为它的常量值,这个优化就可以直接在(注释)语法树上完成:尽管许多优化可以直接在树上完成,但是在很多情况下,优化接近于汇编代码线性化形式的树更为简便。这样节点的变形有许多,但是三元式代码(three-address code )(之所以这样称呼是因为它在存储器中包含了3个(或3个以上)位置的地址)却是标准选择。另一个常见的选 择是P -代码(P - code ),它常用于Pascal编译器中。在前面的例子中,原先的C表达式的三元式代码应是:t = 4 + 2 a [ index] = t (请注意,这里利用了一个额外的临时变量t 存放加法的中间值)。这样,优化程序就将这个代码改进为两步。首先计算加法的结果:t = 6 a [index] = t 接着,将t替换为该值以得到三元语句 a [index] = 6 ,指出源代码优化程序可能通过将其输出称为中间代码(intermediate code )来使用三元式代码。中间代码一直是指一种位于源代码和目标代码(例如三元式代码或类似的线性表示)之间的代码表示形式。但是,我们可以更概括地认为它是编译器使用的源代码的任何一个内部表示。此时,也可将语法树称作中间代码,源代码优化程序则确实能继续在其输出中使用这个表示。有时,这个中间代码也称作中间表示(intermediate representation,IR)。

    折叠代码生成

    代码生成(code generator):代码生成器得到中间代码(IR),并生成目标机器的代码。正是在编译的这个阶段中,目标机器的特性成为了主要因素。当它存在于目标机器时,使用指令不仅是必须的而且数据的形式表示也起着重要的作用。例如,整型数据类型的变量和浮点数据类型的变量在存储器中所占的字节数或字数也很重要。在上面的示例中,现在必须决定怎样存储整型数来为数组索引生成代码。例如,下面是所给表达式的一个可能的样本代码序列(在假设的汇编语言中):

    M O V R0,index ;;

    value of index -> R0 M U L R0,2 ;;

    double value in R0 M O V R1,&a ;;

    address of a -> R1 A D D R1,R0 ;;

    add R0 to R1 M O V *R1,6 ;;

    constant 6 -> address in R1

    在以上代码中,为编址模式使用了一个类似C的协定,因此& a是a的地址(也就是数组的基地址),* R1则意味着间接寄存器地址(因此最后一条指令将值6存放在R1包含的地址中)。这个代码还假设机器执行字节编址,并且整型数占据存储器的两个字节(所以在第2条指令中用2作为乘数)。

    折叠目标代码

    目标代码(target code optimizer ):在这个阶段中,编译器尝试着改进由代码生成器生成的目标代码。这种改进包括选择编址模式以提高性能、将速度慢的指令更换成速度快的,以及删除多余的操作。在上面给出的样本目标代码中,还可以做许多更改:在第2条指令中,利用移位指令替代乘法(通常地,乘法很费时间),还可以使用更有效的编址模式(例如用索引地址来执行数组 存储)。使用了这两种优化后,目标代码就变成:

    MOV R0,index ;;

    value of index -> R0 SHL R0 ;;

    double value in R0 MOV &a[R0],6 ;;

    constant 6 -> address a + R0

    到这里就是编译原理的简要描述,但还应特别强调编译器在其结构细节上差别很大。

    折叠编辑本段数据结构

    编译原理一直是计算机学习的必修课.

    当然,由编译器的阶段使用的算法与支持这些阶段的数据结构之间的交互是非常强大的。编译器的编写者尽可能有效实施这些方法且不引起复杂性。理想的情况是:与程序大小成线性比例的时间内编译器,换言之就是,在0 ( n )时间内,n是程序大小的度量(通常是字符数)。本节将讲述一些主要的数据结构,它们是其操作部分阶段所需要的,并用来在阶段中交流信息。

    折叠记号

    记号(token):当扫描程序将字符收集到一个记号中时,它通常是以符号表示这个记号;这也就是说,作为一个枚举数据类型的值来表示源程序的记号集。有时还必须保留字符串本身或由此派生出的其他信息(例如:与标识符记号相关的名字或数字记号值)。在大多数语言中,扫描程序一次只需要生成一个记号(这称为单符号先行(single symbol lookahead))。在这种情况下,可以用全程变量放置记号信息;而在别的情况(最为明显的是FORTRAN)下,则可能会需要一个记号数组。

    折叠语法树

    语法树(syntax tree):如果分析程序确实生成了语法树,它的构造通常为基于指针的标准结构,在进行分析时动态分配该结构,则整棵树可作为一个指向根节点的单个变量保存。结构中的每一个节点都是一个记录,它的域表示由分析程序和之后的语义分析程序收集的信息。例如,一个表达式的数据类型可作为表达式的语法树节点中的域。有时为了节省空间,这些域也是动态分配或存放在诸如符号表的其他数据结构中,这样就可以有选择地进行分配和释放。实际上,根据它所表示的语言结构的类型(例如:表达式节点对于语句节点或声明节点都有不同的要求),每一个语法树节点本身都可能要求存储不同的属性。在这种情况下,可由不同的记录表示语法树中的每个节点,每个节点类型只包含与本身相关的信息。

    折叠符号表

    符号表(symbol table):这个数据结构中的信息与标识符有关:函数、变量、常量以及数据类型。符号表几乎与编译器的所有阶段交互:扫描程序、分析程序或将标识符输入到表格中的语义分析程序;语义分析程序将增加数据类型和其他信息;优化阶段和代码生成阶段也将利用由符号表提供的信息选 出恰当的代码。因为对符号表的访问如此频繁,所以插入、删除和访问操作都必须比常规操作更有效。尽管可以使用各种树的结构,但杂凑表却是达到这一要求的标准数据结构。有时在一个列表或栈中可使用若干个表格。

    折叠常数表

    常数表(literal table):常数表的功能是存放在程序中用到的常量和字符串,因此快速插入和查找在常数表中也十分重要。但是,在其中却无需删除,这是因为它的数据全程应用于程序而且常量或字符串在该表中只出现一次。通过允许重复使用常量和字符串,常数表对于缩小程序在存储器中的大小显得非常重要。在代码生成器中也需要常数表来构造用于常数和在目标代码文件中输入数据定义的符号地址。

    折叠中间代码

    中间代码(intermediate code):根据中间代码的类型(例如三元式代码和P -代码)和优化的类型,该代码可以是文本串的数组、临时文本文件或是结构的连接列表。对于进行复杂优化的编译器,应特别注意选择允许简单重组的表示。

    折叠临时文件

    临时文件(temporary file):计算机过去一直未能在编译器时将整个程序保留在存储器中。这一问题已经通过使用临时文件来保存翻译时中间步骤的结果或通过"匆忙地"编译(也就是只保留源程序早期部分的足够信息用以处理翻译)解决了。存储器的限制现在也只是一个小问题了,现在可以将整个编译单元放在存储器之中,特别是在可以分别编译的语言中时。但是偶尔还是会发现需要在某些运行步骤中生成中间文件。其中典型的是代码生成时需要反填(backpatch)地址。例如,当翻译如下的条件语句时 if x = 0 then ... else ... 在知道else部分代码的位置之前必须由文本跳到else部分:

    CMP X,0 JNE NEXT ;;

    location of NEXT not yet known < code for then-part > NEXT : < code for else-part >

    通常,必须为NEXT的值留出一个空格,一旦知道该值后就会将该空格填上,利用临时文件可以很容易地做到这一点。

    如果想利用上面的编译原理开发一套属于自己的编程语言,或者想在一个产品中嵌入编程语言,可以参考zengl开源网开发的zengl编程语言,该编程语言为国人使用C语言开发,里面包含两个部分,一个是编译器,一个是解释执行中间代码的虚拟机。编译器包含了词法扫描,语法分析,中间代码输出等,虚拟机则类似JAVA一样解释执行中间代码。作者将所有的版本都公布出来,好让读者可以由浅入深的做研究,并且为了证明该编程语言的实用性,还结合SDL游戏开发库开发了一款图形界面和命令行界面的21点扑克小游戏 。

    zengl编程语言目前适用平台为windows和linux (最开始在Linux下使用gcc开发,后来移植到windows平台)

    折叠编辑本段其他问题

    可从许多不同的角度来观察编译器的结构,还有其他一些可能的观点:编译器的物理结构、操作的顺序等等。由于编译器的结构对其可靠性、有效性、可用性以及可维护性都有很大的影响,所以编译器的编写者应熟悉尽可能多的有关编译器结构的观点。

    折叠分析和综合

    在这个观点中,已将分析源程序以计算其特性的编译器操作归为编译器的分析(analysis) 部分,而将生成翻译代码时所涉及到的操作称作编译器的综合(synthesis )部分。当然,词法分析、语法分析和语义分析均属于分析部分,而代码生成却是综合部分。在优化步骤中,分析和综合都有。分析正趋向于易懂和更具有数学性,而综合则要求更深的专业技术。因此,将分析步骤和综合步骤两者区分开来以便发生变化时互不影响是很有用的。

    折叠前端和后端

    本观点认为,将编译器分成了只依赖于源语言(前端(front end ))的操作和只依赖于目标语言(后端(back end ))的操作两部分。这与将其分成分析和综合两部分是类似的:扫描程序、分析程序和语义分析程序是前端,代码生成器是后端。但是一些优化分析可以依赖于目标语言,这样就是属于后端了,然而中间代码的综合却经常与目标语言无关,因此也就属于前端了。在理想情况下,编译器被严格地分成这两部分,而中间表示则作为其间的交流媒介。这一结构对于编译器的可移植性(portability)十分重要,此时设计的编译器既能改变源代码(它涉及到重写前端),又能改变目标代码(它还涉及到重写后端)。在实际中,这是很难 做到的,而且称作可移植的编译器仍旧依赖于源语言和目标语言。其部分原因是程序设计语言和机器构造的快速发展以及根本性的变化,但是有效地保持移植一个新的目标语言所需的信息 或使数据结构普遍地适合改变为一个新的源语言所需的信息却十分困难。然而人们不断分离前端和后端的努力会带来更方便的可移植性。

    折叠

    编译器发现,在生成代码之前多次处理整个源程序很方便。这些重复就是( pass)。首遍是从源中构造一个语法树或中间代码,在它之后的遍是由处理中间表示、向它增加信息、更换结构或生成不同的表示组成。遍可以和阶段相应,也可无关-遍中通常含有若干个阶段。实际上,根据语言的不同,编译器可以是一遍(one pass )-所有的阶段由一遍完成,其结果是编译得很好,但(通常)代码却不太有效。Pascal语言和C 语言均允许单遍编译。(Modula - 2语言的结构则要求编译器至少有两遍)。大多数带有优化的编译器都需要超过一遍:典型的安排是将一遍用于扫描和分析,将另一遍用于语义分析和源代码层优化,第3遍用于代 码生成和目标层的优化。更深层的优化则可能需要更多的遍:5遍、6遍、甚至8遍都是可能的。

    折叠语言定义和编译器

    程序设计语言的词法和语法结构通常用形式的术语指定,并使用正则表达式和上下文无关文法。但是,程序设计语言的语义通常仍然是由英语(或其他的自然语言)描述的。这些描述(与形式的词法及语法结构一起)一般是集中在一个语言参考手册(language reference manual )或语言定义(language definition)之中。因为编译器的编写者掌握的技术对于语言的定义有很大的影响,所以在使用了一种新的语言之后,语言的定义和编译器同时也能够得到开发。类似地,一种语言的定义对于构造编译器所需的技术也有很 大的关系。编译器的编写者更经常遇到的情况是:正在实现的语言是众所周知的并已有了语言定义。有时这个语言定义已达到了某个语言标准(language standard )的层次,语言标准是指得到诸如美国国家标准协会(American National Standards Institute ,ANSI )或国际标准化组织 (International Organization for Standardization,ISO )的官方标准组织批准的标准。FORTRAN、 Pascal和C语言就具有ANSI标准,Ada有一个通过了美国政府批准的标准。在这种情况下,编译器的编写者必须解释语言的定义并执行符合语言定义的编译器。通常做到这一点并不容易, 但是有时由于有了标准测试程序集(测试组(test suite )),就能够测试编译器(Ada有这样一个测试组),这又变得简单起来了。有时候,一种语言可从数学术语的形式定义(formal definition )中得到它的语义。现在人们已经使用了许多方法,尽管一个称作表示语义(denotational semantics )的方法已经成为较为常用的方法,在函数编程共同体中尤为如此,但现在仍然没有一种可成为标准的方法。当语言有一个形式定义时,那么在理论上就有可能给出编译器与该定义一致的数学证明,但是由于这太难了,而几乎从未有人做过。无论怎样, 运行时环境的结构和行为是尤其受到语言定义影响的编译器构造的一个方面。

    展开全文
  •  静态语义错误: 可被编译器发现的语法错误,比如 (5+6(); 这种在编译器编译的时候就会被发现的语法错误;   #include<iostream> using namespace std; int main() { in...
  • 《现代编译原理:C语言描述(英文版)(本科)》全面讲述了现代编译器的各个组成部分,包括:词法分析、语法分析、抽象语法、语义检查、中间代码表示、指令选择、数据流分析、寄存器分配以及运行时系统等。与大多数编译...
  • 编译流程 1、预处理(Preprocessing) 完成宏替换、文件引入,以及去除空行、注释等,为下一步的编译做准备。 $ gcc -E test.c -o test.i -E让gcc在预处理结束后停止编译,test.i 为预处理后的输出文件。-o:指定...
  • 编译原理全套

    2011-12-03 11:17:21
    6.3.2 有过程嵌套的静态作用域 6.3.3 动态作用域 6.4 参数传递 6.4.1值调用 6.4.2 引用调用 6.4.3 复写-恢复调用 6.4.4 换名调用 第7章 中间代码生成 7.1 中间语言 7.1.1 后缀表示 7.1.2 图形表示 7.1.3 三...
  • java编译原理

    千次阅读 2018-03-27 16:47:31
    4.Java编译原理1.javac是什么?(1)javac是一种编译器,能够将一种语言规范转换成另一种用语言规范,通常编译器是将便于人们理解的语言规范成机器容易理解的语言规范。(2)javac的任务就是将java源代码语言转换成jvm...
  • Javac编译原理

    千次阅读 2017-02-25 17:24:17
    Javac编译原理 转载来源:http://www.cnblogs.com/wade-luffy/p/5925728.html 1概述   java源代码(符合语言规范)-->javac-->.class(二进制文件)-->jvm-->机器语言(不同平台不同种类) 如何让java的语法规则...
  • 编译原理学习基本概念汇总

    千次阅读 多人点赞 2015-07-22 14:04:10
    对于计算机专业的学生来说,肯定听说过或者上过一门课,叫做——编译原理,被称为计算机专业的天书,反正不管是学习这门课的时候,还是现在,我都是没搞懂其中的技术和知识。但就期末考试而言,提前做了几道题目,...
  • 编译原理】引论

    千次阅读 2020-02-18 20:59:54
    文章目录编译原理引论(一)认识编译程序(二)编译过程概述1、阶段划分2、编译程序的结构3、编译程序的生成 编译原理引论 (一)认识编译程序 什么是编译程序? 这要从翻译程序、解释程序以及编译程序的联系与区别...
  • 《现代编译原理:C语言描述》全面讲述了现代编译器的各个组成部分,包括词法分析、语法分析、抽象语法、语义检查、中间代码表示、指令选择、数据流分析、寄存器分配以及运行时系统等。全书分成两部分,第一部分是编译...
  • 1、参考书籍:《编译原理》第三版 清华大学出版社 1、本文内容全部来源于开源社区 GitHub和以上博主的贡献,本文也免费开源(可能会存在问题,评论区等待大佬们的指正) 2、本文目的:开源共享 抛砖引玉 一起学习 3...
  • 编译原理最终复习

    千次阅读 2017-12-30 20:00:56
    编译原理最终复习@(Campus_learning)第一章 引论 编译与汇编的区别 编译:高级语言翻译成机器语言或者汇编语言 汇编:汇编语言到机器语言 一般一段高级语言需要经历以下四个阶段才能够使用: 预处理器→编译器→...
  • 编译原理:总结

    万次阅读 多人点赞 2019-01-08 09:34:59
    类型错误(声明void f()和调用aa = f()) 逻辑:无限循环/递归调用( == → = ) 错误处理目标 清楚、准确地检测、报告错误及其发生位置 快速恢复,继续编译,以便发现后续错误 不能对正确程序的编译速度造成很大影响 ...
  • 编译原理 总结

    万次阅读 多人点赞 2015-03-26 17:36:07
    一、 编译程序1、 编译器是一种翻译程序,它用于将源语言(即用某种程序设计语言写成的)程序翻译为目标语言(即用二进制数表示的伪机器代码写成的)程序。后者在windows操作系统平台下,其文件的扩展名通常为.obj。...
  • 《现代编译原理:C语言描述》全面讲述了现代编译器的各个组成部分,包括词法分析、语法分析、抽象语法、语义检查、中间代码表示、指令选择、数据流分析、寄存器分配以及运行时系统等。全书分成两部分,第一部分是...
  • 《现代编译原理:C语言描述(英文版)(本科)》全面讲述了现代编译器的各个组成部分,包括:词法分析、语法分析、抽象语法、语义检查、中间代码表示、指令选择、数据流分析、寄存器分配以及运行时系统等。与大多数编译...
  • 《现代编译原理:C语言描述》全面讲述了现代编译器的各个组成部分,包括词法分析、语法分析、抽象语法、语义检查、中间代码表示、指令选择、数据流分析、寄存器分配以及运行时系统等。全书分成两部分,第一部分是编译...
  • Android系统编译原理

    千次阅读 2017-01-20 11:41:31
    Android系统编译原理 [1] 历史  2003年Android公司成立,系统开发  2005年Android被google收购  2007年11月5日,google公司推动成立手机开发联盟(HAL)  2008年9月Android 1.0正式发布,HTC G1使用   ...
  • Linux C编译原理

    千次阅读 2018-09-28 22:11:17
    1.编译程序:把一种语言(源语言---高级语言)转换成另一种语言(目标语言---低级语言--&gt; 汇编或机器语言)。 2.词法分析:对输入的字符串进行扫描和分解,识别出一个个字符及其数据类型; 3.语法分析:对...
  • 部分是编译的基础知识,适用于第一门编译原理课程(一个学期);第二部分是高级主题,包括面向 对象语言和函数语言、垃圾收集、循环优化、SSA(静态单赋值)形式、循环调度、存储结构优化等 ,适合于后续课程或研究生...
  • 编译原理第三版答案

    万次阅读 多人点赞 2018-12-19 21:21:23
    答:编译程序主要由以下几个部分组成:词法分析、语法分析、语义分析、中间代码生成、中间代码优化、目标代码生成、错误处理、表格管理。 2. 实现编译程序的主要方法有哪些? 答:主要有:转换法、移植法、自展法...
  • 编译原理复习笔记

    千次阅读 2018-03-04 23:19:21
    第一章 编译引论1、编译程序:将某一种程序设计语言写的程序翻译成等价的另一种语言的程序的程序2、源语言:用来编写源程序的语言(汇编,高级程序设计语言)3、源程序:用源语言写的程序4、目标语言:目标程序描述...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 83,643
精华内容 33,457
关键字:

编译原理静态检查