学习编译原理 做了个简单的C词法分析
/*
词法分析程序,词法分析.c;
1-关键字 2-标识符 3-常量 4-运算符 5-分隔符
*/
#include <stdio.h>
#include <string.h>
char kwords[32][9]={"char","int","short","long","signed","unsigned","float","double",
"const","void","volatile","enum","struct","union","typedef",
"auto","extern","static","register",
"if","else","switch","case","default","while","do","for","break","continue","goto","return","sizeof"
}; /*32个关键字*/
char op[21+11+10][4]={
"(", "", "[", "]", ".", "!", "~", "+", "-", "*", "&", "/", "%", "<", ">", "^", "|", "?", ":", ",", "=",
"->", "++", "--", "<<", ">>", "<=", ">=", "==", "!=", "&&", "||",
"+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>="
}; /*运算符,sizeof处理为关键字*/
int gaps[11]={
32,9,11,10,12,';','{','}','/','*','#'
}; //分隔符包括空格符,水平、垂直制表符,换行符,换页符,分号,大括号({}),注释(/*),井号
FILE *fin;//待分析的文件
int ln=2;//行号
//每次取一个单词(运算符可能不是这样)
int getsym(){
int i,k,j;
char ch,a[100]="";//字符,单词缓冲区
ch=getchar();
if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z'||ch=='_'){
k=0;
do{
a[k++]=ch;
ch=getchar();
}while(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z'||ch=='_'||ch>='0'&&ch<='9'&&k<33);//限制标识符最多有32个字符
if(k<33){
a[k]=0;//字符串末尾补0
fseek(fin,-1,SEEK_CUR);//光标从当前位置回退一个字符
}else {
a[32]=0;
printf("标识符长度错误:%s\n",a);
return -1;
}
i=0;
do{
if(strcmp(a,kwords[i++])==0){
printf("(1,%s)\n",a);//关键字
return 1;
}
}while(i<32);
printf("(2, %s)\n",a);//标识符
return 2;
}
else if(ch>='0'&&ch<='9'){
k=0;
do{
a[k++]=ch;
ch=getchar();
}while(ch>='0'&&ch<='9'&&ch!='.');//得到整数部分
if(ch=='.'){
do{
a[k++]=ch;
ch=getchar();
}while(ch>='0'&&ch<='9'&&ch!='e');//得到小数部分
if(ch=='e'){
do{
a[k++]=ch;
ch=getchar();
}while(ch>='0'&&ch<='9');//得到指数部分
}
}
a[k]=0;
fseek(fin,-1,SEEK_CUR);
printf("(3, %s)\n",a);//数字常量
return 3;
}
else if(ch=='\''){
k=0;
do{
a[k++]=ch;
ch=getchar();
}while(ch!='\''&&k<6);//考虑转义序列,单引号内最多有4个字符
if(k<6){
a[k++]=ch;
a[k]=0;
printf("(3, %s)\n",a);//字符常量
return 2;
}else {
a[6]=0;
printf("字符常量错误:%s\n",a);
return -1;
}
}
else if(ch=='\"'){
k=0;
do{
a[k++]=ch;
ch=getchar();
}while(ch!='\"'&&k<99);//限制了双引号内最多有97个字符再加上双引号和字符串结束符共100个
if(k<99){
a[k++]=ch;
a[k]=0;
printf("(3, %s)\n",a);//字符串常量
return 2;
}else {
a[99]=0;
printf("字符串常量错误:%s\n",a);
return -1;
}
}
else if(ch=='/'){
k=0;
a[k++]=ch;
ch=getchar();
if(ch=='*'){
do{
a[k++]=ch;
ch=getchar();
}while((ch!='/'||a[k-1]!='*')&&k<99);
if(k<99){
a[k++]=ch;
a[k]=0;
printf("(注释, %s)\n",a);//得到注释
return 6;
}else {
a[99]=0;
printf("注释超过长度限制: %s",a);
return -1;
}
}else{//是运算符时
ch='/';
fseek(fin,-1,SEEK_CUR);
}
}
else if(ch==op[0][0]||ch==op[1][0]||ch==op[2][0]||ch==op[3][0]||ch==op[4][0]||ch==op[5][0]||
ch==op[6][0]||ch==op[7][0]||ch==op[8][0]||ch==op[9][0]||ch==op[10][0]||ch==op[11][0]||
ch==op[12][0]||ch==op[13][0]||ch==op[14][0]||ch==op[15][0]||ch==op[16][0]||ch==op[17][0]||
ch==op[18][0]||ch==op[19][0]||ch==op[20][0]){
k=0;
do{
a[k++]=ch;
ch=getchar();
}while(ch==op[0][0]||ch==op[1][0]||ch==op[2][0]||ch==op[3][0]||ch==op[4][0]||ch==op[5][0]||
ch==op[6][0]||ch==op[7][0]||ch==op[8][0]||ch==op[9][0]||ch==op[10][0]||ch==op[11][0]||
ch==op[12][0]||ch==op[13][0]||ch==op[14][0]||ch==op[15][0]||ch==op[16][0]||ch==op[17][0]||
ch==op[18][0]||ch==op[19][0]||ch==op[20][0]&&k<3);
a[k]=0;
fseek(fin,-1,SEEK_CUR);
switch(k){//修改查找范围
case 1: i=21+11+10;j=i;break;//单符运算符时
case 2: i=21;j=21+11+8;break;//双符运算符时
case 3: i=21+11+8;j=21+11+10;//三符运算符时
}
while(i<j){
if(strcmp(a,op)==0){
printf("(4,%s)\n",a);//运算符
return 4;
}
i++;
}
i=0;
while(i<k){
printf("(4,%c)\n",a);//未在表中找到的连续运算符分解为单符运算符
i++;
}
return 4;
}
else if(ch==32||ch==9||ch==11||ch==12){
//printf("(5, %d)\n",ch);//不可打印分隔符
return 5;
}
else if(ch=='\n'){
printf("第 %d 行\n",ln++);//换行符,打印行号
return 5;
}
else if(ch==';'||ch=='{'||ch=='}'||ch=='#'){
printf("(5, %c)\n",ch);//可打印分隔符
return 5;
}
else
if(ch==EOF){
printf("分析完成。\n"//到达文件尾
return 0;
}
printf("不可识别字符:%c\n",ch);//不可识别字符
return -1;
}
int main(void){
FILE *fout;
char *fname="";
int e;
//char fname[100];
//printf("输入.C文件名:"
//scanf("%s", fname);
fname="d:/hello.c";
fin=freopen(fname, "r", stdin);//打开待分析文件,并重定向为标准输入
//fout=freopen("d:/cifa.txt","w",stdout);//新建输出文件,并重定向为标准输出
if(!fin||!fout){
fprintf(stderr,"无法打开 %s。\n", fin?"输出文件":"待分析文件"
return -1;
}
printf("词法分析程序(括号内为分析结果)\n"
printf("1-关键字 2-标识符 3-常量 4-运算符 5-分隔符\n"
printf(".c文件名: %s\n",fname);
printf("分析开始\n"
printf("第 1 行\n"
while((e=getsym())!=-1&&e!=0);//到达文件尾或出错是停止分析
fclose(fin);
//fclose(fout);
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
代码有点乱,看不出DFA的状态
怎么才叫根据DFA来写的程序
while(get) {
switch(stat):
case x1:
......
case x2:
......
.......
}
哦,是这样的,恩。
可惜,都懒得没有画DFA,所以就拍拍脑袋写了个
DFA还是相当重要滴,特别对理解LR文法
LZ即兴的作品. 顶一下.