【编译原理】实验二 预测分析算法的设计与实现

一、实验目的

通过预测分析算法的设计与实现,加深对自上而下语法分析方法的理解,尤其是对自上而下分析条件的理解。

二、实验要求  

输入文法及待分析的输入串,输出其预测分析过程及结果。

三、实验步骤

1. 参考数据结构

(1)/*定义产生式的语法集结构*/

typedef struct{

    char formula[200];//产生式

}grammarElement;

grammarElement  gramOldSet[200];//原始文法的产生式集

  (2)/*变量定义*/

     char terSymbol[200];//终结符号

     char non_ter[200];//非终结符号

     char allSymbol[400];//所有符号

     char firstSET[100][100];//各产生式右部的FIRST集

     char followSET[100][100];//各产生式左部的FOLLOW集

     int M[200][200];//分析表

2. 判断文法的左递归性,将左递归文法转换成非左递归文法。(该步骤可以省略,直接输入非左递归文法)。

3.根据文法求FIRST集和FOLLOW集。

(1)/*求 First 集的算法*/

(2)/*求 FOLLOW 集的算法*/

(这两个算法参见陈火旺版编译原理)

4.构造预测分析表。

(参见)

5.构造总控程序。

程序流程图如图1所示:

1

6.对给定的输入串,给出分析过程及结果。

四、实验报告要求

1.写出编程思路、源代码(或流程图);

2.写出上机调试时发现的问题,以及解决的过程;

3.写出你所使用的测试数据及结果;

4.谈谈你的体会。

5.上机8小时,完成实验报告2小时。

编码实现
#include<iostream>
#include<cstring>
#include<string>
#include<stack>
// #include<string.h>

using namespace std;

typedef struct{
    string formula;//产生式
}grammarElement;
grammarElement  gramOldSet[200];

string terSymbol;//终结符号
string non_ter;//非终结符号
string allSymbol;//所有符号
string firstSET[100];//各产生式右部的FIRST集
string followSET[100];//各产生式左部的FOLLOW集
bool flag[100]={0};
int M[200][200];//分析表

int n=0;

// void grammerIn();

void First(char c);
void Follow(char nont);
void Table();
bool Control();

int addF(string &s, char c);
int is_terSymbol(char c);
int is_non_ter(char c);
bool forkong(char c);
void print(stack<char> S, string str);


int main(){
    cout << "non_ter: ";
    cin >> non_ter;
    cout << "ter: ";
    cin >> terSymbol;
    cout<<"num: ";
    cin>> n;
    for(int i=0;i<n;i++){
        cin>>gramOldSet[i].formula;
    }
    // cout<<gramOldSet[0].formula<<endl;
    terSymbol.push_back('#');

    for(int i=0;i<n;i++){
        if (flag[is_non_ter(gramOldSet[i].formula[0])] == 0){
            First(gramOldSet[i].formula[0]);
        }
    }

    for(int i=0;i<non_ter.size();i++)  cout<<firstSET[i]<<endl;

    for(int i=0;i<n;i++){
        if (flag[is_non_ter(gramOldSet[i].formula[0])] == 1){
            Follow(gramOldSet[i].formula[0]);
        }
    }

    for(int i=0;i<non_ter.size();i++)  cout<<followSET[i]<<endl;

    Table();
    for(int i=0;i<non_ter.size();i++){
        for(int j=0;j<terSymbol.size();j++){
            cout.width(4);
            cout<<M[i][j];
        }
        cout<<endl;
    }

    Control();

    return 0;
}

void First(char nont){

    // char *p = firstSET[is_non_ter(nont)];   //first集存放位置
    int k=0;

    for(int i=0; i<n ;i++) {     //在输入的产生式中查找,不是就continue
        if(gramOldSet[i].formula[0] == nont) {  

            char *pfml = &gramOldSet[i].formula[3];     //产生式的第一个符号
            int isnt = is_non_ter(*pfml);
            int ist = is_terSymbol(*pfml);
            if( ist >= 0 || (gramOldSet[i].formula[3] == '$' && gramOldSet[i].formula.size()==4 ) ){  //第一个字符是终结符或只能推出空
                addF( firstSET[is_non_ter(nont)] , gramOldSet[i].formula[3]);
            }
            else if(isnt>=0){       //第一个字符是非终结符

                //产生式的第一个字符为本身
                if(non_ter[isnt] == nont){  
                    continue;
                } 
                
                else{
                    //没有找过first集
                    if(flag[isnt]==0){
                        First(gramOldSet[i].formula[3]);
                    }
                    if(flag[isnt]==1){
                        for(int j=0;  j<firstSET[isnt].size(); j++)
                            addF(firstSET[is_non_ter(nont)] , firstSET[isnt][j]);
                    }
                    //可推出空字
                    for(int m=4; ;m++){
                        if(forkong(*pfml) && m<gramOldSet[i].formula.size()){    //且不以此符号结尾
                            pfml++;
                        }else if(forkong(*pfml) && m==gramOldSet[i].formula.size()){      //以此符号结尾
                            addF(firstSET[is_non_ter(nont)] , '$');
                            break;
                        }else break;

                        if(flag[ is_non_ter(*pfml) ]==0){   //当前符号没有求first集
                            First(*pfml);
                        }
                        if(flag[ is_non_ter(*pfml) ]==1){
                            for(int j=0; j<firstSET[ is_non_ter(*pfml) ].size(); j++)
                                addF(firstSET[is_non_ter(nont)] , firstSET[ is_non_ter(*pfml) ][j]);
                        }
                    }
                }
            }

        }
        else {
            continue;
        }
    }

    //标记该非终结符已经查找过first集
    flag[is_non_ter(nont)]=1;
    
}


