编译的基本概念

编译器(compiler)可以将Java、C 这类的高级语言转换成计算机可以识别的机器语言
解释器(interpreter)根据用户的输入执行指定的操作

编译器组成

编译器内部可以分为分析(analysis)部分和 整合(synthesis) 两部分。

  • 分析过程把源程序分成多个结构,分别对其格式进行校验,如果违反语法格式则进行提醒。分析部分还会收集有关源程序的信息,会把收集到的信息存放在一个被称为符号表(symbol table) 的数据结构中。符号表和中间表示形式一起传给整合部分。
  • 整合过程是根据分析过程传递的信息来构造用户期待的目标程序。

分析和整合又被称为 前端(front end) 和 后端(back end)
在这里插入图片描述

词法分析

词法分析(Lexical Analyzer)是编译器的第一个步骤,它也被称为 扫描(scanning)。词法分析器通过读取源程序的字符流对其进行扫描,并且把它们组成有意义的词素(lexeme)序列,并产生词法单元(token) 作为输出,传递给语法分析。

词素是 Token 的实例,词法分析器的主要任务就是从源程序中读取字符并产生 token。token 的结构为<token-name, attribute-value>,token-name代表分析的抽象符号,attribute-value指向符号表中该条目的位置。

符号表能够记录源程序中使用变量的名称,并收集和每个名称相关的属性信息,例如变量的存储分配、类型、作用域,对于过程方法还有参数类型、传递方法、返回类型。符号表为每个变量创建一个记录条目,编译器可以迅速查找到记录并对其进行存取。

比如现在源程序中有一个赋值语句

income = mainjob + sideline;

首先,income 是一个词素,它会被映射为 <id,1>,其中 id 是表示的 标识符(identifier) 的抽象符号,而 1 指的是符号表中 income 在符号表中的条数。然后是赋值符号 = ,它也是一个词素,被映射称为 token 中的 < = >。这个 token 不需要属性值,所以没有第二个词
经过词法分析后,上面的源程序会变为

<id,1> < = > <id,2> < + > <id,3>
语法分析

语法分析(syntax analysis)又称为 解析(parsing)。语法分析器使用词法单元的第一个分量来创建树形的中间表示–语法树(syntax tree)。树中的每个非叶节点都表示一个运算,其左右子节点表示运算的分量。编译器的后续步骤都会使用这个语法结构来帮助分析源程序,并声称目标程序。

语义分析

语义分析是由 语义分析器(semantic analyzer) 完成的,它使用语法树和符号表中的信息来检查源程序是否和语言定义的语义一致。语义分析器也收集类型信息,并把这些信息放在语法树或者符号表中,以便后续的中间代码生成器使用。

语义分析一个最重要的功能就是类型检查(type checking),编译器会检查每个运算符是否具有匹配的运算分量。比如设计语言要求一个数组的下标是整数,如果你用浮点数座位下标,编译器就会出错。某些程序设计语言比如 Java 会允许自动类型转换,如果整数和浮点数进行运算,编译器会把整数转换为浮点数。

中间代码生成

在源程序的语法分析和语义分析完成后,很多编译器生成一个明确的低级类机器语言的中间表示。中间形式的代码应该具有两个重要的性质:易于生成,并且能够轻松的被翻译。例如三地址代码(three-address code)的中间表示形式,每个指令有三个运算分量,每个分量象一个寄存器。

代码优化

代码优化会试图改进代码以便生成更好的目标代码。更好通常情况下意味着更快、更短或能耗更低的目标代码。有些简单的优化方法可以提高程序的运行效率且不会降低编译速度。

代码生成

把生成的中间代码映射为目标语言。

如果目标语言是机器代码的话,则需要为每个变量分配寄存器或内存位置,并且将中间指令翻译成机器指令序列。
在这里插入图片描述

编译器构造工具

有一些专业的开发工具来实现编译器的不同阶段,这些工具使用专用的语言描述和实现了特定组件,这些组件中封装了相当复杂的算法过程,我们可以直接使用这些组件并且和编译器其他部分相集成。一些常用的编译器构造工具有:

  1. 语法分析器生成器:可以根据程序设计语言的语法描述自动生成语法分析器
  2. 扫描器生成器:可以根据一个语言的语法单元的正则描述生成词法分析器
  3. 语法制导的翻译引擎:用于生成一组遍历分析树并生成中间代码的例程
  4. 代码生成器的生成器:依据语言翻译规则,生成一个代码生成器
  5. 数据流分析引擎:收集数据流信息,分析程序中的值是如何从一部分传递到另一部分的,常用于代码优化
  6. 编译器构造工具:提供用于构造编译器不同阶段的例程

语言发展

  1. 一开始是机器语言,使用 0 、 1 组成的序列能够告诉计算机以什么样的顺序执行怎样的运算
  2. 后来使用汇编语言对机器语言进行助记,并使用宏指令来定义机器指令序列
  3. 高级程序设计语言:例如用于科学计算的 Fortran 被开发出来,用于商业处理的 Cobol 语言和用于符号计算的 Lisp 语言被开发出来;然后接下来的时间,慢慢很多编程语言被开发出来,比如 C、C++、Java、JavaScript、Python 等
  4. 为特定应用设计的语言,例如SQL

随着新语言的不断出现,编译器设计者一方面需要跟踪新的语言特征来翻译和支持新的语言;另一方面计算机体系结构也在不断更新,设计者需要设计相应的算法尽可能利用硬件能力,例如多核计算机的流行,编译器应当充分利用多处理器的优势 。

编译技术应用

1、设计和实现高级程序语言

2、优化计算机系统

现代高性能系统都采用了两种技术:并行和多级存储结构

并行

