赞
踩
词法分析和语法分析是编译原理中必要的部分,是需要花费一定时间去学习理解的,本文简单介绍了使用c语言如何编写c语言的词法分析器。(ps:完整代码的链接在文末)
词法分析器的功能输入源程序,按照构词规则分解成一系列单词符号。单词是语言中具有独立意义的最小单位,包括关键字、标识符、运算符、界符和常量等。
(1) 关键字:是由程序语言定义的具有固定意义的标识符。例如begin,end,if,while都是保留字。这些字通常不用作一般标识符。
(2) 标识符:用来表示各种名字,如变量名,数组名,过程名等等。
(3) 常数 :常数的类型一般有整型、实型、布尔型、文字型等。
(4) 运算符:如+、-、*、/等等。
(5) 界符 :如逗号、分号、括号、等等。
有了对词法分析器的定义,我们编写的词法分析器的输出理所当然应当是如下的形式:
(单词,单词属性,id(种别码))
如:(if,关键字,3)
id通常情况下可以自己定义,例如无符号整数的id可以设为1,只要能区别不同的属性即可。(ps:如果在编写时有对应的种别码表,照着写就完事儿了。)
种别码表示例
单词符号 | 种别码 |
---|---|
NUM | 0 |
Letter | 1 |
main | 2 |
--建立分析时的缓冲空间
char ch =' '; //存放读入当前的输入字符
int Line_NO; //纪录行号
--建立关键字表
struct keywords{ //关键字
char lexptr[MAXBUF];
int token;
};
struct keywords symtable[MAX];
char str[MAX][10]={"int","char","float","main","double","case","for","if","auto","else","do","while","void","static","return","break","struct","const","union","switch","typedef","enum"}; //记为3~24
--初始化关键字表
void init(){ //关键字表初始化
int j;
for(j=0; j<MAX; j++){
strcpy(symtable[j].lexptr,str[j]);
symtable[j].token=j+3;
}
}
--Iskeyword函数分析关键字
int Iskeyword(char * is_res){ //对关键字进行搜索
int i;
for(i=0;i<MAX;i++){
if((strcmp(symtable[i].lexptr,is_res))==0)
break;
}
if(i<MAX)
return symtable[i].token;
else
return 0;
}
--IsLetter函数分析字母
int IsLetter(char c){ //判断是否为字母
if(((c>='a')&&(c<='z'))||((c>='A')&&(c<='Z')))
return 1;
else
return 0;
}
--IsDigit函数分析数字
int IsDigit(char c){ //判断是否为数字
if(c>='0'&&c<='9')
return 1;
else
return 0;
}
--碰到空格、tab跳过
if(ch==' '||ch=='\t'){}
else if(ch=='\n')
Line_NO++;
--忽略大小写
if((ch<='A')&&(ch>='Z'))
ch=ch+32;
--字符的处理,包括注释的去除,非法字符
switch(ch){ //符号 case'(' :fprintf(fpout,"%s\t\t%d\t\t分界符\n","(",26);break; case')' :fprintf(fpout,"%s\t\t%d\t\t分界符\n",")",27);break; case'[' :fprintf(fpout,"%s\t\t%d\t\t分界符\n","[",28);break; case']' :fprintf(fpout,"%s\t\t%d\t\t分界符\n","]",29);break; case';' :fprintf(fpout,"%s\t\t%d\t\t分界符\n",";",30);break; case'.' :fprintf(fpout,"%s\t\t%d\t\t分界符\n",".",31);break; case',' :fprintf(fpout,"%s\t\t%d\t\t分界符\n",",",32);break; case':' :fprintf(fpout,"%s\t\t%d\t\t分界符\n",":",33);break; case'{' :fprintf(fpout,"%s\t\t%d\t\t分界符\n","{",34);break; case'}' :fprintf(fpout,"%s\t\t%d\t\t分界符\n","}",35);break; case'"' :fprintf(fpout,"%s\t\t%d\t\t分界符\n","\"",36);break; case'+' :fprintf(fpout,"%s\t\t%d\t\t运算符\n","+",37);break; case'-' :fprintf(fpout,"%s\t\t%d\t\t运算符\n","-",38);break; case'*' :fprintf(fpout,"%s\t\t%d\t\t运算符\n","*",39);break; case'=' :fprintf(fpout,"%s\t\t%d\t\t运算符\n","=",40);break; case'>' :{ ch=fgetc(fpin); if(ch=='=') fprintf(fpout,"%s\t\t%d\t\t运算符\n",">=",41); else{ fprintf(fpout,"%s\t\t%d\t\t运算符\n",">",42); fseek(fpin,-1L,SEEK_CUR); } }break; case'<' :{ ch=fgetc(fpin); if(ch=='=') fprintf(fpout,"%s\t\t%d\t\t运算符\n","<=",43); else{ fprintf(fpout,"%s\t\t%d\t\t运算符\n","<",44); fseek(fpin,-1L,SEEK_CUR);} }break; case'%' :{ ch=fgetc(fpin); if(ch=='d'||ch=='f'||ch=='s'||ch=='x') fprintf(fpout,"%s\t\t%d\t\t输出格式符\n","\%",45); else fprintf(fpout,"%s\t\t%d\t\t运算符\n","\%",46); }break; case'/' :{ ch=fgetc(fpin);//出现在/ /之间的全部作为注释部分处理 if(ch=='*'){ while(ch!='/'&&ch!=EOF) ch=fgetc(fpin); if(ch==EOF) fprintf(fpout,"缺少一个'/'"); } else if(ch=='/'){ while(ch!='\n'&&ch!=EOF) ch=fgetc(fpin); } else{ fprintf(fpout,"%s\t\t%d\t\t运算符\n","/",47); fseek(fpin,-1L,SEEK_CUR); } }break; default :fprintf(fpout,"在第%d行无法识别的字符\t%c\n",Line_NO,ch); //非法字符 }
测试文件s.txt
int main(void)
{
int a1,b;
a1=103;
b=2;
if(a1>=b){/*多行
注释*/
a1=a1*b;//单行注释
}
printf("%d",a1);
return 0;
}
输出文件r.txt
int 3 关键字 main 6 关键字 ( 26 分界符 void 15 关键字 ) 27 分界符 { 34 分界符 int 3 关键字 a1 1 标识符 , 32 分界符 b 1 标识符 ; 30 分界符 a1 1 标识符 = 40 运算符 103 2 无符号整数 ; 30 分界符 b 1 标识符 = 40 运算符 2 2 无符号整数 ; 30 分界符 if 10 关键字 ( 26 分界符 a1 1 标识符 >= 41 运算符 b 1 标识符 ) 27 分界符 { 34 分界符 a1 1 标识符 = 40 运算符 a1 1 标识符 * 39 运算符 b 1 标识符 ; 30 分界符 } 35 分界符 printf 1 标识符 ( 26 分界符 " 36 分界符 % 45 输出格式符 " 36 分界符 , 32 分界符 a1 1 标识符 ) 27 分界符 ; 30 分界符 return 17 关键字 0 2 无符号整数 ; 30 分界符 } 35 分界符
完整代码: https://download.csdn.net/download/yiwanxianyutang/20089286?spm=1001.2014.3001.5501
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。