編譯原理:實驗二 遞歸下降語法分析


一、實驗目的

  利用C語言編制遞歸下降分析程序,並對簡單語言進行語法分析。

  編制一個遞歸下降分析程序,實現對詞法分析程序所提供的單詞序列的語法檢查和結構分析。

 

二、實驗原理

  每個非終結符都對應一個子程序。

  該子程序根據下一個輸入符號(SELECT集)來確定按照哪一個產生式進行處理,再根據該產生式的右端:

  • 每遇到一個終結符,則判斷當前讀入的單詞是否與該終結符相匹配,若匹配,再讀取下一個單詞繼續分析;不匹配,則進行出錯處理
  • 每遇到一個非終結符,則調用相應的子程序

 

三、實驗要求說明

  輸入單詞串,以“#”結束,如果是文法正確的句子,則輸出成功信息,打印“success”,否則輸出“error”,並指出語法錯誤的類型及位置。

例如:

  輸入begin a:=9;x:=2*3;b:=a+x end #

  輸出success

  輸入x:=a+b*c  end #

  輸出‘end' error

 

四、實驗步驟

  1.待分析的語言的語法(參考P90)

  2.將其改為文法表示,至少包含

  • –語句
  • –條件
  • –表達式

  3. 消除其左遞歸

  4. 提取公共左因子

  5. SELECT集計算

  6. LL(1)文法判斷

  7. 遞歸下降分析程序

程序詞法分析代碼:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

//函數申明 
void match();          //匹配的方法
void Bparser();     //匹配begin
void Pre();           //對語法進行預處理
void statement();   //匹配語法聲明
void expression();  //匹配運算符 
void term();        //匹配*/運算符 
void factor();      //匹配括號 

char temp[500],test[500];
char ch;
const char *keyword[6]= {"begin","if","then","while","do","end"};   //存儲保留字
int i=0,num,n,ednum=0,bnum=0,k=0;

//匹配的方法
void match() {
    ch=temp[i++];
    while(ch==' ') {
        ch=temp[i++];
    }
    if((ch>='A'&&ch<='Z')||(ch>='a'&&ch<='z')) {        //保留字與標識符判斷
        n=0;
        num=10;
        char a=ch;

        while((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch>='0'&&ch<='9')) { //字符串數組復制
            test[n++]=ch;
            ch=temp[i++];
        }

        test[n++]='\0';

        for(n=0; n<6; n++) {
            if(strcmp(test,keyword[n])==0) {  //判斷兩個字符串是否一致
                num=n+1;
                printf("[%s,%d]\n",test,num);
                if(num==1) {
                    bnum=1;//begin存在 
                }
                if(num==6) {
                    ednum=1;//end存在 
                }
                break;
            }
        }
        i--;
        if(num==10) {
            ch=a;
            printf("[%c,%d]\n",ch,num);
        }
    }

    if(ch>='0'&&ch<='9') {    //數字判斷
        num=11;
        printf("[%c,%d]\n",ch,num);

    } else {
        switch(ch) {    //運算符界符的判斷
            case '#':
                num=0;printf("[%c,%d]\n",ch,num);break;
            case '+':
                num=13;printf("[%c,%d]\n",ch,num);break;
            case '-':
                num=14;printf("[%c,%d]\n",ch,num);break;
            case '*':
                num=15;printf("[%c,%d]\n",ch,num);break;
            case '/':
                num=16;printf("[%c,%d]\n",ch,num);break;
            case ':':
                ch=temp[i++];
                if(ch=='=') {
                    num=18;
                    printf("[:%c,%d]\n",ch,num);
                } else {
                    i--;
                    ch=temp[i];
                    num=17;
                    printf("[%c,%d]\n",ch,num);
                }
                break;
                
            case '<':
                ch=temp[i++];
                if(ch=='=') {
                    num=21;
                    printf("[<%c,%d]\n",ch,num);
                } else if(ch='>') {
                    num=22;
                    printf("[<%c,%d]\n",ch,num);
                } else {
                    i--;
                    ch=temp[i];
                    num=20;
                    printf("[%c,%d]\n",ch,num);
                }
                break;

            case '>':
                ch=temp[i++];
                if(ch=='=') {
                    num=24;
                    printf("[>%c,%d]\n",ch,num);
                } else {
                    i--;
                    ch=temp[i];
                    num=23;
                    printf("[%c,%d]\n",ch,num);
                }
                break;
            case '=':
                num=25;printf("[%c,%d]\n",ch,num);break;
            case ';':
                num=26;printf("[%c,%d]\n",ch,num);break;
            case '(':
                num=27;printf("[%c,%d]\n",ch,num);break;
            case ')':
                num=28;printf("[%c,%d]\n",ch,num);break;
        }
    }
}

//對語法進行預處理,當匹配到分號時,進行一次match匹配下一個字符 
void Pre() {   
    statement();
    while(num==26) {
        match();
        statement();
    }
    return;
}

//匹配begin、end 
void Bparser() {   
    if(num==1) { //begin
        match();
        Pre();
        if(num==6){ //end
            match();
            if(num==0 && k==0){
                printf("【Success】分析完成!\n"); 
            }
        }else if(num==0 && ednum!=1){
            printf("【error】缺失'end'\n");
            k=1; 
        }
    }else{
        Pre(); 
        printf("【error】缺失'begin'\n");
    }
    return;
}

//匹配語法聲明
void statement() {  
    if (num==10) {   
        match();
        if(num==18) { //為 :=
            match();
            expression();
        } else {
            printf("【error】缺失符號':='\n");
            k=1;
        }
    }else{
        printf("【error】'表達式錯誤'\n");
        k=1;
    }
    return;
}

//匹配+-運算符 
void expression() {  
    term();
    while(num==13||num==14) {
        match();
        term();
    }
    return;
}

//匹配*/運算符 
void term() {   
    factor();
    while(num==15||num==16) {
        match();
        factor();
    }
    return;
}

//為標識符或整常數時,讀下一個單詞符號
void factor() {  
    if(num==10||num==11) {
        match();
    } else if(num==27) {
        match();
        expression();
        if(num==28) {
            match();
        } else {
            printf(" 【error】缺失')' \n");
            k=1;
        }
    } else {
        printf("【error】'表達式錯誤'\n");
        k=1;
    }
    return;
}

int main() {
    printf("\t\n請輸入程序,以#號結束:\n");
    ch=getchar();
    while(ch!='#') {
        temp[i]=ch;
        ch=getchar();
        i++;
    }
    temp[i]='#';
    i++;
    temp[i]='\0';
    i=0;
    match();
    Bparser();
}

執行程序會輸出如下結果:

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM