收集一些技术好文大学生活@IT·互联网

一个简易版的词法分析器

2017-04-28  本文已影响313人  插着扇子的石头
单次符号编码

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

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

简易版的词法分析器

#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);
}

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

上一篇 下一篇

猜你喜欢

热点阅读