语法分析程序--编译原理

语法分析程序

实验目的和内容
理解语法分析的功能和实现机制。掌握递归向下的语法分析方法。

实验要求
1. 完成实验的要求
附录是一个简单的算法表达式文法,如a+b*c-b/d就是一个该文法所表示的合法的表达式。请你为该文法编写一个递归向下的语法分析程序。
输入:字符串或者文本文件
输出:“合法表达式”或者“非法表达式”
例如:输入a+b*c-b/d则显示或者输出“合法表达式”,输入aa++–c*则显示或者输出“非法表达式”
提示:先消除文法的左递归

附录:
一个简单的算法表达式文法
〈算术表达式〉∷=〈项〉│〈算术表达式〉+〈项〉│〈算术表达式〉-〈项〉
〈项〉∷=〈因式〉│〈项〉*〈因式〉│〈项〉/〈因式〉
〈因式〉∷=〈变量〉│(〈算术表达式〉)
〈变量〉∷=a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z

说明:为了简化变量,即简化词法分析程序,此文法中变量的定义就是一个字母。


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


/*
消除左递归后的文法:
S->BI
I->+BI|-BI|ξ   //使用I消除左递归
B->CJ
J->*BI|/BI|ξ
C->V|(S)
V->a|…|z
First(S)={a,…,z,(}
First(I)={+,-, ξ}
First(B)={a,…,z,(}
First(J)={*,/, ξ}
First(C)={a,…,z,(}
First(V)={a,…,z}

Follow(S)={#,)}
Follow(B)={+,-,),#}
Follow(I)={#,)}
Follow(J)={+,-,),#}
Follow(C)={*,/,+,-,),#}
Follow(V)={*,/,+,-,),#}

*/

/* 符号 */
enum symbol       //枚举类型
{
    nul, end, ident, plus, times, lparen, divide, rparen, sub,
};

/*enum symbol sym;

#define nul 0
#define ident 1
#define plus 2
#define times 3
#define lparen 4
#define rparen 5
#define divide 6
#define sub 7*/


#define al 10          //标识符的最大长度

enum symbol sym;       //当前的符号
char ch;              //获取当前字符,getch 使用
char a[al+1];         //当前标识符ident

FILE* fin;            //用于指向输入文件的指针

void getsym();        //读单词,将单词类别放入sym中
void S();
void I();
void B();
void J();
void C();
void V();

int main()
{
    char filename[20];     //文件名数组


    printf("请输入分析的文件名:");
    gets(filename);
    //scanf("%s",filename);
    do
    {
        if((fin=fopen(filename,"r"))==NULL)        //以只读方式打开文件,并判断输入文件名是否正确
        {
            printf("不能打开文件.\n");
            return 0;
        }
        getsym();            //读第一个单词,将单词类别放入sym中
        S();                //开始按S->BI  分析
        if (sym==end)       //程序递归中途没有exit(0)则是语法正确
        {
            printf("语法正确\n");
        }
        else
        {
            printf("语法错\n");
        }
        fclose(fin);         //关闭文件
        printf("继续分析则输入文件名,否则回车");
        //scanf("%s",filename);
        gets(filename);
    }
    while (strlen(filename)>0);      //判断文件名字符串是否大于0
}
/*词法分析,获取一个符号*/
void getsym()
{
    ch=fgetc(fin);

    while (ch==' ' || ch==10 || ch==13 || ch==9)  /* 忽略空格、换行、回车和TAB */
        ch=fgetc(fin);

    if (ch==EOF)  sym=end;  //如果到了文件末尾,则赋值为end

    else if (ch>='a' && ch<='z')
        sym = ident;
    else if(ch == '+')
        sym = plus;
    else if (ch == '*')
        sym = times;
    else if (ch == '/')
        sym = divide;
    else if (ch == '-')
        sym = sub;
    else if (ch == '(')
        sym = lparen;
    else if (ch == ')')
        sym = rparen;
    else
    {
       sym = nul;
        printf("--词法错\n");   //不是上面的first集中的元素
        exit(0);
    }
    return;

}

//递归下降分析  分析产生式S->BI
void  S()
{
    if (sym==ident ||sym==lparen)       //如果类型是标识符(变量)或者左括号
    {
        B();           //先按B推导,执行B
        I();           //再按I推导,执行I
    }
    else
    {
        printf("语法错: 缺变量或者左括号\n");
        exit(0);
    }
}



//first集为+或-的时候
void I()
{
    if(sym==plus||sym==sub)     //如果类型是加或者减
    {
        getsym();           //读下一个单词
        B();                //调用执行B
        I();                //调用执行I
    }
    else if(sym==rparen  || sym==end)//右括号或者文件结束则为正确
    {
        return;
    }
    else
    {
        if(sym==nul)
        {
            printf("错误4_1:非法操作符\n");
            exit(0);//无条件的退出程序
        }
        else
        {
            printf("错误5:缺少操作符+或者缺少操作符-");
            exit(0);
        }
    }
}

void B()
{
    C();                        //调用执行C
    J();                        //调用执行J
}

void J()
{
    if(sym==times||sym==divide)     //如果类型是*或者除法
    {
        getsym();           //读取下一个单词
        C();                //调用执行C
        J();                //调用执行J
    }
    else if(sym==plus || sym==sub || sym==rparen || sym==end)//+——)或者结束
    {
        return;
    }
    else
    {
        if(sym==nul)
        {
            printf("错误4_2:非法操作符\n");
            exit(0);
        }
        else
        {
            printf("错误6:缺少操作符×或者÷\n");
            exit(0);
        }
    }

}

void C()
{
    if(sym==lparen)           //如果类型是左括号
    {
        getsym();            //读取下一个单词
        S();                  //调用执行S
        if(sym==rparen)     //如果类型是右括号
        {
            getsym();   //读取下一个单词
            return;
        }
        else
        {
            printf("语法错9: 缺变量或符号\n ");
            exit(0);
        }
    }
    else
    {
        V();                //否则调用执行V
    }
}



void V()
{
    if (sym==ident)          //当前单词为indent(标识符)类型
        getsym();        //读下一个符号
    else
    {
        printf("语法错8: 缺变量\n ");
        exit(0);
    }
}

猜你喜欢

转载自blog.csdn.net/immenselee/article/details/80401599