体现在多个层次,例如指令级并行、处理器级并行。

在指令级别上,编译器可以分析指令流之间的依赖关系,从而重新安排指令执行顺序,使得指令并发执行提高效率,而且这种操作对软件程序员来说是不可见的。

在处理器级别,除了程序员编写多线程代码外,还可以通过编译器生成并行代码来利用多处理器性能

多级内存结构

计算机的存储有CPU-寄存器-cache-内存-外部存储多级别构成,离cpu越近速度越快,但存储容量越小。在访存时提高对高速存储中的命中率有助于整体运行效率的提升。一般高速缓存由硬件自动管理,但是我们可以改变数据布局或访问顺序来提高内存层次的效率。

3、设计指令集

现如今最流行的体系结构是x86,它是基于复杂指令集系统(CISC)设计的,但是其开发的指令集系统越来越复杂,后来在编译器的设计阶段同时开发处理器,有了精简指令集(RISC)

4、程序翻译

实现在不同种类语言之间的翻译操作。

二进制翻译:把为一个机器生成的二进制代码翻译成另一个机器的。使其可以运行

硬件合成:大部分硬件设计也是使用高级硬件描述语言完成的,在寄存器传输层完成设计描述,进而翻译成门电路、晶体管,最后生成物理布局。

SQL解释器:数据库查询语言包含了关系和运算符的断言,它们可以被解释、编译为代码进而在数据库中搜索满足条件的记录

5、程序分析工具

设计一个数据流分析工具,对程序进行静态分析,找出所有可能带有错误的语句并做出提示。例如可以对程序中的变量进行类型检查、越界检查、内存管理

程序语言基础

静态与动态

编译器需要能够对程序作出判定,如果语言能够让编译器静态(非运行)时候决定某个问题,那么我们说这个语言使用了一种 静态(static) 策略,或者说能够在 编译时刻(compile time) 决定。如果让编译器在运行时决定某个策略,那么就是动态策略(dynamic policy),或者被认为是 运行时决定(run time)

如果能够通过阅读程序就能确定一个声明的作用域,那么这个语言就是静态作用域(static scope),或者说是 词法作用域(lexical scope)。否则这个语言使用的是 动态作用域(dynamic scope)

环境与状态

环境是指变量名字到内存位置的映射

状态是指内存位置到值的映射
在这里插入图片描述
名字到位置的映射分为静态绑定和动态绑定,如果能在非运行条件下唯一确定名字到位置,那么就是静态绑定,例如声明的全局变量;如果要在程序运行时才能确定名字和位置的绑定,那么就是动态绑定

静态作用域和块结构

大多数编程语言都有作用域,比如 Java 中的 private,protected,public 等关键字的使用,提供了有效的作用域控制。而且其作用域范围在程序未运行时就可以确定,因此是静态作用域。

块结构也是一种作用域,使用块结构表示的含义是在块内部(block) 作用范围有效,块使用 {} 来界定一个块。这种语法允许在任意函数或者方法的内部嵌入一个块,这种嵌套结构也被称为 块结构(block structure)。

参数传递

值传递

在值传递(call-by-value) 中,会对实参求值或拷贝,将值传递给形式参数的内存位置上,实参本身不会改变。

引用传递

在 引用传递(call-by-reference) 中,实际参数的地址被传递给调用者。在被调用者的代码中使用形式参数,实现方法是沿着这个指针找到调用者指明的内存位置。因此,改变实际参数相当于改变了形式参数。

过程化语言

过程化程序设计语言指需要由编写程序的人员一步一步地安排好程序的执行过程的程序设计语言。

SQL是高级的非过程化编程语言,允许用户在高层数据结构上工作。它不要求用户指定对数据的存放方法,也不需要用户了解具体的数据存放方式,所以具有完全不同底层结构的不同数据库系统可以使用相同的SQL语言作为数据输入与管理的接口。它以记录集合作为操作对象,所有SQL语句接受集合作为输入,返回集合作为输出的语句

结构化语言

结构化程序设计的基本思想是采用"自顶向下,逐步求精",将待开发的软件系统划分为若干个相互独立的模块。按照结构化程序设计的观点,任何算法功能都可以通过由程序模块组成的三种基本程序结构的组合: 顺序结构、选择结构和循环结构来实现。
显著特征是代码和数据的分离,它能够把执行某个特殊任务的指令和数据从程序的其余部分分离出去、隐藏起来。

OLTP&OLAP

OLTP(on-line transaction processing)翻译为联机事务处理, OLAP(On-Line Analytical Processing)翻译为联机分析处理,从字面上来看OLTP是做事务处理,OLAP是做分析处理。

从对数据库操作来看,OLTP主要是对数据的增删改,OLAP是对数据的查询。从应用上来,OLTP主要用来记录某类业务事件的发生,如购买行为,当行为产生后,系统会记录是谁在何时何地做了何事,这样的数据会以增删改的方式在数据库中进行数据的更新处理操作,要求实时性高、稳定性强、确保数据及时更新成功,像公司常见的业务系统如ERP,CRM,OA等系统都属于OLTP。

当数据积累到一定的程度,我们需要对过去发生的事情做一个总结分析时,就需要把过去一段时间内产生的数据拿出来进行统计分析,从中获取我们想要的信息,为公司做决策提供支持,这时候就是在做OLAP了。因为OLTP所产生的业务数据分散在不同的业务系统中,而OLAP往往需要将不同的业务数据集中到一起进行统一综合的分析,这时候就需要根据业务分析需求做对应的数据清洗后存储在数据仓库中,然后由数据仓库来统一提供OLAP分析。所以我们常说OLTP是数据库的应用,OLAP是数据仓库的应用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值