文章目录
一、程序设计语言发展及其高级语言
1.1 程序设计语言的发展
-
机器语言
- 20世纪40年代,第一台电子计算机ENIAC
- 使用0、1序列组成的机器语言编程,有自己的指令系统,可以实现寄存器左移、寄存器右移、寄存器跳转
- [操作码,地址码]
-
汇编语言
- 20世纪50年代,人们对助记汇编语言的开发
- 将一些硬件指令用一些助记符表示,即符号化的机器语言,如"ADD, MOV"
- 用助记符(Memoni)代替操作码,用地址符号(Symbol)或标号(Label)代替地址码,如ADD表示加法操作,SUB表示减法操作等。
- 但是汇编语言对于计算机使用者而言门槛过高,需要了解计算机内部结构
-
高级语言
- 是相对于低级语言而言的,它是较接近自然语言和数学公式的编程语言。它用人们更容易理解的方式编写程序。
- 如Fortran,C++,java,C#,pascal等
但是计算机只能识别机器语言,那么高级语言是如何在计算机上运行的呢?
1.2 高级语言的实现
1、编译方式:源语言为高级语言,目标语言是低级语言(汇编或机器语言)的翻译程序。
如C++,GO等
2、解释方式:一边翻译一边执行,翻译完的同时也执行完了程序。
如python,java等
3、转换方式
是一种变通的方式,假如已有B语言的编译器就,可以把A语言程序转换为B语言程序,用B语言已有的编译器去编译执行。
1.3 编译器和解释器的比较
二、编译程序的组成
2.1 编译程序的前端与后端
到现在为止,我们把编译器看作一个黑盒子,它能够把源程序映射为在语义上等价的目标程序。如果把这个盒子稍微打开一点,我们就会看到这个映射过程由两个部分组成:分析部分和综合部分。
**分析(anylasis)部分将源程序分解成多个组成要素,并在这些要素上加上语法结构。然后,使用这个结构来创建该源程序的一个中间表示。如果分析部分检查出源程序没有按照正确的语法构成,或者语义上不一致,它就必须提供有用的信息,使得用户可以按此进行改正。分析部分还会收集有关源程序的信息,并把信息存放在一个称为符号表(symbol table)**的数据结构中。符号表将和中间表示形式一起传送给综合部分。
**综合(synthesis)**部分根据中间表示和符号表中的信息来构造用户期待的目标程序。
分析(anylasis)部分通常被称为编译器的前端(front end)。综合(synthesis)部分称为后端(back end)。
编译程序通常分为如下多个步骤:
2.2 词法分析
编译器的第一个步骤称为词法分析(lexical analysis)或扫描(scanning)。
词法分析器读入字符流,将其组织成为有意义的词素(lexeme)序列。对于每个词素,词法分析器生成如下**词法单元(token)**作为输出:
<token-name, attribute-value>
token-name 是语法分析步骤使用的抽象符号,attribute-value 指向符号表中关于这个词法单元的条目。
符号表条目信息会被语义分析和代码生成步骤使用。
具体细节在词法分析章节展开。
2.3 语法分析
编译器的第二个步骤称为语法分析(syntax analysis)或解析(parse)。
语法分析器使用由词法分析器生成的各个词法单元的第一个分量来创建树形的中间表示。
该中间表示给出了词法分析产生的词法单元流的语法结构。一个常用的表示方法是语法树(syntax tree),树中的每个内部结点表示一个运算,而该结点的子结点表示该运算的分量。
2.4 语义分析
语义分析器(semantic analyzer)使用语法树和符号表中的信息来检查源程序是否和语言定义的语义一致。它同时也收集类型信息,并把这些信息存放在语法树或符号表中,以便在随后的中间代码生成过程中使用。
2.5 中间代码生成(非必要)
把一个源程序翻译成目标代码的过程中,一个编译器可能构造出一个或多个中间表示。
这些中间表示可以有多种形式,语法树是一种中间表示形式,通常在语法分析和语义分析中使用。
中间表示应该有两个重要的性质:
- 易于生成
- 能够被轻松翻译为目标机器上的语言
2.6 代码优化(非必要)
代码优化步骤试图改进中间代码,以便生成更好的目标代码。'更好”通常意味着更快,但是也可能会有其他目标,如更短的或能耗更低的目标代码。
不同的编译器所做的代码优化工作量相差很大。那些优化工作做得最多的编译器,即所谓的“优化编译器”,会在优化阶段花相当多的时间。有些简单的优化方法可以极大地提高目标程序的运行效率而不会过多降低编译的速度。
2.7 代码生成
代码生成器以源程序的中间表示形式作为输入,并把它映射到目标语言。如果目标语言是机器代码,那么就必须为程序使用的每个变量选择寄存器或内存位置。然后,中间指令被翻译成为能够完成相同任务的机器指令序列。代码生成的一个至关重要的方面是合理分配寄存器以存放变量的值。
2.8 表格管理
编译器的重要功能之一是记录源程序中使用的变量的名字,并收集和每个名字的各种属性有关的信息。
这些属性可以提供一个名字的存储分配、它的类型、作用域(即在程序的哪些地方可以使用这个名字的值)等信息。
对于过程名字,这些信息还包括:它的参数数量和类型、每个参数的传递方法(比如传值或传引用)以及返回类型。
符号表数据结构为每个变量名字创建了一个记录条目。记录的字段就是名字的各个属性。
这个数据结构应该允许编译器迅速查找到每个名字的记录,并向记录中快速存放和获取记录中的数据。
除了符号表,我们还会有语法信息表,类型信息表等。
为了合理的管理表格,设立一些专门子程序称为表格管理程序。
2.9 错误处理
当编译阶段有错误出现时由相应的错误处理模块给出解决方案,使得编译器能够继续进行下去
- 词法分析——词法错误
- 语法分析——语法错误
- 语义分析——语义错误
练习:
1、“用高级语言书写的源程序都必须通过编译,产生目标代码后才能投入运行。”这种说法正确与否?
不正确,实现高级语言的方式包括编译、解释和转换,所以用高级语言编写的源程序可以通过解释方式或转换方式来实现运行。
2、编译程序必须完成的工作有()。
① 词法分析 ② 语法分析 ③ 语义分析
④ 中间代码生成 ⑤ 中间代码优化 ⑥ 目标代码生成①②③⑥
中间代码生成是为了方便优化和移植
3、以下关于高级语言实现方式的说法中错误的是()。
编译方式与解释方式的根本区别在于是否生成目标代码,
编译方式对源程序的处理是先翻译后执行;
解释方式是按源程序中语句的动态顺序逐句地进行分析解释,并立即执行;
解释方式并不对源程序进行翻译D
解释方式也是需要翻译的,只不过是边翻译边执行,不生成目标程序。
D
解释方式也是需要翻译的,只不过是边翻译边执行,不生成目标程序。