编译原理:算符优先分析算法的设计与实现(含代码)

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

写在最前面:我的编译原理学的不是很好,不怎么听课,所以我写代码的思路比较简单。简单的思路也就意味着代码很笨重,介意的话请点叉叉。如果有什么指教欢迎评论区留言。

特别说明:本博代码在识别:
E→E+T
E→E-T
E→T
时,firstvt集和lastvt集可能会出现错误。
最好合并为以下形式:
E→E+T|E-T|T

一、实验目的

1.根据算符优先分析法,对表达式进行语法分析,使其能够判断一个表达式是否正确。

2.通过算符优先分析方法的实现,加深对自下而上语法分析方法的理解。

二、 实验内容

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)
输出:错误

3.根据文法求FIRSTVT集和LASTVT集

给定一个上下文无关文法,根据算法设计一个程序,求文法中每个非终结符的FirstVT 集和LastVT 集。

找Firstvt的三条规则
如果要找A的Firstvt, A的候选式中出现:
A->a…,即以终结符开头,a入 Firstvt
A->B…,即以非终结符开头,B的Firstvt入A的Firstvt
A->Ba…,即先以非终结符开头,紧跟终结符,则a入Firstvt

找Lastvt的三条规则
如果要找A的Lastvt, A的候选式中出现:
A->…a,即以终结符结尾,a入Lastvt
A->…B,即以非终结符结尾,B的Lastvt入A的Lastvt
A->…aB,即先以非终结符结尾,前面是终结符,则a入Lastvt

根据上述求firstvt和lastvt的方法,我们计算一下我给的例子,得到的最终结果如下。
firstvt和lastvt

4.构造算符优先分析表

我先概述一下构造方法:
在右边的产生式中,找每个终结符。

  1. 如果就单一个终结符,那么忽略不看。
  2. 先找出…aB…这种形式,这代表a<firstvt(B)。
    在算符优先分析表的左边一列中找到a,然后向右在对应的每个firstvt(B)的元素的位置上标上<。
  3. 再找…Ba…这种形式,这代表a>lastvt(B)。
    在算符优先分析表的上面一行中找到a,然后向下在对应的每个lastvt(B)的元素的位置上标上>。
  4. 如果有…ab…或…aCb…这两种情况,则在a行b列的位置上标上=。

下面我来结合例子讲一下:
首先构造好表:

+-*/()i#
+
-
*
/
(
)
i
#

然后我们先看文法的第一行:
E->E+T|E-T|T
第一个终结符为+。
其实E+T就代表着lastvt(E) < + < firstvt(T)。
我们每次都要先看<,再看>。
+ < firstvt(T),
即+ < * , / , ( , i。
<是从左向右,所以要在
(+,*) (+,/) (+,() (+,i)
这四个位置标上<。
即:

+-*/()i#
+<<<<
-
*
/
(
)
i
#

然后再看>。
+ > lastvt(E),
即+ > + , - , * , / , ) , i。
>是从上到下,所以要在
( +,+) (-,+) (*,+) (/,+) (),+) (i,+)
这六个位置上标上>。
即:

+-*/()i#
+><<<<
->
*>
/>
(
)>
i>
#

前两行文法:
E->E+T|E-T|T
T->T*F|T/F|F

其中的+ , - , * , /都和我上面说的情况一样。
可得下表:

+-*/()i#
+>><<<<
->><<<<
*>>>><<
/>>>><<
(
)>>>>
i>>>>
#

最后,我们来看最后一个文法:
F->(E)|i
i只是一个终结符,不存在大小关系,不看它。
而(E)就是
( < firstvt(E);
) > lastvt(E)。
并且(E)满足…aBc…的情况,要在第(行,第)列的位置((,))上标上=。
可得下表:

+-*/()i#
+>><<<><
->><<<><
*>>>><><
/>>>><><
(<<<<<=<
)>>>>>
i>>>>>
#

