
编译原理39229.doc
4页编译过程分为分析和综合两个部分,并进一步划分为词法分析、语法分析、 语义分析(中间代码生成)、 代码优化、(存储分配和代码生成)等六个相继的逻辑步骤这六个步骤只表示编译程序各部分之间的逻辑联系,而不是时间关系1.3.1 编译程序总框上述编译过程的五个阶段是编译程序工作时的动态特征编译程序的结构可以按照这五阶段的任务分模块进行设计图1.5给出了编译程序总框 词法分析器,又称扫描器,输入源程序,进行词法分析,输出单词符号语法分析器,简称分析器,对单词符号串进行语法分析(根据语法规则进行推导或归约),识别出各类语法单位,最终判断输入串是否构成语法上正确的“程序”语义分析与中间代码产生器,按照语义规则对语法分析器归约出(或推导出)的语法单位进行语义分析并把它们翻译成一定形式的中间代码有的编译程序在识别出各类语法单位后,构造并输出一棵表示语法结构的语法树,然后,根据语法树进行语义分析和中间代码产生还有许多编译程序在识别出语法单位后并不真正构造语法树,而是调用相应的语义子程序在这种编译程序中,扫描器、分析器和中间代码生成器三者并非是截然分开的,而是相互穿插的中间代码优化器,对中间代码进行优化处理。
目标代码生成器,把中间代码翻译成目标程序除了上述五个功能模块外,一个完整的编译程序还应包括“表格管理”和“出错处理”两部分1.3.5 编译前端与后端概念上,我们有时把编译程序划分为编译前端和编译后端前端主要由与源语言有关但与目标机无关的那些部分组成这些部分通常包括词法分析、语法分析、语义分析与中间代码产生,有的代码优化工作也可包括在前端后端包括编译程序中与目标机有关的那些部分,如与目标机有关的代码优化和目标代码生成等通常,后端不依赖于源语言而仅仅依赖于中间语言1. 词法分析 词法分析器根据词法规则识别出源程序中的各个记号(token),每个记号代表一类单词(lexeme)源程序中常见的记号可以归为几大类:关键字、标识符、字面量和特殊符号词法分析器的输入是源程序,输出是识别的记号流词法分析器的任务是把源文件的字符流转换成记号流本质上它查看连续的字符然后把它们识别为“单词” 2. 语法分析 语法分析器根据语法规则识别出记号流中的结构(短语、句子),并构造一棵能够正确反映该结构的语法树 3. 语义分析 语义分析器根据语义规则对语法树中的语法单元进行静态语义检查,如果类型检查和转换等,其目的在于保证语法正确的结构在语义上也是合法的。
4. 中间代码生成 中间代码生成器根据语义分析器的输出生成中间代码中间代码可以有若干种形式,它们的共同特征是与具体机器无关最常用的一种中间代码是三地址码,它的一种实现方式是四元式三地址码的优点是便于阅读、便于优化注: 查看文章 编译原理中的一些至关重要的二义性2009-03-12 11:38编译原理中的一些二义性理解编译原理的时候,有一些相似但本质上其实根本不一样的东西,,我们作一个归纳和分别凡是正规表达式能匹配的地方,语法分析器就能对他们进行下一步的处理也即,词法分析器是语法分析器的开路者,因为它们基于同样的过程(都是识别出可用的字符串 - 不过词法是识别出由正则表达式简单标识的“标记”,而语法是识别由“标记”本身逻辑上形成的“符号(或组)”而已,说前者是简单标识出是因为只有一个正则表达式,说后者是逻辑上形成是因为有更高级的语法产生式逻辑),而后者正可以以前者的输出作为基础(因为它也是识别嘛)词法分析只是简单的逻辑,它面向粗糙的文本,最终结果是导出一系列可用的“标记”;依据的是正规表达式;而正规表达式只是一种简单的标识匹配逻辑,并非一种高级的产生逻辑(实际上我们呆会会谈到,所谓的产生式逻辑也是归约移进之类的东西而已,而这样东西,其本质上也是一种标识和匹配逻辑,不过我们把它看作更为高级的产生逻辑,因为这里会出现数据结构和算法上的东西)。
语法分析也只是机器的逻辑,比如它把词法分析得出的“标记”进一步识别为“产生式”;依据的是语法产生式我们说了,语法产生式不过也是标识和匹配逻辑而已,不过在这个过程中,除了匹配规则之外(当然不是正规表达式了而是语法产生式),,还涉及到一系列数据结构和算法上的技术逻辑,所以把它看成更高级而已所以这二者本质上都是机器逻辑下的“识别”,是一种形式,只是简单的匹配替换逻辑不过后者比前者要高级那么一点点儿了当然,仅仅就因为这个“更高级一点”的说法,这二个过程实际上就变得本质有不同了,,前者是非语言级的,而后者进入语法阶段了,所以属于编译原理了的前端了(其实词法分析可以是编译原理的一个可有可无的过程,可以不依据正规表达式而直接写提取出串的逻辑,这就是手工写的代码控制的文本处理逻辑了,因为语法分析可不管你前面是词法分析还是什么其它过程,它需要的标记能拿到就可以了)而语义呢,就是不是简单的产生串的集合了它是把串加入了逻辑(语法制导翻译),不过就跟词法分析的匹配和语法分析的匹配是二个不同的过程一样,这里又存在一个二义性即在语法分析的阶段也出现过一次“给串不断加逻辑”的过程我们不妨先来严格区别“串”,“标记”,“符号”这三者的概念,串就是字符串,词法分析一开始需要面对的对象,是简单无意义的东西,标记和符号就是逻辑上的具有意义的“串”,其实它们本质上都是串或串的组合,我们能区别标记和符号是因为“标记”是词法阶段的“串”的说法,而“符号”是语法阶段的“串或串组”的说法(当然词法分析中只有串,而语法分析可能是串或串组)。
在接下来所有的讨论中,我们规范说法,当我们说到语法分析就会说到与它相对而言的下一层即词法分析上的“标记”,当我们说到词法分析就会说到与它相对而言的下一层即源程序文本中的“串”语义分析,我们最后说所以说,所有的标记和符号都是串或串组,不是所有的符号都是标记,但只要是标记(当然,不包括词法分析中忽略的串,比如源程序中的空格啊,什么的),它就是符号我们再来看下语法分析和我们平常的英语的对比我们抽取英语中一个子集来讨论,比如英语“语法”中有“主谓宾”这样的“句子”,和“主谓苹果”这样的“句子”注意到我把一些词加上双引号了)因为在我们所处的年代,大家都是通过用键盘写源程序的方式来写程序的(没有人是用嘴说程序的吧?,这也就是大家说的“面向行的编译器和编译原理了”),所以当我们在源程序中写下苹果的时候,就想到有朝一天它会被词法分析器拿走,苹果这个“字符串“被词法分析器作为“标记”,此时它就是终结符而像上面的主,谓,宾之类的就是“非终结符”了非终结符可以表示某个中间语法产生式非终结符”和“终结符”是单个的“符”,非终结符就是一种语法产生式中的左边的临时符号(相对最终语法产生式“句子”来说)而已它代表一个由串组组成的长语法产生式泛义上的“句子”的形成就是一个根据“语法”不断组合替换“语法产生式”的过程。
所以“句子”可以是:主谓宾I谓宾I谓苹果He吃宾He吃苹果(当然,英语中的句子不会像上面那样不“严格”,实际上英语中的句子要严格得多)而“句子”这个概念是我们最终要得到的在语法分析中,就是起始状态(终极的语法产生式,最终需要的语法产生规则)词法分析中的“终结符”被直接送给语法分析作为“符号”而它产生的非终结符要被语法分析,当然,词法分析器不知道它是不是“终结符”或“非终结符”,这二个概念只能是语法分析器眼里对不同的“标记”产生的概念在词法分析过程中,会给“标记”加上不同的“词性”,比如它是“名词”,“副词”,还是动词(我们知道不同的词性可以做不同的句子结构),当然这只是词法层次的“串属性“,体现在后来的语法分析过程中,就会产生语法层次的不同说法的“属性”了主,还是谓,还是宾这是语法分析过程中,会给串加的“语法”属性,而词性相对而言只是词法范畴会给串加的串属性在人类的编译器技术中,词法分析和语法分析,以及语义分析,从来都是用“标记”符ID的属性来说话的,即“符号表”里的那些内容语法分析过程维护一个符号表每个表项都是一个“词性”,因为它需要词法分析产生的“标记”的这些相关内容对应于编程语言中变量的类型)语法分析进一步给这样拥有“词性”的“符号”加上语法层次的属性。
比如如果标记符ID是一个名词,,那么好,语义分析过程之后,给这个具体的名词又加上了什么样的句子结构属性呢,比如它是作为主语还是宾语,这个不能混淆,否则语法逻辑上就开始出现主宾不分了,更遑论在语义分析中会出现错误了所以,词法分析实际上是一个“文本制层匹配”,语法分析实际上是一个“词法制导产生”给上面一句话接个下巴,语义分析正是针对标记符在语法分析阶段的那些属性进一步给它加上语义级的属性内容所以是“语法制导翻译”注意到了吗,匹配,产生,翻译这三个词在措词上的巨大区别,所以,词法是词法的,语法是语法的,语义是语义的)什么是语义是语义的呢,比如“左值与右值”的区别,int main(){//语法上可以这样“写”,但你的思想里决不能这样“认为”,即语义不是跟语法一致的//因为语法是语法的,语义是语义的//为什么呢这样说呢,看printf()的二个例子 char * mychar = "dsfasdf"; //首先,它是一个数组,其中每个元素都是char * printf("%d\n",sizeof("dsfasdf ")); //大小为8 //而它是一个指针 printf("%d",sizeof(mychar)); //大小为一个指针长,最长为4 return 0;}这就是语法跟语义的区别所在。
