编译概述
编译: 把源程序转换成等价的目标程序的过程
程序设计语言
低级语言:
- 机器语言
- 符号语言,汇编语言
高级语言:
- 过程性语言- 面向用户的语言:C,Pascal
- 专用语言-面向问题的语言:SQL
- 面向对象的语言:Java,C++
高级语言的优点:
- 不必考虑存储空间的分配问题,不需要了解数据从外部形式转换成机器内部形式的细节
- 高级语言独立于机器。所编程序移植性比较好
- 具有丰富对的数据结构和控制结构
- 更接近自然语言
- 编程效率高
1.编译和解释
1.翻译程序:
- 翻译程序扫描所输入的源程序,并将其转换为目标程序或将源程序直接翻译成结果
2.翻译程序分为两大类:
- 编译程序(即编译器): 把源程序翻译成目标程序的翻译程序
- 解释程序(即解释器): 直接执行源程序的翻译过程
1.编译程序:
- 源程序是用高级语言或汇编语言编写的
- 目标程序是用汇编或机器语言表示的
- 两类编译程序:
- 汇编程序
- 编译程序
2.编译和执行阶段
- 编译时间: 实现源程序到目标程序的转换所占用的时间
- 源程序和数据是在不同时间(即分别在编译阶段和运行阶段)进行处理的
1.解释程序:
- 解释程序解释执行源程序,不生成目标程序
- 同时处理源程序和数据
- 一种有效的方法:先将源程序转换成某种中间形式,然后对中间形式的程序解释执行
例:total := total + rate * 4 的解释过程 1.解释程序先将源程序转换成一个树 2.遍历该树,执行结点上所规定的动作
2.编译的阶段和任务
1.分析阶段
根据源语言的定义,分析源程序的结构
- 1.词法分析
- 2.语法分析
- 3.语义分析
2.综合阶段
根据分析结果构造出要求的目标程序
- 4.中间代码生成
- 5.代码优化
- 6.目标代码生成
3.符号表的管理
4.错误诊断和处理
编译原理的典型结构
1.分析阶段
- 任务: 根据源语言的定义,对源程序进行结构分析和语义分析,从而把源程序正文转换为某种内部表示
- 分析阶段是对源程序结构的静态分析
- 任务划分:
- 1.词法分析
- 2.语法分析
- 3.语义分析
1.词法分析
- 扫描,线性分析
- 词法分析器:
- 依次读入源程序中的每个字符,对构成源程序的字符串进行分解,识别出每个具有独立意义的字符串(即单词),将其转换成记号(token),并组织成记号流
- 把需要存放的单词放到符号表中;如:变量名,标号,常量,…
- 单词: 形成记号的字符串叫做该记号的单词(lexeme)
- 工作依据: 源语言的构词规则(即词法),也称为模式(pattern)
- 例:C语言的标识符的模式是:以字母或下划线开头,由字母,数字或下划线组成的符号串
例:对total:=total + rate * 4的词法分析 1.标识符 total 2.赋值号 := 3.标识符 total 4.加号 + 5.标识符 rate 6.乘号 * 7.整常数 4
- 空格,注释的处理及其他
- 分隔单词的空格:被跳过
- 源程序中的注释:被跳过
- 识别出来的标识符要放入符号表中
- 某些记号还要具有属性值
- 例:发现标识符total时,词法分析器不仅产生一个单词符号的类别标记(如:id),还把它的单词total填入符号表(如果total在表中不存在的话),则total的记号就包括两部分:单词符号的类别标记id,属性值(即指向符号表中R条目的指针)
- 例:发现常数3.14时,词法分析器产生一个类别标记(如:num),这样3.14的记号就包两部分:单词符号的类别标记num,属性值(3.14)
2.语法分析
- 层次结构的分析
- 把记号流按语言的语法结构层次地分组,以形成语法短语
- 源程序的语法短语常用分析树来表示
- 工作依据:源语言的语法规则
- 程序的层次结构通常由递归的规则表示,如表达式的定义如下:
- 1.任何一个标识符是一个表达式
- 2.任何一个数是一个表达式
- 3.如果expr1和expr2是表达式,expr1+expr2,expr1*expr2也都是表达式
例:total := total + rate * 4的分析树
- 语句的递归定义
- 如果id是一个标识符,expr是一个表达式,则id:=expr是一个语句
- 如果expr是表达式,stmt是语句,则while(expr)do stmt是语句,if(expr)then stmt 是语句
3.语义分析
- 对语句的意义进行检查分析
- 收集类型等必要信息
- 用语法分析确定的层次结构表示各语法成分
- 工作依据:源语言的语义规则
- 一个重要任务:类型检查
- 根据规则检查每个运算符及其运算对象是否符合要求;
- 数组的下标是否合法
- 过程调用时,形参与实参个数,类型是否匹配等
例:赋值语句total := total + rate * 4 插入转换符的语法树
total := total + rate*4的各分析步骤及其中间结果
2.综合阶段
- 任务: 根据所制定的源语言到目标语言的对应关系,对分析阶段所产生的中间形式进行综合加工,从而得到与源程序等价的目标程序
- 任务划分:
- 4.中间代码生成
- 5.代码优化
- 6.目标代码生成
4.中间代码生成
- 中间代码: 一种抽象的机器程序
- 中间代码应具有两个重要的特点:
- 易于产生
- 易于翻译成目标代码
- 中间代码有多种形式
- 三地址代码具有的特点:
- 每条指令除了赋值号之外,最多还有一个运算符
- 编译程序必须生成临时变量名,以便保留每条指令的计算结果
- 有些三地址指令少于三个操作数
例:total := total + rate * 4 的三地址代码 temp~1~ := intoreal(4) temp~2~ := id~2~ * temp~1~ temp~3~ :=id~1~ + temp~2~ id~1~ := temp~3~
5.代码优化
- 代码优化: 对代码进行改进,使之占用的空间少,运行速度快
- 代码优化首先是在中间代码上进行的
temp~1~ := intoreal(4) temp~2~ := id~2~ * temp~1~ temp~3~ :=id~1~ + temp~2~ id~1~ := temp~3~ 优化后: temp~1~ := id~2~ * 4.0 temp~2~ := id~1~ + temp~1~ id~1~ := temp~2~
优化编译程序: 能够完成大多数优化的编译程序
6.目标代码生成
- 生成的目标代码一般是可以重定位的机器代码或汇编语言代码
- 涉及到的两个重要问题
- 对程序中使用的每个变量要指定存储单元
- 对变量进行寄存器分配
total:= total +rate * 4的目标代码 MOVF R~0~,id~2~ MULF R~0~,#4.0 MOVF R~1~,id~1~ ADDF R~0~,R~1~ MOVF id~1~,R~0~
- 赋值语句total := total + rate*4的各综合步骤及结果
- total := total + rate * 4 的翻译过程
3.符号表管理
- 编译程序的一项重要工作:
- 收集源程序中使用的标识符
- 收集每个标识符的各种属性信息
- 符号表是由若干记录组成的数据结构
- 每个标识符在表中有一条记录
- 记录的域是标识符的属性
- 对符号表结构的要求:
- 应允许快速地找到标识符的记录
- 可在其中存取数据
- 标识符的各种属性是在编译的各个不同阶段填入符号表的
例:声明语句:float total,rate; 词法分析器: float是关键字 total,rate是标识符 在符号表中创建这两个标识符的记录 语法分析器: total,rate都表示变量 float表示这两个变量的类型 可以把这两种属性及存储分配信息填入符号表 在语义分析和生成中间代码时,还要在符号表中填入对这个float型变量进行存储分配的信息
4.错误处理
- 在编译的每个阶段都可能检测到源程序中存在的错误
- 词法分析程序可以检测出非法字符错误
- 语法分析程序能够发现记号流不符合语法规则的错误股
- 语义分析程序试图检测出具有正确的语法结构,但对所涉及的操作无意义的结构
- 代码生成程序可能会发现目标程序区超出了允许范围的错误
- 由于计算机容量的限制,编译程序的处理能力受到限制而引起的错误
- 处理与恢复
- 判断位置和性质
- 适当的恢复
3.编译有关的其他概念
1.前端和后端
- 前端主要由与源语言有关而与目标机器无关的那些部分组成
- 词法分析,语法分析,符号表的建立,语义分析和中间代码生成
- 与机器无关的代码优化工作
- 相应的错误处理工作和符号表操作
- 后端由编译程序中与目标机器有关的部分组成
- 与机器有关的代码优化,目标代码的生成
- 相应的错误处理和符号表操作
- 把编译程序划分成前端和后端的优点
- 便于移植,便于编译程序的构造
2.遍
- 一遍是指对源程序或其中形式从头到尾扫描一遍,并作相关的加工处理,生成新的中间形式或目标程序
- 编译程序的结构受遍的影响
- 遍数
- 分遍方式
- 一遍扫描的编译程序
- 多遍编译程序
- 编译程序分遍的优缺点
- 分遍的主要优点:
- 通过分遍将编译程序的前端和后端分开,可以为编译程序的移植创造条件
- 可使各遍编译程序功能独立,单纯,相互联系简单,编译程序结构清晰
- 能够实现更充分的优化工作,获得高质量目标程序
- 可以减少对主存容量的要求
- 分遍的缺点
- 增加了不少重复性的工作
4.编译程序的前后处理器
1.预处理器
- 预处理器的主要功能
- 1.宏处理
- 预处理器允许用户在源程序中定义宏
例:C语言源程序中的一个宏定义 #define prompt(s) fprintf(stderr,s)
- 宏处理器处理两类语句,即宏定义和宏调用
- 宏定义: 通常用统一的字符或关键字表示,如define或macro,宏定义由宏名字及宏体组成,通常宏处理器允许在宏定义中使用形参
- 宏调用: 由调用宏的命令名(宏名)和所提供的实参组成。宏处理器用实参代替宏体中的形参,再用变换后的宏体替换宏调用本身
- 2.文件包含
- 预处理器把文件包含声明扩展为程序正文
- C语言程序中的头文件包含声明行
例: #include <stdio.h> //预处理器处理到该语句时,就用文件stdio.h的内容替换此句
- 3.语言扩充
- 有些预处理器用更先进的控制流和数据结构来增强原来的语言
- 例:
- 预处理器中可以将类似while或if-then-else语句结构的内部宏提供给用户使用,而这些结构在原来的程序设计语言中是没有的
- 当程序中使用了这样的结构时,由预处理器通过宏调用实现语言功能的扩充
2.汇编程序
- 汇编语言用助记符表示操作码,用标识符表示存储地址
赋值语句b:=a+2相应的汇编语言程序为: MOV R~1~,a ADD R~1~,#2 MOV bm,R~1~,R1
- 最简单的汇编程序对输入作两遍扫描
- 第一遍:
- 找出标志存贮单元的所有标识符,并将它们存贮到汇编符号表中(汇编符号表独立于编译程序的符号表)
- 在符号表中指定该标识符所对应的存储单元地址,此地址是在首次遇到该标识符确定的
- 假定一个字包括4个字节,每个变量占一个字,完成第一遍扫描后,得到汇编符号表
标识符 地址 a 0 b 4
- 第二遍:
- 把每个用助记符表示的操作码翻译为二进制表示的机器代码
- 把用标识符表示的存储地址翻译为汇编符号表中该标识符对应的地址
- 输出通常是可重定位的机器代码
- 起始地址为0,各条指令及其所访问的地址都是相对于0的逻辑地址
- 当装入内存时,,可以指定任意的地址L作为开始单元
- 输出中要对那些需要重定位的指令作出标记
- 标记供装入程序识别,以便计算相应的物理地址
可重定位机器代码
- b:=a+2的汇编代码
MOV R1,a
ADD R1,#2
MOV b,R1- 假定机器指令的格式为:
操作符 寄存器 寻址模式 地址
- 假定:
0001 代表 MOV R,S
0011 代表ADD
0010 代表 MOV D,R- 第二遍输出的可重定位机器代码:
0001 01 00 00000000*
0011 01 10 00000010
0010 01 00 00000100*绝对机器代码
- 假定装入内存的起始地址为0;a,b的的地址分别是15和19
则装入后的机器代码为:
0001 01 00 00001111*
0011 01 10 00000010
0010 01 00 00010011*3.连接装配程序
- 可重定位目标程序的组成:
- 正文:目标程序的主要部分,包括指定代码和数据
- 外部符号表(全局符号表):记录有本程序段引用的名字和被其他程序段引用的名字
- 重定位信息表,记录有重定位所需要的有关信息
- 连接装配程序
- 作用:把多个净多编译或汇编的目标模块连接装配成一个完整的可执行程序
- 连接编译程序:扫描外部符号表,寻找所连接的程序段,根据重定位信息表解决外部引用和重定位,最终将整个程序涉及到的目标模块逐个调入内存并连接在一起,组成一个待装入的程序
- 重定位装配程序:把目标模块的相对地址装换成绝对地址
形式语言与自动机基础
1.语言和文法
1.字母表和符号串
- 字母表
- 符号的非空有限集合
- 典型的符号是字母,数字,各种标点和运算符等
- 符号串
- 定义在某一字母表上
- 由该字母表中的符号组成的有限符号序列
- 同义词:句子,字
- 符号串有关的几个概念
- 长度:
- 符号串α的长度是指α中出现的符号的个数,记作|α|
- 空串的长度为0,常用ε表示
- 前缀
- 符号串α的前缀是指从符号串a的末尾删除0个或多个符号后得到的符号串;如:univ是university的前缀
- 后缀
- 符号串α的后缀是指从符号串a的开头删除0个或多个符号后得到的符号串;如:sity是university的后缀
- 子串
- 符号串α的子串是指删除了α的前缀和/或后缀后得到的符号串。如:ver是university的子串
- 真前缀,真后缀,真子串
- 如果非空符号串β是α的前缀,后缀或子串,并且β≠α,则称β是α的真前缀,真后缀或真子串
- 子序列
- 符号串α的子序列是指从α中删除0个或多个符号(这些符号可以是不连续地)后得到的符号串;如:nvest是university的子序列
2.符号串运算
- 连接
- 符号串α和符号串β的连接αβ是把符号串β加在符号串α之后得到的符号串
- 若α=ab,β=cd;则αβ=abcd,βα=cdab
- 对任何符号串α来说,都有εα=αε=α
- 幂
- 若α是字符串,α的n次幂αn定义为:n个α字符串的连接(αα…αα)
- 当n=0是,α0是空串
- 假如α=ab,则有:α0=ε,α1=ab,α2=abab,…,αn=n个ab相连
1.语言
- 指在某一确定字母表上的符号串的集合
- 空集∅,集合{ε}也是符合此定义的语言
- 这个定义并没有把任何意义赋予语言中的符号串
1.语言的运算(假定L和M表示两个语言)
L和M的并:记作L∪M,L∪M={s|s∈L或s∈M}
L和M的连接:记作LM,LM={st|s∈L并且t∈M}
L的闭包:记作L*,L*=L0L1L2…(即:L的0次或若干次连接)
L的正闭包:记作L+,L+=L1L2L3…(即:L的一次或若干次连接)
L的幂运算:记作Ln,L0={ε},Ln=Ln-1L(即:Ln是语言L与其自身的n-1次连接)
例:L={A,B,…,Z,a,b,…z} ;D={0,1,…,9}
- 既可把L和D看作是字母表也可以看作是语言
- L∪D:表示全部字母和数字的集合
- LD: 表示由一个字母后跟一个数字组成的所有符号串的集合
- L4:表示由4个字母组成的所有符号串的集合
- L*:表示由字母组成的所有符号串(包括ε)的集合
- L(L∪D)* :表示以字母开头,后跟字母,数字组成的所有符号串的集合
- D+:表示由一个或若干个数字组成的所有符号串(不包括ε)的集合
2.文法
- 指描述语言的语法结构的形式规则
1.文法的形式
- 任何一个文法都可以表示为一个四元组G=(VT,VN,S,φ)
- VT:是一个非空的有限集合,它的每个元素称为终结符号
- VN:是一个非空的有限集合,它的每个元素称为非终结符号
- S:是一个特殊的非终结符号,称为文法的开始符号
- φ:是一个非空的有限集合,它的每个元素称为产生式
- 注意:VT∩VN=φ
- 1.终结符号:
- 1.小写字母(如:a,b,c)
- 2.运算符号(如:+,-,*,/)
- 3.各种标点符号(如:括号,逗号,冒号,等于号)
- 4.数字(如:1~9)
- 5.黑体字符串
- 2.非终结符号:
- 1.大写字母(如:A,B,C)
- 2.小写的斜体符号串
- 3.开始符号:
- 1.第一个产生式的左部符号是文法的开始符号
- 2.大写字母S常用作文法的开始符号
- 4.产生式:
- 1.产生式的形式为:α->β
- 2.->表示定义为(或由…组成)
- 3.α,β∈(VT∪VN)*,且α≠ε
- 4.左部相同的产生式α->β1,α->β2,…,α->βn可以缩写成α->β1|β2|…|βn(|表示或,每个βi(i=1,2,…n)称为α的一个候选式)
- 例:
- G=({+,*,(,),i},{E,T,F},E,φ)
- φ:F->E+T|F,T->T*F|F,F->(E)|i
2.文法的分类
- 根据对产生式施加的限制不同,定义了四类文法和相应的四种形式语言类
文法类型 产生式形式的限制 文法产生的语言类 0型文法 α->β,其中α,β∈(VN∪VT)*,|α|≠0 0型语言 1型文法(即上下文有关文法CSG) α->β,其中α,β∈(VN∪VT)*,|α|≤|β| 1型语言(即上下文有关语言CSL) 2型文法(即上下文无关文法CFG) A->β,其中A∈VN,β∈(VN∪VT)*,|α|≠0 2型语言(即上下文无关语言CFL) 3型文法(即正规文法RG) A->a或A->aB(右线性);A->a或A->Ba(左线性),其中A,B∈VN,a∈VT∪{ε} 3型语言(即正规语言RL)
3.推导和短语
1.推导
- 假定A->y是一个产生式,α和β是任意的文法符号串,则有αAβ=>αyβ
- =>表示一步推导
- 利用产生式对左边符号串中的一个非终结符进行替换得到右边的符号串
- 称αAβ直接推导出αyβ或者αyβ直接归约到αAβ
- 如果有直接推导序列:α1=>α2=>…αn,则称这个序列是α1到αn的长度为n的推导,记作α1=>*αn,=> * 表示0步或多步推导
- 1.最左推导
- 如果α=>* β,并且在每一步推导中都替换α中最左边的非终结符号,则称这样的推导为最左推导,记作 α=>*lm β
- 2.最右推导
- 如果α=>* β,并且在每一步推导中都替换α中最右边的非终结符号,则称这样的推导为最右推导(也称规范推导),记作 α=>*rm β
- 句型,句子,语言
- 1.句型:
- 对于文法G(VN,VT,S,φ),如果S=>*α,则称α是当前文法的一个句型
- 若S=>*lm α,则α是当前文法的一个左句型
- 若S=>*rm α,则α是当前文法的一个右句型
- 2.句子
- 仅含有终结符号的句型是文法的一个句子
- 3.语言
- 文法G产生的所有句子组成的集合是文法G所定义的语言,记作L(G)
- L(G)={α|S=>*α,α∈VT *}
- 例:文法G[S]:
- 1.S->aSBE
- 2.S->aBE
- 3.EB->BE
- 4.aB->ab
- 5.bB->bb
- 6.bE->be
- 7.eE->ee
- L(G)={anbnen|n≥1}
- 结果:S=>aSBE=>aaBEBE=>aaBBEE=>aabBEE=>aabbEE=>aabbeE=>aabbee
- 4.文法的等价
- 若L(G1)=L(G2),则称文法G1和G2是等价的
- 例:
- 文法G1[A]:A->0R,A->01,R->A1
- 文法G2[S]:S->0S1,S->01
- 因为L(G1)={0n1n}=L(G2)={0n1n} ,所以文法G1和G2是等价的
- 短语,直接短语,句柄
- 对于文法G=(VT,VN,S,φ),假定αβδ是文法G的一个句型
- 如果存在S=>*αAδ,并且A=>+β,则称β是句型αβδ关于非终结符A的短语
- 如果存在S=>*αAδ,并且A=>β,则称β是句型αβδ关于非终结符A的直接短语
- 一个句型的最左直接短语被称为该句型的句柄
2.分析树及二义性
- 分析树 :推导的图形表示,又称推导树
- 它是一颗有序有向树,因此具有树的性质
- 分析树的特点:每一个节点都有标记
- 根节点由文法的开始符号标记
- 每个内部节点由非终结符标记,它的子节点由这个非终结符的这次推导所用产生式的右部各符号从左到右依次标记
- 叶节点由非终结符号或终结符号标记,它们从左到右排列起来,构成句型
- 子树:分析树中的一个特有的节点,连同它的全部后裔节点,;连接这些节点的边以及这些节点的标记
- 子树的根节点可能不是文法的开始符号
- 如果子树的根节点标记为非终结符A,则可称该子树为A子树
- 子树与短语的关系
- 一个子树的所有叶节点自左至右排列起来,形成此句型相对于该子树根的短语
- 分析树中只有父子两代的子树的所有叶节点自左向右排列起来,形成此句型相对于该子树根的直接短语
- 分析树中最左边的那颗只有父子两代的子树的所有叶节点自左向右排列起来,就是该句型的句柄
- 二义性
- 如果一个文法的某个句子不止有一颗分析树,则这个句子是二义性的
- 含有二义性句子的文法是二义性的文法
- 句型的分析
- 句型分析就是识别一个符号串是否为某文法的句型
- 句型的分析算法可分为:
- 1.自上而下分析法:
- 从文法的开始符号出发,反复使用文法的产生式,寻找与输入符号串匹配的推导
- 2.自下而上分析法:
- 从输入符号串开始,逐步进行规约,直至规约到文法的开始符号
3.自动机
1.有限自动机
- 1.有限自动机是具有离散输入与输出系统的一种数学模型
- 2.系统可处于有限个内部状态的任何一个之中
- 3.系统的当前状态概括了有关过去输入的信息
2.确定的有限自动机
- 指在当前状态下,输入一个符号,有限自动机将切换到唯一的下一个状态(该状态称为后继状态)
3.非确定的有限自动机
- 指在当前状态下,输入一个符号,可能有两种以上可选择的后继状态,并且非确定的有限自动机所对应的状态转换图可以有标记为ε的边
1.确定的有限自动机(DFA)
1.状态转换图
2.说明:
- 1.指一张有限的方向图
- 2.图中结点代表状态,用圆圈表示,且只含有限个状态;
- 3.其中只有一个初始状态,可以有若干个终结状态,终态用双圆圈表示
- 4.状态之间用有向边连接,边上的标记表示在射出结点状态下可能出现的输入符号
3.利用状态转换图,识别符号串
- 1.识别方法
- 1.起点为初态S,从符号串的最左符号开始,重复步骤2,直到达到符号串的最右符号为止
- 2.扫描符号串的下一个符号,在当前状态的所有射出边中找出标记为该字符的边,沿此边过度到下一个状态
- 3.例:上图能识别的所有符号串:L(M)={10,110,111,01,000,001}
- 4.状态转换图所能识别的符号串的全体称为该状态转换图所识别的语言
5.确定的有限自动机的定义
- 1.一个确定的有限自动机(DFA,记作M)是一个五元组:M=(∑,Q,q0,F,Õ)
- ∑:是一个字母表,它的每个元素称为一个输入符号
- Q:是一个有限的状态集合
- q0:q0∈Q,是一个初始状态
- F:F∈Q,是终结状态集合
- Õ:是一个从Q×∑到Q的单值映射
- 2.转换函数Õ(q,a)=q’(其中q,q’∈Q,a∈∑),表示当前状态为q,输入符号为a时,自动机将转换到下一个状态q‘,q’称为q的一个后继
- 3.若Q={q1,q2,…qn},∑={a1,a2,…am},则Q×∑=(Õ(qi,aj))n×m是一个n行m列的矩阵,它称为DFA的状态转换矩阵
- 4.实例:有DFA M=({0,1},{A,B,C,S,f},S,{f},Õ)
- 1.其中Õ(S,0)=B,Õ(A,0)=f,Õ(B,0)=C,Õ(C,0)=f,Õ(S,1)=A,Õ(A,1)=C,Õ(B,1)=f,Õ(C,1)=f
- 5.解析:
- 1.状态转换矩阵:
- 5行2列的矩阵
- 每一行对应M的一个状态
- 每一列对应M的一个输入符号
- 6.DFA M可用一张状态转换图来表示
- 1.若DFA M有n个状态,m个输入符号;则状态转换图有n个状态结点,每个结点最多有m条射出边
- 2.若q,q’∈Q,a∈∑,并且Õ(q,a)=q’,则从q到q’有一条标记为a的边
- 3.整个图包含唯一的一个初态
- 7.DFA M所识别的语言
- 1.对∑上的任何符号串ω∈∑*,若存在一条从初态结点到终态结点的路径,该路径上每条边的标记连接成的符号串恰好是ω,则称ω为DFA所识别
- 2.DFA M所能识别的符号串的全体记为L(M),称为DFA M所识别的语言
2.非确定的有限自动机(NFA)
1.NFA的定义
- 1.一个非确定的有限自动机M(记作:NFA M)是一个五元组
- 2.M=(∑,Q,q0,F,Õ)
- ∑:是一个字母表,它的每个元素称为一个输入符号
- Q:是一个有限的状态集合
- q0:q0∈Q,是一个初始状态
- F:F∈Q,是终结状态集合
- Õ:是一个从Q×∑到Q的子集的映射,即:Q×∑—>2Q;(2Q是Q的幂集,也就是Q的所有子集组成的集合)
2.NFA M状态转换图及识别的语言
- 1.状态转换图
- 1.NFA M含有n个状态,m个输入符号
- 2.图中含有n个状态结点,每个结点可射出若干条边
- 3.图中有唯一的一个初态结点
- 2.对∑上的任何符号串ω∈∑*,若存在一条从初态结点到终态结点的路径,该路径上每条边的标记连接成的符号串恰好是ω,则称ω为NFA M所识别
- 3.NFA M所能识别的符号串的全体记为L(M),称为NFA M所识别的语言
- 4.如果q0∈ F
- 1.存在一条从初态结点到终态结点的ε-道路
- 2.空串可为该NFA M所识别,即ε∈L(M)
3.NFA实例:
1.设有NFA M=({a,b},{0,1,2,3,},0,{3},Õ)
2.其中Õ(0,a)={0,1},Õ(0,b)={0},Õ(1,b)={2},Õ(2,b)={3}
3.状态转换矩阵为:
4.状态转换图为:
5.NFA M所识别的语言
- L(M)={(a|b)*abb}
6.定理:对任何的一个NFA M,都存在一个与之等价的DFA D,即:L(M)=L(D)
7.实例:构造与下面的NFA M等价的DFA D
- 1.NFA M=({a,b},{A,B},A,{B},Õ)
- 2.其中Õ(A,a)={A,B},Õ(A,b)={B},Õ(B,b)={A,B}
- 3.首先画出该NFA M的状态转换图
- 4.子集构造法:构造与NFA M等价的DFA D
- 1.列出NFA M的每个子集及该子集相对于每个输入符号的后继子集
- 1.假设DFA D=({a,b},Q’,q0’,F’,δ)
- Q’:指原来Q的所有子集组成的集合,即Q’={φ,{A},{B},{A,B}}
- q0’:不变,还是原本的q0
- F’:所有含有原NFA M终态的Q的子集组成的集合,即:F’={{B},{A,B}}
- δ:δ({q1,q2…qn},a)=δ(q1,a)∪δ(q2,a)…δ(qn,a)
- δ(φ,a)=φ,δ(φ,b)=φ
- δ({A},a)={A,B},δ({A},b)={B}
- δ({B},a)= -,δ({B},b)={A,B}
- δ({A,B},a)=δ({A},a)∪δ({B},a)={A,B}
- δ({A,B},b)=δ({A},b)∪δ({B},b)={A,B}
- 2.即DFA D=({a,b},{φ,{A},{B},{A,B}},0,{{B},{A,B}},δ)
- 3.其中δ如上所示
- 4.DAF D的状态转换矩阵和状态转换图
- 2.对所有子集重新命名,得到DFA D的状态转换矩阵
输入 a b 0 2 1 1 - 2 2 2 2
3.具有ε-转移的非确定有限自动机(NFA)
- 1.定义:一个具有ε-转移的非确定有限自动机M(记作:NFA M)是一个五元组M=(∑,Q,q0,F,Õ)
- ∑:是一个字母表,它的每个元素称为一个输入符号
- Q:是一个有限的状态集合
- q0:q0∈Q,是一个初始状态
- F:F∈Q,是终结状态集合
- Õ:是一个从Q×∑到Q的子集的映射,即:Q×∑—>2Q;(2Q是Q的幂集,也就是Q的所有子集组成的集合)