void Follow(char nont){

    for(int i=0;i<n;i++){
        if(gramOldSet[i].formula[0] == nont){

            char *pfml;

            if(i==0){
                addF(followSET[is_non_ter(nont)] , '#');
            }

            //寻找存在该非终结符的产生式
            for(int j=0;j<n;j++){
                if(gramOldSet[j].formula.find(nont)>=3){

                    //当它为产生式结尾
                    if(gramOldSet[j].formula.find(nont) == gramOldSet[j].formula.size()-1) {
                        //非终结符是否求过follow集
                        if(flag[is_non_ter(gramOldSet[j].formula[0])]==1) {
                            Follow(gramOldSet[j].formula[0]);
                        }
                        if(flag[is_non_ter(gramOldSet[j].formula[0])]==0) {
                            for(int k=0;k<followSET[is_non_ter(gramOldSet[j].formula[0])].size(); k++){
                                addF(followSET[is_non_ter(nont)], followSET[is_non_ter(gramOldSet[j].formula[0])][k]);
                            }
                        }
                    }
                    //当它不是产生式结尾
                    else if(gramOldSet[j].formula.find(nont) < gramOldSet[j].formula.size()-1){

                        pfml = &gramOldSet[j].formula[ gramOldSet[j].formula.find(nont) ];  //该非终结符在队中的位置指针
                        
                        
                        bool is_kong=true;
                        int k=0;
                        for( k=gramOldSet[j].formula.find(nont)+1; k < gramOldSet[j].formula.size();k++){

                                //终结符,添加本身
                                if(is_terSymbol(gramOldSet[j].formula[k])>=0){
                                    addF(followSET[is_non_ter(nont)], gramOldSet[j].formula[k]);
                                    break;
                                }
                                //非终结符,添加first集
                                for(int p=0; p<firstSET[is_non_ter(gramOldSet[j].formula[k])].size(); p++){
                                    if(firstSET[is_non_ter(gramOldSet[j].formula[k])][p] == '$')    continue;
                                    addF(followSET[is_non_ter(nont)], firstSET[is_non_ter(gramOldSet[j].formula[k])][p]);
                                }

                            if(!forkong(gramOldSet[j].formula[k])){
                                is_kong=false;
                                break;
                            }
                        }
                        //能推出空字符todo
                        if (is_kong){

                            // if(flag[is_non_ter(pfml[1])] == 1)  Follow(pfml[1]);

                            if(flag[is_non_ter(pfml[1])] == 0) {
                                for(int m=0;m<followSET[is_non_ter(gramOldSet[j].formula[0])].size(); m++){
                                    addF(followSET[is_non_ter(nont)], followSET[is_non_ter(gramOldSet[j].formula[0])][m]);
                                }
                            }
                        }
                        
                        
                    }
                }
                else{
                    continue;
                }
            }
        }
        else{
            continue;
        }
    }

    flag[is_non_ter(nont)]=0;
}

//构造预测分析表
void Table(){
    for(int i=0;i<non_ter.size();i++){
        for(int j=0;j<terSymbol.size();j++){

            M[i][j]=-1;
            if(firstSET[i].find(terSymbol[j])!=-1 || followSET[i].find(terSymbol[j])!=-1){
                //k为当前产生式编号
                for(int k=0;k<n;k++){
                    if(gramOldSet[k].formula[0]==non_ter[i]){

                        bool is_kong = true;
                        
                        for(int p=3;p<gramOldSet[k].formula.size();p++){
                            //为终结符
                            if(is_terSymbol(gramOldSet[k].formula[p])>=0 && gramOldSet[k].formula[p]==terSymbol[j]){
                                M[i][j]=k;
                                is_kong=false;
                                break;
                            }
                            //当前非终结符first集中有该j
                            else if (firstSET[is_non_ter(gramOldSet[k].formula[p])].find(terSymbol[j])!=-1){
                                M[i][j]=k;
                                break;
                            }

                            //阿尔法不能推出空
                            if(!forkong(gramOldSet[k].formula[p])&&gramOldSet[k].formula[p]!='$'){
                                is_kong=false;
                                break;
                            }
                            
                        }

                        if(is_kong){
                            if(followSET[i].find(terSymbol[j])!=-1){
                                M[i][j]=k;
                            }
                        }

                    }
                }
            }

        }
    }
}

