第二章 程序语言基础知识
2.1 程序语言概述
2.1.1 程序语言的基本概念
- 低级语言和高级语言
- 低级语言
- 机器语言:由0、1组成的机器指令序列。
- 汇编语言:由容易记忆的符号表示的指令。
- 高级语言
- 面向各类应用的程序语言:如Java。此类语言和人类使用的自然语言比较接近。
- 编译程序和解释程序
- 汇编程序:将汇编语言翻译成目标程序。机器上运行的是目标程序。
- 编译程序:将高级语言翻译成目标程序,机器上运行的是目标程序。
- 解释程序:不生成独立的目标程序,机器上运行的是源程序(或其某种等价表示)和解释程序。
- 程序设计语言的定义
- 语法:指由程序语言的基本符号组成程序中的各个语言结构(包括程序)的规则。可用形式语言进行描述。
- 词法规则:由基本字符构成的符号(单词)书写规则。
- 语法规则:由符号构成语法成分的规则。
- 语义:指程序语言中按语法规则构成的各个语法成分的含义。
- 静态语义:指编译时可以确定的含义。
- 动态语义:指运行时才能确定的含义。
- 语用:表示构成语言的各个记号和使用者的关系,涉及符号的来源、使用和影响。
- 程序设计语言的分类
- 命令式和结构化程序设计语言:基于动作的语言,计算被看成是动作的序列。如C语言。
- 面向对象的程序设计语言:抽象机制不断提高。如Java。
- 函数式程序设计语言:函数是一种对应规则(映射),使定义域中每个元素和值域中唯一的元素相对应。如LISP。
- 逻辑型程序设计语言:以形式逻辑为基础。适用于书写自动定理证明、专家系统和自然语言理解等问题的系统,如Prolog。
2.1.2 程序语言的基本成分
- 数据成分
- 数据成分:指其程序中的数据对象,数据是程序操作的对象。
- 数据的属性
- 存储类别:说明数据在内存中的位置和生存期。
- 类型:说明数据占用内存的大小和存放形式。
- 名称:由用户通过标识符命名。
- 作用域:说明可以使用数据的代码范围。
- 生存期:说明数据占用内存的时间范围。
- 数据的分类
-
按程序运行时数据的值能否改变:常量和变量。
-
按数据的作用域范围:全局变量和局部变量。
-
按数据组织形式的不同:
基本类型:整型(int)、字符型(char)、实型(float、double)、布尔类型(bool)。
特殊类型:空类型(void)。
用户定义类型:枚举类型(enum)。
构造类型:数组、结构、联合。
指针类型:type *。
抽象数据类型:类。
-
- 运算成分
- 运算成分:指明语言允许使用的运算符号及运算规则。
- 基本运算:算术运算、关系运算和逻辑运算,有些语言如C/C++还提供位运算。
- 运算符号的使用与数据类型密切相关。为了明确结果,运算符号要规定优先级和结合性,必要时还要使用圆括号。
- 控制成分
- 控制成分:指明语言允许表述的控制结构。
- 三种控制结构:
- 顺序结构。
- 选择结构。
- 循环结构,包括初始化、循环体和循环条件。
- 传输成分
- 传输成分:指明语言允许的数据传输方式。
- 数据传输方式:如赋值处理、数据的输入和输出等。
- 函数
-
函数:是一段具有独立功能的程序代码。
- C程序由一个或多个函数组成,每个函数都有一个名字,其中有且仅有一个名为
main
的函数,作为程序运行时的起点。
- C程序由一个或多个函数组成,每个函数都有一个名字,其中有且仅有一个名为
-
函数的使用涉及三个概念:函数定义、函数声明和函数调用。
- 函数定义:函数首部和函数体。
返回值类型 函数名(形式参数列表){ 函数体; }
- 函数声明:先声明后使用,声明函数使用函数原型。
返回值类型 函数名(参数类型列表);
- 函数调用:需要知道被调函数的名字、返回值和需要向被调函数传递的参数(个数、类型、顺序)。
函数名(实参列表);
递归调用:指函数自己调用自己。
- 函数定义:函数首部和函数体。
-
调用函数和被调函数之间交换信息的方法
- 值调用(Call by value):实参给形参传递相应类型值的副本,形参不能向实参传递信息。
- 引用调用(Call by Reference):形参实际上是实参的别名,对形参的访问实际上就是对实参的访问。
2.2 程序语言翻译基础
2.2.1 汇编程序基本原理
- 汇编语言
- 含义:用汇编语言编写的程序。
- 分类
-
指令语句:将其汇编后能产生相应的机器代码,如ADD、SUB和AND等。
指令语句可分为:传送指令、算术运算指令、逻辑运算指令、移位指令、转移指令和处理机控制指令。
-
伪指令语句:指示汇编程序在汇编源程序时完成某些工作,如给某变量分配存储单元、给某个符号赋值等。
伪指令与指令的区别:伪指令经汇编后不产生机器代码;伪指令所指示的操作在编译时完成,指令在运行时完成。
-
宏指令语句:允许用户将多次重复使用的程序段定义为宏。宏指令语句就是宏的引用。
-
- 汇编程序
- 功能:将汇编语言所编写的源程序翻译成机器指令程序。
- 汇编过程:两次扫描。
-
第一次扫描:定义符号的值并创建一个符号表ST,ST记录汇编时所遇到的符号的值。
固定的机器指令表MOT1:记录每条指令的记忆码和指令的长度。
位置计数器或单元地址计数器LC:是下一条被汇编的指令的偏移地址。
伪指令表POT1:伪指令助记符和相应的子程序入口。
-
第二次扫描:产生目标程序,将机器指令助记符转换为二进制机器指令操作码,求出操作数区各操作数的值。
机器指令表MOT2:机器指令助记符、机器指令的二进制操作码、格式和长度。
伪指令表POT2:伪指令助记符和相应的子程序入口,与第一次扫描的不同之处:对伪指令有不同的处理。
-
2.2.2 编译程序基本原理
- 编译过程概述
- 编译程序作用:把用某高级语言编写的源程序翻译成与之等价的目标程序(汇编语言或机器语言形式)。
- 编译程序工作过程
-
词法分析:对源程序从前到后(从左到右)逐个字符地扫描,从中识别除=出一个个"单词"符号。
"单词"符号:如关键字、标识符、常数、运算符和分隔符(标点符号、左右括号等)。
如 X := Y + Z * 60,经过词法分析和语法分析后表示为id1 := id2 + id3 * 60。
-
语法分析:将单词符号序列分解成各类语法单位,如"表达式"、“语句”、"程序"等。(可构造出语法树)
-
语义分析:检查源程序是否包含静态语义错误,并收集类型信息供后面的代码生成阶段使用。
语义分析一个重要工作是进行类型分析和检查。
程序语言中的一个数据类型一般包含两个方面的内容:类型的载体及其上的运算。
-
中间代码生成:与具体的机器无关,常用三地址码,实现方式采用四元式(运算符,运算对象1,运算对象2,运算结果)。
-
代码优化:可在中间代码生成阶段(优化控制流和数据流)进行,也可在目标代码生成阶段进行。
-
目标代码生成:与具体的机器密切相关。
-
符号表管理
作用:记录源程序中各符号的必要信息,以辅助语义的正确性检查和代码生成。
建立:可始于词法分析阶段,也可放到语法分析和语义分析阶段。
使用:有时会延迟到目标代码的运行阶段。
-
出错处理
静态语义错误:编译程序时发现,分为语法错误和静态语义错误。
① 语法错误:如单词拼写错误、标点符号错误、表达式中缺少操作数、括号不匹配等有关语言结构上的错误。
② 静态语义错误:如语义分析时发现运算符与运算对象类型不合法等错误。动态语义错误:程序运行时发现,例如变量取零时作除数、引用数组元素下标错误等。
-
- 文法和语言的形式描述
- 语言:是有限字母表Σ上有限长度字符串的集合,这个集合中的字符串是按照一定规则生成的。
- 文法:描述语言语法结构的形式规则称为文法。
- 词法分析
- 词法分析任务
- 语言中具有独立含义的最小语法单位是符号(单词),如标识符、无符号常数与界限符等。
- 词法分析就是将构成源程序的字符串转换成单词符号序列。
- 语法分析
- 语法分析任务
- 分析单词串是否构成短语和句子,即是否为合法的表达式、语句和程序等基本语言结构;
- 同时检查和处理程序中的语法错误。
- 程序设计语言的绝大多数语法规则可以采用上下文无关法进行描述。
- 语法制导翻译和中间代码生成
- 语法制导翻译
- 程序语言的语义分为静态语义和动态语义。
- 描述程序语义的形式化方法主要有属性文法、公理语义、操作语义和指称语义等。属性文法是对上下文无关文法的扩充。
- 目前应用最广泛的静态语义分析方法是语法制导翻译。
- 中间代码的表示形式
- 后缀式(逆波兰式),适合解释器。
- 树形表示,适合解释器。
- 四元表达式,适合编译器。
- 中间代码优化和目标代码生成
- 代码生成所需考虑的问题
- 中间代码形式。
- 目标代码形式:汇编语言形式和机器指令形式(又分绝对定位机器指令代码和可再定位机器指令代码)。
- 寄存器的分配。
- 计算次序的选择。
2.2.3 解释程序基本原理
- 解释程序的基本结构
- 分析部分:词法分析、语法分析、语义分析,生成中间代码(常用逆波兰形式表示)。
- 解释部分:对分析部分产生的中间代码进行解释执行。由两部分构成:
- 程序计数器PC。
- 保存了源程序中间代码和解释部分各子程序的内存MEM。
- 编译与解释方式的比较
- 效率:编译 > 解释。一次翻译可多次运行。
- 灵活性:解释 > 编译。反复扫描使得"在运行中"修改程序成为可能。
- 可移植性:解释 > 编译。解释器也是程序语言编写的,只要重新编译解释器,就可使其运行在不同环境中。