【开发语言及实现平台或实验环境】
C++/Clion

【实验目的】
(1)理解语法分析在编译程序中的作用,以及它与词法分析程序的关系
(2)加深对递归下降语法分析原理的理解
(3)掌握递归下降语法分析的实现方法

【实验内容】
编制一个递归下降分析程序,实现对词法分析程序提供的单词序列的语法检查和结构分析。

【实验要求】
(1)待分析的简单语言的词法同实验1
(2)待分析的简单语言的语法
用扩充的BNF表示如下:
1)<程序>::=begin<语句串>end
2) <语句串>::=<语句>{;<语句>}
3) <语句>::=<赋值语句>
4) <赋值语句>::=ID:=<表达式>
5) <表达式>::=<项>{+<项>|-<项>}
6) <项>::=<因子>{*<因子>|/<因子>}
7) <因子>::=ID|NUM|(<表达式>)
(3)语法分析程序的功能
输入单词串以”#”结束,如果是文法正确的句子,输出成功信息;否则输出错误信息。
例如:
输入 begin a:=9; x:=2 * 3; b:=a + x end #
输出 success
输入 x:=a + b * c end #
输出 error

【实验步骤】
(1)根据图2.1递归下降分析程序示意图构建主程序框架
实验2 递归下降语法分析程序设计_语法分析
(2)编写各语法单位分析函数
1)编写语句串及语句分析函数
代码提示:

yucu()//语句串分析函数
{
		调用statement();//语句分析函数
		while(syn=26){
			读入下一个单词符号;
			调用statement();
}
return;
}
statement()
{
		if(syn=10){
		读入下一个单词符号;
		if(syn=18)
			{
读入下一个单词符号;
调用expression函数;//表达式分析函数
}
else{输出赋值号错误;kk=1//出错标记}
}
else{输出语句号错误;kk=1;}
return;
}

2)编写表达式分析过程
3)编写项分析过程
4)编写因子分析过程
(3)调试程序,验证输出结果

【实验代码】

#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

char prog[80], token[8];
char ch;
int syn, p, m, n, sum, kk;
char *pString[6] = {"begin", "if", "then", "while", "do", "end"};

int scanner();           //调用scanner函数
int lrparscr();          //调用lrparscr函数
int yucu();                 //调用yucu函数
int statement();         //调用statement函数
int expression();         //调用expression函数
int term();                 //调用term函数
int factor();             //调用factor函数

int main() {
    p = 0;
    cout << "\nPlease input string:" << endl;
    do {
        cin.get(ch);
        prog[p++] = ch;         //输入源程序字符串,送到缓冲区prog[p++]中
    } while (ch != '#');
    p = 0;
    kk = 0;
    scanner();
    lrparscr();
    getchar();
    getchar();
    return 0;
}

int lrparscr() {
    if (syn == 1) {
        scanner();            //读下一个单词符号
        yucu();
        if (syn == 6) {       //syn=6 对应单词符号end
            scanner();      //读下一个单词符号
            if ((syn == 0) && (kk == 0))
                printf("success!\n");
        } else if (kk != 1) {
            cout << "出现缺end错误!" << endl;
            kk = 1;
        }
    } else {
        cout << "出现缺begin错误!" << endl;
        kk = 1;
    }
    return 0;
}

int yucu() {                    //语句串分析函数
    statement();
    while (syn == 26) {
        scanner();          //读下一个单词符号
        statement();        //调用statement函数
    }
    return 0;
}

int statement() {
    if (syn == 10) {
        scanner();         //读下一个单词符号
        if (syn == 18) {
            scanner();     //读下一个单词符号
            expression();
        } else {
            cout << "出现赋值号错误!" << endl;
            kk = 1;
        }
    } else {
        cout << "出现语句错误!" << endl;
        kk = 1;
    }
    return 0;
}

int expression() {
    term();
    while ((syn == 13) || (syn == 14)) {
        scanner();                      //读下一个单词符号
        term();
    }
    return 0;
}

int term() {
    factor();
    while ((syn == 15) || (syn == 16)) {
        scanner();                     //读下一个单词符号
        factor();
    }
    return 0;
}

