姓名:__ ******_ 学号_ *******_ 年级专业及班级 _08计算机科学与技术 成绩 ____________ 实验名称 词法分析程序设计与实现 完成日期 2011/4/12 指导教师 ******* 实验目的:能够米用C编程语言实现简单的词法分析程序;设计、编制并调试一个词法分析程序,加深对词法 分析原理的理解 实验要求:1.对单词的构词规则有明确的定义; 2.编与的分析程序能够正确识别源程序中的单词付号; 3. 识别出的单词以 <单词符号,种别码 >的形式保存在符号表中(链表); 4•词法分析中源程序的输入以.c格式,分析后的符号表,将二元组保存在.txt文件中。 实验内容:选择高级语言(C语言),编制它的词法分析程序。词法分析程序的实现可以采用任何一种编程工具 实验原理:1、算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号; 2、其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。 实验分析:(1)关键字:if else while do case int break (2) <= <> > >==;() (3) 其他单词是标识符(ID)和整型常数(SUM,通过以下正规式定义: ID = _ | letter (letter | digit)* NUM = digit digit* (4) 空格有空白、制表符和换行符组成。空格一般用来分隔 分析阶段通常被忽略。 (5) 注释被忽略 等所有的关键字都是小写。 运算符和界符:=+ - * / < 等 ID、SUM运算符、界符和关键字,词 法单词符号 auto int break 种别码 1 3 5 单词符号 double struct else 种别码 2 4 6 -1 -
long case register char retur n const short con ti nue sig ned default sizeof do static \\a \\f \ \\\\ 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 switch enum typedef exter n union float un sig ned for void goto volatile while if \\b \\n \\v \\? 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 41 \\0 \\ xhh 标识符 ( 43 45 47 49 \\ddd 数字 # ) -2 -
44 46 48 50
[ { C : % + = & < >= >> << <= ++ - -> %A (A 可为 d's'c) 51 53 55 ] } * 52 54 56 58 57 59 61 63 65 67 69 71 73 75 77 79 81 A ? 1 ! > == != && II ?= -- a 60 62 64 66 68 70 72 74 76 78 80 82 84 83 85 / 86 88 87 89 90 其他类别 99 91 -3 -
-4 -
扫描数字:
Ch为数字或‘
预读ch
Ch是否为‘-'
是f判别为自减符
判别为”-> ”
回退3
预读ch
判别为负号 预读ch
-5 -
扫描引号:
0
-6 -
扫描单词:
-7 -
-8 -
实验步骤:
1、 准备:用TC、VC++等开发工具;
2、 对本实验的任务进行分析,确定实现功能的函数; 3、 写好程序,仔细修改函数;
4、 上机操作:输入源程序,修改、调试,运行。 5、 写好试验报告。
实验调试过程及测试结果
/******************************* 代^码 ******************************/
#in clude FILE *fp,*fp1; int hanjsq=1;〃 行计数器, 保存行号 int guanjz(char 关键字和标识符判断ch1[]);〃 char ch,i 定义输入和输出文件名 nfile[15],outfile[15];〃 prin tf(\"*****************E nter the infile name***************** sca nf(\"%s\输入需要扫描的文件名 Enter the outfile n ame******************\\ n\"); scan f(\"%s\输入需要另存为的文件名 printf( if((fp = fope n(i nfile,\"r\")) == NULL)// { prin tf(\"ca nnot ope n file\\n\"); exit(0); } if((fp1 = fope n(outfile,\"w\")) == NULL)// 打开需要存入的文件 打开需要扫描的文件 -9 - { printf(\"cannot open file'n\"); exit(O); } printf(\"\\n******************************************************** printf(\"* 》 开始进行词法分析 《*\\ n\"); printf( \"******************************************************* printf(\"\\n******************************************************** printf(” 行号 字符串 种别码\\n\"); printf( \"******************************************************* fprin tf(fp1, \"******************************************************* fprin tf(fp1,\" 行号 字符串 种别码\\n\"); **\\ n\"); fprin tf(fp1, while(!feof(fp)) { ch=fgetc(fp); if(ch==1O)hanjsq++; 扫描头文件单词及保留字 ********************* if(isalpha(ch) || ch=='_')〃 { int i=0; char ch1[30];〃 ch1[i++]=ch;〃 如果第一个字符为字母或下划线则判断为标识符 假疋母个标识付取长为 将ch保存到ch1[0]中并使i自加1 while(!feof(fp)) { ch=fgetc(fp); if(ch==1O)hanjsq++;〃 如果ch为换行符,则行计数器自加 if(isalpha(ch) || isdigit(ch) || ch=='') 1 -10 - chi {//如果ch为字母、数字或下划线就把 ch放到ch1[i]中并使i自加1 ch1[i++]=ch; } if(ch=='.')〃 如果ch为小数点则判断是否为头文件 { if((ch=fgetc(fp))=='h')如果小数点后一位为 h则判定其为头文件 〃 { if(ch==10)hanjsq++; chi[i++]='.'; chi[i++]='h'; ch1[i]='\\0';〃 把结束标志放到 chi[i]中作为单词结束标志 prin tf(\"li ne %d: %s 83\\n\〃 以字符串形式输出 ch1 fprin tf(fp1,\"li ne %d: %s 83\\n\ break; else//如果小数点后一位不是 h则判定其为标识符 { fseek(fp,-1,1);//fp 回退 1 ch1[i]='\\0';〃 把结束标志放到 ch1[i]中作为单词结束标志 prin tf(\"li ne %d: %s %d\\n\〃 以字符串形式输fprin tf(fp1,\"li ne %d: %s %d\\n\" ,hanjsq,ch1,guanjz(ch1)); break; } } if(!isalpha(ch) && !isdigit(ch) && ch!='_' && ch!='.') {//如果ch不为字母、数字、下划线和点时判断其为标识符 ch1[i]='\\0'; prin tf(\"li ne %d: fprin tf(fp1,\"li ne %d:%s %d\\n\%d\\n ”,hanjsq,ch1,guanjz(ch1)); %s -11 - 出 break; /************************ if(isdigit(ch) || ch=='-')〃 j扫描数*************************/ 如果ch为数字或'-' if(isdigit(ch))// 如果ch为数字 prin tf(\"li ne %d: %c\ %c\ fprintf(fp1,\"line %d: while(!feof(fp)) ch=fgetc(fp);〃 预读一位如果 ch为数字和点则循环输出 if(isdigit(ch) || ch=='.') prin tf(\"%c\fprin tf(fp1,\"%c\ else//否则视为数字结束 printf(” fprin tf(fp1,\" fseek(fp,-1,1);〃 46\\n\"); 46\\n\"); 回退一位 ch='O:〃 置ch为0,以免影响下面误判并顺利退出扫描数字 break; if(ch=='-')〃 如果ch为'-' -12 - ch=fgetc(fp);〃 预读一位 if(ch=='-')〃 如果ch还是为'-'则判断为自减符'--' { prin tf(\"li ne %d: fprintf(fp1,\"line %d: } if(ch=='>')〃 { prin tf(\"li ne %d: - 80\\n\ 80\\n\ 如果ch为'>',则判断为结构体运算符’->' > - 81\\ n\ > 81\\ n\ fprin tf(fp1,\"li ne %d: } if(isdigit(ch))〃 { 如果ch为数字则可能为减号或负号 fseek(fp,-3,1);〃 ch=fgetc(fp); if(isdigit(ch))〃 回退 3 为判断 如果ch为数字则判断'-'为减号 ch=fgetc(fp); prin tf(\"li ne %d: % %c 79\\n\ c fprin tf(fp1,\"li ne %d: } else //否则判断'-'为负号 { ch=fgetc(fp); prin tf(\"li ne %d: fprin tf(fp1,\"li ne %d: while(!feof(fp)) { %c\ %c\ 预读一位如果 ch为数字和点则循环输出 ch=fgetc(fp);〃 79\\n\" ,hanjsq,ch); -13 - if(isdigit(ch) || ch=='.') { prin tf(\"%c\fprin tf(fp1,\"%c\} 扫描注释 ********************** else//否则视为数字结束 { printf(” fprin tf(fp1,\" fseek(fp,-1,1);// 46\\n\"); 46\\n\"); 回退1 break; } } } if(ch=='/')〃 如果ch为'/'则可能为注释 { ch=fgetc(fp);〃 读下一个字符 if(ch==10)hanjsq++; if(ch=='/')〃 { while(fgetc(fp)!=10); if(ch==10)hanjsq++;〃 } if(ch=='*')〃 如果该字符为'*'则判断为注释多行 直到遇到换行符出现才认为注释结束 如果该字符也为'/'则判断为注释一行 {//直到出现’*/' 才认为注释结束 -14 - while(!feof(fp)) { ch=fgetc(fp); if(ch==10)hanjsq++; if(ch=='*')〃 出现'*' {//且接着出现'/' if((ch=fgetc(fp))=='/') break; else// 否则原样输出'/' prin tf(\"li ne %d: fprintf(fp1,\"line %d: fseek(fp,-1,1);〃 回退1 break; /*********************** 扫描引号 ************************/ if(ch==””)〃 出现引号 int i=0; prin tf(\"li ne %d: %c fprin tf(fp1,\"li ne %d: %c prin tf(\"li ne %d: \ fprin tf(fp1,\"li ne %d: \ while(!feof(fp)) 83\\n\ 83\\n\ 82\\n\ 82\\n\ -15 - {//先整体输出引号内所有字符并定为第 99类 ch=fgetc(fp); i++;〃用于积累回退长度 if(ch==10)hanjsq++; if(ch!=””) { if(ch!=32) { prin tf(\"%c\fprin tf(fp1,\"%c\} } else break; } printf(” 99\\n\"); fprin tf(fp1,\" 99\\n\"); fseek(fp,-i,1);// 回退到引号开始 for(;i>0;i--) { ch=fgetc(fp); if(ch==92)// 如果ch为'\\'则可能为转义字符 { char ch5[13]={\"abfntv\\\\?'\\\"0\ch=fgetc(fp);// 预读一位 for(int k=0;k<12;k++) {//如果为转义字符则输出 if(ch==ch5[k]) { 转义字符集 -16 - printf(” line %d: \\\\%c%d\\n\" ,hanjsq,ch,k+33); -17 - fprin tf(fp1,\" li ne %d: \\\\%c } } if(ch=='d' && isdigit(fgetc(fp)) && isdigit(fgetc(fp)))〃 { fseek(fp,-2,1); prin tf(\" line %d: %c%c fprin tf(fp1,\" line %d: %c%c } if(ch=='x' && isdigit(fgetc(fp)) && isdigit(fgetc(fp)))// { fseek(fp,-2,1); prin tf(\" line %d: %c%c fprin tf(fp1,\" line %d: %c%c } } if(ch=='%')〃 如果为'%'则可能为%s%c%d { ch=fgetc(fp); char bfh[4]={\"dcs\ for(i=0;i<3;i++) { if(bfh[i]==ch) { prin tf(\" line %d: %%%c fprin tf(fp1,\" line %d: %%%c } } } } -18 - %d\\n\ 任意字符转换为三位八进制 44\\n\ 44\\n “,hanjsq,fgetc(fp),fgetc(fp)); 任意字符转换为二位十六进制 45\\n\ 45\\n\ 83\\n\ 83\\n\ /********************* 描其他符^号 ********************/ if(!isdigit(ch) && !isalpha(ch) && ch!='_' && ch!=”” && ch!='/') char ch2[14]={\"#()[]{}'*:~%A\〃char ch3[9]={\"+?=|&!<>\char ch4[9]={\"+==|&===\ 定义部分单符号集 定义部分单符号或双符号(前半部分)集 定义部分双符号(后半部分) for(i nt i=0;i<13;i++) {//判断单个符号 if(ch==ch2[i]) prin tf(\"li ne %d: fprintf(fp1,\"line %d: %c %c %d\\n\" ,hanjsq,ch,i+48); %d\\n\ for(i nt j=0;j<8;j++) {//判断双符号 if(ch==ch3[j]) {//如果ch与ch3中第j 个字符匹配 预读一位 ch=fgetc(fp);// //if(ch==10)hanjsq++; if(ch==ch4[j]) {//且ch与ch4第j个匹配,则表示 ch3[j]与ch4[j] 连起来为一个双符号 %d\\n\ %d\\n\ prin tf(\"li ne %d: fprin tf(fp1,\"li ne %d: if(ch=='<' && ch3[j]=='<')〃 %c%c %c%c 判断'<<'符 -19 - prin tf(\"li ne %d: fprin tf(fp1,\"li ne %d: } if(ch=='>' && ch3[j]=='>')〃 { prin tf(\"li ne %d: << << 77\\n\ 77\\n\ 判断'>>'符 >> >> fprin tf(fp1,\"li ne %d: 78\\n\ 78\\n\ } else//否则表示ch3[j] { 为单符号,不是双符号的 部分 %c prin tf(\"li ne %d: %c fprin tf(fp1,\"li ne %d: fseek(fp,-1,1); } } } } %d\\n\ %d\\n\" ,hanjsq,ch3[j],j+61) ****************************************************************************************** printf( prin tf(\"* prin tf(\"* prin tf(\"* printf( fprin tf(fp1, fprin tf(fp1,\"* 》 fprin tf(fp1,\"* 》 》 》 》 词法分析结束 分析结果保存在文件%$中 **\\n\"); 《*\\n\"); 《*\\ n\《*\\n\"); 欢迎下次使用,谢谢! **\\n\"); **\\ n\"); 词法分析结束 欢迎下次使用,谢谢! -20 - 《*\\ n\"); 《*\\ n\"); **\\ n\"); in t guanjz(char ch1[])〃 { 关键字和标识符判断 char ch2[32][9]={\"auto\ \"register\nst\ned\\"volatile\〃 for(int i=0;i<32;i++) {//逐个比对如果为关键字则返回类别 if(!strcmp(ch1,ch2[i]))return i+1; i+1 定义关键字集 return 47;// 否则返回一般标识符类 竝船悅Q)動勒卜 test ・曹■:M曹Entei' t hs outf ile ri之盯日****^***-¥******<^^ cf FMQI, txt at ■ waw at it at ■ at ituif at it at U tguit at ■ • ac n unit ar・ at ariMiM at MTM at :M at ■ u at 心 史舱行词法分析 <* 1 Inc 1: u line 12 iniclude 1 ine 1* < . Ili line 1 = lino is lliw 2s U lima 2s inaludo a IM 2? < line 2s atAlib.h linfi 2: > line 3; void line main line 3: < J. inc 3 = > line : 1 inc 3Ss riLE 讪: 开\"Ik 1: 血 1: line 1: Ike]: HUE 2: Iine2: line 2: lines: !k2: line 3: line 3: line 5; line 3: lineS: lint 5: J5QE 5: inclut stdinh :■ :• S3 =; 4S 4? b'f B3 hV > 4R 47 67 GS <17 ba S3 47 4? 阴 CaiL i7 占 FILE 丰 1 Irte 5: lime S; __ sft fl -21 - : B豪溥■ ar河*\"百■苜筒n w i{耳鼻p n t尸广 『卄戸1 nt- _i I n Finp 卄 可・w耳黑図耳溥■ ar ・鼻*E E 戸F trst«t具t ■ if 耳材imcirHirjtKjnfifK^nrBl* Th& outf lie 寺暮打補整并*需斗弭書!**祥略再整番 cffXQ-tXt at ir uif at ■ u u KM at ■・ at MENU at ■ U M~W;M at WM at aa・:■■■!< IT ar ~K af ME :I mat at nwu at 心 开给进行词法分析 3 K X KM X MM X X MJ4 K M M X KM X K M X MMX M M M MM M X K M X -22 - = ! 1血2& + 61 lint 2& T a lint 2& ■ccmt r lint 26 1 ) 50 line A else 6 血27 if IT f $4 1血H EtringX Ji9 血H [ 51 ]ine 牙 1 r lillE H ] 1 血H L IM 二 line 卵 - 1遊H 1遊2T ) 血2T J1 ]inc 2T ) line 28 printf 眄 line 28 ■: 19 1U23 if ILDE 28 册 总结: lhe加 line 29: 1) :rintf ( * rfrrfinlMtn 血亚 line 3: lii printF < V I gfPFFInCKdXn Nd \\n 诃; line SO; liit 31: liiE 31: ine 3U: ine SI R * HJ \\p L.+ + + + lbue 50: c a unt \\be 卄 30: line 30: line:fl: Hie 50: luie 馬: i :w 血数 分析结果保 y Ike y c-uritrirqiue lhs33! line J3: kqj JI\"■q i r^:nu u 4 -r»rI-inIu——i rr^uv= Frhfdc -f LpJ .F lr 指导教师签名: 2011年4月12日星期二 -23 - 因篇幅问题不能全部显示,请点此查看更多更全内容