1《编译原理》实验书2010年11月实验目录:实验1:词法分析程序(3学时,第12周).......................................................................2实验2:语法分析-递归子程序法(3学时,第13周)....................................................11实验3:语法分析-预测分析法(选做).............................................................................27实验4:语义分析和代码生成(12学时,第14~17周).................................................37适用专业及实验总学时:2007级计算机科学与技术专业(软件方向),18学时。任课教师:黄玲E-mail:huangl@mailbox.gxnu.edu.cn恭喜你!你将进入非常重要的专业课程的实践。编译原理的知识影响到专业人员的素质,除编译程序外有大量专业工作与编译技术相关。你现在需要通过脚踏实地的实践学习(很辛苦的!),把自己的专业水平提高一个层次。你需要在实验课前自己阅读程序代码,在实验课中调试程序,实验课后完成实验报告(每一个实验上交一份实验报告),实验报告必须阐述清楚你的所做的工作,内容包含修改思路、关键修改代码、运行结果、对运行结果的评价、进一步改进的建议。最重要的是,通过实践你可以获得专业的能力和自信。加油!2实验1:词法分析程序(3学时,第12周)一、实验目的和内容:1.实验目的:通过词法分析程序,了解词法分析的过程。2.实验内容:用C实现对Pascal的子集程序设计语言的词法识别。3.实验要求:要求修改文法和程序,增加浮点数处理功能。4.实验环境是Windows操作系统、VisualC++开发环境。二、未增加浮点数处理的原设计:1.程序设计语言的描述:程序→程序首部分程序.程序首部→PROGRAM标识符;分程序→[常量说明部分][变量说明部分][过程说明部分]复合语句常量说明部分→CONST常量定义{,常量定义};常量定义→标识符=无符号整数变量说明部分→VAR变量定义{,变量定义};变量定义→标识符{,标识符}:类型类型→INTEGER|LONG过程说明部分→过程首部分程序;{过程首部分程序;}过程首部→PROCEDURE标识符;|PROCEDURE标识符(标识符:类型);语句→赋值语句|条件语句|当型循环语句|过程调用语句|读语句|写语句|复合语句|ε赋值语句→标识符:=表达式条件语句→IF条件THEN语句当型循环语句→WHILE条件DO语句过程调用语句→标识符|标识符(表达式)读语句→READ(标识符,{标识符})写语句→WRITE(表达式{,表达式})复合语句→BEGIN语句{;语句}END条件→表达式关系运算符表达式|ODD表达式表达式→[+|-]项{加型运算符项}项→因子{乘型运算符因子}因子→标识符|无符号整数|(表达式)加型运算符→+|-乘型运算符→*|/关系运算符→=|||=||=其中:用左右尖括号括起来的符号串表示非终结符→定义为{}表示该语法成分可以重复0~n次[]表示方括号内为可选项,即0或1次32.程序设计语言单词的内部编码:(35个终结符)内码单词内码单词内码单词内码单词1PROGRAM2CONST3VAR4INTEGER5LONG6PROCEDURE7IF8THEN9WHILE10DO11READ12WRITE13BEGIN14END15ODD16+17-18*19/20=212223=2425=26.27,28;29:30:=31(32)33无符号整数34标识符35#3.下面是一个词法分析程序,该程序能够将源程序,也就是相应字符流转换成内码,并输出到文件。程序的执行需要提供两个参数,第一个参数是源程序文件名,第二个参数是存放分析结果的文件名,第二个参数可以省略,可由程序自动生成。Vc++6程序参数的设置方法:菜单project下子菜单settings中的debug选项卡下programarguments对话框中,输入参数。如采用VisualStudio2008开发环境,构建控制台应用程序,参数设置:项目属性-(活动debug模式)配置属性-调试-命令参数,同时工作目录为当前工程下debug。#includestdio.h#includectype.h#includestring.h#includeprocess.h#definelenth115//保留字表的长度#definelenth217//运算符界符表长度struct{charname[21];inttype;intaddr;}indent[1000];//符号表structst{charname[21];intcode;}sym;//当前单词FILE*f1,*f2;intline=1,row=1,val;//行号、列号、数字串的值charch='';//当前字符intlenth3=0;//符号表中实际的标识符个数voidgetsym();chargetchr();voiderror(int);main(intargc,char*argv[]){charft[12],*fc;if((f1=fopen(argv[1],r))==NULL){//打开源程序文件printf(cannotopenfile.\n);exit(0);}if(argc=2){//如果没有提供第二个参数strcpy(ft,argv[1]);if((fc=strchr(ft,'.'))!=NULL)//如果第一个参数即源文件名,有后缀.xxx4strcpy(fc,.mid);//结果文件名:源文件名非后缀部分.midelsestrcat(ft,.mid);//结果文件名:源文件名.mid}elsestrcpy(ft,argv[2]);if((f2=fopen(ft,w))==NULL)//打开结果文件{printf(cannotopenfile2\n);exit(0);}while(!feof(f1)){//只要没有遇到源文件的结尾,继续循环。getsym();//获取一个单词放到symprintf(%s%d\n,sym.name,sym.code);//显示当前单词的名字及其内码fprintf(f2,%s%d\n,sym.name,sym.code);//向输出文件写入:单词名字单词内码}fclose(f1);fclose(f2);}voidgetsym(){staticchara[lenth1][10]={PROGRAM,CONST,VAR,INTEGER,LONG,PROCEDURE,IF,THEN,WHILE,DO,READ,WRITE,BEGIN,END,ODD};//保留字表staticchard[lenth2][3]={+,-,*,/,=,,,=,,=,.,,,;,:,:=,(,)};//运算符界符表charstr[21];inti,n;while(isspace(ch))ch=getchr();if(isalpha(ch)){//如果当前字符是字母,则后面几行代码就是识别标识符的自动机的实现n=0;while(isalpha(ch)||isalnum(ch)){//当前字符是字母或者数字,继续循环if(isalpha(ch))ch=tolower(ch);if(n20)str[n++]=ch;//构造字符串ch=getchr();//从文件中读取下一个字符}str[n]='\0';for(i=0;ilenth1;i++){//检查当前符号串是否保留字if(!strcmp(str,a[i]))break;//如果字符串已经登记在保留字表,中断循环}if(ilenth1){//如果该字符串是保留字,将当前单词写入symstrcpy(sym.name,a[i]);sym.code=i+1;5}else{//该单词不是保留字,而是标识符for(i=0;ilenth3;i++){//在符号表里检查是否已经登记过该标识符if(!strcmp(str,indent[i].name))break;//如果登记过,中断循环}if(i==lenth3){strcpy(indent[i].name,str);//如果没有登记过该标识符,登记它到符号表。lenth3++;}strcpy(sym.name,indent[i].name);//当前标识符写入symsym.code=34;}}elseif(isalnum(ch)){//如果当前字符是数字,则后面就是识别数字串的自动机的实现val=0;n=0;while(isalnum(ch)){val=val*10+ch-‘0’;sym.name[n++]=ch;ch=getchr();}sym.name[n]=’\0’;sym.code=33;}else{//当前字符是运算符或者界符if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='='||ch=='.'||ch==','||ch==';'||ch=='('||ch==')'){str[0]=ch;str[1]='\0';ch=getchr();//从文件中读入一个字符for(i=0;ilenth2;i++)//在运算符界符表查询,是否有此ch字符if(!strcmp(str,d[i])){strcpy(sym.name,str);//有,sym.code=i+16;}}else{//处理符号==::=n=0;if(ch==''||ch==':'){str[n++]=ch;if((ch=getchr())=='='){//=或:=str[n++]=ch;ch=getchr();}6}elseif(ch==''){str[n++]=ch;ch=getchr();if(ch=='='||ch==''){//=或str[n++]=ch;ch=getchr();}}elseif(ch=-1){strcpy(sym.name,);sym.code=35;//#}//elseerror(1);str[n]='\0';//str为一个完整的单词}for(i=0;ilenth2;i++)//查运算符界符表,看是否有此符号串strif(!strcmp(str,d[i])){strcpy(sym.name,str);sym.code=i+16;}}}chargetchr(){charch=fgetc(f1);if(ch=='\n'){row=1;line++;}elseif(ch!=''&&ch!='\t')row++;return(ch);}voiderror(intn){printf(%derrorhappens.\n,n);exit(0);}74.词法分析程序getsym()流程图YN标识符或者保留字YNNYNYch的符号是空格?读入下一个字符到chch的符号是字母?ch的符号是字母或数字?ch的符号是字母?将ch的字母变为小写字母将ch的符号加入到字符数组str尾读入下一个符号到ch在str尾增加\0,构建一个字符串在保留字表a中查找str的位置i8NY标识符保留字YNYNNYi保留字表长度?登记单词str到sym,内码i+1在标识符表查找str的位置ii为标识符表的末尾?在标识符表末尾登记str登记str到sym,内码34标识符表