1《编译原理》实验指导书适用专业:计算机科学与技术网络工程湖南人文科技学院计算机科学技术系2008年8月2前言本实验指导书是《编译原理》的配套实验指导书。本课程的总体目标是:通过实验学习编译程序调试技巧和设计编译程序的一般原则,加深对词法分析、语法分析、语义分析和中间代码生成等编译阶段及实用编译系统的认识,初步掌握编译程序构造的基本原理与技术,从形式语言理论的角度,进一步认识与理解程序设计语言。通过编译程序的编写和调试能力的训练,激发学生进一步思考问题,培养学生的学习兴趣和创新能力。并进一步培养学生的抽象思维能力,进一步巩固《编译原理》课程所学知识。书中共设计了6个实验,其中有3个验证型实验和3个设计型实验,开课教师可以根据大纲要求进行选取。为了克服以往的实验指导书指导过细,学生完全依赖于实验指导书的弊端,该指导书在算法提示上采取从有到无、从多到少的方式。实验内容和设计题目的设计将针对我校学生的实际情况,做到难易适中,验证型实验和设计型实验分别在实验要求上分成不同的层次,力争让学生经过一定的努力,都能够完成相应题目,收获成功的喜悦,从而激发起他们学习的兴趣和积极性。另外,书中附录部分专门设计了针对该课程的实验报告和设计报告,并对报告各个部分的写法和要求作了详细说明。本指导书使用伪语言来描述和实现相关算法,实验环境是可以是VC6.0语言。本指导书可供计算机软件工程、计算机科学与技术、网络工程以及计算机学科其他相关专业选用。说明:本实验指导书所提供的源程序均已在VC6.0下调试运行过.3目录实验一:消去C、C++程序中的注释........................................................................................1实验二:词法分析.......................................................................................................................3实验三:递归下降分析法.........................................................................................................10实验四:语法分析程序LL(1).............................................................................................18实验五:语法分析程序LR(1).............................................................................................25实验六:算术表达式的逆波兰表示与计算.............................................................................321实验一:消去C、C++程序中的注释实验学时:2实验类型:验证实验要求:必修一、实验目的掌握C语言文件的基本操作,消除源C语言程序中的注释,为以后的编译提供方便。二、实验内容注释对于高级语言程序设计可以提高程序的可阅读性,但是对于编译系统而言,注释是没有实际意义的,所以编译系统在预编译阶段首先就要去掉注释。在VC中有两种注释,即单行注释,由//引入到行未,由/*…..*/所包围的注释。要求去掉VC中这两种注释而不改变程序的其它部分。三、实验原理或算法算法原理:逐字符读入源程序,并判断相邻2个字符是否为//或/*或*/,如果不是,则直接将读入的字符写入新文件中;如果是,则跳过注释部分。四、程序清单在VC6.0下程序清单://削除单行注释与多行注释即//与/*...*/#includestdio.h#includestdlib.hmain(){FILE*fp1,*fp2;charch1,ch2,ch3,ch4,flag=0;if((fp1=fopen(input.cpp,r))==NULL)//input.cpp为任意带注释的C程序{printf(filecannotbeopened\n);exit(1);}if((fp2=fopen(output.cpp,w))==NULL)//ouput.cpp为去掉注释后的程序{printf(filecannotbewrited\n);exit(1);}2ch1=fgetc(fp1);ch2=fgetc(fp1);while(!feof(fp1)){if(ch1=='/')if(ch2=='*'||ch2=='/'){if(ch2=='*'){ch3=fgetc(fp1);ch4=fgetc(fp1);while(!(ch3=='*'&&ch4=='/')&&!feof(fp1)){ch3=ch4;ch4=fgetc(fp1);//readonlynotwrite}ch2=fgetc(fp1);}if(ch2=='/')while((ch2=fgetc(fp1))!=10);//readonly/notwrite}elsefputc(ch1,fp2);elsefputc(ch1,fp2);ch1=ch2;ch2=fgetc(fp1);}fputc(ch1,fp2);fclose(fp1);fclose(fp2);return1;}五、实验结果分析比对源文件和产生的新文件,对照验证程序所产生的结果。六、思考题(1)将输入输出文件改成可由键盘输入的文件名。(2)如果在字符串中出现连续的//或/*或*/则不应做处理,请修改上面的程序。3实验二:词法分析实验学时:4实验类型:综合实验要求:必修一、实验目的通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。二、实验内容编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号自身值。(遇到错误时可显示“Error”,然后跳过错误部分继续显示)。三、实验原理或算法1、词法分析器的功能和输出格式词法分析器的功能是输入源程序,输出单词符号。词法分析器的单词符号常常表示成以下的二元式(单词种别码,单词符号的属性值)。本实验中,采用的是一类符号一种别码的方式。2、单词的BNF表示标识符-字母字母数字串字母数字串-字母字母数字串|数字字母数字串|下划线字母数字串|ε无符号整数-数字数字串数字串-数字数字串|ε加法运算符-+减法运算符--大于关系运算符-大于等于关系运算符-=3、“超前搜索”方法词法分析时,常常会用到超前搜索方法。如当前待分析字符串为“a=”或“ab”,当前字符为’’,此时,分析器倒底是将其分析为大于关系运算符还是大于等于关系运算符呢?显4然,只有知道下一个字符是什么才能下结论。于是分析器读入下一个字符’=’或’b’,这时可知应将’’解释为大于或大于等于运算符。但此时,超前读了一个字符’b’,所以要回退一个字符,词法分析器才能正常运行。在分析标识符,无符号整数等时也有类似情况。4、编程思路这里以开始定义的C语言子集的源程序作为词法分析程序的输入数据。在词法分析中,自文件头开始扫描源程序字符,一旦发现符合“单词”定义的源程序字符串时,将它翻译成固定长度的单词内部表示,并查填适当的信息表。经过词法分析后,源程序字符串(源程序的外部表示)被翻译成具有等长信息的单词串(源程序的内部表示),并产生两个表格:常数表和标识符表,它们分别包含了源程序中的所有常数和所有标识符。5、单词种别码要求:识别保留字:if、int、for、while、do、return、break、continue;单词种别码为1。分隔符包括:,、;、{、}、(、);单词种别码为2。运算符包括:+、-、*、/、=、;单词种别码为3。关系运算符:、、==、=、=、!=;单词种别码为4。标识符;单词种别码为5。常数为无符号整形数;单词种别码为6。四、程序清单//词法分析程序#includestdio.h#includectype.h#includestdlib.h#includestring.h#defineNULL0FILE*fp;charcbuffer;char*key[8]={if,else,for,while,int,return,break,continue};char*border[6]={,,;,{,},(,)};char*arithmetic[5]={+,-,*,/,=};char*relation[6]={,=,==,,=,!=};char*consts[20];char*label[20];intconstnum=0,labelnum=0;5intsearch(charsearchchar[],intwordtype){inti=0;switch(wordtype){case1:for(i=0;i=7;i++)if(strcmp(key[i],searchchar)==0)return(i+1);return0;case2:for(i=0;i=5;i++)if(strcmp(border[i],searchchar)==0)return(i+1);return(0);case3:for(i=0;i=4;i++)if(strcmp(arithmetic[i],searchchar)==0)return(i+1);return(0);case4:for(i=0;i=5;i++)if(strcmp(relation[i],searchchar)==0)return(i+1);return(0);case5:for(i=0;iconstnum;i++)if(strcmp(consts[i],searchchar)==0)return(i+1);consts[i]=(char*)malloc(sizeof(searchchar));strcpy(consts[i],searchchar);constnum++;return(i+1);case6:for(i=0;ilabelnum;i++)if(strcmp(label[i],searchchar)==0)return(i+1);label[i]=(char*)malloc(sizeof(searchchar));strcpy(label[i],searchchar);labelnum++;return(i+1);}}charalphaprocess(charbuffer)//字母开头串的处理(可能是保留字或标识符){intatype;inti=-1;charalphatp[20];6while((isalpha(buffer))||(isdigit(buffer))){alphatp[++i]=buffer;buffer=fgetc(fp);}alphatp[i+1]='\0';//printf(%s,search=%d,alphatp,search(alphatp,1));if(atype=search(alphatp,1))printf((%s,1,%d)\n,alphatp,atype);else{atype=search(alphatp,6);printf((%s,6,%d)\n,alphatp,atype);}return(buffer);}chardigitprocess(charbuffer)//常量串{inti=-1;chardigittp[20];intdtype;whi