编译原理:实验二 递归下降语法分析

一、实验目的

  利用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();
}

执行程序会输出如下结果:

 

 

 

 

posted @ 2019-11-29 00:11  琴时  阅读(4132)  评论(0编辑  收藏  举报