【学习笔记】编译原理:编译程序概述

 

高级语言程序的处理过程

【学习笔记】编译原理:编译程序概述_第1张图片

 

编译的各个阶段

【学习笔记】编译原理:编译程序概述_第2张图片

编译各阶段的工作都涉及到构造、查找或更新有关的表格,因此需要有表格管理的工作;

如果编译过程中发现源程序有错误,编译程序应报告错误的性质和错误发生的地点,并且将错误所造成的影响限制在尽可能小的范围内,使得源程序的其余部分能继续被编译下去,有些编译程序还能自动校正错误,这些工作称之为出错处理。

 

词法分析

词法分析阶段是编译过程的第一个阶段。这个阶段的任务是从左到右一个字符一个字符地读入源程序,对构成源程序的字符流进行扫描和分解,从而识别出一个个单词(也称单词符号或符号)。

 

有关的英文

       -编译程序---compiler

  -源语言---source language

  -源程序---source program

  -目标语言---target or object language

  -目标程序---target or object program

  -实现语言---implementation language

  词法分析---lexical analysis 或者scanning

  单词---token

  保留字---resered word

  标识符 ---identifier(user-defined name)

 

语法分析

语法分析是编译过程的第二个阶段。语法分析的任务是在词法分析的基础上将单词序列分解成各类语法短语,如"程序","语句","表达式"等等。一般这种语法短语,也称语法单位可表示成语法树。

id1∶=id2+id3*10经语法分析得

【学习笔记】编译原理:编译程序概述_第3张图片

【学习笔记】编译原理:编译程序概述_第4张图片

 

语法分析所依据的是语言的语法规则,即描述程序结构的规则。通过语法分析确定整个输入串是否构成一个语法上正确的程序。程序的结构通常是由递归规则表示的,例如,我们可以用下面的规则来定义表达式:

  (1) 任何标识符是表达式。

  (2) 任何常数(整常数、实常数)是表达式。

  (3) 若表达式1和表达式2都是表达式,那么:表达式1+表达式2以及表达式1 * 表达式2都是表达式。

类似地,语句也可以递归地定义,如

  (1) 标识符∶=表达式是语句。

  (2) while(表达式)do语句和if(表达式 )then语句 else语句都是语句。

 

词法分析和语法分析

词法分析和语法分析本质上都是对源程序的结构进行分析。但词法分析的任务仅对源程序进行线性扫描即可完成,比如识别标识符,因为标识符的结构是字母打头的字母和数字串,这只要顺序扫描输入流,遇到既不是字母又不是数字字符时,将前面所发现的所有字母和数字组合在一起而构成单词标识符。但这种线性扫描则不能用于识别递归定义的语法成分,比如就无法仅用线性扫描去匹配表达式中的括号。

语义分析

语义分析阶段的任务是审查源程序有无语义错误。源程序中有些语法成分,按照语法规则去判断,它是正确的,但它不符合语义规则。比如使用了没有声明的变量;或者给一个过程名赋值;或者调用函数时参数类型不合适或者参加运算的两个变量类型不匹配等等。比如下边的程序片段:

  int arr[2],c;

  c = arr1 * 10 ;

其中的赋值语句是符合语法规则的,但是因为没有声明变量arr1,而存在语义错。

 

一般,语义分析的工作还包括类型审查,类型提升以及为代码生成阶段收集类型信息. 比如审查每个算符是否实施于具有语言规范允许的运算对象,当不符合语言规范时,编译程序应报告错误。又比如对实数用作数组下标的情况报告错误。又比如某些语言规定运算对象可被强制,那么当二目运算施于一个整型量和一个实型量时,编译程序应将整型量自动转换成实型量而不能认为是源程序的错误,或者给出警告信息后将整型量自动转换成实型量。

假如在赋值语句sum∶=first+count*10中,算符*的两个运算对象分别是count和10,而count是实型变量,10是整型量.语义分析阶段进行类型审查之后,将整型量提升为实型量.在语法分析所得到的分析树上增加一个一目算符结点,这个结点的名称为inttoreal,表示进行将整型量变成实型量的语义处理:

 【学习笔记】编译原理:编译程序概述_第5张图片

语义分析主要的任务----

  完成静态语义审查和处理

  上下文相关性审查

  类型匹配审查

  类型转换

 中间代码生成阶段

在进行了上述的词法分析,语法分析和语义分析阶段的工作之后,有的编译程序将源程序变成一种内部表示形式,这种内部表示形式叫做中间语言或中间代码。所谓"中间代码"是一种结构简单、含义明确的记号系统,这种记号系统可以设计为多种多样的形式,重要的设计原则为两点:一是容易生成;二是容易将它翻译成目标代码。很多编译程序采用了一种近似"三地址指令"的"四元式"中间代码,这种四元式的形式为:(运算符,运算对象1,运算对象2,结果)。

 

比如源程序sum ∶= first+count*10可生成四元式序列,如图1.7所示,其中ti(i=1,2,3)是编译程序生成的临时名字,用于存放运算结果的。  

 

1.7 id1:= id2 + id3 * 10的四元式序列

(1)
(2)
(3)
(4)

(inttoreal
*
+
:=

10
id3
id2
t3

-
t1
t2
-

t1 )
t2 )
t3 )
id1 )

 

四元式(运算符,运算对象1,运算对象2,结果)常写成赋值语句的形式(结果=运算对象1 运算符 运算对象2),比如c语言的源程序a = b * c + b * d 的四元式序列为

  (1) t1 = b * c

  (2) t2 = b * d

  (3) t3 = t1 + t2

  (4) a = t3

  翻译分支,循环和函数调用等语句时,四元式的生成通常要比上述例子复杂些。比如源程序:

  if ( a <= b)

  a = a – c;

  c = b * c;

  翻译成的四元式:

  t1 = a > b

  if t1 goto l

  t2 = a – c

  a = t2

  l : t3 = b * c

  c = t3

