非常小的词法分析程序

来源:互联网 发布:广电网络宽带投诉电话 编辑:程序博客网 时间:2024/05/16 10:05

最近看了人家的C词法分析程序,就抽了一个C非常小的子集来做练习

/** 简单语言词法分析程序 关键字:if else while for           KEY 1 标识符:(字母|_)(字母|数字|_)*      IDT 2 运算符:= == + - * / != > <         OPT 3 常量数字:数字(数字)*               DGT 4 分界符:;( ) { } ,                 LMT 5 空白符:\n \t 空格  (文件结束符EOF作分析完毕的参照点) 2012.8.13 cc*/#include <stdlib.h>#include <stdio.h>#include <string.h>#include <assert.h>#define KEY 1#define IDT 2#define OPT 3#define DGT 4#define LMT 5char *keywords[5]={"if","else","while","for","break"};char *opts[7]={"=","==","!=","+","-","*","/"};char delimiter[7]={';','(',')','{','}',',',' '};char whitepace[3]={'\n','\t',' '};int number;//当前常数char curr[20];//当前字符串char file[1000];//当前文件的内存映射int curpos;//处理的文件当前字符串位置char filename[]="d:\\test.c";void prehandle(char *src);int isLimiter(char ch);int isLetter(char ch);int isDigit(char ch);int isOperator(char *ch);int isWhitepace(char *src);//包括: \n \t 连续两个空白符//处理字母开始的串int handleLetter(char *src){assert(isLetter(*src));int pos=0;char curch;//如果是字母可能是两种情况  标识符/关键字curch=*(src);while((isLetter(curch))||(curch=='_')||(isDigit(curch))){curr[pos]=curch;curch=*(src+pos+1);pos++;}curr[pos]='\0';curpos+=strlen(curr);//得到了当前字符串curr,判断curr的属性,可能是关键字或者标识符for(int i=0;i<5;i++){if(strcmp(keywords[i],curr)==0){return KEY;}}return IDT;}//处理下划线开始的串int handleUnderline(char *src){assert(*src=='_');int pos=0;char curch=*(src+curpos);while((isLetter(curch))||(curch=='_')||(isDigit(curch))){curr[pos++]=curch;curpos++;curch=*(src+curpos);}return IDT;}//处理数字开始的串int handleDigit(char *src){assert(isDigit((*src)));int pos=0;char curch=*(src);while(isDigit(curch)){curr[pos]=curch;curch=*(src+pos+1);pos++;}curr[pos]='\0';curpos+=strlen(curr);return DGT;}//处理分界符int handleLimitter(char *src){assert(isLimiter(*src));curr[0]=*src;curr[1]='\0';curpos++;return LMT;}//处理运算符int handleOperator(char *src){assert(isOperator(src));char curch=*src;if((curch=='+')||(curch=='-')||(curch=='*')||(curch=='/')||(curch=='>')||(curch=='<')){curr[0]=curch;curr[1]='\0';curpos++;return OPT;} // !=else if((curch=='!')&&((*(src+1))=='=')){curr[0]='!';curr[1]='=';curr[2]='\0';curpos+=2;return OPT;}// == / =else if((curch=='=')){if(((*(src+1))=='=')){curr[0]='=';curr[1]='=';curr[2]='\0';curpos+=2;return OPT;}else{curr[0]='=';curr[1]='\0';curpos++;return OPT;}}return OPT;}int main(){FILE *fp;curpos=0;if((fp=fopen(filename,"r"))==NULL){printf("Open file <%s> error .\n",filename);return 0;}//fgets(file,200,fp);int pos=0;while(!feof(fp)){file[pos++]=fgetc(fp);}file[pos]=EOF;//strcpy(file,"while(asdd==2);");puts(file);prehandle(file);puts(file);char curch;while((*(file+curpos))!=EOF){curch=*(file+curpos);int curType;while(curch==' '){curpos++;curch=*(file+curpos);}//字母if(isLetter(curch)){curType=1;}//下划线else if(curch=='_'){curType=2;}//数字else if(isDigit(curch)){curType=3;}//分界符else if(isLimiter(curch)){curType=4;}//运算符else if(isOperator((file+curpos))){curType=5;}else if(curch==EOF){printf("Lex analysis is done.\n");break;}else{curType=0;}switch(curType){case 1:printf("<%d,%s>\n",handleLetter(file+curpos),curr);break;case 2:printf("<%d,%s>\n",handleUnderline(file+curpos),curr);break;case 3:printf("<%d,%s>\n",handleDigit(file+curpos),curr);break;case 4:printf("<%d,%s>\n",handleLimitter(file+curpos),curr);break;case 5:printf("<%d,%s>\n",handleOperator(file+curpos),curr);break;default:printf("error.\n");return 0;}}fclose(fp);return 0;}//预处理掉空白符void prehandle(char *src){int pos=0;char cur;while((cur=(*(src+pos)))!=EOF){if(cur=='\n'||cur=='\t'){*(src+pos)=' ';}++pos;}}//判断是否是空白符int isWhitepace(char *src){char cur;cur=*src;//换行和tab是空白符if(cur=='\n'&&cur=='\t'){return 1;}//连续两个空白符算,第一个算,连续n个空格符,前面n-1个算,保留最后一个if(cur==' '){if(*(src+1)==' '){return 1;}}return 0;}//判断是否是分界符int isLimiter(char ch){for(int i=0;i<sizeof(delimiter)/sizeof(char);i++){if(delimiter[i]==ch){return 1;}}return 0;}//判断是否是数字int isDigit(char ch){if(ch>='0'&&ch<='9'){return 1;}else{return 0;}}//是否是字母int isLetter(char ch){if(((ch>='a'&&ch<='z'))||((ch>='A')&&(ch<='Z'))){return 1;}else{return 0;}}//判断是否是运算符int isOperator(char *ch){char curch=*ch;if((curch=='+')||(curch=='-')||(curch=='*')||(curch=='/')||(curch=='<')||(curch=='>')){return 1;}//!=else if((curch=='!')&&((*(ch+1))=='=')){return 1;}//==else if((curch=='=')){return 1;}elsereturn 0;}


1.代码扩展性。比如当要增加关键字的时候,要修改很大部分代码

可以用文件来处理,把关键字保存在一个配置文件中,提供一个增加关键字接口,一方面用户可以用这个接口来灵活添加关键字,另一方面我们也可以通过修改文件来设置哪些算关键字。

2.效率问题。当关键字很多时,一个源文件会涉及很多关键字,难道每一个查找都用完全遍历方法,这无疑会是编译效率大大降低

可以用hash来解决,有很多字符串哈希算法,包括BKDB,ELF等等,来提高编译效率


当作练习好了


原创粉丝点击