实验一词法扫描器设计一实验目的通过设计调试词法分析程序,实现从源程序中分出各种单词的方法;加深对课堂教学的理解;提高词法分析方法的实践能力。二实验内容设计一个简单的类C语言的词法扫描器。三实验要求1、根据附录给定的文法,从输入的类C语言源程序中,识别出各个具有独立意义的单词,即关键字、标识符、常数、运算符、分隔符五大类;文法见最后附录。2、提供源程序输入界面;3、词法分析后可查看符号表和TOKEN串表;4、保存符号表和TOKEN串表(如:文本文件);5、遇到错误时可显示提示信息,然后跳过错误部分继续进行分析。四实验报告(一)系统功能(包括各个子功能模块的功能说明)程序主要实现的功能:通过词法分析程序,在源程序中识别并分别出数字、标识符和保留字,并分别将记录到指定的文本文档中,过程中不符合符号表要求的字符视为错误处理。子功能模块:关键字处理;数字处理;字母的处理(标识符和保留字);运算符处理;主程序。(二)开发平台(操作系统、设计语言)Windows7,MicrosoftVisualC++6.0。(三)设计方案(1)主数据流图开始读入文件内容关闭文件调用caculate()函数进行词法分析结束(2)主要子程序的流程框图子流程开始打开或者创建分析结果输入文件读取文件内容判断是否是空格,缩进,换行不做处理Y是否是字符将字符临时赋值给字符串变量Y读取下一个字符N判断所获得的字符串变量是否是关键字将变量类型1和关键字输入到界面并写入文件将变量类型2和标识符输入到界面并写如文件是否是字符或者数字YNYN是否数字N将数值赋给变量读取下一字符输入数字或者指数或者小数点YY将变量类型3和数字写入结果N是否运算符N对每一运算符去相应的判断措施(省略)字符,无法识别类型写入结果结束子流程文件读完NY(3)主要数据结构:idLettertempint10Numint10|NumOP+|-|*|/|||=|(|)|;|‘|==|=|=|!=Keywordif|then|else|while|doLettera|b|c|d|e|f|g|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|ZNum0|1|2|3|4|5|6|7|8|9|εtempLettertemp|Numtemp|ε(四)具体设计过程(包括主控程序、各个功能模块的具体实现)主模块:judge(FILE*,char*);用词法分析过程的判断子功能模块:Keyword(string);用于判断字符串是否是关键词Letter(charc);用于判断c是否是字母Num(charc);用于判断c是否是数字(五)源代码#defineMAX50//长度最大值50charch='';//字符空格stringkeyword[50]={bool,break,case,include,char,const,continue,default,do,double,else,false,float,for,if,int,long,namespace,new,return,short,signed,struct,switch,true,using,void,while,then,class};//常见关键字数组只用了部分30个//************************关键字的处理过程****************************************intgjz(stringc){inti;for(i=0;iMAX;i++){if(keyword[i].compare(c)==0)return1;//与关键字数组中用相同的就返回真,否则假}return0;}//************************字母的处理过程****************************************intzm(charc){if(((c='z')&&(c='a'))||((c='Z')&&(c='A')))return1;//比较字母的ASCII码值,在大小写范围内,返回真,否则假。elsereturn0;}//************************数字的处理过程****************************************intnum(charc){if(c='0'&&c='9')return1;//比较字母的ASCII码值,在0-9范围内,返回真,否则假。elsereturn0;}//************************运算符处理过程*******************************************//过程中指针总是向前看一个,决定当前的各种单词是否结束,或是根据后边的输入消除当前字符二义性。voidcaculate(FILE*fpin){ofstreamout(lex.txt,ios::out);//文件token.txt输入内存stringarr=;//字符串while((ch=fgetc(fpin))!=EOF){//没到文件末尾,循环至末尾arr=;if(ch==''||ch=='\t'||ch=='\n'){}//空格,缩进,换行,均不做操作elseif(zm(ch)){//若有字符while(zm(ch)||num(ch)){//当有字符或数字的时候,循环arr=arr+ch;//组织拼接字符串ch=fgetc(fpin);//ch得到文件输入字符}fseek(fpin,-1L,SEEK_CUR);//循环结束后,重定位流指针,从当前位置左移一位。开始判断新的输入是什么类型if(gjz(arr)){outarr\t1\t关键字endl;}//若是关键字,则输出类型1,关键字elseoutarr\t2\t标识符endl;//若是标识符,则输出类型2,标识符}elseif(num(ch)){//若是数字while(num(ch)||ch=='.'&&num(fgetc(fpin))||fgetc(fpin)=='e'||ch=='e')//数字||.&&(得到一个字符||字符是e||输入是e){if(ch=='.')//.fseek(fpin,-1L,SEEK_CUR);//指针左移arr=arr+ch;if(ch=='e')//e,自然对数的底数{ch=fgetc(fpin);//新读入if(ch=='+')arr+='+';else{arr+='-',fseek(fpin,-1L,SEEK_CUR);};//指针左移}ch=fgetc(fpin);}fseek(fpin,-3L,SEEK_CUR);//指针左移3outarr\t3\t无符号数endl;//无符号数3}elseswitch(ch){case'+':case'-':case'*':case'=':case'/':outch\t4\t运算符endl;break;//+-*/=运算符4case'(':case')':case'[':case']':case';':case'#':case'.':case',':case'{':case'}':outch\t5\t界限符endl;break;//(){}[],.#;界限符case'':{stringstring1=;do{string1+=ch;ch=fgetc(fpin);}while(ch!='');//循环得到string1+=ch;outstring1\t6\t字符串endl;//字符串6}break;case':':{ch=fgetc(fpin);if(ch=='=')out:=\t4\t运算符endl;//运算符:=else{out=\t4\t运算符endl;;//运算符=fseek(fpin,-1L,SEEK_CUR);}//当指针回退一个字符}break;case'':{ch=fgetc(fpin);if(ch=='=')out=\t4\t运算符endl;//运算符=if(((ch='z')&&(ch='a'))||((ch='Z')&&(ch='A'))){fseek(fpin,-1L,SEEK_CUR);//指针回退一个字符out\t5\t界限符endl;}//界限符elseif(ch=='')out\t7\t控制符endl;//控制符elseif(ch=='')out\t4\t运算符endl;//运算符else{out\t4\t运算符endl;//运算符fseek(fpin,-1L,SEEK_CUR);}//指针回退一个字符}break;case'':{ch=fgetc(fpin);if(ch=='=')out=\t4\t运算符endl;//运算符=if(ch=='')out\t7\t控制符endl;//控制符if(ch=='\n'){fseek(fpin,-1L,SEEK_CUR);out\t5\t界限符endl;}//界限符后边没有操作数。else{out\t4\t运算符endl;//运算符fseek(fpin,-1L,SEEK_CUR);}}break;default:outch\t无法识别字符endl;//无法识别字符}}}voidread(){ifstreamin(lex.txt,ios::out);//内存输出lex.txt内容stringx;while(in)//输入格式的确定{inx;//cinx;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。coutx'\t';inx;cout.width(30);coutx'\t';inx;cout.width(30);coutxendl;}}//**************************************主程序***************************************voidmain(){charin_fn[30];//定义存放文件路径的数组FILE*fpin;cout请输入源文件名(包括路径和后缀名):\n;for(;;){//无条件循环cinin_fn;//输入路径名if((fpin=fopen(in_fn,r))!=NULL)break;//以只读方式打开文件,如果成功跳出循环继续,若不成功则输出错误信息。elsecout文件路径错误!请输入源文件(包括路径和后缀名):;}cout\n********************词法分析结果如下*********************endl;caculate(fpin);//调用分析程序fclose(fpin);//关闭文件coutendl;//结束行read();//调用read(),完成输出//分析文本文件内容为一个简单的C语言程序cout\n********************lex.txt词法分析完毕*********************endl;system(pause);//屏幕停留}五实验结果运行结果源代码六实验总结通过本次试验,我更加详细的了解了词法分析器的构造过程和工作原理。作为编译器的第一步,词法分析器起着重要的作用,它识别并分别出数字和字母(标识符和保留字),构成并输出TOKEN序列,为后面的语法分析和语义分析建立基础。同时,本实验也是我对于编译器的一些基本行为有了一定的了解,让我能够更加有效率的编写