《词法分析器(共25页).doc》由会员分享,可在线阅读,更多相关《词法分析器(共25页).doc(25页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、精选优质文档-倾情为你奉上课 程 设 计 说 明 书设计题目: 词法分析器的实现 专业: 班级: 设计人: 山 东 科 技 大 学2014年 6 月 24日课 程 设 计 任 务 书学院:信息科学与工程学院 专业: 班级: 姓名: 一、 课程设计题目: 词法分析器的实现 二、 课程设计主要参考资料(1) 编译原理 韩太鲁、孙忠林著 (2) 三、课程设计应解决的主要问题(1) 词法分析器的实现 (2) (3) 四、任务发出日期: 2014-4-21 课程设计完成日期: 2014-6-24 指导教师签字: 系主任签字 : 指导教师对课程设计的评语成绩: 指导教师签字: 年 月 日词法分析器的实现一
2、、 设计目的1熟悉词法分析的基本原理,词法分析的过程以及词法分析中要注意的问题。2复习高级语言,进一步加强用高级语言来解决实际问题的能力。3通过完成词法分析程序,了解词法分析的过程。二、 设计要求1根据状态转换图直接编程编写一个词法分析程序,它从左到右逐个字符的对源程序进行扫描,产生一个个的单词的二元式,形成二元式(记号)流文件输出。在此,词法分析程序作为单独的一遍,如下图所示。处理过程:在扫描源程序字符串时,一旦识别出关键字、分隔符、标识符、无符号常数中之一,即以单词形式(各类单词均采用相同的结构,即二元式编码形式)输出。每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直至整个
3、源程序全部扫描完毕,并形成相应的单词串形式的源程序。具体任务有:(1)组织源程序的输入(2)拼出单词并查找其类别编号,形成二元式输出,得到单词流文件(3)删除注释、空格和无用符号(4)发现并定位词法错误,需要输出错误的位置在源程序中的第几行。将错误信息输出到屏幕上。(5)对于普通标识符和常量,分别建立标识符表和常量表(使用线性表存储),当遇到一个标识符或常量时,查找标识符表或常量表,若存在,则返回位置,否则返回0并且填写符号表或常量表。标识符表结构:变量名,类型(整型、实型、字符型),分配的数据区地址注:词法分析阶段只填写变量名,其它部分在语法分析、语义分析、代码生成等阶段逐步填入。常量表结构
4、:常量名,常量值2编写DFA模拟程序算法如下:DFA(S=S0,MOVE,F,ALPHABET)/*S为状态,初值为DFA的初态,MOVE为状态转换矩阵,F 为终态集,ALPHABET 为字母表,其中的字母顺序与MOVE 中列标题的字母顺序一致。*/Char Wordbuffer10=“”/单词缓冲区置空Nextchar=getchar();/读i=0;while(nextchar!=NULL)/NULL代表此类单词 if (nextchar!ALPHABET) ERROR(“非法字符”),return(“非法字符”); S=MOVESnextchar /下一状态 if(S=NULL)retu
5、rn(“不接受”);/下一状态为空,不能识别,单词错误 wordbufferi=nextchar ; /保存单词符号 i+; nextchar=getchar();Wordbufferi=0;If(SF)return(wordbuffer); /接受 Else return(“不接受”);该算法要求:实现DFA算法,给定一个DFA(初态、状态转换矩阵、终态集、字母表),调用DFA(),识别给定源程序中的单词,查看结果是否正确。1能对任何S语言源程序进行分析在运行词法分析程序时,应该用问答形式输入要被分析的S源语言程序的文件名,然后对该程序完成词法分析任务。2能检查并处理某些词法分析错误词法分析
6、程序能给出的错误信息包括:总的出错个数,每个错误所在的行号,错误的编号及错误信息。本实验要求处理以下两种错误(编号分别为1,2):1:非法字符:单词表中不存在的字符处理为非法字符,处理方式是删除该字符,给出错误信息,“某某字符非法”。2:源程序文件结束而注释未结束。注释格式为:/* */三、 设计说明(一)、需求分析1、设计要求:(1)、对给定的程序通过词法分析器能够识别一个个单词符号,并以二元式(单词类型,单词符号)显示;(2)、可以将要分析的程序保存到文件中进行读取;(3)、删除无用的空白字符、回车符、及其它非实质性符号。2、词法分析的任务从左至右逐个字符地对源程序进行扫描,产生一个个单词
7、符号,把作为字符串的源程序改造成为单词符号串的中间程序。因此,词法分析是编译的基础。执行词法分析的程序称为词法分析器或称扫描器 。3、词法分析程序功能:(1)读入源程序字符串,识别开具有独立含义的最小语法单位单词(符号);(2)把单词变换成长度统一的且为定长的属性字;(3)滤掉空格,跳过注释、换行符(4)某些预加工处理4、单词的分类(1) 基本字,也称关键词。如PASCAL语言中的begin,end,if,while和var等。(2)标识符。用来表示各种名字,如常量名、变量名、过程名和函数名等。(3)常数。各种类型的常数,如25,2.71828,a,hello和TRUE等。(4)算符。如+,-
8、,*,)(7)Error函数:输出错误信息到屏幕(8)Flag_Num函数:查填常量表(9)Flag_Sign函数:查填符号表4、程序流程图下图为程序执行的主要流程,具体内容如下:图3-4 程序执行的主要流程源代码:#include#include#include#defineLENGTH 46#define N 100typedef struct tokenchar name30;int code;int addr;token;typedef struct KeyWord/关键字char name30;/关键字名字int code;KeyWord;typedef struct symble/
9、字符char name30;/字符名字int number;/字符编码int type;/字符类型symble;char ch;int error_count; /错误出现的个数int var_count; /字符个数int num_count; /数字个数int label_count;int code_count; /代码数量int addr_count; /内码编址int LineOfPro; /错误出现的行号char filename30;FILE *Source; /源文件KeyWord key14=void,1,main,2,int,3,float,4,const,5,for,6,
10、if,7,else,8,then,9,while,10,switch,11,break,12,begin,13,end,14;token CurrentToken;token zancun;symble CurrentSimble;symble SymbleListN;symble NumListN;/错误类型void Error(int a)error_count+;switch(a)case 1:printf(error %2d 非法字符 %3d行.n,error_count,LineOfPro+1);break;case 2:printf(error %2d 没有匹配的注释符 %3d行.
11、n,error_count,LineOfPro+1);break;return;/输出void OutPut() int i=0;if(CurrentToken.code=17) / 标志符输出CurrentSimble.number=CurrentToken.addr; CurrentSimble.type=CurrentToken.code;strcpy(CurrentSimble.name,CurrentToken.name);Flag_Sign(); printf(,addr_count);elseif(CurrentToken.code=18) / 数字输出 CurrentSimbl
12、e.number=CurrentToken.addr; CurrentSimble.type=CurrentToken.code; strcpy(CurrentSimble.name,CurrentToken.name); Flag_Num(); printf(,num_count); else if(CurrentToken.code=1)&(CurrentToken.code=14)/关键字的输出 printf(,zancun.name);else/符号的输出printf(,CurrentToken.name);/判断是否是数字void IsNum()int k=0;while(ch=0)
13、&(ch=a)&(ch=A)&(ch=Z)|ch=_)/将完整的单词放入单词缓冲区CurrentToken.namei+=ch;ch=fgetc(Source);zancun=CurrentToken;for(i=0;i14;i+)/将单词缓冲区中的词和关键字数组中的词比较,看是不是关键字for(j=0;j30;j+)if(CurrentToken.namej=keyi.namej)h=0;elseh=1;break;if(h=0) break; if(h=0)CurrentToken.code=keyi.code;/将第i个关键字的机内码给单词缓冲区中现有单词的机内码CurrentToken
14、.addr=-1;/关键字地址为-1OutPut();else CurrentToken.code=17;CurrentToken.addr=addr_count+;/如果不是关键字就是普通标识符,地址加OutPut();/判断是否是注释void IsAno()char ch1;ch1=ch;ch=fgetc(Source);if(ch=*)for(;) ch=fgetc(Source);if(ch=EOF)Error(2);break;/到最后没有*说明注释不完全,有错误 if(ch=*)ch1=ch;ch=fgetc(Source);if(ch=/)/如果最后有*/说明注释完整ch=fge
15、tc(Source);break;else error_count+;Error(2);CurrentToken.name0=/;/如果注释不完整,将第一个字母看成/CurrentToken.code=22;CurrentToken.addr=-1;/符号的地址是-1OutPut();/判断是否是其它void IsOther()char ch1;int i;for(i=0;i30;i+)CurrentToken.namei=0;/将缓冲区初始化switch(ch)case+:ch1=fgetc(Source);if(ch1=) CurrentToken.name0=+;CurrentToken
16、.name1=; CurrentToken.code=38; CurrentToken.addr=-1; OutPut(); ch=fgetc(Source); break;elseCurrentToken.name0=+;CurrentToken.code=19;CurrentToken.addr=-1;OutPut();ch=fgetc(Source); break;case-:ch1=fgetc(Source);if(ch1=) CurrentToken.name0=-;CurrentToken.name1=; CurrentToken.code=39; CurrentToken.add
17、r=-1; OutPut(); ch=fgetc(Source); break;elseCurrentToken.name0=-;CurrentToken.code=20;CurrentToken.addr=-1;OutPut();ch=fgetc(Source); break;case*:ch1=fgetc(Source);if(ch1=) CurrentToken.name0=*;CurrentToken.name1=; CurrentToken.code=40; CurrentToken.addr=-1; OutPut(); ch=fgetc(Source); break;elseCur
18、rentToken.name0=*;CurrentToken.code=21;CurrentToken.addr=-1;OutPut();ch=fgetc(Source); break;case%:if(ch1=) CurrentToken.name0=%;CurrentToken.name1=; CurrentToken.code=41; CurrentToken.addr=-1; OutPut(); ch=fgetc(Source); break;elseCurrentToken.name0=%;CurrentToken.code=23;CurrentToken.addr=-1;OutPu
19、t();ch=fgetc(Source); break;case(:CurrentToken.name0=(;CurrentToken.code=24;CurrentToken.addr=-1;OutPut();ch=fgetc(Source); break;case):CurrentToken.name0=);CurrentToken.code=25;CurrentToken.addr=-1;OutPut();ch=fgetc(Source); break;case:CurrentToken.name0=;CurrentToken.code=26;CurrentToken.addr=-1;O
20、utPut();ch=fgetc(Source); break;case:CurrentToken.name0=;CurrentToken.code=27;CurrentToken.addr=-1;OutPut();ch=fgetc(Source); break;case:ch1=fgetc(Source);if(ch1=) CurrentToken.name0=;CurrentToken.name1=; CurrentToken.code=31; CurrentToken.addr=-1; OutPut(); ch=fgetc(Source); break;else CurrentToken
21、.name0=:ch1=fgetc(Source);if(ch1=) CurrentToken.name0=;CurrentToken.name1=; CurrentToken.code=32; CurrentToken.addr=-1; OutPut(); ch=fgetc(Source); break;else CurrentToken.name0=; CurrentToken.code=30; CurrentToken.addr=-1; OutPut(); ch=fgetc(Source); break;case=:CurrentToken.name0=;CurrentToken.cod
22、e=33;CurrentToken.addr=-1;OutPut();ch=fgetc(Source); break;case!:ch1=fgetc(Source);if(ch1=) CurrentToken.name0=!;CurrentToken.name1=; CurrentToken.code=34; CurrentToken.addr=-1; OutPut(); ch=fgetc(Source); break;else CurrentToken.name0=n; CurrentToken.name1=o; CurrentToken.name2=t; CurrentToken.code
23、=44; CurrentToken.addr=-1; OutPut(); ch=fgetc(Source); break;case;:CurrentToken.name0=;CurrentToken.code=35;CurrentToken.addr=-1;OutPut();ch=fgetc(Source); break; case|:ch1=fgetc(Source);if(ch1=|) CurrentToken.name0=O;CurrentToken.name1=R; CurrentToken.code=42; CurrentToken.addr=-1; OutPut(); ch=fge
24、tc(Source); break;case&:ch1=fgetc(Source);if(ch1=&) CurrentToken.name0=A;CurrentToken.name1=N; CurrentToken.name2=D; CurrentToken.code=43; CurrentToken.addr=-1; OutPut(); ch=fgetc(Source); break;case 10: / /n换行LineOfPro+;ch=fgetc(Source);break;case 13: / 回车换行LineOfPro+;ch=fgetc(Source);break;case :
25、/ 空格CurrentToken.code=60;ch=fgetc(Source);break;default:Error(1);ch=fgetc(Source); break;/查添符号int Flag_Sign()int flag,i=0;/用缓冲符号表中的符号和符号数组中的比较for(i=0;i(var_count-1);i+)flag=strcmp(CurrentSimble.name,SymbleListi.name);if(flag=0)CurrentToken.addr=var_count;/如果存在,将符号数组的地址返回return 0;SymbleListvar_count-
26、1.number=CurrentToken.addr; SymbleListvar_count-1.type=CurrentToken.code;strcpy(SymbleListvar_count-1.name,CurrentToken.name);/不存在写入printf(,SymbleListvar_count-1.name,var_count);var_count=var_count+1;return 1;/常量int Flag_Num()int flag,i=0;/用缓冲常量表中的常量和常量数组中的比较for(i=0;i(num_count-1);i+)flag=strcmp(Cur
27、rentSimble.name,NumListi.name);if(flag=0)CurrentToken.addr=num_count;/如果存在,将符号数组的地址返回return 0;NumListnum_count-1.number=CurrentToken.addr; NumListnum_count-1.type=CurrentToken.code;strcpy(NumListnum_count-1.name,CurrentToken.name);/不存在写入num_count=num_count+1;return 1;int main()int i=0,j=0;code_count=0; /代码数量var_count=1; /字符个数 label_count=1; addr_count=0; /地址计数num_count=0; /数字计数 LineOfPro=0; /行号 printf(词法分析开始:n);if(Source=fopen(D:a.txt,r)=NULL)printf(无法打开文件%s!n,filename);exit(1);ch=fgetc(Source);while(ch!=EOF)
限制150内