编译原理词法分析和语法分析报告+代码(C语
言版)
-CAL-FENGHAI.-(YICAI)-Company One1
信息工程学院
实验 报 告
(2010 ~2011 学年度 第 一 学期 )
课程名称 实验名称
编译原理 词法分析器
姓名:柳冠天 学号:2081908318 班级:083
词法分析
2
一、实验目的
设计、编制并调试一个词法分析程序,加深对词法分析原理的理解。 二、实验要求
2.1 待分析的简单的词法
(1)关键字:
begin if then while do end 所有的关键字都是小写。 (2)运算符和界符
: = + - * / < <= <> > >= = ; ( ) #
(3)其他单词是标识符(ID)和整型常数(SUM),通过以下正规式定义:
ID = letter (letter | digit)* NUM = digit digit*
(4)空格有空白、制表符和换行符组成。空格一般用来分隔ID、SUM、运算符、界符和关键字,词法分析阶段通常被忽略。 2.2 各种单词符号对应的种别码:
表2.1 各种单词符号对应的种别码
单词符号 bgin If Then wile do end lettet(letter|digit)* dight dight* + — * / 种别码 1 2 3 4 5 6 10 11 13 14 15 16 单词符号 : := < <> <= > >= = ; ( ) # 种别码 17 18 20 21 22 23 24 25 26 27 28 0 3
2.3 词法分析程序的功能:
输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。 其中:syn为单词种别码;
token为存放的单词自身字符串; sum为整型常数。
例如:对源程序begin x:=9: if x>9 then x:=2*x+1/3; end #的源文件,经过词法分析后输出如下序列:
(1,begin)(10,x)(18,:=)(11,9)(26,;)(2,if)…… 三、词法分析程序的算法思想:
算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。
3.1 主程序示意图:
主程序示意图如图3-1所示。其中初始包括以下两个方面: ⑴ 关键字表的初值。
关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。如能查到匹配的单词,则该单词为关键字,否则为一般标识符。关键字表为一个字符串数组,其描述如下:
Char *rwtab[6] = {“begin”, “if”, “then”, “while”, “do”, “end”,};
置初值 4
否
调用扫描子程序 输出单词二元组 输入串结 是
结束 图3-1
(2)程序中需要用到的主要变量为syn,token和sum 3.2 扫描子程序的算法思想:
首先设置3个变量:①token用来存放构成单词符号的字符串;②sum用来整型单词;③syn用来存放单词符号的种别码。扫描子程序主要部分流程如图3-2所示。
变量初始忽略空格 是 是 是否文件结束 返 5
否
字母
数字 其他 拼字符串
拼数 运算符、 符号 界符等符号 否 是否关键 是
syn为对应关键字 syn=10 对不同符号报错 syn=11返回 图 3-2
四、词法分析程序的C语言程序源代码:
#include char prog[80],token[8],ch; int syn,p,m,n,sum; char *rwtab[6]={\"begin\scaner(); main() { p=0; printf(\"\\n please input a string(end with '#'):/n\"); do{ scanf(\"%c\ 6 prog[p++]=ch; }while(ch!='#'); p=0; do{ scaner(); //调用函数scaner switch(syn) {case 11:printf(\"( %-10d%5d )\\n\如果为11,则输出(整形常数,种别码) break; case -1:printf(\"you have input a wrong string\\n\");//如果为-1,则输出错误 getch(); exit(0); default: printf(\"( %-10s%5d )\\n\ break; } }while(syn!=0); getch(); } scaner() 定义函数scaner { sum=0; for(m=0;m<8;m++)token[m++]=NULL; ch=prog[p++]; m=0; while((ch==' ')||(ch=='\\n'))ch=prog[p++]; if(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))) { while(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))||((ch>='0')&&(ch< ='9'))) { token[m++]=ch; ch=prog[p++]; } p--; syn=10; for(n=0;n<6;n++) //判断是否为关键字 if(strcmp(token,rwtab[n])==0) 7 { syn=n+1; break; } } else if((ch>='0')&&(ch<='9')) //判断是否为数字 { while((ch>='0')&&(ch<='9')) { sum=sum*10+ch-'0'; // ch=prog[p++]; } p--; syn=11; } else switch(ch) { case '<':token[m++]=ch; ch=prog[p++]; if(ch=='=') { syn=22; token[m++]=ch; } else { syn=20; p--; } break; case '>':token[m++]=ch; ch=prog[p++]; if(ch=='=') //判断是否为’>=’ { syn=24; token[m++]=ch; } Else //判断是否为’>’ { syn=23; 8 p--; } break; case '+': token[m++]=ch; ch=prog[p++]; if(ch=='+') { syn=17; token[m++]=ch; } else { syn=13; p--; } break; case '-':token[m++]=ch; ch=prog[p++]; if(ch=='-') { syn=29; token[m++]=ch; } else { syn=14; p--; } break; case '!':ch=prog[p++]; if(ch=='=') { syn=21; token[m++]=ch; } else { syn=31; p--; } break; case '=':token[m++]=ch; ch=prog[p++]; if(ch=='=') 9 { syn=25; token[m++]=ch; } else { syn=18; p--; } break; case '*': syn=15; token[m++]=ch; break; case '/': syn=16; token[m++]=ch; break; case '(': syn=27; token[m++]=ch; break; case ')': syn=28; token[m++]=ch; break; case '{': syn=5; token[m++]=ch; break; case '}': syn=6; token[m++]=ch; break; case ';': syn=26; token[m++]=ch; break; case '\\\"': syn=30; token[m++]=ch; break; case '#': syn=0; token[m++]=ch; break; case ':':syn=17; token[m++]=ch; break; default: syn=-1; break; } token[m++]='\\0'; } 五、结果分析: 10 输入begin x:=9: if x>9 then x:=2*x+1/3; end # 后经词法分析输出如下序列:(begin 1)(x 10)(:17)(= 18)(9 11)(;26)(if 2)…… 如图5-1所示: 图5-1 六、总结: 词法分析的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。通过本试验的完成,更加加深了对词法分析原理的理解。 11 语法分析 一、实验目的 编制一个递归下降分析程序,实现对词法分析程序所提供的单词序列的语法检查和结构分析。 二、实验要求 利用C语言编制递归下降分析程序,并对简单语言进行语法分析。 2.1 待分析的简单语言的语法 用扩充的BNF表示如下: ⑴<程序>::=begin<语句串>end ⑵<语句串>::=<语句>{;<语句>} ⑶<语句>::=<赋值语句> ⑷<赋值语句>::=ID:=<表达式> ⑸<表达式>::=<项>{+<项> | -<项>} ⑹<项>::=<因子>{*<因子> | /<因子> ⑺<因子>::=ID | NUM | (<表达式>) 2.2 实验要求说明 输入单词串,以“#”结束,如果是文法正确的句子,则输出成功信息,打印“success”,否则输出“error”。 例如: 输入 begin a:=9; x:=2*3; b:=a+x end # 输出 success! 输入 x:=a+b*c end # 12 输出 error 2.3 语法分析程序的酸法思想 (1)主程序示意图如图2-1所示。 置初值 调用scaner读下一个单词调用lrparser 结束 图2-1 语法分析主程序示意图 (2)递归下降分析程序示意图如图2-2所示。 (3)语句串分析过程示意图如图2-3所示。 调用scaner 调用语句串分析程序 调用scaner 13 是 是否 ; 否 是 是否否 调用statement函数 否 是否 是 调用statement函数 调用scaner 否 出错处理 syn=0&&kk= 图2-3 语句串分析示意图 是 打印分析成 出错处理 图2-2 递归下降分析程序示意图 (4)statement语句分析程序流程如图2-4、2-5、2-6、2-7所示。 是否标识否 调用scaner 否 是否+ , - 否 调用term函是否:=? 调用scaner 调用expression是 调用scaner 调用term函出错处理 出错处理 图2-4 statement语句分析函数示意图 图2-5 expression表达式分析函 数示意图 14 图 2-6 term分析函数示意图 三、语法分析程序的C语言程序源代码: 调用factor函是否标识是否* , / 否 否 是 是 调用scaner 是 调用factor函是否整常出错处理 否 否 是否( 是 调用scaner 调用expression否 是否) 是 出错处理 调用调用图2-7 factor分析过程示意图 #include \"stdio.h\" #include \"string.h\" char prog[100],token[8],ch; char *rwtab[6]={\"begin\int syn,p,m,n,sum; int kk; 15 factor(); expression(); yucu(); term(); statement(); lrparser(); scaner(); main() { p=kk=0; printf(\"\\nplease input a string (end with '#'): \\n\"); do { scanf(\"%c\ prog[p++]=ch; }while(ch!='#'); p=0; scaner(); lrparser(); getch(); } lrparser() { if(syn==1) { scaner(); /*读下一个单词符号*/ yucu(); /*调用yucu()函数;*/ if (syn==6) { scaner(); if ((syn==0)&&(kk==0)) printf(\"success!\\n\"); } else { if(kk!=1) printf(\"the string haven't got a 'end'!\\n\"); kk=1; } } else { printf(\"haven't got a 'begin'!\\n\"); kk=1; } return; } yucu() { 16 statement(); /*调用函数statement();*/ while(syn==26) { scaner(); /*读下一个单词符号*/ if(syn!=6) statement(); /*调用函数statement();*/ } return; } statement() { if(syn==10) { scaner(); /*读下一个单词符号*/ if(syn==18) { scaner(); /*读下一个单词符号*/ expression(); /*调用函数statement();*/ } else { printf(\"the sing ':=' is wrong!\\n\"); kk=1; } } else { printf(\"wrong sentence!\\n\"); kk=1; } return; } expression() { term(); while((syn==13)||(syn==14)) { scaner(); /*读下一个单词符号*/ term(); /*调用函数term();*/ } return; } term() { factor(); 17 while((syn==15)||(syn==16)) { scaner(); /*读下一个单词符号*/ factor(); /*调用函数factor(); */ } return; } factor() { if((syn==10)||(syn==11)) scaner(); else if(syn==27) { scaner(); /*读下一个单词符号*/ expression(); /*调用函数statement();*/ if(syn==28) scaner(); /*读下一个单词符号*/ else { printf(\"the error on '('\\n\"); kk=1; } } else { printf(\"the expression error!\\n\"); kk=1; } return; } scaner() { sum=0; for(m=0;m<8;m++)token[m++]=NULL; m=0; ch=prog[p++]; while(ch==' ')ch=prog[p++]; if(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))) { while(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))||((ch>='0')&&(ch<='9'))) {token[m++]=ch; ch=prog[p++]; } p--; syn=10; token[m++]='\\0'; for(n=0;n<6;n++) if(strcmp(token,rwtab[n])==0) 18 { syn=n+1; break; } } else if((ch>='0')&&(ch<='9')) { while((ch>='0')&&(ch<='9')) { sum=sum*10+ch-'0'; ch=prog[p++]; } p--; syn=11; } else switch(ch) { case '<':m=0; ch=prog[p++]; if(ch=='>') { syn=21; } else if(ch=='=') { syn=22; } else { syn=20; p--; } break; case '>':m=0; ch=prog[p++]; if(ch=='=') { syn=24; } else { syn=23; p--; } break; case ':':m=0; ch=prog[p++]; if(ch=='=') { syn=18; } else { syn=17; p--; 19 } break; case '+': syn=13; break; case '-': syn=14; break; case '*': syn=15;break; case '/': syn=16;break; case '(': syn=27;break; case ')': syn=28;break; case '=': syn=25;break; case ';': syn=26;break; case '#': syn=0;break; default: syn=-1;break; } } 四、结果分析: 输入 begin a:=9; x:=2*3; b:=a+x end # 后输出success! 如图4-1所示: 图4-1 输入 x:=a+b*c end # 后输出 error 如图4-2所示: 20 图4-2 五、总结: 通过本次试验,了解了语法分析的运行过程,主程序大致流程为:“置初值”调用scaner函数读下一个单词符号调用IrParse结束。递归下降分析的大致流程为:“先判断是否为begin”不是则“出错处理”,若是则“调用scaner函数”调用语句串分析函数“判断是否为end”不是则“出错处理”,若是则调用scaner函数“判断syn=0&&kk=0是否成立”成立则说明分析成功打印出来。不成立则“出错处理”。 21 语义分析程序 #include \"stdio.h\" #include \"string.h\" char prog[100],token[8],ch; char *rwtab[6]={\"begin\int syn,p,m,n,sum,q; int kk; struct { char result1[8]; char ag11[8]; char op1[8]; char ag21[8]; } quad[20]; char *factor(); char *expression(); int yucu(); char *term(); int statement(); 22 int lrparser(); char *newtemp(); scaner(); emit(char *result,char *ag1,char *op,char *ag2); main() { int j; q=p=kk=0; printf(\"\\nplease input a string (end with '#'): \"); do { scanf(\"%c\ prog[p++]=ch; }while(ch!='#'); p=0; scaner(); lrparser(); if(q>19)printf(\" to long sentense!\\n\"); else for (j=0;j int lrparser() 23 { int schain=0; kk=0; if (syn==1) { scaner(); schain=yucu(); if(syn==6) { scaner(); if((syn==0)&&(kk==0)) printf(\"Success!\\n\"); } else { if(kk!=1)printf(\"short of 'end' !\\n\"); kk=1; getch(); exit(0); } } else { printf(\"short of 'begin' !\\n\"); kk=1; getch(); exit(0); } 24 return (schain); } int yucu() { int schain=0; schain=statement(); while(syn==26) { scaner(); schain=statement(); } return (schain); } int statement() { char tt[8],eplace[8]; int schain=0; if (syn==10) { strcpy(tt,token); scaner(); if(syn==18) { scaner(); strcpy(eplace,expression()); 25 emit(tt,eplace,\"\ schain=0; } else { printf(\"short of sign ':=' !\\n\"); kk=1; getch(); exit(0); } return (schain); } } char *expression() { char *tp,*ep2,*eplace,*tt; tp=(char *)malloc(12); ep2=(char *)malloc(12); eplace=(char *)malloc(12); tt=(char *)malloc(12); strcpy(eplace,term()); while((syn==13)||(syn==14)) { if (syn==13)strcpy(tt,\"+\"); 26 else strcpy(tt,\"-\"); scaner(); strcpy(ep2,term()); strcpy(tp,newtemp()); emit(tp,eplace,tt,ep2); strcpy(eplace,tp); } return (eplace); } char *term() { char *tp,*ep2,*eplace,*tt; tp=(char *)malloc(12); ep2=(char *)malloc(12); eplace=(char *)malloc(12); tt=(char *)malloc(12); strcpy(eplace,factor()); while((syn==15)||(syn==16)) { if (syn==15)strcpy(tt,\"*\"); else strcpy(tt,\"/\"); scaner(); 27 strcpy(ep2,factor()); strcpy(tp,newtemp()); emit(tp,eplace,tt,ep2); strcpy(eplace,tp); } return (eplace); } char *factor() { char *fplace; fplace=(char *)malloc(12); strcpy(fplace,\"\"); if(syn==10) { strcpy(fplace,token); scaner(); } else if(syn==11) { itoa(sum,fplace,10); scaner(); } else if(syn==27) 28 { scaner(); fplace=expression(); if(syn==28) scaner(); else { printf(\"error on ')' !\\n\"); kk=1; getch(); exit(0); } } else { printf(\"error on '(' !\\n\"); kk=1; getch(); exit(0); } return (fplace); } char *newtemp() { char *p; char m[8]; p=(char *)malloc(8); 29 kk++; itoa(kk,m,10); strcpy(p+1,m); p[0]='t'; return(p); } scaner() { sum=0; for(m=0;m<8;m++)token[m++]=NULL; m=0; ch=prog[p++]; while(ch==' ')ch=prog[p++]; if(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))) { while(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))||((ch>='0')&&(ch<=' {token[m++]=ch; ch=prog[p++]; } p--; syn=10; token[m++]='\\0'; 30 for(n=0;n<6;n++) if(strcmp(token,rwtab[n])==0) { syn=n+1; break; } } else if((ch>='0')&&(ch<='9')) { while((ch>='0')&&(ch<='9')) { sum=sum*10+ch-'0'; ch=prog[p++]; } p--; syn=11; } else switch(ch) { case '<':m=0; ch=prog[p++]; if(ch=='>') { syn=21; } 31 else if(ch=='=') { syn=22; } else { syn=20; p--; } break; case '>':m=0; ch=prog[p++]; if(ch=='=') { syn=24; } else { syn=23; p--; } break; case ':':m=0; ch=prog[p++]; 32 if(ch=='=') { syn=18; } else { syn=17; p--; } break; case '+': syn=13; break; case '-': syn=14; break; case '*': syn=15;break; case '/': syn=16;break; case '(': syn=27;break; case ')': syn=28;break; case '=': syn=25;break; case ';': syn=26;break; case '#': syn=0;break; default: syn=-1;break; } } 33 emit(char *result,char *ag1,char *op,char *ag2) { strcpy(quad[q].result1,result); strcpy(quad[q].ag11,ag1); strcpy(quad[q].op1,op); strcpy(quad[q].ag21,ag2); q++; } 34 因篇幅问题不能全部显示,请点此查看更多更全内容\\n\\n\getch(); }