最后的最后,如果要考虑#。
我们按照#E#的样子考虑。
即:
# < firstvt(E);
# > lastvt(E)。
并且#E#满足…aBc…的情况,要在第#行,第#列的位置(#,#)上标上=。
可得最终表:

+-*/()i#
+>><<<><>
->><<<><>
*>>>><><>
/>>>><><>
(<<<<<=<
)>>>>>>
i>>>>>>
#<<<<<<=

这就是我们要求的算符优先分析表了。

5.对给定的表达式,给出准确与否的分析过程,给出表达式的计算结果。
在规约的时候我们其实可以直接看文法就行了(如果文法比较简单的话),但我还是讲一下如何根据算符优先分析表来进行规约。

一句话:栈的最右边的终结符,和输入串的最左边的终结符,在表中查出对应位置为<,>还是=。<则移进,>则规约,=则先移进再规约。若表中对应位置是空格,则表示该表达式是错误的。

举个例子:#(i+i)/i+i-(i+i/i)#

步骤输入串动作
0#(i+i)/i+i-(i+i/i)#预备
1#(i+i)/i+i-(i+i/i)#查表,(#,()=<,移进
2#(i+i)/i+i-(i+i/i)#查表,((,i)=<,移进
3#(N+i)/i+i-(i+i/i)#查表,(i,+)=>,规约(N可以换成其它大写字母)
4#(N+i)/i+i-(i+i/i)#((,+)=<,移进
5#(N+i)/i+i-(i+i/i)#(+,i)=<,移进
6#(N+N)/i+i-(i+i/i)#(i,))=>,规约
7#(N)/i+i-(i+i/i)#(+,))=>,规约
8#(N)/i+i-(i+i/i)#((,))==,先移进
9#N/i+i-(i+i/i)#后规约
10#N#好了,偷个懒,不想写了,反正<,>,=三种情况都有了,自己举一反三吧

三、实验代码

