实验三 算符优先分析算法的设计与实现

实验三 算符优先分析算法的设计与实现(8学时)

一、 实验目的
根据算符优先分析法,对表达式进行语法分析,使其能够判断一个表达式是否正确。通过算符优先分析方法的实现,加深对自下而上语法分析方法的理解。
二、 实验要求
1、输入文法。可以是如下算术表达式的文法(你可以根据需要适当改变):

E→E+T|E-T|T
T→T*F|T/F|F
F→(E)|i

2、对给定表达式进行分析,输出表达式正确与否的判断。
程序输入/输出示例:
输入:1+2
输出:正确
输入:(1+2)/3+4-(5+6/7)
输出:正确
输入:((1-2)/3+4
输出:错误
输入:1+2-3+(*4/5)
输出:错误
三、实验步骤
1、参考数据结构

char *VN=0,*VT=0;//非终结符和终结符数组
char firstvt[N][N],lastvt[N][N],table[N][N];
typedef struct   //符号对(P,a)
{
	char Vn;
	char Vt;
} VN_VT;
typedef struct  //栈
{
    VN_VT *top;
	     VN_VT *bollow;
	     int  size;
}stack;

2、根据文法求FIRSTVT集和LASTVT集
给定一个上下文无关文法,根据算法设计一个程序,求文法中每个非终结符的FirstVT 集和LastVT 集。
算符描述如下:
/求 FirstVT 集的算法/
PROCEDURE insert(P,a);
IF not F[P,a] then
begin
F[P,a] = true; //(P,a)进栈
end;
Procedure FirstVT;
Begin
for 对每个非终结符 P和终结符 a do
F[P,a] = false
for 对每个形如 P a…或 P→Qa…的产生式 do
Insert(P,a)
while stack 非空
begin
栈顶项出栈,记为(Q,a)
for 对每条形如 P→Q…的产生式 do
insert(P,a)
end;
end.
同理,可构造计算LASTVT的算法。
3、构造算符优先分析表
依据文法和求出的相应FirstVT和 LastVT 集生成算符优先分析表。
算法描述如下:
for 每个形如 P->X1X2…Xn的产生式 do
for i =1 to n-1 do
begin
if Xi和Xi+1都是终结符 then
Xi = Xi+1
if i<= n-2, Xi和Xi+2 是终结符, 但Xi+1 为非终结符 then
Xi = Xi+2
if Xi为终结符, Xi+1为非终结符 then
for FirstVT 中的每个元素 a do
Xi < a ;
if Xi为非终结符, Xi+1为终结符 then
for LastVT 中的每个元素 a do
a > Xi+1 ;
end
4、构造总控程序
算法描述如下:
stack S;
k = 1; //符号栈S的使用深度
S[k] = ‘#’
REPEAT
把下一个输入符号读进a中;
If S[k] VT then j = k else j = k-1;
While S[j] > a do
Begin
Repeat
Q = S[j];
if S[j-1] VT then j = j-1 else j = j-2
until S[j] < Q;
把S[j+1]…S[k]归约为某个N,并输出归约为哪个符号;
K = j+1;
S[k] = N;
end of while
if S[j] < a or S[j] = a then
begin k = k+1; S[k] = a end
else error //调用出错诊察程序
until a = ‘#’
5、对给定的表达式,给出准确与否的分析过程
6、给出表达式的计算结果。(本步骤可选作
四、实验报告要求
1.写出编程思路、源代码(或流程图);

#include<bits/stdc++.h>

using namespace std;

typedef struct{
    string formula;//产生式
}grammarElement;

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

#define MINXY(x)     ((x) <= 5 ? (x) : 5) 
#define MAXXY(y)     ((y) >= 2 ? (y) : 2) 

int sum;
int n;//文法产生式的个数
string terSymbol;//终结符号
string non_ter;//非终结符号
string allSymbol;//所有符号
string FIRSTVT[100];//各非终结符的FIRSTVT集
string LASTVT[100];//各非终结符的LASTVT集
string M[200][200];//算符优先关系表
string str_cin;//输入串
vector <char> S;//符号栈
string form;//表达式


string duplictae(string s){//去除字符串中的重复字符
    if(s.size()<2)
        return s;
    string temp("\0");
    temp += s[0];
    string::size_type y;
    for(string::size_type x = 1; x < s.size(); x++){
        for( y = 0; y < temp.size(); y++){
            if(temp[y] == s[x]) 
                break;
        }
        if(y == temp.size())
            temp += s[x];
    }
    return temp;
}

string dealForm(string s){//预处理表达式
    string s1;
    s1 = s;
    s1 += '#';
    for(int i = 0; i < s.length(); i++){
        if( '0' <= s[i] && s[i] <= '9'){
            s1[i] = 'i';
        }
    }
    return s1;
}

string PrintStack(vector <char> &ss){//打印符号栈
    string S_print;
	for(vector<char>::iterator it = ss.begin();it != ss.end(); it++)//打印符号栈
        S_print += *it;
    return S_print;
}

string PrintStrCin(string s,int num){//打印输入串
    string s_print;
    for(int i = num; i<s.length();i++)
        s_print += s[i];
    return s_print;
}

void initSet(grammarElement s[],int n1){//处理 | 后的产生式集
    s[0].formula = "S->##";//扩广文法S->#E#
    s[0].formula.insert(4,1,s[1].formula[0]);
    non_ter.insert(0,1,'S');//文法符号是开始符号S
    n++;
    for(int i = 1; i <= n1; i++){
        string temp = s[i].formula;;//暂时保存需要处理的产生式
        for(int j = s[i].formula.length() - 1; j >= 0; j-- ){
            if(s[i].formula[j]  == '|'){//确定带有 | 的产生式 
                s[n++].formula = temp.erase(3,j-2);//加上新的产生式
                temp = s[i].formula.erase(j);//去除 |
            }
        }
    }
}

void dealFIRSTVT(){//构造与文法有关的非终结符的FIRSTVT集
    int num = non_ter.length();
//    FIRSTVT[0] += '#';//文法符号是开始符号S
    terSymbol += '#';//#看成终结符
    while(num > 0){//检查每个产生式的候选式
        string temp;//暂存产生式的非终结符
        temp = non_ter[num];
        for(int i = 0; i < n; i++){
            for(int j = 3; j < MINXY(gramOldSet[i].formula.length()); j++){//若有产生式P->a..或P->Qa..,则a∈FIRSTVT(P)
                if((terSymbol.find(gramOldSet[i].formula[j]) != -1) && (j == 3)){//若有P->a..,则a∈FIRSTVT(P)
                    char ch1 = gramOldSet[i].formula[j];//暂存a
                    if(FIRSTVT[non_ter.find(gramOldSet[i].formula[0])].find(ch1) == -1)//在FIRSTVT集中确认未重复
                        FIRSTVT[non_ter.find(gramOldSet[i].formula[0])] += ch1;//把a加至FIRSTVT(P)中
                }
                if((non_ter.find(gramOldSet[i].formula[j]) != -1) && (j == 3)){//若有产生式P->Q..,则a∈FIRSTVT(P)
                    char ch2;//暂存a
                    string str1 = FIRSTVT[non_ter.find(gramOldSet[i].formula[j])];//暂存FIRSTVT(Q)
                    if(FIRSTVT[non_ter.find(gramOldSet[i].formula[0])].find(str1) == -1)//a在FIRSTVT集中确认未重复
                        FIRSTVT[non_ter.find(gramOldSet[i].formula[0])] += str1;//则a∈FIRSTVT(P)
                    if((terSymbol.find(gramOldSet[i].formula[j+1]) != -1)){//若有产生式P->Qa..,则a∈FIRSTVT(P)
                        ch2 = gramOldSet[i].formula[j+1];//暂存a
                        if(FIRSTVT[non_ter.find(gramOldSet[i].formula[0])].find(ch2) == -1)//a在FIRSTVT集中确认未重复
                            FIRSTVT[non_ter.find(gramOldSet[i].formula[0])] += ch2;//把a加至FIRSTVT(P)中
                    }
                }
            }
        }
        num--;
    }  
    for(int j = 0;j < non_ter.length();j++){
        cout<<"非终结符\'"<<non_ter[j]<<"\'的FIRSTVT集元素有:{ ";
        FIRSTVT[j] = duplictae(FIRSTVT[j]);//去除重复字符串
        for(int k = 0; k < FIRSTVT[j].length(); k++)
            cout<<FIRSTVT[j][k]<<" ";
        cout<<"}"<<endl;
    }
    cout<<endl;
}

void dealLASTVT(){//构造与文法有关的非终结符的LASTVT集
    int num = non_ter.length();
//    LASTVT[0] += '#';//文法符号是开始符号S,
    while(num > 0){//检查每个产生式的候选式
        string temp;//暂存产生式的非终结符
        temp = non_ter[num];
        for(int i = 0; i < n; i++){
            for(int j = gramOldSet[i].formula.length() - 1; j > MAXXY(gramOldSet[i].formula.length() - 3); j--){//若有产生式P->..b或P->..bQ,则b∈LASTVT(P)
                if((terSymbol.find(gramOldSet[i].formula[j]) != -1) && 
                (j == gramOldSet[i].formula.length() - 1)){//若有P->..b,则b∈LASTVT(P)
                    char ch1 = gramOldSet[i].formula[j];//暂存b
                    if(LASTVT[non_ter.find(gramOldSet[i].formula[0])].find(ch1) == -1)//在LASTVT集中确认未重复
                        LASTVT[non_ter.find(gramOldSet[i].formula[0])] += ch1;//把b加至LASTVT(P)中
                }
                if((non_ter.find(gramOldSet[i].formula[j]) != -1) && 
                (j == gramOldSet[i].formula.length() - 1)){//若有产生式P->..Q,则b∈LASTVT(P)
                    char ch2;//暂存b
                    string str1 = LASTVT[non_ter.find(gramOldSet[i].formula[j])];//暂存LASTVT(Q)
                    if(LASTVT[non_ter.find(gramOldSet[i].formula[0])].find(str1) == -1)//b在LASTVT集中确认未重复
                        LASTVT[non_ter.find(gramOldSet[i].formula[0])] += str1;//则b∈LASTVT(P)
                    if((terSymbol.find(gramOldSet[i].formula[j-1]) != -1)){//若有产生式P->..bQ,则b∈LASTVT(P)
                        ch2 = gramOldSet[i].formula[j-1];//暂存b
                        if(LASTVT[non_ter.find(gramOldSet[i].formula[0])].find(ch2) == -1)//b在LASTVT集中确认未重复
                            LASTVT[non_ter.find(gramOldSet[i].formula[0])] += ch2;//把b加至LASTVT(P)中
                    }
                }
            }
        }
        num--;
    }  
    for(int j = 0;j < non_ter.length();j++){
        cout<<"非终结符\'"<<non_ter[j]<<"\'的LASTVT集元素有:{ ";
        LASTVT[j] = duplictae(LASTVT[j]);//去除重复字符串
        for(int k = 0; k < LASTVT[j].length(); k++)
            cout<<LASTVT[j][k]<<" ";
        cout<<"}"<<endl;
    }
    cout<<endl;
}

void dealTable(){//构造算符优先关系表`
    // terSymbol += '#';
    int cnt = 0;//每条产生式P->X1X2..Xn,计数产生式的个数
    int x_Cor,y_Cor;//M的横纵坐标
    do{
        int gramlen = gramOldSet[cnt].formula.length() - 3; //Xn的n值
        if(gramlen > 1){
            for(int i = 3; i < gramlen + 2; i++){
                if((terSymbol.find(gramOldSet[cnt].formula[i]) != -1) &&
                (terSymbol.find(gramOldSet[cnt].formula[i + 1]) != -1)){//Xi为终结符和Xi+1为终结符,Xi=Xi+1
                    x_Cor = terSymbol.find(gramOldSet[cnt].formula[i]);
                    y_Cor = terSymbol.find(gramOldSet[cnt].formula[i+1]);
                    M[x_Cor][y_Cor] = '=';
                }
                if( i <= gramlen && (terSymbol.find(gramOldSet[cnt].formula[i]) != -1)){// i<= n-2,Xi为终结符和Xi+2为终结符
                    if((terSymbol.find(gramOldSet[cnt].formula[i + 2]) != -1) &&//但Xi+1为非终结符,Xi=Xi+2
                        (non_ter.find(gramOldSet[cnt].formula[i + 1]) != -1)){
                        x_Cor = terSymbol.find(gramOldSet[cnt].formula[i]);
                        y_Cor = terSymbol.find(gramOldSet[cnt].formula[i+2]);
                        M[x_Cor][y_Cor] = '=';
                        }
                }
                if((terSymbol.find(gramOldSet[cnt].formula[i]) != -1) &&//Xi为终结符而Xi+1为非终结符,Xi<FIRSTVT(Xi+1)中的a
                    (non_ter.find(gramOldSet[cnt].formula[i + 1]) != -1)){
                        int cnt1 = 0;//FIRSTVT的位置指针
                        while(cnt1 < FIRSTVT[non_ter.find(gramOldSet[cnt].formula[i + 1])].length()){
                            x_Cor = terSymbol.find(gramOldSet[cnt].formula[i]);
                            y_Cor = terSymbol.find(FIRSTVT[non_ter.find(gramOldSet[cnt].formula[i + 1])][cnt1]);
                            M[x_Cor][y_Cor] = '<';
                            cnt1++;
                        }
                }
                if((terSymbol.find(gramOldSet[cnt].formula[i]) == -1) &&//Xi为终结符而Xi+1为非终结符,LASTVT(Xi)中的a>Xi
                    (non_ter.find(gramOldSet[cnt].formula[i + 1]) == -1)){
                        int cnt2 = 0;//LASTVT的位置指针
                        do{
                            x_Cor = terSymbol.find(LASTVT[non_ter.find(gramOldSet[cnt].formula[i])][cnt2]);
                            y_Cor = terSymbol.find(gramOldSet[cnt].formula[i+1]);
                            M[x_Cor][y_Cor] = '>';
                            cnt2++;
                        }while(cnt2 < LASTVT[non_ter.find(gramOldSet[cnt].formula[i])].length());
                }
            }
        }
        cnt++;
    }while(cnt < n);
    cout<<"优先关系表为:"<<endl;
    cout<<"\t";
    for(int i = 0; i < terSymbol.length(); i++){
        cout<<terSymbol[i]<<"\t";
    }
    cout<<endl;
    for(int i = 0;i < terSymbol.length();i++){
        cout<<terSymbol[i]<<"\t";
        for(int j = 0;j < terSymbol.length()+1;j++)
            cout<<M[i][j]<<"\t";
        cout<<endl;
    }
}

void allContronl(){//总控程序
    cout<<"输入表达式:";
    cin>>form;//表达式
    // cout<<"待分析的输入串为(‘#’是输入串的结束符):";
    str_cin = dealForm(form);//输入串
    cout<<"表达式化为输入串(‘#’是输入串的结束符):"<<str_cin<<endl;
    // cin>>str_cin;
    cout<<"利用算符优先关系表进行规范归约的步骤为:"<<endl;
    char a;//当前的输入符a
    bool flag1=true;
    int j,pos = 0, counter = 1;//pos输入串的指示坐标,counter步骤计数器
    cout<<setw(8)<<std::left<<"步骤"<<setw(15)<<std::left<<"符号栈";
    cout<<setw(15)<<std::right<<"输入串"<<"\t\t"<<setw(15)<<std::left<<"动作"<<endl;
    S.push_back('#');//置初值
    cout<<setw(8)<<std::left<<"0"<<setw(15)<<std::left<<PrintStack(S);
    cout<<setw(15)<<std::right<<PrintStrCin(str_cin,pos)<<"\t\t"<<setw(15)<<std::left<<"预备"<<endl;
    int k = 0;//k代表符号栈的使用深度
    // a = str_cin[pos];
	do{
        char N;//N为归约成的符号
	    a = str_cin[pos];//把下一个输入符号读进a中
	    if(terSymbol.find(S[k]) != -1){//S[k]∈Vt
	        j = k;
	    }else{
	        j = k - 1;
	    }
	    while(M[terSymbol.find(S[j])][terSymbol.find(a)] == ">"){//S[j] > a
	     	char Q;
            string str1;//保存S[j+1]..S[k]
            string str_gram;//归约所用式子
	        do{
	            Q = S[j];
	            if(terSymbol.find(S[j-1]) != -1){//S[j-1]∈Vt
	                j = j - 1;
	            }else{
	                j = j - 2;
	            }
	        }while(M[terSymbol.find(S[j])][terSymbol.find(Q)] != "<");
            bool flag = true;//归约标志
            int Maxnum = 0;
            for(int i0 = j+1; i0 <= k; i0++)
                str1 += S[i0];
            while(flag&&Maxnum < 3){            
                for(int i1 = 0; i1 < n; i1++){
                    string str2;
                    str2 = gramOldSet[i1].formula.substr(3);//保存产生式右部
                    if(str1 == str2){//归约
                        N = gramOldSet[i1].formula[0];
                        str_gram = gramOldSet[i1].formula;
                        str1 = N;
                        if((S[j] == '/' | S[j] == '*')&&(N == 'F'))
                            flag = false;
                        if((S[j] == '+'| S[j] == '-'| a == '*'| a == '/')&&(N == 'T'))
                            flag = false;
                        break;
                    }
                }
                Maxnum++;
            }//把S[j+1]..S[k]归约为某个N}
            if(N == ' ') break;
            for(int m = j+1; m <= k;m++)//归约
                S.pop_back();
            k = j+1;
            S.push_back(N);
            N = ' ';
            cout<<setw(8)<<std::left<<counter++<<setw(15)<<std::left<<PrintStack(S);//步骤加1
            cout<<setw(15)<<std::right<<PrintStrCin(str_cin,pos)<<"\t\t"<<setw(15)<<std::left<<"归,用"+str_gram<<endl;
        }
	    if((M[terSymbol.find(S[j])][terSymbol.find(a)] == "<") ||
	      (M[terSymbol.find(S[j])][terSymbol.find(a)] == "=")){//S[j] < a 或 S[j] = a 
	        k++;
	        S.push_back(a);
            ++pos;
            // a = str_cin[++pos];//把下一个输入符号读进a中
            cout<<setw(8)<<std::left<<counter++<<setw(15)<<std::left<<PrintStack(S);//步骤加1
            cout<<setw(15)<<std::right<<PrintStrCin(str_cin,pos)<<"\t\t"<<setw(15)<<std::left<<"进"<<endl;
	    }else{ 
	        cout<<"错误"<<endl;
            flag1 = false;
            break;
	    }
	}while(a != '#');
    if((a == '#' ) && flag1){
        cout<<setw(8)<<std::left<<counter<<setw(15)<<std::left<<PrintStack(S);
        cout<<setw(15)<<std::right<<PrintStrCin(str_cin,pos)<<"\t\t"<<setw(15)<<std::left<<"接受"<<endl;
        cout<<"正确"<<endl;
    }
}

int main(){
    cout<<"非终结符号如下:  ";
    cin>>non_ter;
    cout<<"终结符号如下:  ";
    cin>>terSymbol;
    allSymbol = non_ter + terSymbol;
    cout<<"文法产生式的个数:  ";
    cin>>n;
    cout<<endl;
    for(int i = 1;i <= n;i++){
        cout<<"请输入第"<<i<<"产生式:"<<endl;
        cin>>gramOldSet[i].formula;
    }
    cout<<"\n\n去除 | 之后的产生式:"<<endl;
    initSet(gramOldSet,n);    
    for(int i = 0;i < n; i++){
        cout<<gramOldSet[i].formula<<endl;
    }
    cout<<endl;
    dealFIRSTVT();
    dealLASTVT();
    dealTable();
    for(int i = 0;i<4;i++){
        allContronl();
        S.clear();
    }
    return 0;
}

2.写出上机调试时发现的问题,以及解决的过程;
(1)规约时,如果有连续的单个非终结符进行归约,那么会发现无法归约到指定的字符串,因为书本上的算法并没有指出应把所找到的最左素短语归约到哪一个非终结符‘N’。即算符优先一般不等价于规范归约。因此在进行归约的时候要根据前后符号的情况进行归约,判断要归约到那个非终结符,因此需要在归约过程中加入自身以及外界情况的的一些考量从而对代码进行修正。
3.写出你所使用的测试数据及结果;
测试数据:

ETF
+-*/()i
3
E→E+T|E-T|T
T→T*F|T/F|F
F→(E)|i
1+2
(1+2)/3+4-(5+6/7)
((1-2)/3+4
1+2-3+(*4/5)

结果:
结果截图1
结果截图2

结果截图3
结果截图4
4.谈谈你的体会。
由于算符优先分析并未对文法非终结符定义优先关系,所以就无法发现由单个非终结符组成的可规约串。也就是说,在算符优先归约过程中,我们无法用那些右部仅含一个非终结符的产生式(称为单非产生式,如P->Q)进行归约。(建议自行体会.jpg
5.上机8小时,完成实验报告2小时。

实验报告

  • 10
    点赞
  • 126
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
算符优先分析算法是一种自底向上的语法分析算法,用于判断输入源程序是否符合语法规则。该算法的主要思想是利用算符优先关系来进行语法分析。 下面是算符优先分析算法实验步骤: 1. 定义文法:首先需要定义待分析的文法,可以使用巴科斯范式(BNF)或扩展巴科斯范式(EBNF)来示文法。 2. 构造算符优先关系:根据文法中的终结符和运算符,构造算符优先关系。其中,算符优先关系一个二维矩阵,行和列分别代两个运算符,中的值示它们之间的优先关系。 3. 读入待分析的源程序:从文件中读入待分析的源程序,可以使用词法分析器将源程序转换成一个个单词。 4. 进行算符优先分析:根据算符优先关系输入的单词序列,利用栈来进行算符优先分析。具体过程如下: - 初始化栈,将结束符号 $ 和文法的开始符号压入栈中。 - 从输入的单词序列中读入一个单词。 - 判断栈顶符号和当前读入的单词之间的优先关系,如果栈顶符号的优先级高于当前单词,则进行规约操作,即将栈顶符号和它的子树弹出,然后根据规约产生式将它们替换成非终结符号。 - 如果栈顶符号和当前单词之间的优先级低于或等于当前单词,则进行移进操作,即将当前单词压入栈中。 - 重复上述步骤,直到栈中只剩下结束符号 $,并且输入的单词序列已经分析完毕。 5. 输出分析结果:如果分析成功,则输出“分析成功”;否则,输出“分析失败”。 以上就是算符优先分析算法实验步骤,希望对你有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值