首页 陈意云编译原理全套陈意云编译原理全套ch1

陈意云编译原理全套陈意云编译原理全套ch1

举报
开通vip

陈意云编译原理全套陈意云编译原理全套ch1第一章 词法分析 本章主要掌握下面一些内容。 1.词法分析器的作用和接口,用高级语言编写词法分析器等内容,它们与词法分析器的实现有关。(我们没有安排这方面的习题,因为大部分教材上都有这方面的例子)。 2.掌握下面涉及的一些概念,它们之间转换的技巧、方法或算法。 ( 非形式描述的语言 ( 正规式((表示两个方向的转换都要掌握) ( 正规式 ( NFA(非确定的有限自动机) ( 非形式描述的语言 ( NFA ( NFA ( DFA(确定的有限自动机) ( DFA ( 最简DFA (...

陈意云编译原理全套陈意云编译原理全套ch1
第一章 词法 分析 定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析 本章主要掌握下面一些内容。 1.词法分析器的作用和接口,用高级语言编写词法分析器等内容,它们与词法分析器的实现有关。(我们没有安排这方面的习题,因为大部分教材上都有这方面的例子)。 2.掌握下面涉及的一些概念,它们之间转换的技巧、方法或算法。 ( 非形式描述的语言 ( 正规式((表示两个方向的转换都要掌握) ( 正规式 ( NFA(非确定的有限自动机) ( 非形式描述的语言 ( NFA ( NFA ( DFA(确定的有限自动机) ( DFA ( 最简DFA ( 非形式描述的语言 ( DFA(或最简DFA) 1.1.叙述正规式(00 | 11)( ( (01 | 10) (00 | 11) ( (01 | 10) (00 | 11) ( ) (描述的语言。 答案 该正规式所描述的语言是,所有由偶数个0和偶数个1构成的串。另外,和该正规式等价的正规式有( 00 | 11 | ( (01 | 10) (00 | 11) ( (01 | 10) ) ) (。 分析 叙述正规式描述的语言并没有一种统一的办法,只能是通过对正规式的具体分析去总结。 该正规式的一个重要特点是,它是两个字符一组来考虑的。正规式(00 | 11)(表示的串的长度是偶数,每两个字符一组的话,不是00就是11。再看正规式(01 | 10) (00 | 11) ( (01 | 10),它表示的串由01或10开始,中间有若干组00或11,最后出现01或10。这样的串仍然由偶数个0和偶数个1构成,只不过第一组是01或10的话,那么一定还要有一组01或10才能保证它们的偶数性。显然,正规式(01 | 10) (00 | 11) ( (01 | 10) (00 | 11) (表示的串也仍然是由偶数个0和偶数个1构成。这样,可以判断题目所给的正规式表示的语言的每个句子都是由偶数个0和偶数个1构成。 反过来还需要考虑,任何由偶数个0和偶数个1构成的串是否都在这个语言中。这实际上是问,每个这样的串,其结构是否都符合正规式(00 | 11)( ( (01 | 10) (00 | 11) ( (01 | 10) (00 | 11) ( ) (所做的刻划。我们可以这样叙述由偶数个0和偶数个1构成的串,从左向右,每两个字符一组地考察,它 1,由若干个(强调一下,可以是零个)00或11开始(这由正规式(00 | 11)(描述); 2.一旦出现一个01或10,那么经过若干个00或11后,一定会出现一个01或10。这第二个01或10的后面可能还有若干个00或11,一直到串的结束,或者到再次出现01或10为止。如果串没有结束的话,就是重复出现这里所描述的结构(所以这由( (01 | 10) (00 | 11)( (01 | 10) (00 | 11) ( ) (描述)。 因此正规式(00 | 11)( ( (01 | 10) (00 | 11) ( (01 | 10) (00 | 11) ( ) (描述的是偶数个0和偶数个1构成的串。 可能会提出一个问题,这样的串是否能用更简单的观点来看待,也就是该语言是否能用更简洁的正规式描述。这是可能的。我们写出这样的正规式, ( 00 | 11 | ( (01 | 10) (00 | 11) ( (01 | 10) ) ) ( 它是基于这样的考虑,满足 要求 对教师党员的评价套管和固井爆破片与爆破装置仓库管理基本要求三甲医院都需要复审吗 的最简单的串有三种形式(空串除外): 1.00 2.11 3.(01 | 10) (00 | 11) ( (01 | 10) 它们任意多次的重复构成的串仍然满足要求。 1.2.写出语言“由偶数个0和奇数个1构成的所有0和1的串”的正规定义。 答案 even_0_even_1 ( (00 | 11)( ( (01 | 10) (00 | 11) ( (01 | 10) (00 | 11) ( ) ( even_0_odd_1 ( 1 even_0_even_1 | 0 (00 | 11)( (01 | 10) even_0_even_1 分析 有了上一题的结果,这个问题应该容易解决。首先给上一题的正规式起个名字: even_0_even_1 ( (00 | 11)( ( (01 | 10) (00 | 11) ( (01 | 10) (00 | 11) ( ) ( 对于偶数个0和奇数个1构成的串,其第一个字符可能是0或1。 1.如果是1,那么剩下的部分一定是偶数个0和偶数个1。 2.如果是0,那么经过若干个00或11,一定会出现一个01或10,才能保证0的个数是偶数,1的个数是奇数。若串还没有结束,剩余部分一定是偶数个0和偶数个1。 这样,正确的正规定义是: even_0_odd_1 ( 1 even_0_even_1 | 0 (00 | 11)( (01 | 10) even_0_even_1 1.3.写出语言“所有相邻数字都不相同的非空数字串”的正规定义。 答案 no_0-8 ( 9 no_0-7 ( (8 | no_0-8 8 ) (no_0-8 8 )( (no_0-8 | ( ) | no_0-8 no_0-6 ( (7 | no_0-7 7 ) (no_0-7 7 )( (no_0-7 | ( ) | no_0-7 no_0-5 ( (6 | no_0-6 6 ) (no_0-6 6 )( (no_0-6 | ( ) | no_0-6 no_0-4 ( (5 | no_0-5 5 ) (no_0-5 5 )( (no_0-5 | ( ) | no_0-5 no_0-3 ( (4 | no_0-4 4 ) (no_0-4 4 )( (no_0-4 | ( ) | no_0-4 no_0-2 ( (3 | no_0-3 3 ) (no_0-3 3 )( (no_0-3 | ( ) | no_0-3 no_0-1 ( (2 | no_0-2 2 ) (no_0-2 2 )( (no_0-2 | ( ) | no_0-2 no_0 ( (1 | no_0-1 1 ) (no_0-1 1 )( (no_0-1 | ( ) | no_0-1 answer ( (0 | no_0 0 ) (no_0 0 )( (no_0 | ( ) | no_0 分析 刚拿到这个问题,一定不知从哪儿下手。其实和上面一样,关键是找到一种合适的看待这种句子结构的观点。我们的观点是这样,每个这样的句子由若干个0把它分成若干段,如 123031357106678035590123 可以看成 123, 0, 313571, 0, 6678, 0, 3559, 0, 123 由0隔开的每一段,如313571,它不含0,并且又可以看成是由若干个1把它分成若干段。如此下去,就能找到该语言的正规定义。 按这个思路,上面的正规定义应该逆序看。 answer ( (0 | no_0 0 ) (no_0 0 )( (no_0 | ( ) | no_0 表示一个句子由若干个0分成若干段,特殊情况是整个句子不含0。在这个正规定义中,所引用的no_0表示不含0的串,它的定义和这个定义的形式一样,因为串的形式是一样的,只不过没有数字0。所以有 no_0 ( (1 | no_0-1 1 ) (no_0-1 1 )( (no_0-1 | ( ) | no_0-1 其中no_0-1表示不含0和1的串。依此类推,最后no_0-8是表示不含0, …, 8的没有重复数字的串,它只可能是单个9。 1.4.构造一个DFA,它接受 ( = {0, 1}上0和1的个数都是偶数的字符串。 答案 见图1.1。 分析 对于这样的问题,不要急于去尝试画DFA,先把问题分析一下,这里要接受的是偶数个0和偶数个1的串,和偶数相对的是奇数,因此,对于任意一个0和1的串,不论其0和1的个数有多少,总归不是偶数个就是奇数个。因此任意一个串属于下面四种情况之一。 0:偶数个0和偶数个1; 1:偶数个0和奇数个1; 2:奇数个0和偶数个1; 3:奇数个0和奇数个1。 并且不管一个串是处于上面哪一种情况,该串再添加一个0或1后,总是处于上面另一种情况。由此分析可以知道,DFA只需四个状态就够了,并且状态转换也很容易画出来。答案中的四个状态对应到这儿的四种情况。空串是属于偶数个0和偶数个1的情况,因此0状态是开始状态。因为我们接受偶数个0和偶数个1的串,因此它也是接受状态。 1.5.构造一个DFA,它接受 ( = {0, 1}上能被5整除的二进制数。 答案 见图1.2。 分析 由上题我们知道,构造DFA之前,首先搞请楚问题的状态空间。即想明白应该有多少个状态,状态之间的转换条件,以及针对该问题的开始状态和接受状态。对于本题目,任意一个二进制数除以5时,只有余数为0(即整除),1,2,3和4五种情况。图中的五个状态也是这样起名字的。一个二进制数的后面添上一个0意味着其值变成原来的两倍,而后面添上一个1意味着其值变成原来的两倍再加1。不管是哪一种情况,都很容易从原来的余数决定值变化后的余数。这样,我们很快可以得出所有的状态转换。例如,我们考虑状态4。任何一个余4的数,两倍后一定余3,两倍再加1后一定还是余4。所以,状态4的0转换到状态3,而1转换到本身。显然,状态0既是开始状态又是接受状态。 需要注意的是,考虑状态空间时,还要检查我们是否取的是最简情况(即状态数极小)。例如,对于本题目,假如我们从这样的观点出发,每个二进制数都可以转换成一个十进制数。十进制数的末位有0到9十种情况,其中末位为0和5是能被5整除的情况。这样我们很可能会构造十个状态的DFA,接受状态有两个。这也是一种解,但它不是最简的DFA。 1.6处于/* 和 */之间的串构成注解,注解中间没有*/。画出接受这种注解的DFA的状态转换图。 答案 见图1.3。标记为others的边是指字符集中未被别的边指定的任意其它字符。 分析 这个DFA的状态数及含义并不难确定,见下面的五个状态说明。 状态1:注释开始状态。 状态2:进入注释体前的中间状态。 状态3:表明目前正在注释体中的状态。 状态4:离开注释前的中间状态。 状态5:注释结束状态,即接受状态。 在这个DFA中,最容易忽略的是状态4到本身的’*’转换。这个边的含义是:在离开注释前的中间状态,若下一个字符是’*’,那么把刚才读过的’*’看成是注释中的一个字符,而把这下一个字符看成可能是结束注释的第一个字符。若没有这个边,那么象 /**** This is a comment ****/ 这样的注释就被拒绝。 另外,上面的状态转换图并不完整。例如,对于状态1,没有指明遇到其它字符怎么办。要把状态转换图画完整,还需引入一个死状态6,进入这个状态就再也出不去了。因为它不是接受状态,因此进入这个状态的串肯定不被接受。完整的状态转换图见下面图1.4,其中all表示任意字符。在能够说清问题时,通常我们省略死状态和所有到它的边。 1.7 某操作系统下合法的文件名为 device:name.extension 其中第一部分(device:)和第三部分(.extension)可缺省,若device, name和extension都是字母串,长度不限,但至少为1,画出识别这种文件名的DFA。 答案 见图1.5,图中的标记d表示任意字母。 分析 这个DFA和一些教材上接受无符号数的DFA有类似的地方。我们首先考虑device:和.extension全都出现的情况。这时的DFA比较容易构造,见图1.6。 然后考虑缺省情况。因为.extension可缺省,因此把状态4也作为接受状态。因为name和device一样,都是字母序列,因此在device:缺省时,把到状态2为止得到的字母序列看成是name,所以从状态2画一条转换边到状态5,标记为’.’。(如果构成name和device的字符完全不一样,那么可以从状态1到状态4画一条边,其标记同状态3到状态4的标记一样。)由于device:和.extension都可缺省,因此把状态2也作为接受状态。 1.8 为正规式(a | b)( a (a | b) (a | b)构造NFA。 答案 该NFA的状态转换图见图1.7。 分析 各种教材在介绍有限状态自动机和正规表达式的等价时,都给出了从正规表达式构造等价的NFA的算法。不同书上的构造算法虽然不一样,但有一个共同的特点,或多或少引入了(转换,使状态转换图变得复杂。尤其是,如果题目还要求你画出DFA,那么状态数的增多,使得手工完成NFA确定化为DFA的过程变得更容易出错。因此,我们既要会用书上的算法构造NFA,也要会手工构造更简一些的NFA,尽量避免在NFA中出现(转换。这在大多数情况下是可以做到的,本题就是一个例证。 1.9 用状态转换图表示接收(a | b)( aa的确定的有限自动机。 答案 状态转换图见图1.8。 分析 和上一题不同的是,现在是直接构造DFA。我们仍然坚持这一点,大家既要会按教材上的算法从NFA的确定化得到DFA,也要会手工直接构造DFA。我们通过本题和下一题来说明,手工直接构造DFA也并不困难。 该正规式表示的语言是,字母表(= {a, b}上最后两个字符都是a的串的集合。抓住这个特点,我们首先画出构造过程中的第一步,见图1.9。它表明最简单的句子是aa。 然后,因为在第一个a前可以有若干个b,因此状态0有到自身的b转换。在最后两个字符都是a的串的末尾添加若干个a,能够保持串的这个性质,因此状态2有到自身的a转换。这样我们有图1.10。 最后,在状态1和状态2碰到b时,前面刚读过的a,不管连续有多少个,都不可能作为句子结尾的那两个字符a,因此状态1和状态2的b转换回到状态0。所有状态的a转换和b转换都已给出,这就得到最后结果。 1.10 用状态转换图表示接收(a | b)( a (a | b) (a | b)的确定的有限自动机。 答案 状态转换图见图1.11。 分析 该正规式表示的语言是,字母表(= {a, b}上倒数第三个字符是a的串的集合。根据上题的经验,我们首先画出图1.12。因为最后两个字符任意,因此有这样的分杈,并有四个接受状态。 现在考虑这四个接受状态上的转换。 1.状态4 该状态表示最后三个字符是aaa,若再添加一个a,最后三个字符仍是aaa,因此状态4的a转换到本身。若添加的是b,那么最后三个字符是aab,而状态5表示最后三个字符是aab,因此状态4的b转换到状态5。 2.状态5 该状态表示最后三个字符是aab,若再添加一个a,最后三个字符成了aba,而状态6表示最后三个字符是aba,因此状态5的a转换到状态6。若添加的是b,那么最后三个字符是abb,而状态7表示最后三个字符是abb,因此状态5的b转换到状态7。 3.状态6 该状态表示最后三个字符是aba,若再添加一个a,最后三个字符成了baa,其由a开始的后缀是aa,因此状态6的a转换到状态2(因为从状态0出发经aa是到状态2)。若添加的是b,那么最后三个字符是bab,其由a开始的后缀是ab,因此状态6的b转换到状态3。 4.状态7 该状态表示最后三个字符是abb,若再添加一个a,最后三个字符成了bba,其由a开始的后缀是a,因此状态7的a转换到状态1。若添加的是b,那么最后三个字符是bbb,不存在由a开始的后缀,因此状态7的b转换到状态0。 这样,所有状态的a转换和b转换都已给出,也就得到了最后结果。 1.11 将1.8得到的NFA变换成DFA。 答案 所求的DFA就是1.10题的结果。 分析 我们之所以选这个题目,是为了比较一下,从正规式到NFA,再把NFA确定化,这样得的结果同1.10题直接构造DFA的结果是否一样。 按照教材上的子集构造法,作为结果的DFA并不难得到。另外由于没有(转换,构造过程相对简单了很多。 NFA的开始状态是0,因此首先从NFA的状态集合{0}开始,它是DFA的开始状态,起名叫状态0(。它的a转换和b转换所得到的NFA的状态集合见下面第一行。根据子集构造法所得的DFA的所有状态和它们的转换函数都列在下面。 状态0(:{0} move ({0}, a) = {0, 1} move ({0}, b) = {0} 状态1(:{0, 1} move ({0, 1}, a) = {0, 1, 2} move ({0, 1}, b) = {0, 2} 状态2(:{0, 1, 2} move ({0, 1, 2}, a) = {0, 1, 2, 3} move ({0, 1, 2}, b) = {0, 2, 3} 状态3(:{0, 2} move ({0, 2}, a) = {0, 1, 3} move ({0, 2}, b) = {0, 3} 状态4(:{0, 1, 2, 3} move ({0, 1, 2, 3}, a) = {0, 1, 2, 3} move ({0, 1, 2, 3}, b) = {0, 2, 3} 状态5(:{0, 2, 3} move ({0, 2, 3}, a) = {0, 1, 3} move ({0, 2, 3}, b) = {0, 3} 状态6(:{0, 1, 3} move ({0, 1, 3}, a) = {0, 1, 2} move ({0, 1, 3}, b) = {0, 2} 状态7(:{0, 3} move ({0, 3}, a) = {0, 1} move ({0, 3}, b) = {0} 状态4(, 5(, 6(和7(中都含原NFA的接受状态3,因此它们都是DFA的接受状态。不难看出所得的DFA和1.10题的结果是同构的,仅状态名不一样。 1.12 将图1.13的DFA极小化。 答案 最简DFA见图1.14。 分析 本题要注意的是,在使用极小化算法前,一定要检查一下,看状态转换函数是否为全函数,即每个状态对每个输入符号都有转换。若不是全函数,需加入死状态,然后再用极小化算法。有些教材上没有强调这一点,有的习题解上的示例甚至忽略了这一点,本题将告诉你,这一点是重要的。本题加入死状态5后的状态转换图见图1.15。 使用极小化算法,先把状态集分成非接受状态集{0, 1, 2, 3, 5}和接受状态集{4}这两个子集。 1.集合{4}不能再分解,我们看集合{0, 1, 2, 3, 5}。 move ({0, 1, 2, 3, 5}, a) = {1, 2, 5} move ({0, 1, 2, 3, 5}, b) = {3, 4, 5} 由于b 转换的结果{3, 4, 5}不是最初划分的某个集合的子集,因此{0, 1, 2, 3, 5}需要再分,由于状态1和状态2的b转换都到状态4。因此状态集合的进一步划分是: {1, 2},{0, 3, 5}和{4} 2.由于 move ({1, 2}, a) = {2, 5} move ({1, 2}, b) = {4} move ({0, 3, 5}, a) = {1, 5} move ({0, 3, 5}, b) = {3, 5} 显然{1, 2}和{0, 3, 5}需要再分,分别分成: {1}和{2}以及{0, 3}和{5} 3.由于 move ({0, 3}, a) = {1} move ({0, 3}, b) = {3} 因此不需要再分。这样状态0和状态3合并成一个状态,我们取0为代表,再删去死状态5,就得到该题的结果。 如果不加死状态,我们来看一下极小化算法的结果。最初的划分是{0, 1, 2, 3}和{4}。 1.状态集合的进一步划分是: {1, 2},{0, 3}和{4} 2.忽略了死状态的影响,会认为它们都不需要再分,此时得到的DFA如图1.16。 显然,它和原来的DFA不等价。 1.13 将习题1.10结果的DFA极小化。 答案 化简的结果仍是习题1.10结果的DFA,即该DFA已是最简DFA。这说明手工构造最简DFA是完全可能的。 分析 我们简要说明执行过程。 初始时将状态集分成两组:{0, 1, 2, 3}和{4, 5, 6, 7}。 1.由于 move ({0, 1, 2, 3}, a) = {1, 2, 4, 6} move ({0, 1, 2, 3}, b) = {0, 3, 5, 7} move ({4, 5, 6, 7}, a) = {1, 2, 4, 6} move ({4, 5, 6, 7}, b) = {0, 3, 5, 7} 因此进一步分成{0, 1}、{2, 3}、{4, 5}和{6, 7}四组。 2.由于 move ({0, 1}, a) = {1, 2} move ({0, 1}, b) = {0, 3} 因此{0, 1}还要进一步分,其它几组也是这样。因此最终分成了每个集合中都只有一个状态。 3.所以原来的DFA已经是最简形式了。 1.14 若L是正规语言,证明下面L(语言也是正规语言。L(语言的定义是 L( = {x | xR ( L } xR表示x的逆。 答案 若我们能定义出接受语言L(的一个NFA,那么L(是正规语言。因为L是正规语言,那么一定存在接受L的DFA M,我们就基于M来构造接受L(的NFA M(,并且我们基于M的状态转换图来叙述。 1.将状态转换图上的所有边改变方向,边上的标记不变。 2.将原来的开始状态改成接受状态。 3.增添一个状态作为开始状态,从它有(转换到原来的每一个接受状态,并把原来的这些接受状态都改成普通的状态。 所得到的新状态转换图就是M(的状态转换图。 分析 简单说,判断一个串是否为L(的句子,只要在原来的状态转换图上逆行就可以了。由于M可能有多个接受状态,而不管是DFA还是NFA都只有唯一的开始状态,因此有上面的第3步。 注意经过上面的改造后,得到的可能不是一个DFA的状态转换图。除了上面第3步有可能引入不确定性外,第1步也可能引入不确定性。 本题介绍的证明语言的正规性的方法在下一题表现得更加充分,叙述也比本题严格。 1.15.若L是正规语言,证明下面 L语言也是正规语言。 L语言的定义是 L = {x | (y. xy ( L & |x| = |y| } 答案 因为L是正规语言,那么存在一个DFA M = (S, (, (, s, F),它接受语言L。接受语言 L的DFA M( = (S(, (, ((, s(, F()可如下构造。 1.S(的每个状态是一个二元组(s1, S1(,其中s1(S,S1 ( S。 2.(( ((s1, S1(, a) = (s2, S2(,其中 s2 = ( (s1, a) S2 = { s2 | ( s1( S1((b(((( (s2, b) = s1} 3.s( = (s, F( 4.F( = {(s1, S1( | s1 ( S1} 可以证明这是接受语言 L的DFA,因此 L是正规语言(证明比较复杂,我们在此略去)。 分析 这个题目超出的编译课程的范围。但是如果理解了这儿的解答,那就掌握了证明正规语言的一种很重要的技巧。下面我们说明,为什么这样定义DFA M(。 长度为n的串w,若它是语言L的某个句子的前缀,那么从M的开始状态s,经n步转换,到达某个状态sn。该串是否属于 L,取决于是否存在从sn开始到某个接受状态的路径,其长度为n。 怎样判断是否存在这样的到某个接受状态的路径呢?我们可以在M的状态转换图上按下面的步骤办。 1.首先找出从任意接受状态逆向任意走一步能到达的所有状态,把这个状态集合称做R1。 2.再找出从R1的任意状态逆向任意走一步能到达的所有状态,把这个状态集合称做R2。 3.这样逆向操作n步后,得到状态集合Rn。 4.若sn在Rn中,那么串w属于 L,否则不是。 可以看出,上面定义的M(是在M上同时跟踪从开始状态出发的正向状态转换和从接受状态集合出发的逆向搜索所有状态。我们再看一下M(的定义。 1.S(的每个状态之所以是一个二元组(s1, S1(,是因为需要用s1来表示正向的状态转换,用S1来表示逆向搜索。 2.再看状态转换的定义(( ((s1, S1(, a) = (s2, S2(,其中s2 = ( (s1, a)表示了M上正向一步转换到达的状态,S2 = { s2 | ( s1( S1((b(((( (s2, b) = s1}表示了M上逆向一步搜索到达的状态集合。 3.开始状态s( = (s, F(表示在M上的跟踪是从开始状态和接受状态集合这两端启动。 4.接受状态F( = {(s1, S1( | s1 ( S1}表达的意思是,若在M上从开始状态经n转换到s1,那么一定存在长度为n的从s1到某个接受状态的路径。 下面我们以1.4题的正规语言为例。不难理解,该语言的 语言应该是字母表(={0, 1}上的所有串。我们用上面的方法来构造接受它的DFA。该DFA的开始状态s0 = (0, {0}(。 状态s0: (0, {0}( ( (s0, 0) = (2, {1, 2}( ( (s0, 1) = (1, {1, 2}( 状态s1: (2, {1, 2}( ( (s1, 0) = (0, {0, 3}( ( (s1, 1) = (3, {0, 3}( 状态s2: (1, {1, 2}( ( (s2, 0) = (3, {0, 3}( ( (s2, 1) = (0, {0, 3}( 状态s3: (0, {0, 3}( ( (s3, 0) = (2, {1, 2}( ( (s3, 1) = (1, {1, 2}( 状态s4: (3, {0, 3}( ( (s4, 0) = (1, {1, 2}( ( (s4, 1) = (2, {1, 2}( 从s0到s4的这五个状态,每个状态的第一元都在第二元的集合中,因此这五个状态都是接受状态。这个DFA的图形表示见图1.17(图中用状态0, 1, 2, 3和4代替了这里对应的状态)。显然,它能接受字母表(={0, 1}上所有的串,化简这个DFA可以得到只有一个状态的DFA。 1.16 保留字、关键字和 标准 excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载 标识符之间的区别是什么? 答案 保留字是语言预先确定了含义的单词,程序员不可以对这样的单词重新声明它的含义。如PASCAL语言的type 和procedure等。词法分析器读到一个符合标识符拼写的单词时,都要和保留字进行比较,以确定该单词是标识符呢还是哪个保留字。 很多语言的关键字是保留的,因此和上面的保留字没有区别,如C语言和Java语言。但是FORTRAN语言的关键字不保留,如IF,当它作为语句的第一个单词时,很可能是关键字,但也不排除是用户定义的标识符。这给词法分析带来很大困难,因为识别单词和该单词所处的上下文有关。现在的语言都不会象FORTRAN这样来定义关键字。 标准标识符是预先确定了含义的单词,但是程序员可以重新声明它的含义。在这个声明的作用域内,程序员声明的含义起作用,而预先确定的含义消失,如PASCAL语言的integer和true等。词法分析器对标准标识符没有什么特别的处理,由符号表管理来解决这件事。 1.17 词法分析器能查出源程序中什么样的错误,举例说明。 答案 词法分析器对源程序采取非常局部的观点,因此象C语言的语句 fi (a == f (x) ) … 中,词法分析器把fi当作一个普通的标识符交给编译的后续阶段,而不会把它看成是关键字if的拼写错。 PASCAL语言要求作为实型常量的小数点后面必须有数字,如果程序中出现小数点后面没有数字情况,它由词法分析器报错。 1.18 一个C语言编译器编译下面的函数时,报告parse error before ‘else’。这是因为else的前面少了一个分号。但是如果第一个注释 /* then part */ 误写成 /* then part 那么该编译器发现不了遗漏分号的错误。这是为什么? long gcd(p,q) long p,q; { if (p%q == 0) /* then part */ return q else /* else part */ return gcd(q, p%q); } 答案 此时编译器认为 /* then part return q else /* else part */ 是程序的注释,因此它不可能再发现else 前面的语法错误。 分析 这是注释用配对括号表示时的一个问题。注释是在词法分析时忽略的,而词法分析器对程序采取非常局部的观点。当进入第一个注释后,词法分析器忽略输入符号,一直到出现注释的右括号为止,由于第一个注释缺少右括号,所以词法分析器在读到第二个注释的右括号时,才认为第一个注释处理结束。 为克服这个问题,后来的语言一般都不用配对括号来表示注释。例如Ada语言的注释始于双连字符(--),随行的结束而终止。如果用Ada语言的注释格式,那么上面函数应写成 long gcd(p,q) long p,q; { if (p%q == 0) -- then part return q else -- else part return gcd(q, p%q); } 3 2 1 0 0 1 1 1 1 0 0 0 0 start 1 2 3 4 start 0 0 0 0 0 1 1 1 1 1 / * * * / others others 2 5 start 4 2 1 * others start / * * / 2 5 2 1 4 others 6 others others all all 1 3 5 2 4 6 start d : d d . d d d . 2 d d d . d d : d 6 1 0 5 4 3 2 1 3 start start a a a b b a b b a a a start 2 0 b 1 1 b 图1.9 构造过程中的第一步 a a stars 2 0 1 0 start a a 2 b a start b b a a b b a a 7 6 5 4 3 1 0 2 a 4 2 start b b a b b a a 7 6 5 3 1 0 b a a b a b a b 3 a b b . 4 b b a b 0 1 2 a start start a a 4 b a 5 b b b 2 1 0 a start a 2 1 0 b a b b 4 b b a 3 a, b 4 a start a a 1 0 0 b b 1 2 3 4 start 0 0 0 0 1 1 1 1 1 0 图1.1 接受偶数个0和偶数个1的的DFA 图1.2 接受能被5整除的二进制数的DFA 图1.3 接受注释的DFA 图1.4 接受注释的完整DFA 图1.5 接受文件名的DFA 图1.6 文件名的三部分都出现的DFA 图1.7 接受正规式(a | b)( a (a | b) (a | b)的NFA 图1.8 接收(a | b)( aa的DFA 图1.17 接受(={0, 1}上所有串的一个DFA 图1.16 一个不正确的结果 图1.15 加入死状态后的DFA 图1.14 最简DFA 图1.13 一个DFA 图1.12 构造过程的第一步 图1.11 接收(a | b)( a (a | b) (a | b)的DFA 图1.10 构造过程中的第二步 1 8 _1044093299.unknown
本文档为【陈意云编译原理全套陈意云编译原理全套ch1】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_792169
暂无简介~
格式:doc
大小:211KB
软件:Word
页数:12
分类:
上传时间:2018-09-06
浏览量:14