//owner:junfuxiaotong
//date:2021/11/28
#include<bits/stdc++.h>
#include<cstdlib>
using namespace std;
#define N 100
#define true 1
#define false -1
char wenfa[N][N];
char VN[N],VT[N];
char firstvt[N][N],lastvt[N][N],table[N][N];
int vnvt(int n)//获取vn vt
{
    int flag=true;
    for(int i=0;i<n;i++)
    {
        if((wenfa[i][0]>='A'&&wenfa[i][0]<='Z')&&wenfa[i][1]=='-'&&wenfa[i][2]=='>')
        {
            int sign=true;
            for(int j=0;j<strlen(VN);j++)
            {
                if(VN[j]==wenfa[i][0])
                {
                    sign=false;
                    break;
                }
            }
            if(sign==true)
            {
                VN[strlen(VN)]=wenfa[i][0];
            }
            else if(sign==false)
            {
                continue;
            }
        }
        else
        {
            flag=false;
            break;
        }
    }
    if(flag==false)
    {
        return flag;
    }
    else
    {
        int k=0;
        int l=0;
        for(int i=0;i<n;i++)
        {
            for(int j=3;wenfa[i][j]!='\0';j++)
            {
                if((wenfa[i][j]<'A'||wenfa[i][j]>'Z')&&wenfa[i][j]!='|')
                {
                    for(l=0;l<k;l++)
                    {
                        if(wenfa[i][j]==VT[l])
                        {
                            break;
                        }
                    }
                    if(l==k)
                    {
                        VT[k]=wenfa[i][j];
                        k++;
                    }
                }
            }
        }
        return flag;
    }
}
void getfirstvt(int n)
{
    // int point=0;//用于指向每一个产生式的前两个符号
    for(int i=0;i<n;i++)//首先是找到每个产生式的前两个符号是否是终结符,是就加入到对应的firstvt集中。
    {
        int flag=true;
        for(int j=3;;)
        {
            for(int k=0;k<strlen(VT);k++)
            {
                if(wenfa[i][j]==VT[k])
                {
                    int mark=true;//用于检查firstvt集中是否已经存在该终结符。
                    for(int l=0;l<strlen(firstvt[i]);l++)
                    {
                        if(wenfa[i][j]==firstvt[i][l])
                        {
                            mark=false;
                            break;
                        }
                    }
                    if(mark==true)//若不存在,则加入到firstvt集中
                    {
                        int length=strlen(firstvt[i]);
                        firstvt[i][length]=wenfa[i][j];
                    }
                }
                if(wenfa[i][j+1]==VT[k])
                {
                    int mark=true;
                    for(int l=0;l<strlen(firstvt[i]);l++)
                    {
                        if(wenfa[i][j+1]==firstvt[i][l])
                        {
                            mark=false;
                            break;
                        }
                    }
                    if(mark==true)
                    {
                        int length=strlen(firstvt[i]);
                        firstvt[i][length]=wenfa[i][j+1];
                    }
                }
            }
            while(wenfa[i][j]!='|')
            {
                if(wenfa[i][j]=='\0')
                {
                    flag=false;
                    break;
                }
                j++;
            }
            j++;
            if(flag==false)
            {
                break;
            }
        }
    }
    //下面的代码是循环查看哪些非终结符的firstvt集可以加入到另一些非终结符的firstvt集中,一直循环添加,直到每个非终结符的长度不再变化为止。
    int *origin=new int[n];//用于记录遍历之前的数组长度,看是否有变化。
    while(1)
    {
        int sign=true;//用于标识遍历前后firstvt是否有变化。mark,symbol。
        for(int i=0;i<n;i++)
        {
            if(origin[i]!=strlen(firstvt[i]))
            {
                sign=false;//长度有变化
                origin[i]=strlen(firstvt[i]);
            }
        }
        if(sign==true)
        {
            break;
        }
        for(int i=0;i<n;i++)
        {
            for(int j=3;;)
            {
                for(int k=0;k<n;k++)
                {
                    if(k==i)
                    {
                        continue;
                    }
                    else if(wenfa[i][j]==wenfa[k][0])
                    {
                        for(int l=0;l<strlen(firstvt[k]);l++)
                        {
                            int flag=true;//用于标识一个终结符是否已经在firstvt集中,true为不在其中的意思。
                            for(int m=0;m<strlen(firstvt[i]);m++)
                            {
                                if(firstvt[k][l]==firstvt[i][m])
                                {
                                    flag=false;
                                    break;
                                }
                            }
                            if(flag==false)
                            {
                                continue;
                            }
                            else
                            {
                                int length=strlen(firstvt[i]);
                                firstvt[i][length]=firstvt[k][l];
                            }
                        }
                    }
                }
                int flag=true;
                while(wenfa[i][j]!='|')
                {
                    if(wenfa[i][j]=='\0')
                    {
                        flag=false;
                        break;
                    }
                    j++;
                }
                if(flag==false)
                {
                    break;
                }
                j++;
            }
        }
    }
}
void getlastvt(int n)//获取lastvt集,此函数下标我是从abc...这么开始的,我也不知道为啥要这么干
{
    for(int a=0;a<n;a++)
    {
        for(int b=0;;)
        {
            int sign=true;//用于标识是否到了一句分法的末尾
            while(wenfa[a][b]!='|')
            {
                if(wenfa[a][b]=='\0')
                {
                    sign=false;
                    break;
                }
                b++;
            }
            for(int c=0;c<strlen(VT);c++)
            {
                if(wenfa[a][b-1]==VT[c])
                {
                    int flag=true;
                    for(int e=0;e<strlen(lastvt[a]);e++)
                    {
                        if(wenfa[a][b-1]==lastvt[a][e])
                        {
                            flag=false;
                            break;
                        }
                    }
                    if(flag==true)
                    {
                        int length=strlen(lastvt[a]);
                        lastvt[a][length]=VT[c];
                    }
                }
                if(wenfa[a][b-2]==VT[c])
                {
                    int flag=true;
                    for(int e=0;e<strlen(lastvt[a]);e++)
                    {
                        if(wenfa[a][b-2]==lastvt[a][e])
                        {
                            flag=false;
                            break;
                        }
                    }
                    if(flag==true)
                    {
                        int length=strlen(lastvt[a]);
                        lastvt[a][length]=VT[c];
                    }
                }
            }
            if(sign==false)
            {
                break;
            }
            b++;//这里设置一个b++是因为wenfa[a][b]=='|',这样的话前面的while循环无法进行前进下标扫描,所以在这先把下标跳一个。
        }
    }
    //下面的代码和getfirstvt的后半段代码一模一样,只是把所有的firstvt改成lastvt就行了。
    int *origin=new int[n];//用于记录遍历之前的数组长度,看是否有变化。
    while(1)
    {
        int sign=true;//用于标识遍历前后lastvt是否有变化。mark,symbol。
        for(int i=0;i<n;i++)
        {
            if(origin[i]!=strlen(lastvt[i]))
            {
                sign=false;//长度有变化
                origin[i]=strlen(lastvt[i]);
            }
        }
        if(sign==true)
        {
            break;
        }
        for(int i=0;i<n;i++)
        {
            for(int j=3;;)
            {
                for(int k=0;k<n;k++)
                {
                    if(k==i)
                    {
                        continue;
                    }
                    else if(wenfa[i][j]==wenfa[k][0])
                    {
                        for(int l=0;l<strlen(lastvt[k]);l++)
                        {
                            int flag=true;//用于标识一个终结符是否已经在lastvt集中,true为不在其中的意思。
                            for(int m=0;m<strlen(lastvt[i]);m++)
                            {
                                if(lastvt[k][l]==lastvt[i][m])
                                {
                                    flag=false;
                                    break;
                                }
                            }
                            if(flag==false)
                            {
                                continue;
                            }
                            else
                            {
                                int length=strlen(lastvt[i]);
                                lastvt[i][length]=lastvt[k][l];
                            }
                        }
                    }
                }
                int flag=true;
                while(wenfa[i][j]!='|')
                {
                    if(wenfa[i][j]=='\0')
                    {
                        flag=false;
                        break;
                    }
                    j++;
                }
                if(flag==false)
                {
                    break;
                }
                j++;
            }
        }
    }
}
void gettable(int n)
{
    char data[N];//用于保存每个产生式
    for(int i=0;i<n;i++)//<
    {
        int dt=0;
        // int flag=true;
        for(int j=3;;)
        {
            if(wenfa[i][j]=='|'||wenfa[i][j]=='\0')
            {
                if(strlen(data)!=1)
                {
                    for(int k=0;k<strlen(data);k++)
                    {
                        if(data[k]<'A'||data[k]>'Z')
                        {
                            if(data[k+1]!='\0'&&data[k+1]>='A'&&data[k+1]<='Z')
                            {
                                int x;
                                int yk;
                                for(int l=0;l<strlen(VT);l++)
                                {
                                    if(data[k]==VT[l])
                                    {
                                        x=l;
                                        break;
                                    }
                                }
                                for(int l=0;l<strlen(VN);l++)
                                {
                                    if(data[k+1]==VN[l])
                                    {
                                        yk=l;
                                        break;
                                    }
                                }
                                for(int l=0;l<strlen(firstvt[yk]);l++)
                                {
                                    for(int m=0;m<strlen(VT);m++)
                                    {
                                        if(firstvt[yk][l]==VT[m])
                                        {
                                            if(table[x][m]=='\0')
                                            {
                                                table[x][m]='<';
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                if(wenfa[i][j]=='\0')
                {
                    break;
                }
                j++;
                memset(data,'\0',sizeof(data));
                dt=0;
            }
            else
            {
                data[dt]=wenfa[i][j];
                j++;
                dt++;
            }
        }
    }
    for(int i=0;i<n;i++)//>,和上面的<差不多其实
    {
        int dt=0;
        // int flag=true;
        for(int j=3;;)
        {
            if(wenfa[i][j]=='|'||wenfa[i][j]=='\0')
            {
                if(strlen(data)!=1)
                {
                    for(int k=0;k<strlen(data);k++)
                    {
                        if(data[k]<'A'||data[k]>'Z')
                        {
                            if(k>=1&&data[k-1]>='A'&&data[k-1]<='Z')
                            {
                                int y;
                                int xk;
                                for(int l=0;l<strlen(VT);l++)
                                {
                                    if(data[k]==VT[l])
                                    {
                                        y=l;
                                        break;
                                    }
                                }
                                for(int l=0;l<strlen(VN);l++)
                                {
                                    if(data[k-1]==VN[l])
                                    {
                                        xk=l;
                                        break;
                                    }
                                }
                                for(int l=0;l<strlen(lastvt[xk]);l++)
                                {
                                    for(int m=0;m<strlen(VT);m++)
                                    {
                                        if(lastvt[xk][l]==VT[m])
                                        {
                                            if(table[m][y]=='\0')
                                            {
                                                table[m][y]='>';
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                if(wenfa[i][j]=='\0')
                {
                    break;
                }
                j++;
                memset(data,'\0',sizeof(data));
                dt=0;
            }
            else
            {
                data[dt]=wenfa[i][j];
                j++;
                dt++;
            }
        }
    }
    for(int i=0;i<n;i++)//=
    {
        int dt=0;
        // int flag=true;
        for(int j=3;;)
        {
            if(wenfa[i][j]=='|'||wenfa[i][j]=='\0')
            {
                if(strlen(data)!=1)
                {
                    for(int k=0;k<strlen(data);k++)
                    {
                        if(data[k]<'A'||data[k]>'Z')
                        {
                            if(data[k+1]!='\0'&&(data[k+1]<'A'||data[k+1]>'Z'))
                            {
                                int x,y;
                                for(int l=0;l<strlen(VT);l++)
                                {
                                    if(data[k]==VT[l])
                                    {
                                        x=l;
                                    }
                                    if(data[k+1]==VT[l])
                                    {
                                        y=l;
                                    }
                                }
                                if(table[x][y]=='\0')
                                {
                                    table[x][y]='=';
                                }
                            }
                            if(data[k+2]!='\0'&&(data[k+2]<'A'||data[k+2]>'Z'))
                            {
                                int x,y;
                                for(int l=0;l<strlen(VT);l++)
                                {
                                    if(data[k]==VT[l])
                                    {
                                        x=l;
                                    }
                                    if(data[k+2]==VT[l])
                                    {
                                        y=l;
                                    }
                                }
                                if(table[x][y]=='\0')
                                {
                                    table[x][y]='=';
                                }
                            }
                        }
                    }
                }
                if(wenfa[i][j]=='\0')
                {
                    break;
                }
                j++;
                memset(data,'\0',sizeof(data));
                dt=0;
            }
            else
            {
                data[dt]=wenfa[i][j];
                j++;
                dt++;
            }
        }
    }
    int jinghao=strlen(VT);
    table[jinghao][jinghao]='=';
    for(int i=0;i<strlen(VT);i++)
    {
        for(int j=0;j<strlen(firstvt[0]);j++)
        {
            if(VT[i]==firstvt[0][j])
            {
                table[jinghao][i]='<';
                break;
            }
        }
    }
    for(int i=0;i<strlen(VT);i++)
    {
        for(int j=0;j<strlen(lastvt[0]);j++)
        {
            if(VT[i]==lastvt[0][j])
            {
                table[i][jinghao]='>';
                break;
            }
        }
    }
}
void fenxi(char *sentence)
{
    char in[N];
    in[0]='#';
    char out[N];
    for(int i=0;i<strlen(sentence);i++)
    {
        out[i]=sentence[i];
    }
    out[strlen(sentence)]='#';
    int step=0;
    int lin=1;
    int lout=strlen(sentence)+1;
    cout<<step<<'\t';
    for(int i=0;i<lin;i++)
    {
        cout<<in[i];
    }
    cout<<'\t';
    for(int i=0;i<lout;i++)
    {
        cout<<out[i];
    }
    cout<<'\t'<<"预备"<<endl;
    int flag=true;
    while(true)
    {
        int i=lin-1;
        while(in[i]=='N')
        {
            i--;
        }
        int j=0;
        int x,y;
        for(int k=0;k<strlen(VT);k++)
        {
            if(in[i]==VT[k])
            {
                x=k;
            }
            if(out[0]==VT[k])
            {
                y=k;
            }
        }
        if((in[i]>='a'&&in[i]<='z')||(in[i]>='0'&&in[i]<='9'))
        {
            for(int k=0;k<strlen(VT);k++)
            {
                if('i'==VT[k])
                {
                    x=k;
                }
            }
        }
        if((out[0]>='a'&&out[0]<='z')||(out[0]>='0'&&out[0]<='9'))
        {
            for(int k=0;k<strlen(VT);k++)
            {
                if('i'==VT[k])
                {
                    y=k;
                }
            }
        }
        if(in[i]=='#')
        {
            x=strlen(VT);
        }
        if(out[0]=='#')
        {
            y=strlen(VT);
        }
        if(x==y&&y==strlen(VT))
        {
            break;
        }
        if(table[x][y]=='<')
        {
            in[lin]=out[0];
            lin++;
            lout--;
            for(int l=0;l<lout;l++)
            {
                out[l]=out[l+1];
            }
            step++;
            cout<<step<<'\t';
            for(int l=0;l<lin;l++)
            {
                cout<<in[l];
            }
            cout<<'\t';
            for(int l=0;l<lout;l++)
            {
                cout<<out[l];
            }
            cout<<'\t'<<"移进"<<endl;
        }
        else if(table[x][y]=='=')
        {
            step++;
            cout<<step<<'\t';
            for(int l=0;l<lin;l++)
            {
                cout<<in[l];
            }
            cout<<out[0]<<'\t';
            for(int l=1;l<lout;l++)
            {
                cout<<out[l];
            }
            cout<<'\t'<<"移进"<<endl;
            in[i]='N';
            int lin1=lin;
            for(int k=i+1;k<lin1;k++)
            {
                in[k]='\0';
                lin--;
            }
            lout--;
            for(int k=0;k<lout;k++)
            {
                out[k]=out[k+1];
            }
            step++;
            cout<<step<<'\t';
            for(int l=0;l<lin;l++)
            {
                cout<<in[l];
            }
            cout<<'\t';
            if(out[0]=='#')
            {
                cout<<'#';
            }
            else
            {
                for(int l=1;l<lout;l++)
                {
                    cout<<out[l];
                }
            }
            cout<<'\t'<<"规约"<<endl;
        }
        else if(table[x][y]=='>')
        {
            while(true)
            {
                if(in[i-1]=='N')
                {
                    i--;
                }
                else
                {
                    break;
                }
            }
            in[i]='N';
            int lin1=lin;
            for(int k=i+1;k<lin1;k++)
            {
                in[k]='\0';
                lin--;
            }
            step++;
            cout<<step<<'\t';
            for(int k=0;k<lin;k++)
            {
                cout<<in[k];
            }
            cout<<'\t';
            if(out[0]=='#')
            {
                cout<<'#';
            }
            else
            {
                for(int k=0;k<lout;k++)
                {
                    cout<<out[k];
                }
            }
            cout<<'\t'<<"规约"<<endl;
        }
        else
        {
            flag=false;
            break;
        }
    }
    if(flag==true)
    {
        cout<<"恭喜你,你的句子没有问题。"<<endl;
    }
    else if(flag==false)
    {
        cout<<"算符优先分析表中没有这俩非终结符的对应关系,匹配失败。"<<endl;
    }
}
int main()
{
    cout<<"请使用英文输入法输入文法,输入#代表结束。另:此程序对文法右部无检错功能。"<<endl;
    int n;
    while(1)
    {
        int i=0;
        do
        {
            cin>>wenfa[i];
            i++;
        } while (wenfa[i-1][0]!='#');
        n=i-1;//文法数量
        // for(i=0;i<n;i++)
        // {
        //     cout<<wenfa[i]<<endl;
        // }
        if(vnvt(n)==false)
        {
            cout<<"您所输入的文法左部可能有误,请检查后再重新输入。"<<endl;
        }
        else
        {
            break;
        }
    }
    getfirstvt(n);
    getlastvt(n);
    gettable(n);
    cout<<"---------------------------------------------------"<<endl<<"非终结符有:VN={";
    for(int i=0;i<strlen(VN);i++)
    {
        cout<<VN[i];
        if(i!=strlen(VN)-1)
        {
            cout<<',';
        }
    }
    cout<<'}'<<endl<<"终结符有:VT={";
    for(int i=0;i<strlen(VT);i++)
    {
        cout<<VT[i];
        if(i!=strlen(VT)-1)
        {
            cout<<',';
        }
    }
    cout<<'}'<<endl<<"---------------------------------------------------"<<endl;
    for(int i=0;i<strlen(VN);i++)
    {
        cout<<"FIRSTVT("<<VN[i]<<")={";
        for(int j=0;j<strlen(firstvt[i]);j++)
        {
            cout<<firstvt[i][j];
            if(j!=strlen(firstvt[i])-1)
            {
                cout<<',';
            }
        }
        cout<<'}'<<endl;
    }
    cout<<endl;
    for(int i=0;i<strlen(VN);i++)
    {
        cout<<"LASTVT("<<VN[i]<<")={";
        for(int j=0;j<strlen(lastvt[i]);j++)
        {
            cout<<lastvt[i][j];
            if(j!=strlen(lastvt[i])-1)
            {
                cout<<',';
            }
        }
        cout<<'}'<<endl;
    }
    cout<<"---------------------------------------------------"<<endl<<"算符优先分析表如下:"<<endl<<'\t';
    for(int i=0;i<strlen(VT);i++)
    {
        cout<<VT[i]<<'\t';
    }
    cout<<'#'<<endl;
    for(int i=0;i<strlen(VT)+1;i++)
    {
        if(i==strlen(VT))
        {
            cout<<'#'<<'\t';
        }
        else
        {
            cout<<VT[i]<<'\t';
        }
        
        for(int j=0;j<strlen(VT)+1;j++)
        {
            cout<<table[i][j]<<'\t';
        }
        cout<<endl;
    }
    char sentence[N];
    while(true)
    {
        cout<<"请输入你要识别的句子,若输入#则代表没有需要识别的句子了:"<<endl;
        cin>>sentence;
        if(sentence[0]=='#')
        {
            break;
        }
        cout<<"步骤"<<'\t'<<"栈"<<'\t'<<"输入串"<<'\t'<<"动作"<<endl;
        fenxi(sentence);
    }
    system("pause");
    return 0;
}

运行结果如下:

在这里插入图片描述

输入几个例子的结果如下:

说明一下,我的代码把所有数字和小写字母都看作了i。

eg1:1+2
在这里插入图片描述

eg2:(1+2)/3+4-(5+6/7) (其实就是我举的例子,我为了简单全部换成了i)

在这里插入图片描述

eg3:((1-2)/3+4 (错误的例子)

在这里插入图片描述

最后只要输入#结束运行就行了。

好了,拜拜,祝大家生活愉快。

有什么错误的地方欢迎评论区指正。

  • 80
    点赞
  • 368
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论
算符优先分析法是一种自下而上的语法分析方法,它可以用于分析和处理算术达式、布尔达式等。下面是算符优先分析法的实现步骤: 1. 定义终结符和非终结符:终结符是指不能再分解的基本符号,如数字、运算符等;非终结符是指可以分解成其他符号的符号,如达式、语句等。 2. 定义运算符之间的优先关系和结合性质:将运算符按照优先级从高到低排列,相同优先级的运算符再按照结合性质(左结合或右结合)进行排列。 3. 构造算符优先关系:根据定义的运算符优先关系和结合性质,构造算符优先关系中的行和列分别示两个相邻的运算符,中的元素示它们之间的优先关系(“<”示优先级低,“>”示优先级高,“=”示优先级相等)。 4. 进行语法分析:将输入的达式转换成一个个终结符和非终结符的序列,然后根据算符优先关系进行分析。具体地,从左到右扫描输入序列,将扫描到的符号压入栈中,同时比较栈顶符号和下一个输入符号之间的优先关系,如果栈顶符号的优先级低于或等于下一个输入符号的优先级,则将下一个输入符号压入栈中;否则,从栈中弹出一个或多个符号进行归约,直到栈顶符号的优先级低于或等于下一个输入符号的优先级。 5. 进行达式求值:在进行归约时,如果遇到两个相邻的终结符之间有一个运算符,则可以对它们进行求值,并将结果压入栈中。最终,栈中只剩下一个值,即为达式的值。 下面是一个简单的算符优先分析法的实现例子,用于分析和处理四则运算达式: ```python # 定义终结符和非终结符 terminals = ['+', '-', '*', '/', '(', ')', 'num'] non_terminals = ['E', 'T', 'F'] # 定义运算符之间的优先关系和结合性质 precedence = { '+': {'+': '>', '-': '>', '*': '<', '/': '<', '(': '<', ')': '>', 'num': '<'}, '-': {'+': '>', '-': '>', '*': '<', '/': '<', '(': '<', ')': '>', 'num': '<'}, '*': {'+': '>', '-': '>', '*': '>', '/': '>', '(': '<', ')': '>', 'num': '<'}, '/': {'+': '>', '-': '>', '*': '>', '/': '>', '(': '<', ')': '>', 'num': '<'}, '(': {'+': '<', '-': '<', '*': '<', '/': '<', '(': '<', ')': '=', 'num': '<'}, ')': {'+': '>', '-': '>', '*': '>', '/': '>', '(': ' ', ')': '>', 'num': ' '}, 'num': {'+': '>', '-': '>', '*': '>', '/': '>', '(': ' ', ')': '>', 'num': ' '} } # 构造算符优先关系 table = {} for i in range(len(terminals)): table[terminals[i]] = {} for j in range(len(terminals)): table[terminals[i]][terminals[j]] = precedence[terminals[i]][terminals[j]] # 进行语法分析 def parse(expr): stack = ['#'] tokens = expr.split() for token in tokens: while table[stack[-1]][token] == '>': op = stack.pop() if op in ['+', '-', '*', '/']: b = stack.pop() a = stack.pop() stack.append(str(eval(a + op + b))) else: stack.pop() if table[stack[-1]][token] == '<' or table[stack[-1]][token] == '=': stack.append(token) else: raise ValueError('Invalid expression') while stack[-1] != '#': op = stack.pop() if op in ['+', '-', '*', '/']: b = stack.pop() a = stack.pop() stack.append(str(eval(a + op + b))) else: raise ValueError('Invalid expression') return stack[0] # 进行达式求值 expr = '3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3' result = parse(expr) print(result) # 输出:3.0001220703125 ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

俊夫小瞳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值