编译原理第一章笔记 -- 绪论

本文中内容整理西安交通大学软件学院吴晓军老师的ppt中,仅供学习使用,请勿转载或他用
参考教材:《程序设计语言 编译原理》(第3版) 陈火旺等 国防工业出版社

什么是编译程序

三大经典系统软件:

  • 操作系统
  • 编译程序
  • 数据库管理系统

编译程序历史

编译程序是系统软件中资格最老的成员之一。

目前已经形成了一种系统化的编译理论与方法

编译理论与其他课程关系

  • 自动机和形式语言是编译理论的基础
  • 操作系统是编译理论的控制对象

编译理论的应用

翻译程序

翻译程序(Translator)是一种程序,其输入是某种语言的一系列语句,而其输出则是另一种语言的一系列语句。

编译程序

编译程序(Compiler)是一种程序。他把用高级语言写的源程序作为数据接受,经过翻译转换,产生面向机器的代码作为输出。这当中代码还可能要有汇编程序或装配程序做进一步加工,得出目标程序,交由计算机执行。

源语言要高级,目标语言要低级。

翻译与编译

  • 翻译仅强调从一种语言到另外一种语言的转变
  • 而编译强调的是从高级语言到低级语言的转变

编译过程概述

本课程仅覆盖到了前三个阶段

第一阶段:词法分析

所做的转换是:源程序字符串 -> 单词符号

依据是构词规则

主要理论基础是自动机理论

词法分析的任务是:输入源程序,对构成源程序的字符串进行扫描和分解,识别出一个个的单词(也称为单词符号或简称符号),如基本字(begin、end、if、for、while等),标识符、常数、算符和界符(标点符号、左右括号等)

例子:

第二阶段:语法分析

所做的转换是:单词符号 -> 语法单位(语法范畴)

依据是语法规则

主要理论基础是上下文无关文法

语法分析的任务是:在词法分析的基础上,根据语言的语法规则,把单词符号串分解成各类语法单位(语法范畴),如“短语”、“字句”、“语句”、“程序段”、“程序”等。

通过语法分析,确定整个输入字符串是否构成语法上正确的“程序”。

第三阶段:语义分析与中间代码生成

所做的转换是:语法单位(语法范畴)-> 中间代码

依据是语义规则

主要理论基础是属性文法

并不是所有的语法范畴都有对应的中间代码

这一阶段的任务是:对语法分析所识别出的各类语法范畴,分析其含义,并进行初步翻译(产生中间代码)

通常包括两方面的工作:

  • 首先,对每种语法范畴进行静态语义检查
  • 然后如果语义正确的话则进行另一方面的工作,即进行中间代码的翻译

例如许多编译程序采用了一种与“三地址指令”非常近似的**“四元式”**作为中间代码,其形式如下:

算符左操作数右操作数结果

它的意义是:对“左,右操作数”进行某种运算(由“算符”知名),把运算所得到的值作为“结果”保留下来

在采用四元式作为中间代码的情形,中间代码产生的任务就是按语言的语义规则把各类语法范畴翻译成四元式序列

一般而言,中间代码是一种独立于具体硬件的记号系统,常用的中间代码,除了四元式之外,还有三元式、间接三元式、逆波兰记号和树形表示等等

例子:

例如对于如下代码片段

for K: = 1 to 100 do
	begin
		M: = I + 10 * K;
		N: = J + 10 * K;
	end

其转换为中间代码如下:

image-20220117131334706

第四阶段:优化

所做的转换是:中间代码 -> 中间代码(优化后)

依据是程序等价变换规则

主要理论基础是数据流方程

优化的任务在于对前段产生的中间代码进行加工变换,以期在最后阶段能产出更为高效(省时间和空间)的目标代码

优化的主要方面有:公共子表达式的提取、循环优化、删除无用代码等等,有时候为了便于“并行运算”,我们还可以对代码进行并行化处理。

例如对上面的代码进行优化,则可以得到下面的等价代码:

具体优化的部分是将原来程序中3,5行的两个乘法优化掉了,对于原程序,总共做了300次加法和200次乘法;对于优化后的程序,在循环中只做了300次加法,而且我们很清楚的是在多数硬件中,乘法比加法费时的多。

关于乘法部分的优化可以先分析一下原程序,我们可以发现M和N的值仅与K有关,并且K每次仅增长1,也就是说乘法部分的值在每次循环时仅相差10,加法部分一直都是一个常数,因此我们可以将上一次计算的结果保存起来,在下一次循环加10即可获得和原来一样的效果

image-20220117132503904

第五阶段:目标代码生成

所做的转换是:中间代码 -> 目标代码

依据是硬件体系结构、指令系统

主要使用的方法是查表法

目标代码形式绝对指令、可重定位指令、汇编指令

这一阶段的任务是:把中间代码(或经优化处理之后)变换成特定机器上的低级语言代码

这阶段的工作非常复杂,涉及到硬件系统功能能部件的运用,机器指令的选择,各种数据类型变量的存储空间分配,以及寄存器和后援寄存器的调度等

如果目标代码是绝对指令代码,则这种目标代码可以立即执行。如果目标代码是汇编指令代码,则需要汇编器汇编之后才能运行

