一个简易版的词法分析器

单次符号编码

编译原理这门课在计算机基础课程中绝对是金牌杀手,无论是大学还是研究生,挂科率都挺高。当初现学现卖的编译原理老师对我们说:“好歹你们也是学过编译原理的人,给我写个词法分析器看看!”下面马上传来唉声叹气的声音。老师又安慰我们说:“没让你们写语法分析器算好的了,词法分析器比语法分析器简单多了,你们试着做一下。”

上大学那会儿,我还是个乖宝宝,特听话。回去就写了一个简易版的词法分析器,然后发给老师。下次上课的时候,老师就说:“怎么只有一个人给我交作业,还是个女生,真是‘巾帼不让须眉’。”接着,老师引出重点:“你们这些男生,要加油啊!”结果一周后,大部分男生都提交了词法分析器。

简易版的词法分析器

#include"stdio.h"
#include"string.h"
#include"stdlib.h"

typedef struct{
    char wordSymbol[20];  //单词符号
    //int  code;  //种别编码
    char mnemonic[20];  //助记符
}Token;

Token token[15];
char c[1000];

void initTable();
int  findCode(char c[],int len);
int  isIdentifier(char c[],int len);
int  isInteger(char c[],int len);

void initTable(){
    strcpy(token[1].wordSymbol,"DIM");
    strcpy(token[1].mnemonic,"$DIM");
    strcpy(token[2].wordSymbol,"IF");
    strcpy(token[2].mnemonic,"$IF");
    strcpy(token[3].wordSymbol,"DO");
    strcpy(token[3].mnemonic,"$DO");
    strcpy(token[4].wordSymbol,"STOP");
    strcpy(token[4].mnemonic,"$STOP");
    strcpy(token[5].wordSymbol,"END");
    strcpy(token[5].mnemonic,"$END");

    strcpy(token[6].wordSymbol,"标识符");
    strcpy(token[6].mnemonic,"$IDN");
    strcpy(token[7].wordSymbol,"整数");
    strcpy(token[7].mnemonic,"$INT");

    strcpy(token[8].wordSymbol,"=");
    strcpy(token[8].mnemonic,"$ASG");
    strcpy(token[9].wordSymbol,"+");
    strcpy(token[9].mnemonic,"$PLUS");
    strcpy(token[10].wordSymbol,"*");
    strcpy(token[10].mnemonic,"$STAR");
    strcpy(token[11].wordSymbol,"**");
    strcpy(token[11].mnemonic,"$POWER");
    strcpy(token[12].wordSymbol,",");
    strcpy(token[12].mnemonic,"$COMMA");
    strcpy(token[13].wordSymbol,"(");
    strcpy(token[13].mnemonic,"$SLP");
    strcpy(token[14].wordSymbol,")");
    strcpy(token[14].mnemonic,"$SRP");
    
}

//找到种别编码
int  findCode(char c[],int len){
    int i;
    for(i=1;i<6;i++)
        if(!stricmp(c,token[i].wordSymbol) )
            return i;

    if( isIdentifier(c,len) )
        return 6;
    if( isInteger(c,len) )
        return 7;

    for(i=8;i<15;i++)
        if(!stricmp(c,token[i].wordSymbol) )
            return i;
    return 0;
}

//根据种别码返回单词符号信息
void wordInfor(char c[],int len,int code){
    if(code==0)
        printf("ERROR WORD !");
    else {
        if(code==6 || code==7)
            printf("%s%s\t",token[code].wordSymbol,c);
        else
            printf("%s\t\t",token[code].wordSymbol);
        printf("%d %s",code,token[code].mnemonic);
    }
}

//判断是否是标识符
int isLetter(char c){
    if(c<='z'&&c>='a' || c<='Z'&&c>='A')
        return 1;
    return 0;
}

int isNum(char c){
    if(c<='9'&&c>='0')
        return 1;
    return 0;
}

int isIdentifier(char c[],int len){
    int i;
    if( !isLetter(c[0]) )
        return 0;
    for(i=1;i<len;i++){
        if( !isLetter(c[i]) && !isNum(c[i]) )
            return 0;
    }
    return 1;
}

