走进编译的世界(编译原理0-0)



人与人交流离不开语言, 什么是语言? 什么是程序设计语言?

编程语言属于形式语言, 这又不得不提到chomsky


我们今天讨论的话题是编译器或者说是语言处理器更准确一些


一 什么是语言处理器?

        我所见到的就是这些框框了

        1.编译器

        2.解释器(java虚拟机也是解释器)

        3.编译器+解释器(混合型hybrd)

        编译器编译后的目标程序, 并不一定是可执行程序; 解释器就如一个高级的处理器, 它能理解复杂的源程序,

        直接去执行程序, 但它的内部做了很多与编译器相同的工作, 而且最终还要用真正的机器指令去执行, 这也

        使得解释程序一般较编译程序运行的更慢, 但它非常灵活, 实时性高

        明白它们的特点是重要的, 由于侧重点不同, 在不同场合叫法可能不同



         

             大家看图思考编译器和解释器各有什么优缺点?

二 它干了什么呢?

         目前能看到的, 也就是:

         1.将源程序翻译为目标程序

         2.将源程序直接执行, 完成我们部署的任务


三 一个典型且完整的语言处理系统

         未必所有的语言处理器都是这样的结构, 因为这都是人造的. 随着计算机技术的发展一些概念是演变的, 抓住重点是关键




          1. 其中的各个模块都做了什么呢?

              <1>. 预处理器: 一个源程序可能被分为多个不同的模块, 并存放在不同的文件中, 它的一个作用就是将源程序聚合在一起.

                                         在C/C++中它还负责处理预处理指令, 就是#开头的东西.

                                         但它一般不会将源程序转换为一种中间形式(特点)

             <2>. 编译器: 编译器会接受预处理后的源程序(预处理器处理了它不认识的东西), 产生一个目标程序作为输出

             <3>. 汇编器: 接收特定的汇编程序, 然后产生特定机器代码;

                                    这里的汇编指令(真指令)和机器指令是对应的, 可以说汇编器是最早的编译器类型.

                                    人们通常把这组指令的集合, 称做指令集(RISC,CISC)

                                    它是软硬件的接口, 任何需要软件支持的机器生产出来, 都一定定义一套指令集.

            <4>. 连接器: 它能够解决外部内存地址问题.

                                   这不得不说汇编器产生的可重定位机器代码,

                                   这里的可重定位是指某些汇编程序定义的内存区 (数据区, 文本区, Bss区<Block Started by Symbol) 的地址需要重新安排.

            <5>. 加载器: 把可执行文件放到内存中执行

        2. 语言处理系统为什么要这样划分模块呢?

             为了好实现它啊. 为了组件的重用啊. 等等的我就不知道了...

             随着计算机的发展, 各种体系的处理器被生产出来, 各种语言被发明出来, 软件危机后软件工程的革命. 让这种方法成为必然.

             就如独立的汇编器, 可以为不同语言所共用, 人们就不用再重复的实现一种东西了

             这种独立允许一对多, 多对一的映射, 这是非常灵活的

            