//总控程序
bool Control(){
    stack<char> S;
    string str;
    char x;

    S.push('#');
    S.push(gramOldSet[0].formula[0]);
    bool flag=true;
    cin>>str;
    // char *a=&str[0];
    string::iterator a = str.begin();

    print(S,str);
    cout<<endl;
    
    while(flag){
        // x = S.top();
        //x==a=='#'时
        if(S.top()=='#'){
            if(S.top()==*a){
                flag=false;
            }else{
                cout<<"error"<<endl;
                return false;
            }
        }
        //栈顶为终结符
        else if(terSymbol.find(S.top())!=-1){
            if(S.top()==*a){
                S.pop();
                a=str.erase(a);
                print(S,str);
                cout<<endl;
            }else{
                cout<<"error"<<endl;
                return false;
            }
        }
        //栈顶为非终结符
        else if(non_ter.find(S.top())!=-1){
            int num=M[is_non_ter(S.top())][is_terSymbol(*a)];
            S.pop();
            if(num>=0){
                for(int i=gramOldSet[num].formula.size()-1;i>=3;i--){
                    if(gramOldSet[num].formula[i]=='$') break;
                    S.push(gramOldSet[num].formula[i]);
                }
            }
            print(S,str);
            cout<< gramOldSet[num].formula <<endl;

        }else{
            return false;
        }
    }

}

//向first或follow集中添加
int addF(string &s, char c){
    if(s.find(c)!=-1)    return 0;
    else{
        s.push_back(c);
        return 1;
    }
}

int is_terSymbol(char c){
    if(terSymbol.find(c)>=0) return terSymbol.find(c);
    else return -1;
}

int is_non_ter(char c){
    if(non_ter.find(c)>=0) return non_ter.find(c);
    else return -1;
}

//能退出空返回true,不能返回false
bool forkong(char c){
    if(is_terSymbol(c)>=0) return false;
    int s=is_non_ter(c);
    for(int i=0; i<n; i++){
        if(c==gramOldSet[i].formula[0]){
            if(gramOldSet[i].formula[3]=='$' && gramOldSet[i].formula.size()==4) return true;
            else if (is_non_ter(gramOldSet[i].formula[3])>=0){
                return forkong(gramOldSet[i].formula[3]);       //递归查看是否为空
            }
        }
    }
    return false;
}

//格式化输出
void print(stack<char> S, string str){
    static int i=0;
    cout.width(5);
    cout<< left << i ;
    i++;
    string sta;
    for(int j=S.size()-1;j>=0;j--){
        sta.insert(sta.begin(),S.top());
        S.pop();
    }
    cout.width(10);
    cout<< left << sta ;
    cout.width(10);
    cout<< right << str <<"   ";
}

测试数据:

ASDFG
i+*()
8
A->DS
S->+DS
S->$
D->GF
F->*GF
F->$
G->(A)
G->i
i*i+i#

输出依次为按输入非终结符顺序的First集和Follow集、预测分析表、分析过程与结果。

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理实验中,使用Scala编程语言进行分析是一种常见的做法。Scala是一门功能强大的多范式编程语言,它融合了面向对象编程和函数式编程的特性。 在编译原理实验中,我们通常需要实现语言的词法分析和语法分析两个重要的步骤。词法分析器主要负责将源代码分解为各种词法单元,例如关键字、标识符、运算符和常量等。而语法分析器则根据词法单元构建语法树,以验证源代码是否符合给定的文法规则。 Scala提供了丰富的语言特性和工具,便于我们实现词法分析器和语法分析器。例如,我们可以使用Scala的正则表达式库来定义词法规则,并使用模式匹配语法来进行单词的匹配和提取。此外,Scala还支持高阶函数和匿名函数的特性,使得我们可以更方便地实现语法分析器。 除了词法分析和语法分析编译原理实验中还需要实现其他功能,如语义分析、中间代码生成和目标代码生成等。Scala作为一门面向对象和函数式的编程语言,具有良好的可扩展性和可维护性,能够有效地支持这些功能的实现。 在实验过程中,我们可以利用Scala的强类型系统和模式匹配等特性来提高代码的可靠性和可读性。此外,Scala还提供了丰富的工具库和框架,如ANTLR和ScalaTest等,可以进一步简化编译过程中的实现和测试工作。 总之,使用Scala编程语言进行编译原理实验分析是一种有效和方便的选择。Scala的多范式特性、丰富的语言特性和工具支持,可以帮助我们实现词法分析器、语法分析器和其他编译器的各个部分,并提高代码的可读性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值