int factor() {
    if ((syn == 10) || (syn == 11))     //是否是标识符或整型常数
        scanner();                     //读下一个单词符号
    else if (syn == 27) {                    // 是否是 (
        scanner();                     //读下一个单词符号
        expression();
        if (syn == 28)                 // 是否是 )
            syn = scanner();             //读下一个单词符号
        else {
            cout << "出现 ) 错误!" << endl;
            kk = 1;
        }
    } else {
        cout << "出现表达式错误!" << endl;
        kk = 1;
    }
    return 0;
}

int scanner() {
    for (n = 0; n < 8; n++) token[n] = '\0';
    ch = prog[p++];                     //读下一个单词符号并赋给ch
    while (ch == ' ') {                   //如果是空格,读下一字符
        ch = prog[p];
        p++;
    }
    if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {            //如果是字母字符
        m = 0;
        while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {   //如果是字母字符
            token[m++] = ch;                 //当前字符送入token
            ch = prog[p++];                //读下一个单词符号并赋给ch
        }
        token[m++] = '\0';                //单词结束
        p--;                               //回退一个字符
        syn = 10;                         //标识符
        for (n = 0; n < 6; n++)                 //与关键字表进行比较,确定syn的值
            if (strcmp(token, pString[n]) == 0) {
                syn = n + 1;                     //给出syn值
                break;
            }
    } else if ((ch >= '0' && ch <= '9')) {        //如果是数字字符
        {
            sum = 0;
            while ((ch >= '0' && ch <= '9')) {  //如果是数字字符
                sum = sum * 10 + ch - '0';   //ch送入sum,并更新数字
                ch = prog[p++];              //读下一个单词符号并赋给ch
            }
        }
        p--;                                   //回退一个字符
        syn = 11;                            //数字字符
        if (sum > 32767)
            syn = -1;                         //出现错误
    } else
        switch (ch) {                         //其他字符时
            case '<':
                m = 0;
                token[m++] = ch;
                ch = prog[p++];                       //读下一个单词符号并赋给ch
                if (ch == '>') {
                    syn = 21;                         //不等于
                    token[m++] = ch;
                } else if (ch == '=') {
                    syn = 22;                        //小于等于
                    token[m++] = ch;
                } else {
                    syn = 23;                        //大于
                    p--;                            //回退一个字符
                }
                break;
            case '>':
                m = 0;
                token[m++] = ch;
                ch = prog[p++];                    //读下一个单词符号并赋给ch
                if (ch == '=') {
                    syn = 24;                    //大于等于
                    token[m++] = ch;
                } else {
                    syn = 20;                    //小于
                    p--;                            //回退一个字符
                }
                break;
            case ':':
                m = 0;
                token[m++] = ch;
                ch = prog[p++];                    //读下一个单词符号并赋给ch
                if (ch == '=') {
                    syn = 18;                    //等于
                    token[m++] = ch;
                } else {
                    syn = 17;                    //冒号:
                    p--;
                }
                break;
            case '+':
                syn = 13;
                token[0] = ch;
                break;
            case '-':
                syn = 14;
                token[0] = ch;
                break;
            case '*':
                syn = 15;
                token[0] = ch;
                break;
            case '/':
                syn = 16;
                token[0] = ch;
                break;
            case '=':
                syn = 25;
                token[0] = ch;
                break;
            case ';':
                syn = 26;
                token[0] = ch;
                break;
            case '(':
                syn = 27;
                token[0] = ch;
                break;
            case ')':
                syn = 28;
                token[0] = ch;
                break;
            case '#':
                syn = 0;
                token[0] = ch;
                break;
            case '\n':
                syn = -2;
                break;
            default:
                syn = -1;
                break;
        }
    return syn;
}

【运行结果】

实验2 递归下降语法分析程序设计_递归_02
实验2 递归下降语法分析程序设计_语法分析_03
实验2 递归下降语法分析程序设计_数字字符_04
实验2 递归下降语法分析程序设计_分析函数_05
实验2 递归下降语法分析程序设计_递归_06