四 更进一步

       这个图反应了一般编译器的各个阶段.


           1. 词法分析: 将一个个字符(有限集 & 需要处理编码格式)比喻为描述一个人的特点的集合(发型, 五官 ...),

                                 在这里就是一个组成词法单元(token)的必要元素, 它是独立的, 简单的理解就是一个字符;

                                 它看到所有特点以后就能确定这个人是谁了(词法单元token), 如果不认识这个人, 那么就报错(不过这似乎不容易发生, 思考为什么).

                                 词法单元是一个无限的集合(所有字符的任意组合),怎样用有限的东西描述无限的东西?


           2. 语法分析: 它只认识词法单元流, 只认识每个人, 你拿来他的衣服, 它不知道是谁的. 它会分析这群人是不是按照它要求组织的,

                                 如, 列队必须从左到右从高到低排列,  你不这样排列它就会告诉你这样不行;语法规定了源程序的组织方法,

                                 同样程序的集合是无限的, 自然语法也是一个无限的集合


           3. 语义分析: 顾名思义, 分析这群人要干嘛? 有什么要求? 如, 男女面对面站, 哦你们几个要结婚啊!


           4. 中间代码生成器: 知道了你们什么意思, 那我们(编译器)也没钱啊! 不过我们就是给你们传话的, 但这个最有资本的厉害家伙(处理器)

                                只能明白几句话(指令集), 而且很忙! 说厉害其实最傻逼, 你说什么它做什么, 所以一定要把话说的简练. 不然就给你

                                浪费时间. 所以为了说好话就生成一个好处理的话(ps:这说的什么话啊). 中间代码生成器就做了这个工作, 典型的有三地址代码,

                                这里的中间代码是与机器无关的, 有两个重要的性质: (1)易于生成 (2)能够方便的翻译为目标机器上的语言


           5. 机器无关代码优化器: 它就是让话说的更短更好, 但它不知道处理器理解那种话更快, 所以它不会管机器


           6. 代码生成器: 它负责将这些优化好的代码, 翻译成特定的处理器上的指令


           7. 机器相关代码优化: 这里在优化这些机器认识的指令


           8. 符号表: 它是记录程序中使用的变量的名字, 并在分析过程中收集名字的各种属性信息, 它是非常重要的, 它贯穿编译器的大部阶段

          

           看了这些, 一定了解了编译器还有两个重要的工作: (1)错误处理, (2)优化


           在这个过程中有三个分析(analysis)和中间代码生成, 把这称为编译器的前端(front end), 它们的工作完全何机器无关

           而综合(synthesis)是为了构造我们所要的目标程序, 被称为后端(back end)

           与机器无关的优化通常是加在编译器的前端与后端, 为了生成更好的目标代码

           前端是分析后端是综合分析的结果产生目标程序, 如果不做任何优化, 为前端优化生成的中间代码也不是必须的, 不过一般不会这么做

           编译器将优化看的很重要

           前面说的编译器的各个阶段是编译器的逻辑组织方式. 在一个特定的实现中, 多个阶段的活动可以被组合为一趟或叫一(pass).

           每遍读入一个输入文件产生一个输出文件(特点), 这便是pass的概念


五 我们常说的, 你理解吗?

    1.动静之别

      什么静态XX,动态XX;什么意思呢?

      为一个语言设计编译器时,我们有一个主要矛盾:编译器能够为一个程序做出那些判定

      如果一个语言使用的策略支持编译时(compile time)判定,那么我们就说这个语言的这个策略为静态策略(static)

      相反一个只允许在程序运行时(run time)才能确定的策略称为动态策略(dynamic)

      就像还在妈妈肚子里(编译时)的胎儿一样,他刚生下来(编译结束,就是这个点)就有一些确定的事实,大眼睛,双眼皮...

      这当然在妈妈肚子里的时候就决定了(编译时),我们就可以说决定眼睛的大小是静态策略,而这个孩子的性格我们

      还是不能直接看出的,这就看他走这一遭了(运行时),这里决定性格便是动态策略

      哎! 例子有些rubbish啊


    2.环境与状态

     

      这里的名字就是我们程序中的各种标识符,它是高级语言提供给我们的超级武器啊! 编译器为名字做了大量工作

     环境是一个名字内存位置(变量)的映射, 所谓变量其实是内存的抽象,我们平时说的变量其实是一个侧重的说法

      是命令式语言的特色,这样才有了副作用,左值之说(具体见从程序设计语言的发展谈起)

      环境是什么,龙书里这样说“环境的改变需遵循语言的作用域规则”,不同的作用域里可以有相同的名字,但环境会让他们

      找到自己的家

      状态是一个内存位置到他们的映射,用C语言的说法就是状态将左值映射为他们相应的右值

     

      了解了这些大家是否可以思考C中的值调用(call-by-value)/传值和引用调用(call-by-reference)/传址的区别了,wiki上有关与这些的讲解

   

    3.声明和定义

      声明是告诉我们名字的类型, 而定义告诉我们它的值

      int i = 1;

      int i; 是i的一个声明,  i = 1; 是i的一个定义(定值)

      同样函数什么都一样的道理

     

          转载请注明出处 哈喽易http://blog.csdn.net/openhfc   

          :这篇博文主要让大家对编译系统有一个感觉, 若文中存在任何不当之处, 希望大家指出

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值