词法分析程序的构造
- 格式:doc
- 大小:482.50 KB
- 文档页数:15
实验一词法分析一、实验目的通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。
并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。
并依次输出各个单词的内部编码及单词符号自身值。
二、实验内容(1)功能描述:该程序是实现一个词法分析器,词法分析器的功能是输入源程序,输出单词符号。
词法分析器的单词符号常常表示成以下的二元式(单词种别码,单词符号的属性值)。
本实验中,采用的是将单词分为五种的方法。
识别关键字:main、if、int、for、while、do、return、break、continue;单词种别码为1。
标识符:单词种别码为2。
常数:为无符号整形数;单词种别码为3。
运算符:包括:+、-、*、/、=、>、<、>=、<=、!= ;单词种别码为4。
分隔符:包括:,、;、{、}、(、);单词种别码为5。
(2)程序结构描述:输入:从控制台输入一段源程序代码,对输入的代码进行词法分析,处理:分离出关键字、标识符、数值、运算符和界符。
输出:在词法分析结果表中输出每个单词所在行号、类型以及它所对应的编码。
其中,编码是自定义的,一种类型对应一个编码。
词法分析结果显示在控制台上。
(3)程序设计思路1、定义编码表,用ArrayList集合存放单词,如:关键字、运算符、分界符。
这三种单词是固定的,标示符和数字这两种单词不存放在集合中。
编码表是固定的,只需要初始化一次就够了,所以将集合定义为static类型,使其在类加载时,进行一次初始化。
2、static char allstr[] = new char[100000];该数组用于存储用户从控制台输入的所有字符。
3、//从键盘获取一个一个的字符public char Getchar() {try {ch = (char) System.in.read();} catch (Exception e) {e.printStackTrace();}return ch;}4、用while循环遍历allstr数组中存放的字符,判断分离出关键字、标示符、数字、运算符、标示符。
编译原理实验词法分析程序实验一:词法分析程序1、实验目的从左至右逐个字符的对源程序进行扫描,产生一个个单词符号,把字符串形式的源程序改造成单词符号形式的中间程序。
2、实验内容表C语言子集的单词符号及内码值单词符号种别编码助记符内码值while 1 while --if 2 if --else 3 else --switch 4 switch --case 5 case --标识符 6 id id在符号表中的位置常数7 num num在常数表中的位置+ 8 + --- 9 - --* 10 * --<= 11 relop LE< 11 relop LT== 11 relop LQ= 12 = --; 13 ; --输入源程序如下if a==1 a=a+1;else a=a+2;输出对应的单词符号形式的中间程序3、实验过程实验上机程序如下:#include "stdio.h"#include "string.h"int i,j,k;char s ,a[20],token[20];int letter(){if((s>=97)&&(s<=122))return 1;else return 0;}int Digit(){if((s>=48)&&(s<=57))return 1;else return 0;}void get(){s=a[i];i=i+1;}void retract(){i=i-1;}int lookup(){if(strcmp(token, "while")==0)return 1;else if(strcmp(token, "if")==0)return 2;else if(strcmp(token,"else")==0)return 3;else if(strcmp(token,"switch")==0)return 4;else if(strcmp(token,"case")==0)return 5;else return 0;}void main(){printf("please input you source program,end('#'):\n");i=0;do{i=i+1;scanf("%c",&a[i]);}while(a[i]!='#');i=1;memset(token,0,sizeof(char)*10);j=0;get();while(s!='#'){if(s==' '||s==10||s==13)get();else{switch(s){case'a':case'b':case'c':case'd':case'e':case'f':case'g':case'h':case'i':case'j':case'k':case'l':case'm':case'n':case'o':case'p':case'q':case'r':case's':case't':case'u':case'v':case'w':case'x':case'y':case'z':while(Digit()||letter()){token[j]=s;j=j+1;get();}retract();k=lookup();if(k==0)printf("(6,%s)\n",token); elseprintf("(%d,null)\n",k); break;case'0':case'1':case'2':case'3':case'4':case'5':case'6':case'7':case'8':case'9':while(Digit()){token[j]=s;j=j+1;get();}retract();printf("(%d,%s)\n",7,token); break;case'+':printf("(+,null)\n"); break;case'-':printf("(-,null)\n"); break;case'*':printf("(*,null)\n"); break;case'<':get();if(s=='=')printf("(relop,LE)\n"); else{retract();printf("(relop,LT)\n");}break;case'=':get();if(s=='=')printf("(relop,EQ)\n"); else{retract();printf("(=,null)\n");}break;case';':printf("(;,null)\n"); break;default:printf("(%c,error)\n",s);break;}memset(token,0,sizeof(char)*10);j=0;get();}}}4、实验结果实验结果分析:if是关键字,对应种别编码为2,输出(2,null)a是标识符,对应种别编码为6,值为a,输出(6,a)==的助记符是relop,内码值为LE,输出(relop,LE)1是常数,对应种别编码为7,值为1,输出(7,1)a是标识符,对应种别编码为6,值为a,输出(6,a)=是赋值符号,直接输出,(=,null)a是标识符,对应种别编码为6,值为a,输出(6,a)+是运算符,直接输出(=,null)1是常数,对应种别编码为7,值为1,输出(7,1);是语句结束符号,直接输出(;,null)else是关键字,对应种别编码为3,输出(3,null)a是标识符,对应种别编码为6,值为a,输出(6,a)=是赋值符号,直接输出,(=,null)a是标识符,对应种别编码为6,值为a,输出(6,a)+是运算符,直接输出(=,null)2是常数,对应种别编码为7,值为2,输出(7,2);是语句结束符号,直接输出(;,null)#是输入结束标志编译原理实验语法分析程序实验二:语法分析程序1、实验目的:将单词组成各类语法单位,讨论给类语法的形成规则,判断源程序是否符合语法规则3、实验内容:给定文法:G[E]:E→E+E|E-E|E*E|E/E|(E)E→0|1|2|3|4|5|6|7|8|9首先把G[E]构造为算符优先文法,即:G’[E]:E→E+T|TT→T-F|FF→F*G|GG→G/H|HH→(E)|i得到优先关系表如下:+ - * / i ( ) # + ·><·<·<·<·<··>·> - ·>·><·<·<·<··>·> * ·>·>·><·<·<··>·> / ·>·>·>·><·<··>·>i ·>·>·>·>·>·>( <·<·<·<·<·<·=) ·>·>·>·>·>·> # <·<·<·<·<·<·=构造出优先函数+ - * / i ( ) #f 6 8 10 12 12 2 12 2g 5 7 9 11 13 13 2 2要求输入算术表达式:(1+2)*3+2*(1+2)-4/2输出其对应的语法分析结果4、实验过程:上机程序如下:#include "stdio.h"#include "string.h"char a[20],optr[10],s,op;int i,j,k,opnd[10],x1,x2,x3;int operand(char s){if((s>=48)&&(s<=57))return 1;else return 0;}int f(char s){switch(s){case'+':return 6;case'-':return 8;case'*':return 10;case'/':return 12;case'(':return 2;case')':return 12;case'#':return 2;default:printf("error");}}int g(char s){switch(s){case'+':return 5;case'-':return 7;case'*':return 9;case'/':return 11;case'(':return 13;case')':return 2;case'#':return 2;default:printf("error");}}void get(){s=a[i];i=i+1;}void main(){printf("请输入算数表达式,并以‘#’结束:\n");i=0;do{scanf("%c",&a[i]);i++;}while(a[i-1]!='#');i=0;j=0;k=0;optr[j]='#';get();while((optr[j]!='#')||(s!='#')){if(operand(s)){opnd[k]=s-48;k=k+1;get();}else if(f(optr[j])<g(s)){j=j+1;optr[j]=s;get();}else if(f(optr[j])==g(s)){if(optr[j]=='('&&s==')'){j=j-1;get();}else if(optr[j]=='('&&s=='#'){printf("error\n");break;}else if(optr[j]=='#'&&s==')'){printf("error\n");break;}}else if(f(optr[j])>g(s)){op=optr[j];j=j-1;x2=opnd[k-1];x1=opnd[k-2];k=k-2;switch(op){case'+':x3=x1+x2;break;case'-':x3=x1-x2;break;case'*':x3=x1*x2;break;case'/':x3=x1/x2;break;}opnd[k]=x3;k=k+1;printf("(%c,%d,%d,%d)\n",op,x1,x2,x3);}else{printf("error\n");break;}}if(j!=0||k!=1)printf("error\n");}5、实验结果:实验结果分析:(1+2)*3+2*(1+2)-4/2#因为‘)’优先级大于‘*’,先计算1+2=3,并输出(+,1,2,3)原式变为:3*3+2*(1+2)-4/2#因为‘*’优先级大于‘+’,先计算3*3=9,并输出(*,3,3,9)原式变为:9+2*(1+2)-4/2#因为‘)’优先级大于‘-’,先计算1+2=3,并输出(+,1,2,3)原式变为:9+2*3-4/2#因为‘*’优先级大于‘-’,先计算2*3=6,并输出(*,2,3,6)原式变为:9+6-4/2#因为‘/’优先级大于‘#’,先计算4/2=2,并输出(/,4,2,2)原式变为:9+6-2#因为‘-’优先级大于‘#’,先计算6-2=4,并输出(-,6,2,4)原式变为:9+4#因为‘+’优先级大于‘#’,计算9+4=13,并输出(+,9,4,13)原式变为13#优先级等于#,跳出while循环,运算结束!。
词法分析程序的设计与实现方法1:采用C作为实现语言,手工编制一.文法及状态转换图1.语言说明:C语言有以下记号及单词:(1)标识符:以字母开头的、后跟字母或数字组成的符号串。
(2)关键字:标识符集合的子集,该语言定义的关键字有32个,即auto,break,case,char,const,continue,default,do,double,else,enum, extern,float,for,goto,if,int,long,register,return,short,signed,static, sizeof,struct,switch,typedef ,union,unsigned ,void, volatile和while。
(3)无符号数:即常数。
(4)关系运算符:<,<=,==,>,>=,!=。
(5)逻辑运算符:&&、||、!。
(6)赋值号:=。
(7)标点符号:+、++、-、--、*、:、;、(、)、?、/、%、#、&、|、“”、,、.、{}、[]、_、^等(8)注释标记:以“/*”开始,以“*/”结束。
(9)单词符号间的分隔符:空格。
2.记号的正规文法:仅给出各种单词符号的文法产生式(1)标识符的文法id->letter ridrid->ε|letter rid|digit rid(2)无符号整数的文法digits->digit remainderremainder->ε|digit remainder(3)无符号数的文法num->digit num1num1->digit num1|. num2|E num4|εnum2->digit num3num3->digit num3|E num4|εnum4->+digits|-digits|digit num5digits->digit num5num5->digit num5|ε(4)关系运算符的文法relop-> <|<=|==|>|>=|!=(5)赋值号的文法assign_op->=(6)标点符号的文法special_symbol->+|-|*|%|#|^|(|)|{|}|[|]|:|;|”|?|/|,|.& (7)逻辑运算符的文法logic->&&| || | !(8)注释头符号的文法note->/starstar->*3.状态转换图其中,状态0是初始状态,若此时读入的符号是字母,则转换到状态1,进入标识符识别过程;如果读入的是数字,则转换到状态2,进入无符号数识别过程;……;若读入的符号是/,转换到状态11,再读入下一个符号,如果读入的符号是*,则转换到状态12,进入注释处理状态;如果在状态0读入的符号不是语言所定义的单词符号的开始字符,则转换到状态13,进入错误处理状态。
一、词法分析实验报告一、实验目的与要求通过编写和调试一个词法分析程序,掌握在对程序设计语言的源程序进行扫描的过程中,将字符形式的源程序流转化为一个由各类单词符号组成的流的词法分析方法。
二、实现方法与环境词法分析是编译程序的第一个处理阶段,可以通过两种途径来构造词法分析程序。
其一是根据对语言中各类单词的某种描述或定义(如BNF),用手工的方式(例如可用C语言)构造词法分析程序。
一般地,可以根据文法或状态转换图构造相应的状态矩阵,该状态矩阵连同控制程序一起便组成了编译器的词法分析程序;也可以根据文法或状态转换图直接编写词法分析程序。
构造词法分析程序的另外一种途径是所谓的词法分析程序的自动生成,即首先用正规式对语言中的各类单词符号进行词型描述,并分别指出在识别单词时,词法分析程序所应进行的语义处理工作,然后由一个所谓词法分析程序的构造程序对上述信息进行加工。
如美国BELL实验室研制的LEX就是一个被广泛使用的词法分析程序的自动生成工具。
总的来说,开发一种新语言时,由于它的单词符号在不停地修改,采用LEX等工具生成的词法分析程序比较易于修改和维护。
一旦一种语言确定了,则采用手工编写词法分析程序效率更高。
三、实验内容完成无符号常数这一类典型单词的识别和各种常数、关键字、标识符和各种运算符的扫描器的设计和实现。
输入:由符合和不符合所规定的单词类别结构的各类单词组成的源程序文件。
输出:把单词的字符形式表示翻译成编译器的内部表示,确定单词串的输出形式,并将其结果放到某个文件中。
要求所输出的每一单词均按形如(CLASS,V ALUE)的二元式编码。
对于变量和常数,CLASS字段为相应的类别码;V ALUE字段则是该标识符、常数的具体值或在其符号表中登记项的序号(要求在变量名表登记项中存放该标识符的字符串;常数表登记项中则存放该常数的二进制形式)。
对于关键字和运算符,采用一词一类的编码形式;由于采用一词一类的编码方式,所以仅需在二元式的CLASS字段上放置相应的单词的类别码,V ALUE字段则为“空”。
实验1-3 《编译原理》S语言词法分析程序设计方案一、实验目的了解词法分析程序的两种设计方法之一:根据状态转换图直接编程的方式;二、实验内容ﻩ1.根据状态转换图直接编程编写一个词法分析程序,它从左到右逐个字符的对源程序进行扫描,产生一个个的单词的二元式,形成二元式(记号)流文件输出。
在此,词法分析程序作为单独的一遍,如下图所示。
具体任务有:(1)组织源程序的输入(2)拼出单词并查找其类别编号,形成二元式输出,得到单词流文件(3)删除注释、空格和无用符号(4)发现并定位词法错误,需要输出错误的位置在源程序中的第几行。
将错误信息输出到屏幕上。
(5)对于普通标识符和常量,分别建立标识符表和常量表(使用线性表存储),当遇到一个标识符或常量时,查找标识符表或常量表,若存在,则返回位置,否则返回0并且填写符号表或常量表。
标识符表结构:变量名,类型(整型、实型、字符型),分配的数据区地址注:词法分析阶段只填写变量名,其它部分在语法分析、语义分析、代码生成等阶段逐步填入。
常量表结构:常量名,常量值三、实验要求1.能对任何S语言源程序进行分析ﻩ在运行词法分析程序时,应该用问答形式输入要被分析的S源语言程序的文件名,然后对该程序完成词法分析任务。
2.能检查并处理某些词法分析错误词法分析程序能给出的错误信息包括:总的出错个数,每个错误所在的行号,错误的编号及错误信息。
本实验要求处理以下两种错误(编号分别为1,2):1:非法字符:单词表中不存在的字符处理为非法字符,处理方式是删除该字符,给出错误信息,“某某字符非法”。
2:源程序文件结束而注释未结束。
注释格式为:/* …… */四、保留字和特殊符号表单词的构词规则:字母=[A-Za-z]数字=[0-9]标识符=(字母|_)(字母|数字)*数字=数字(数字)*(.数字+| )四、S语言表达式和语句说明ﻩ1.算术表达式:+、-、*、/、%ﻩ2.关系运算符:>、>=、<、<=、==、!=3.赋值运算符:=,+=、-=、*=、/=、%=ﻩ4.变量说明:类型标识符变量名表;5.类型标识符:int char floatﻩ6.If语句:if表达式then 语句[else语句] ﻩ7.For语句:for(表达式1;表达式2;表达式3) 语句ﻩ8.While语句:while表达式do 语句9.S语言程序:由函数构成,函数不能嵌套定义。
编译程序的⼯作过程:词法分析、语法分析、语义分析、优化、
⽬标代码⽣成
词法分析:也就是从左到右⼀个⼀个地读⼊源程序,识别⼀个单词或符号,并进⾏归类。
语法分析:在词法分析的基础上,将单词序列分解成各类语法短语,如“程序”语句“表达式”等
语义分析:审查源程序是否有语义的错误,当不符合语⾔规范的时候,程序就会报错。
代码优化:这个阶段是对前阶段的中间代码进⾏变换或改造,⽬的是使⽣成的⽬标代码更为⾼效,即节省时间和空间。
⽬标代码⽣成:也就是吧优化后的中间代码变换成指令代码或汇编代码。
实验一:词法分析程序设计【开发语言及实验环境】开发语言:C/C++/C#实验环境:Microsoft V isual Studio 6.0/ Microsoft V isual Studio .NET 2005【实验目的】1、理解词法分析在编译程序中的作用2、加深对有穷自动机模型的理解3、掌握词法分析程序的实现方法和技术【实验要求】对一个简单的语言的子集编制一个一遍扫描的词法分析程序。
【实验内容】1、待分析的简单语言词法(1)关键字main if else int char return void while所有关键字都是小写。
(2)专用符号= + - * / < <= > >= == != ; : , { } [ ] ( )(3)其他单词是标识符(ID)和整形常数(NUM),通过以下正规式定义:ID=letter(letter|digit)* NUM=digit(digit)*Letter→a|…|z|A|…|Z digit→0|…|9(4)空格由空白、制表符和换行符组成。
空格一般用来分隔ID、NUM、运算符、界符和关键字。
词法分析阶段空格通常被忽略。
2、各种单词符号对应的种别编码单词符号种别码单词符号种别码单词符号种别码main 1 - 23 : 34int 2 * 24 > 35char 3 / 25 < 36if 4 ( 26 >= 37else 5 ) 27 <= 38for 6 [ 28 == 39while 7 ] 29 != 40ID 10 { 30 '\0' 1000NUM 20 } 31 ERROR -1= 21 , 32+ 22 : 333、词法分析程序的功能输入:所给文法的源程序字符串输出:二元组(syn,token或sum)构成的序列。
syn为单词种别码;token为存放的单词自身字符串;sum为整形常数。
C 语言词法分析器构造实验报告02计算机(2) 2002374203 冯绍欣一、题目要求:完成一个C 语言的词法分析器的构造。
此词法分析器能识别附值语句、循环语句、条件语句、并能处理注释。
二、设计方案:这个词法分析器分析的主要关键字有:main, int, float, char, if, else, for, while, do, switch, case, break; default 。
选择要分析的c 文件,首先对其去掉注释和与空格处理,再根据字符的不同类型分析。
1、全局数据结构:字符数组 set[ ]:存放从文件中读到的所有字符;str[ ]:存放经过注释处理和预空格处理的字符;strtoken[ ]:存放当前分析的字符;结构体 KEYTABLE :存放关键字及其标号;全局字符变量 ch :当前读入字符;全局整型变量 sr, to :数组str, strtoken 的指针。
2、以层次图形式描述模块的组成及调用关系3、主要函数的设计要求(功能、参数、返回值):openfile :打开文件;GetChar :将下一个输入字符读到ch 中,搜索指示器前移一字符位置;GetBC :检查ch 中的字符是否为空白。
若是,则调用GetChar 直至ch 中进入一个非空白字符; Main ( )Openfile ( ) Analysis ( )Reflesh() Process()Set32()GetChar() GetBC()Concat()Reserve()IsLetter() IsDigit()Retract()GetChar()Concat :将ch 中的字符连接到strtoken 之后;IsLetter 和IsDigit :布尔函数过程,分别判断ch 中的字符是否为字母和数字;Reserve :整型函数过程,对strtoken 中的字符串查找关键字表,若是关键字则返回编码,否则返回-1;Retract :将搜索指示器回调一个字符位置,将ch 置为空白字符;reflesh :刷新,把strtoken 数组置为空;prearrange1:将注释部分置为空格;prearrange2:预处理空格,去掉多余空格;analysis:词法分析;main :主函数。
实验一词法分析设计实验学时:4实验类型:综合实验要求:必修一、实验目的通过本实验的编程实践,使学生了解词法分析的任务,掌握词法分析程序设计的原理和构造方法,使学生对编译的基本概念、原理和方法有完整的和清楚的理解,并能正确地、熟练地运用。
二、实验内容用VC++/VB/JAVA语言实现对C语言子集的源程序进行词法分析。
通过输入源程序从左到右对字符串进行扫描和分解,依次输出各个单词的内部编码及单词符号自身值;若遇到错误则显示“Error”,然后跳过错误部分继续显示;同时进行标识符登记符号表的管理。
以下是实现词法分析设计的主要工作:(1)从源程序文件中读入字符。
(2)统计行数和列数用于错误单词的定位。
(3)删除空格类字符,包括回车、制表符空格。
(4)按拼写单词,并用(内码,属性)二元式表示。
(属性值——token的机内表示)(5)如果发现错误则报告出错(6)根据需要是否填写标识符表供以后各阶段使用。
单词的基本分类:◆关键字:由程序语言定义的具有固定意义的标识符。
也称为保留字例如if、 for、while、printf ;单词种别码为1。
◆标识符:用以表示各种名字,如变量名、数组名、函数名;◆常数:任何数值常数。
如 125, 1,0.5,3.1416;◆运算符:+、-、*、/;◆关系运算符: <、<=、= 、>、>=、<>;◆分界符:;、,、(、)、[、];三、实验要求1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。
2、将标识符填写的相应符号表须提供给编译程序的以后各阶段使用。
3、根据测试数据进行测试。
测试实例应包括以下三个部分:◆全部合法的输入。
◆各种组合的非法输入。
◆由记号组成的句子。
4、词法分析程序设计要求输出形式:例:输入VC++语言的实例程序:If i=0 then n++;a﹤= 3b %);输出形式为:单词二元序列类型位置(行,列)(单词种别,单词属性)for (1,for ) 关键字(1,1)i ( 6,i ) 标识符(1,2)= ( 4,= ) 关系运算符(1,3)0 ( 5,0 ) 常数(1,4)then ( 1,then) 关键字(1,5)n (6,n ) 标识符(1,6)++ Error Error (1,7); ( 2, ; ) 分界符(1,8)a (6,a ) 标识符(2,1)﹤= (4,<= ) 关系运算符(2,2)3b Error Error (2,4)% Error Error (2,4)) ( 2, ) ) 分界符(2,5); ( 2, ; ) 分界符(2,6)实验报告正文:◆功能描述:该程序具有词法分析功能,即面对一段程序源代码,通过该程序,能检查出源代码是否由词法错误。
通达学院专业课程设计II 题目:词法分析程序的构造专业计算机通信学生姓名班级学号28班********指导教师徐佳指导单位计算机学院计算机科学与技术系日期2012.11.12-2012.11.23词法分析程序的构造一、课题内容和要求通过状态转换图构造C或者PASCAL语言子集的词法分析程序。
原理解析:选取语言,例如选取了C语言,选取其中一个子集,例如包含了部分关键字main、float、if、for等等,特殊符号( 、<、=、+等等,特殊定义的标识符变量以及部分常量等,采用《编译原理》词法分析中有穷自动机的思想构建出该语言子集的状态转换图,并编码实现。
基本要求:(1)将选取的语言子集编写一个简单程序,放在一个文本文件中;(2)要将一个个单词区分清楚并归类(例如for属于关键字)。
二、需求和思路分析本课题是用C++语言设计,选取的是C语言子集。
编写对简单语言进行词法分析的词法分析程序。
1、识别子集中的关键字、标识符、常数、运算符和分界符等。
2、对子集中的字符类型进行归类三、概要设计(1)状态转换图:(2)核心代码:1)定义:char cbuffer;char*keyword[14]={"if","else","for","while","do","float","return","break","continue","int","void ","main","const","printf"}; //关键字char *border[8]={ "," , ";" , "{" , "}" , "(" , ")" ,":=","."}; //分隔符char *arithmetic[6]={"+" , "-" , "*" , "/" , "++" , "--"}; //运算符char *relation[7]={"<" , "<=" , "=" , ">" , ">=" , "==" ,"!="}; //关系运算符char *lableconst[80]; //标识符2)函数调用:search(char searchchar[],int wordtype)//查找类型alphaprocess(char buffer) //字符处理过程digitprocess(char buffer) //数字处理过程otherprocess(char buffer) //分隔符、运算符、逻辑运算符等main()//主函数3) 状态类型:状态转换图的形式:■每个状态对应一个带标号的case语句■转向边对应goto语句switch (wordtype){case 1:{ for (i=0;i<=13;i++) //关键字{if (strcmp(keyword[i],searchchar)==0)return(i+1);}return(0);}case 2:{for (i=0;i<=7;i++) //分隔符{if (strcmp(border[i],searchchar)==0)return(i+1);}return(0);}case 3:{for (i=0;i<=5;i++) //运算符{if (strcmp(arithmetic[i],searchchar)==0)return(i+1);}return(0);}case 4:{for (i=0;i<=6;i++) //关系运算符{if (strcmp(relation[i],searchchar)==0)return(i+1);}return(0);}case 5:{for (t=40;t<=constnum;t++) //常数{if (strcmp(searchchar,lableconst[t])==0)//判断该常数是否已出现过return(t+1);}lableconst[t-1]=(char *)malloc(sizeof(searchchar)); //为新的元素分配内存空间strcpy(lableconst[t-1],searchchar); //为数组赋值lableconst 指针数组名constnum++; //常数个数自加return(t);}case 6:{for (i=0;i<=lableconstnum;i++){if (strcmp(searchchar,lableconst[i])==0) //判断标识符是否已出现过return(i+1);}lableconst[i-1]=(char *)malloc(sizeof(searchchar));strcpy(lableconst[i-1],searchchar);lableconstnum++; //标识符个数自加return(i);}5) 单字符判断if (otypetp=search(othertp,3)) //判断该运算符是否是由连续的两个字符组成的{cout<<"row: "<<row<<" String= "<<othertp<<"\t\t\t"<<"运算符"<<endl;fp.get(buffer);goto out;}else //单字符逻辑运算符{othertp[1]='\0';cout<<"row: "<<row<<" String= "<<othertp<<"\t\t\t"<<"逻辑运算符"<<endl;goto out;}四、详细设计实验环境:visual C++6.0 win7系统源程序代码:#include <iostream>#include <ctype.h>#include <fstream>#include <string.h>#include <malloc.h>using namespace std;ifstream fp("09002801.txt",ios::in);char cbuffer;char *keyword[14]={"if","else","for","while","do","float","return","break","continue","int","void" ,"main","const","printf"}; //关键字char *border[8]={ "," , ";" , "{" , "}" , "(" , ")" ,":=","."}; //分隔符char *arithmetic[6]={"+" , "-" , "*" , "/" , "++" , "--"}; //运算符char *relation[7]={"<" , "<=" , "=" , ">" , ">=" , "==" ,"!="}; //关系运算符char *lableconst[80]; //标识符int constnum=40;int lableconstnum=0; //统计常数和标识符数量int row=1;int search(char searchchar[],int wordtype){int i=0,t=0;switch (wordtype){case 1:{ for (i=0;i<=13;i++) //关键字{if (strcmp(keyword[i],searchchar)==0)return(i+1);}return(0);}case 2:{for (i=0;i<=7;i++) //分隔符{if (strcmp(border[i],searchchar)==0)return(i+1);}return(0);}case 3:{for (i=0;i<=5;i++) //运算符{if (strcmp(arithmetic[i],searchchar)==0)return(i+1);}return(0);}case 4:{for (i=0;i<=6;i++) //关系运算符{if (strcmp(relation[i],searchchar)==0)return(i+1);}return(0);}case 5:{for (t=40;t<=constnum;t++) //常数{if (strcmp(searchchar,lableconst[t])==0)//判断该常数是否已出现过return(t+1);}lableconst[t-1]=(char *)malloc(sizeof(searchchar)); //为新的元素分配内存空间strcpy(lableconst[t-1],searchchar); //为数组赋值lableconst指针数组名constnum++; //常数个数自加return(t);}case 6:{for (i=0;i<=lableconstnum;i++){if (strcmp(searchchar,lableconst[i])==0) //判断标识符是否已出现过return(i+1);}lableconst[i-1]=(char *)malloc(sizeof(searchchar));strcpy(lableconst[i-1],searchchar);lableconstnum++; //标识符个数自加return(i);}default:cout<<"错误!";}}char alphaprocess(char buffer) //字符处理过程{int atype;int i=-1;char alphatp[20];while ((isalpha(buffer))||(isdigit(buffer)))//这两个函数分别是判字符和判数字函数位于ctype.h中{alphatp[++i]=buffer;fp.get(buffer);}alphatp[i+1]='\0';//在末尾添加字符串结束标志if (atype=search(alphatp,1))cout<<"row: "<<row<<" String= "<<alphatp<<"\t\t\t"<<"关键字"<<endl;else{atype=search(alphatp,6); //标识符cout<<"row: "<<row<<" String= "<<alphatp<<"\t\t\t"<<"标识符"<<endl;}return(buffer);}char digitprocess(char buffer) //数字处理过程{int i=-1;char digittp[20];int dtype;while ((isdigit(buffer))){digittp[++i]=buffer;fp.get(buffer);}digittp[i+1]='\0';dtype=search(digittp,5);cout<<"row: "<<row<<" String= "<<digittp<<"\t\t\t"<<"数字"<<endl;return(buffer);}char otherprocess(char buffer) //分隔符、运算符、逻辑运算符等{int i=-1;char othertp[20];int otype,otypetp;othertp[0]=buffer;othertp[1]='\0';if (otype=search(othertp,3)){fp.get(buffer);othertp[1]=buffer;othertp[2]='\0';if (otypetp=search(othertp,3)) //判断该运算符是否是由连续的两个字符组成的{cout<<"row: "<<row<<" String= "<<othertp<<"\t\t\t"<<"运算符"<<endl;fp.get(buffer);goto out;}else //单字符逻辑运算符{othertp[1]='\0';cout<<"row: "<<row<<" String= "<<othertp<<"\t\t\t"<<"逻辑运算符"<<endl; goto out;}}if (otype=search(othertp,4)) //关系运算符{fp.get(buffer);othertp[1]=buffer;othertp[2]='\0';if (otypetp=search(othertp,4)) //判断该关系运算符是否是由连续的两个字符组成的{cout<<"row: "<<row<<" String= "<<othertp<<"\t\t\t"<<"关系运算符"<<endl; fp.get(buffer);goto out;}else //单字符逻辑运算符{othertp[1]='\0';cout<<"row: "<<row<<" String= "<<othertp<<"\t\t\t"<<"逻辑运算符"<<endl; goto out;}}if (buffer=='!') //"=="的判断{fp.get(buffer);if (buffer=='=')//cout<<"!= (2,2)\n";fp.get(buffer);goto out;else{if (otype=search(othertp,2)) //分界符{cout<<"row: "<<row<<" String= "<<othertp<<"\t\t\t"<<"分隔符"<<endl;fp.get(buffer);goto out;}}if ((buffer!='\n')&&(buffer!=' '))cout<<"错误!非法字符为:"<<"\t\t\t"<<buffer<<endl;fp.get(buffer);out:return(buffer);}void main(){printf("=========================词法分析器==========================\n"); int i;for (i=0;i<=50;i++){lableconst[i]=" ";//用于保存标识符}if (!fp)cout<<"源文件无法打开,请检查!"<<endl;else{fp.get (cbuffer);while (!fp.eof()){if(cbuffer=='\n'){row++;fp.get(cbuffer);}else if (isalpha(cbuffer)){cbuffer=alphaprocess(cbuffer);}else if (isdigit(cbuffer))cbuffer=digitprocess(cbuffer);}elsecbuffer=otherprocess(cbuffer);}cout<<"标识符个数是:"<<lableconstnum<<"分别是"<<endl; i=0;while(i<lableconstnum){cout<<lableconst[i++]<<" ";}cout<<endl;cout<<"词法分析结束!\n";getchar();}}(3)程序流程图:五、测试数据及其结果分析若源程序中没有09002801.txt文档,则会出现如下提示:若文档中包含09002801.txt文档,文档代码为:运行后结果如下:六、调试过程中的问题在代码调试过程中,由于代码编写时将主函数main和文件打开的顺序颠倒,导致未写入源文档也会提示词法分析结束,实际上并未进行词法分析过程,应该提示文件打开错,返回检查。