代码优化

代码优化阶段的任务是对前阶段产生的中间代码进行变换或进行改造,目的是使生成的目标代码更为高效,即省时间和省空间。比如图1.7的代码可变换为图1.8的代码,仅剩了两个四元式而执行同样的计算。

 

图1.8 id1:= id2 + id3 * 10的优化后四元式序列

 

  (1) ( * id3 10.0 t1 )

  (2) ( + id2 t1 id1 )

代码优化工作会降低编译程序的编译速度,因此编译优化阶段常常作为可选择阶段,编译程序具有控制机制以允许用户在编译速度和目标代码的质量间进行权衡。

 

目标代码生成

目标代码生成阶段的任务是把中间代码变换成特定机器上的绝对指令代码或可重定位的指令代码或汇编指令代码。这是编译的最后阶段,它的工作与硬件系统结构和指令含义有关,这个阶段的工作很复杂,涉及到硬件系统功能部件的运用、机器指令的选择、各种数据类型变量的存储空间分配以及寄存器和后缓寄存器的调度等。

 

前面说过,上述编译过程的阶段划分是一种典型的处理模式,事实上并非所有的编译程序都包括这样几个阶段。有些编译程序并不要中间代码,即不存在中间代码生成阶段;有些编译程序不进行优化,优化阶段即可省去;有些最简单的编译程序只有词法分析,语法分析;语义分析和目标代码生成。

 

编译阶段的组合

在前面所讨论的编译过程中阶段的划分是编译程序的逻辑组织。有时,常常把编译的过程分为前端(front end)和后端(back end),前端的工作主要依赖于源语言而与目标机无关, 后端工作依赖于目标机而一般不依赖源语言.通常前端包括词法分析、语法分析、语义分析和中间代码生成这些阶段,某些优化工作, 即中间代码优化也可在前端做,也包括与前端每个阶段相关的出错处理工作和符号表管理等工作。后端工作包括目标代码生成和目标代码优化,以及相关出错处理和符号表操作。

 

编译阶段也常常划分为两大步骤,分析步骤和综合步骤

  分析步骤是指对源程序的分析

  -线性分析(词法分析或扫描)

  -层次分析(语法分析)

  -语义分析

  综合步骤是指后端的工作,为目标程序的生成而进行的综合。

 

高级语言解释系统

为了实现在一个计算机上运行高级语言的程序,主要有两个途径:

第一个途径是把该程序翻译为这个计算机的指令代码序列,这就是我们已经描述的编译过程。

第二个途径是编写一个程序,它解释所遇到的高级语言程序中的语句并且完成这些语句的动作,这样的程序就叫解释程序。

从功能上说,一个解释程序能让计算机执行高级语言。它与编译程序的主要不同是它不生成目标代码,它每遇到一个语句,就要对这个语句进行分析以决定语句的含义,执行相应的动作。

编译系统生成的目标代码由计算机执行才能生成结果。使用编译系统时会区分编译阶段和运行阶段,编译阶段对源程序进行编译,运行阶段是指目标程序的运行。而解释系统则是边解释边执行。从存储组织来看,在编译阶段,存储区一般要有源程序缓冲区,目标代码缓冲区,名字表以及编译程序使用的源程序中间表示和各种表格等等。在运行阶段,存储区只有目标代码和数据区了。对解释系统来说,在它工作的自始至终,存储区中要有源程序,名字表,标号表等表格,输入输出缓冲区以及数据区等等...

 

 

编译阶段和运行阶段存储结构

 

 

 

源程序缓冲区

 

名字表

 

目标代码缓冲区

 

编译用源程序中间表示各种表格

编译时

 

 

目标代码区

 

数据区

运行时

 

 

 

解释系统存储结构

 

 

 

 

解释系统

 

源程序

 

工作单元

名字表

 

标号表

 

缓冲区

(输入输出)

 

栈区

 

 翻译:是按源程序的实际输入顺序,处理程序语句,得到执行的目标程序。

解释:是按源语言的定义边解释边执行。

解释执行是按照被解释的源程序逻辑流程进行工作的。

【学习笔记】编译原理:编译程序概述_第6张图片

解释执行

① 不生成目标代码

② 能支持交互环境(同增量式编译系统)

 优点:交互方便,节省空间。

 缺点:效率低。因对源程序的循环语句部分要反复解释执行。

 共同点:都需进行词法、语法、语义分析。

 可比喻为:

  -编译是笔译(产生目标程序)

  -解释是口译(不产生目标程序)

  很多语言如BASIC,LISP和PROLOG等等最初都是解释执行的,后来也都有了编译系统。号称最具生命力的JAVA环境同时需要解释和编译系统的支持。

 

编译实现方式的发展

  -手工

   机器语言

   汇编

   系统程序设计语言

  -自动构造工具lex yacc gcc

推动编译技术发展的因素

  语言范型(计算模式)

  计算机体系结构

语言范型

 -命令式(imperative language)

 -应用式(applicative)

 -基于规则的(rule-based)

 -面向对象的(object-oriented)

 -并行计算(parallel computing)

体系结构

 -万诺曼机体系结构

 -并行体系结构

 -嵌入系统

编译程序执行环境

 -批处理

 -交互环境

 -嵌入系统环境

并行编译技术

 【学习笔记】编译原理:编译程序概述_第7张图片

交叉编译

编译程序在一个机器(宿主机)上运行,产生另一个机器(目标机)的汇编语言。嵌入式系统中的应用程序正是借助这样的编译程序生成。

【学习笔记】编译原理:编译程序概述_第8张图片

你可能感兴趣的:(学习笔记)