//判断是否是整数
int isDecimalDigit(char c[],int len){
    int i=0;
    if( c[0]=='0' && len!=1)
        return 0;
    for(i=0;i<len;i++)
        if( !isNum(c[i]) )
            return 0;
    return 1;
}

int isOctalDigit(char c[],int len){
    int i=0;
    if(len==1 || c[0]!='0' )
        return 0;

    for(i=0;i<len;i++)
        if( c[i]>'7' || c[i]<'0' )
            return 0;
    return 1;
}

int isHexDigit(char c[],int len){
    int i=0;
    if(len<=2 || c[0]!='0' )
        return 0;

    if( !(c[1]=='x')||(c[1]=='X') )
        return 0;
    for(i=2;i<len;i++)
        if( !isNum(c[i]) && !(c[i]<='f'&&c[i]>='a' || c[i]<='F'&&c[i]>='A'))
            return 0;
    return 1;
}

int isInteger(char c[],int len){
    return isDecimalDigit(c,len) || isOctalDigit(c,len)  || isHexDigit(c,len)  ;
}

void output(int code,FILE *fp){
    fputs(token[code].wordSymbol,fp);
    fputs("\t\t",fp);
    if(code<10)
        putc(code+48,fp);
    else{
        putc('1',fp);
        putc(code+38,fp);
    }
    fputs("\t\t",fp);
    fputs(token[code].mnemonic,fp);
    fputs("\t\t",fp);
    fputs(c,fp);
    fputc('\n',fp);
}

main(){
    FILE *fs,*fd;
    char ch;
    char str[50]="WordSymbol\tCode\t\tMnemonic\t\tString\n";
    initTable();
    
    //open file
    if((fs=fopen("source.txt","r"))==NULL){
        printf("ERROR OPEN FILE!");
        exit(1);
    }
    if((fd=fopen("destination.txt","w"))==NULL){
        printf("ERROR OPEN FILE!");
        exit(1);
    }
    
    fputs(str,fd);
    //扫描单词序列
    ch=fgetc(fs);
    while(!ch)
        ch=fgetc(fs);
    while(ch!=EOF){
        if(isLetter(ch)||isNum(ch)){
            int i = 0,code=0;
            while(ch!=EOF  && ( isLetter(ch)||isNum(ch) ) ){
                //putchar(ch);
                c[i]=ch;
                i++;
                ch=fgetc(fs);
                //fputc(ch,fd);
            }

            c[i]='\0';
            code=findCode(c,strlen(c));
            if(!strcmp(c," ")||!strcmp(c,"\n")||!strcmp(c,"\t")){
                ch=fgetc(fs);
                continue;
            }

            if(!code){
                fputs(" \tERROR WORD\t\t",fd);
                fputs("\t\t",fd);
                fputs(c,fd);
                fputc('\n',fd);
            }
            else
                output(code,fd);
        }
        else{
            int code=0;
            if(ch==' '){
                ch=fgetc(fs);
                continue;
            }
            c[0]=ch;
            c[1]='\0';
            code=findCode(c,strlen(c));
            if(8<=code&&code<=14){
                if(code!=10){
                    output(code,fd);
                    ch=fgetc(fs);
                }
                else{
                    ch=fgetc(fs);
                    if(ch=='*'){
                        c[1]=ch;
                        c[2]='\0';
                        output(code+1,fd);  
                        ch=fgetc(fs);
                    }
                    else
                        output(code,fd);
                }
            }
            else if(!strcmp(c," ")||!strcmp(c,"\n")||!strcmp(c,"\t")){
                ch=fgetc(fs);
                continue;
            }

            if(!code){
                fputs(" \tERROR WORD\t\t",fd);
                fputs("\t\t",fd);
                fputs(c,fd);
                fputc('\n',fd);
                ch=fgetc(fs);
            }       
        }
    }

    fflush(fd);
    fclose(fs);
    fclose(fd);
}

几年后,回看这份作业,心情略为复杂。一方面,觉得自己的代码风格和模块划分还有待改进。另一方面,也为过去自己的那份认真而感动。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容