必须要指出的是,现代多数使用编译程序所产生的的目标代码都是一种可重定位的指令代码。这种目标代码在运行前必须借助于一个连接装配程序把各个目标模块(包括系统提供的库模块)连接在一起,确定程序变量(或常数)在主存中的位置,装入内存中指定的起始地址,使之成为一种可以运行的绝对指令代码程序。

编译程序的结构

编译程序总框

上述编译过程的五个阶段是编译程序工作时的动态特征。编译程序的结构可以按照这五阶段的任务分模块进行设计,如下图所示:

  • 词法分析器,又称扫描器,输入源程序,进行词法分析,输出单词符号
  • 语法分析器,又称分析器,对单词符号串进行语法分析(根据语法规则进行推到或规约),识别出各类语法单位,最终判断输入串是否构成语法上正确的”程序“
  • 语义分析与中间代码产生器,按照语义规则对语法分析器规约出(或者推导出)的语法单位进行语义分析并把它们翻译成一定形式的中间代码
  • 优化器,对中间代码进行优化处理
  • 目标代码生成器,把中间代码翻译成目标程序

表格与表格管理

编译程序在工作过程中需要保持一系列的表格,以登记源程序的各类信息和编译各阶段的进展情况。

最重要的是符号表,他用来登记源程序中出现的每个名字以及名字的各种属性

除此之外,还有常数表、标号表、入口名表、过程引用表、循环表、等价名表、公用链表、格式表、中间代码表

编译的各阶段都涉及到构造、查找或更新有关的表格

当扫描器识别到一个名字(标识符)后,他把改名字填入到符号表中,但这时不能完全确定名字的属性,它的各种属性要在后续的各阶段才能填入。例如,名字的类型等信息要在语义分析时才能确定,而名字的地址可能要到目标代码生成才能确定

出错处理

一个编译程序不仅应能对书写正确的程序进行翻译,而且应能对出现在源程序中的错误进行处理。如果源程序中有错误,编译程序应设法发现错误,把有关错误信息报告给用户。这部分工作是专门的一组程序(叫做出错处理程序)完成的。

一个好的编译程序应能最大限度地发现源程序或在那个的各种错误,准确地指出错误的性质和发生错误的地点,并且能将错误所造成的的影响限制在尽可能小的范围内,使得源程序的其余部分能继续被编译下去,以便进一步发现其他可能的错误。

编译过程的每一阶段都有可能检测出错误,其中,绝大多数错误可以在编译的前三阶段检测出来。

源程序中的错误通常分为语法错误语义错误两大类

  • 语法错误是指源程序中不符合语法(或词法)规则的错误
    • 这些错误可以在词法分析或者语法分析的时候检测出来。
    • 例如,词法分析阶段能够检测出“非法字符”之类的错误;语法分析阶段能够检测出诸如“括号不匹配”、“缺少 ;”之类的错误
  • 语义错误是指源程序中不符合语义规则的错误
    • 这些错误一般是在语义分析时检测出来的,有些需要在运行时才能检测出来
    • 通常包括:说明错误、作用域错误、类型不一致等等。

所谓”遍“就是对源程序或源程序的中间结果从头到尾扫描一次,并做有关的加工处理,生成新的中间结果或目标程序。

通常,每遍的工作由从外存上获得的前一遍的中间结果开始(对于第一遍而言,从外存上获得源程序),完成它所含的有关工作之后,再把结果记录于外存。

既可以将几个不同阶段合为一遍,也可以把一个阶段的工作分为若干遍。

当一遍中包含若干阶段的时候,各个阶段的工作是穿插进行的。例如,我们可以把词法分析、语法分析及语义分析与中间代码生成这三个阶段安排成一遍。这时,语法分析器处于核心位置,当它识别语法结构而需要下一单词符号时,他就调用词法分析器,一旦识别出一个语法单位的时候,他就调用中间代码生成器,完成相应的语义分析并产生相应的中间代码。

编译前端与后端

是否与目标机有关

概念上,我们有时候把编译程序划分为编译前端编译后端

  • 前端主要由与源语言有关但与目标机无关的那些部分组成。这些部分通常包括词法分析、语法分析、语义分析与中间代码生成,有的代码优化工作也可包括在前端。
  • 后端包括编译程序中与目标机有关的那些部分,如与目标机有关的代码优化和目标代码生成等。
    • 通常,后端不依赖于源语言,而仅仅依赖于中间语言

编译程序的生成

编译程序构造工具

以往人们构造编译程序大多使用机器语言汇编语言

现在编译程序的构造越来越多采用高级语言

有时候为了充分发挥效率或满足不了不同需求,仍然采用机器语言或汇编语言构造编译程序(或其核心部分)

T型图

  • S (source):源语言
  • T (target):目标语言
  • I (implement):编译程序的实现语言

用高级语言L1构造编译程序

编译程序的移植

30min

看不懂,麻了

自编译方式

先对语言的核心部分构造一个小小的编译程序(可用低级语言实现)

再以它为工具构造能够编译更多原因成分的较大编译程序。

如此不断扩展,最后形成整个编译程序(滚雪球)

构造工具

构造编译程序的工具称为编译程序-编译程序编译程序产生器翻译程序书写系统

自动产生扫描器(词法分析器):LEX、FLEX

自动产生语法分析器:YACC、BISON

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hydrion-Qlz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值