学习编译原理 做了个简单的C词法分析

发布于 2022-09-19 12:16:14 字数 20378 浏览 15 评论 0

/*
词法分析程序,词法分析.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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

披肩女神 2022-09-26 12:16:14

代码有点乱,看不出DFA的状态

煮酒 2022-09-26 12:16:14

怎么才叫根据DFA来写的程序

烛影斜 2022-09-26 12:16:14

while(get) {
     switch(stat):
      case x1:
                ......
      case x2:
                ......
      .......
}

爱*していゐ 2022-09-26 12:16:14

哦,是这样的,恩。
可惜,都懒得没有画DFA,所以就拍拍脑袋写了个

带上头具痛哭 2022-09-26 12:16:14

DFA还是相当重要滴,特别对理解LR文法

゛清羽墨安 2022-09-26 12:16:14

LZ即兴的作品. 顶一下.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文