PL/0語言詞法分析程序

字號:

//這是我編譯原理的一次作業(yè),中間有許多不足之處希望大家指正
    /*編寫PL/0語言的詞法分析程序
    要求:
    1、讀入用PL/0語言編寫的源程序,正確的進(jìn)行詞法分析,并輸出二元式序列。
    2、若源程序有詞法錯誤,能夠給出出錯的準(zhǔn)確位置。
    3、詞法代號如下
    (+,+);
    (-,-);
    (*,*);
    (/,/);
    ((,();
    (),));
    (,,,);
    (;,;);
    (.,.);
    (#,#);
    (=,=);
    (>,>);
    (<,<);
    (:=,a);
    (>=,b);
    (<=,c);
    (數(shù)字,d);
    (標(biāo)識符,e);
    關(guān)鍵字代號:
    (begin,f);
    (call,g);
    (const,h);
    (do,i);
    (end,j);
    (if,k);
    (odd,l);
    (procedure,m);
    (read,n);
    (then,o);
    (var,p);
    (while,q);
    (write,r);
    4、等于運算符號為一個 =
    測試程序:
    A.C
    ======================
    CONST A=10;
    VAR B,C;
    PROCEDURE P;
    VAR D;
    PROCEDURE Q;
    VAR X;
    BEGIN
    READ(X);
    D:=X;
    WHILE X<0
    DO CALL P;
    END;
    BEGIN
    WRITE(D);
    CALL Q;
    END;
    BEGIN
    CALL P;
    END.
    */
    /*program name:chifufenxi*/
    /*作者:小萬 QQ:421404493*/
    /*date:2004.10.11*/
    #include
    #include
    #include
    #include
    #include
    #define N 256//每一行的字符數(shù)不能超過256個
    char buffer[N]; //用作存放一行字符
    char word[20]; //用作存放經(jīng)過分析單詞
    char *kword[13]={"begin","call","const","do","end","if","odd","procedure","read","then","var","while","write"};
    char ktype[13]={'f','g','h','i','j','k','l','m','n','o','p','q','r'};
    int len;//記錄每一行的長度
    int count=0;//用來記錄行數(shù)
    void write(char *wstr,char wc,FILE *wout)//將分析結(jié)果按照規(guī)則寫入到文件
    {
    fputc('(',wout);
    fputs(wstr,wout);
    fputc(',',wout);
    fputc(wc,wout);
    fputc(')',wout);
    }
    int readbuffer(FILE *fp)
    {
    char ch;
    len=0;
    ch=fgetc(fp);
    while(!feof(fp) && ch!='\n')//讀取字符到緩沖區(qū)
    {
    buffer[len]=ch;
    ch=fgetc(fp);
    len++;
    }
    len--;//用來控制詞法分析時行分析中字母的個數(shù)
    if(feof(fp))//標(biāo)志文件是否結(jié)束
    return 0;
    else
    return 1;
    }
    void error(int type)
    {
    if(type==1)
    printf("為無效字符,第%d行詞法出錯,標(biāo)志符不能以數(shù)字開頭\n",count);
    else if(type==2)
    printf("第%d行詞法出錯,賦值符應(yīng)為\:\= \n ",count);
    else printf("為無效字符,第%d行詞法出錯\n",count);
    }
    void check(char *str,FILE *out);//聲明函數(shù),此函數(shù)用來分類單詞
    void fenxi(char *row,FILE *op)//此函數(shù)用來對每一行的單詞進(jìn)行語法分析
    {
    //printf("%d\n",count);
    int k=0;//用作控制臨時存放單詞的變量str0
    int i=0;//定義兩個變量用作控制每一行是否結(jié)束,
    int ferror=0;//用作出錯標(biāo)志
    char str0[20];//臨時存放單詞的變量
    while(i<=len)
    {
    k=0;//將k置0
    strcpy(word,"\0");//將存放單詞的變量清空
    /*去除空格*/
    if(isspace(row[i]))//去出空格,跳格符,換行符
    {
    i++;
    continue;
    }
    /*去出無效字符*/
    while(!isalpha(row[i])&&!isdigit(row[i])&&i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))
    {
    putchar(row[i]);
    i++;
    ferror=1;//設(shè)置錯誤標(biāo)志符
    }
    if(ferror==1)
    {
    error(3);//調(diào)用出錯處理函數(shù)
    ferror=0;
    }
    /*對注釋進(jìn)行處理,假設(shè)此語言的注釋只能單行注釋以雙斜杠“//”為注釋開始標(biāo)志*/
    if(row[i]=='/')
    {
    i++;
    if(row[i]=='/')
    {
    i=len+1;//忽略注釋符后面的單詞
    continue;
    }
    else
    i--;
    }
    /*判斷是否為數(shù)字*/
    if(isdigit(row[i]))
    {
    while(i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))
    //當(dāng)不到行尾,是數(shù)字或字母當(dāng)然有可能是無效字符
    {
    if(isdigit(row[i]))//是數(shù)字則將字符逐個存入臨時數(shù)組
    {
    str0[k]=row[i];
    i++;
    k++;
    // putchar('e');
    }
    else //數(shù)字中加有字母或無效字符則報錯
    {
    // putchar('x');
    ferror=1;break;//已經(jīng)出錯設(shè)置標(biāo)志并退出循環(huán)
    }
    }
    if(ferror==1)//檢測是否出錯
    { /*將剛剛的那個單詞后面的數(shù)字和字母
    清空,如123abc123或則123$$23等,當(dāng)出現(xiàn)錯誤后,需
    要消除abc123和$$23 以免誤作為下一個標(biāo)志符*/
    for(int j=0;j  putchar(str0[j]);
    while(i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))
    {
    putchar(row[i]);
    i++;
    }
    error(1);//putchar('e');//調(diào)用出錯處理函數(shù)
    ferror=0;//重新設(shè)置錯誤標(biāo)志位
    //i--;//strcpy(word,"");
    }
    else//未出錯照常處理
    {
    str0[k]='\0';
    strcpy(word,str0);
    i--;//減一是為了使最后取出的那個字符不在被下面的程序判斷
    // str0[0]='\0';
    }
    }
    /*判斷是否為標(biāo)志符和關(guān)鍵字即由字母開頭并且不含標(biāo)點符號用ispunct(int ch)判斷標(biāo)點符號*/
    if(isalpha(row[i]))//標(biāo)志符或關(guān)鍵字由字母開頭
    {
    k=0;
    while(i<=len&&row[i]!=32&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))//關(guān)鍵字和標(biāo)志符由數(shù)字和字母組成
    {
    if(isalpha(row[i])||isdigit(row[i]))//由數(shù)字和字母組成
    {
    str0[k]=row[i];
    i++;
    k++;
    }
    else//出錯,原因可能是出現(xiàn)了不可識別的字符
    {
    ferror=1;break;
    }
    }
    if(ferror)
    {
    for(int j=0;j  putchar(str0[j]);
    while(i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))
    {
    putchar(row[i]);//消除整個非法單詞
    i++;
    }
    ferror=0;
    error(3);
    //i--;
    }
    else
    {
    str0[k]='\0';
    strcpy(word,str0);
    str0[0]='\0';
    i--;
    }
    }
    /*判斷運算符*/
    if(row[i]=='+' ||row[i]=='-' ||row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'||row[i]=='.'||row[i]=='#' || row[i]=='=')
    {
    str0[0]=row[i];
    str0[1]='\0';
    strcpy(word,str0);
    str0[0]='\0';
    }//要先判斷單個字符的運算符,以避免諸如>=的運算符后面的=再次被判斷
    if(row[i]==':')
    {
    i++;
    if(row[i]=='=')
    {
    //word[0]=':';
    //word[1]='=';
    //word[2]='\0';
    strcpy(word,">=");
    }
    else
    {
    error(2);//出錯后調(diào)用處理函數(shù)
    i--;
    }
    }
    if(row[i]=='>')
    {
    i++;
    if(row[i]=='=')
    {
    strcpy(word,">=");
    }
    else
    {
    strcpy(word,">");
    i--;
    }
    }
    if(row[i]=='<')
    {
    i++;
    if(row[i]=='=')
    {
    strcpy(word,"<=");
    }
    else
    {strcpy(word,"<");i--;}
    }
    //puts(word);
    check(word,op);/*
    調(diào)用分類函數(shù),辨別每一個單詞的類別要求
    輸入的每一個單詞必須符合詞法規(guī)則*/
    //word[0]='\0';
    i++;//使指針后移,取出下一個字母
    }
    }
    void check(char *str,FILE *out)
    {
    if(isdigit(str[0]))/*如果第一個字符是數(shù)字那么整個單詞都是數(shù)字組成的,即為常數(shù)*/
    {
    write(str,'d',out);//調(diào)用寫函數(shù)將分好類的單詞寫入文件
    }
    if(isalpha(str[0]))/*如果第一個字符是字母,那么這個單詞是標(biāo)志符或關(guān)鍵字*/
    {
    int fyiyong=0;//用作標(biāo)記這個單詞是否已被分類
    /*以下判別是否是關(guān)鍵字*/
    for(int ct=0;ct<13;ct++)
    {
    if(!strcmp(str,kword[ct]))
    {
    write(str,ktype[ct],out);
    fyiyong=1;
    }
    }
    /*經(jīng)過以上判別,可以判別是否是關(guān)鍵字,不是即為標(biāo)志符*/
    if(fyiyong!=1)
    {
    write(str,'e',out);
    }
    }
    /*以下對運算符分類*/
    if(str[0]=='>')
    {
    if(str[1]=='=')
    {
    write(str,'b',out);
    }
    else
    {
    write(str,'>',out);
    }
    }
    if(str[0]=='<')
    {
    if(str[1]=='=')
    {
    write(str,'c',out);
    }
    else
    {
    write(str,'<',out);
    }
    }
    if(!strcmp(str,":="))
    {
    write(str,'a',out);
    }
    if(str[0]=='+' || str[0]=='-' || str[0]=='*' || str[0]=='/' || str[0]=='(' || str[0]==')' || str[0]==',' || str[0]==';'|| str[0]=='.'|| str[0]=='#' || str[0]=='=' )
    {
    write(str,str[0],out);
    }
    }
    void main()
    {
    count=1;
    char scfilename[20],rsfilename[20];//定義用來存放輸入源文件和輸出目標(biāo)文件的名字
    printf("Please input your source file name:");
    gets(scfilename);
    printf("Please input your result file name:");
    gets(rsfilename);
    FILE *fp,*op;
    fp=fopen(scfilename,"r");
    op=fopen(rsfilename,"w");
    if(fp)//打開文件成功后調(diào)用函數(shù)對源文件進(jìn)行詞法分析
    {
    while(readbuffer(fp))
    {
    fenxi(buffer,op);
    count++;//行加一
    }
    }
    else//while the file not exist
    {
    printf("Your souce file not exist!!!\n");
    exit(0);
    }
    fclose(fp);//close the files
    fclose(op);
    printf("ok!");//output the mark of end
    getchar();
    }