算符優(yōu)先分析算法的設(shè)計與實現(xiàn)
寫在最前面:我的編譯原理學(xué)的不是很好,不怎么聽課,所以我寫代碼的思路比較簡單。簡單的思路也就意味著代碼很笨重,介意的話請點叉叉。如果有什么指教歡迎評論區(qū)留言。
特別說明:本博代碼在識別:
E→E+T
E→E-T
E→T
時,firstvt集和lastvt集可能會出現(xiàn)錯誤。
最好合并為以下形式:
E→E+T|E-T|T
一、實驗?zāi)康?/strong>
1.根據(jù)算符優(yōu)先分析法,對表達式進行語法分析,使其能夠判斷一個表達式是否正確。
2.通過算符優(yōu)先分析方法的實現(xiàn),加深對自下而上語法分析方法的理解。
二、 實驗內(nèi)容
1.輸入文法??梢允侨缦滤阈g(shù)表達式的文法(你可以根據(jù)需要適當改變):
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.根據(jù)文法求FIRSTVT集和LASTVT集
給定一個上下文無關(guān)文法,根據(jù)算法設(shè)計一個程序,求文法中每個非終結(jié)符的FirstVT 集和LastVT 集。
找Firstvt的三條規(guī)則:
如果要找A的Firstvt, A的候選式中出現(xiàn):
A->a…,即以終結(jié)符開頭,a入 Firstvt
A->B…,即以非終結(jié)符開頭,B的Firstvt入A的Firstvt
A->Ba…,即先以非終結(jié)符開頭,緊跟終結(jié)符,則a入Firstvt
找Lastvt的三條規(guī)則:
如果要找A的Lastvt, A的候選式中出現(xiàn):
A->…a,即以終結(jié)符結(jié)尾,a入Lastvt
A->…B,即以非終結(jié)符結(jié)尾,B的Lastvt入A的Lastvt
A->…aB,即先以非終結(jié)符結(jié)尾,前面是終結(jié)符,則a入Lastvt
根據(jù)上述求firstvt和lastvt的方法,我們計算一下我給的例子,得到的最終結(jié)果如下。
4.構(gòu)造算符優(yōu)先分析表
我先概述一下構(gòu)造方法:
在右邊的產(chǎn)生式中,找每個終結(jié)符。
- 如果就單一個終結(jié)符,那么忽略不看。
- 先找出…aB…這種形式,這代表a<firstvt(B)。
在算符優(yōu)先分析表的左邊一列中找到a,然后向右在對應(yīng)的每個firstvt(B)的元素的位置上標上<。 - 再找…Ba…這種形式,這代表a>lastvt(B)。
在算符優(yōu)先分析表的上面一行中找到a,然后向下在對應(yīng)的每個lastvt(B)的元素的位置上標上>。 - 如果有…ab…或…aCb…這兩種情況,則在a行b列的位置上標上=。
下面我來結(jié)合例子講一下:
首先構(gòu)造好表:
+ | - | * | / | ( | ) | i | # | |
---|---|---|---|---|---|---|---|---|
+ | ||||||||
- | ||||||||
* | ||||||||
/ | ||||||||
( | ||||||||
) | ||||||||
i | ||||||||
# |
然后我們先看文法的第一行:
E->E+T|E-T|T
第一個終結(jié)符為+。
其實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只是一個終結(jié)符,不存在大小關(guān)系,不看它。
而(E)就是
( < firstvt(E);
) > lastvt(E)。
并且(E)滿足…aBc…的情況,要在第(行,第)列的位置((,))上標上=。
可得下表:
+ | - | * | / | ( | ) | i | # | |
---|---|---|---|---|---|---|---|---|
+ | > | > | < | < | < | > | < | |
- | > | > | < | < | < | > | < | |
* | > | > | > | > | < | > | < | |
/ | > | > | > | > | < | > | < | |
( | < | < | < | < | < | = | < | |
) | > | > | > | > | > | |||
i | > | > | > | > | > | |||
# |
最后的最后,如果要考慮#。
我們按照#E#的樣子考慮。
即:
# < firstvt(E);
# > lastvt(E)。
并且#E#滿足…aBc…的情況,要在第#行,第#列的位置(#,#)上標上=。
可得最終表:
+ | - | * | / | ( | ) | i | # | |
---|---|---|---|---|---|---|---|---|
+ | > | > | < | < | < | > | < | > |
- | > | > | < | < | < | > | < | > |
* | > | > | > | > | < | > | < | > |
/ | > | > | > | > | < | > | < | > |
( | < | < | < | < | < | = | < | |
) | > | > | > | > | > | > | ||
i | > | > | > | > | > | > | ||
# | < | < | < | < | < | < | = |
這就是我們要求的算符優(yōu)先分析表了。
5.對給定的表達式,給出準確與否的分析過程,給出表達式的計算結(jié)果。
在規(guī)約的時候我們其實可以直接看文法就行了(如果文法比較簡單的話),但我還是講一下如何根據(jù)算符優(yōu)先分析表來進行規(guī)約。
一句話:棧的最右邊的終結(jié)符,和輸入串的最左邊的終結(jié)符,在表中查出對應(yīng)位置為<,>還是=。<則移進,>則規(guī)約,=則先移進再規(guī)約。若表中對應(yīng)位置是空格,則表示該表達式是錯誤的。
舉個例子:#(i+i)/i+i-(i+i/i)#
步驟 | 棧 | 輸入串 | 動作 |
---|---|---|---|
0 | # | (i+i)/i+i-(i+i/i)# | 預(yù)備 |
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,+)=>,規(guī)約(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,))=>,規(guī)約 |
7 | #(N | )/i+i-(i+i/i)# | (+,))=>,規(guī)約 |
8 | #(N) | /i+i-(i+i/i)# | ((,))==,先移進 |
9 | #N | /i+i-(i+i/i)# | 后規(guī)約 |
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;//用于指向每一個產(chǎn)生式的前兩個符號
for(int i=0;i<n;i++)//首先是找到每個產(chǎn)生式的前兩個符號是否是終結(jié)符,是就加入到對應(yīng)的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集中是否已經(jīng)存在該終結(jié)符。
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;
}
}
}
//下面的代碼是循環(huán)查看哪些非終結(jié)符的firstvt集可以加入到另一些非終結(jié)符的firstvt集中,一直循環(huán)添加,直到每個非終結(jié)符的長度不再變化為止。
int *origin=new int[n];//用于記錄遍歷之前的數(shù)組長度,看是否有變化。
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;//用于標識一個終結(jié)符是否已經(jīng)在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集,此函數(shù)下標我是從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++;//這里設(shè)置一個b++是因為wenfa[a][b]=='|',這樣的話前面的while循環(huán)無法進行前進下標掃描,所以在這先把下標跳一個。
}
}
//下面的代碼和getfirstvt的后半段代碼一模一樣,只是把所有的firstvt改成lastvt就行了。
int *origin=new int[n];//用于記錄遍歷之前的數(shù)組長度,看是否有變化。
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;//用于標識一個終結(jié)符是否已經(jīng)在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];//用于保存每個產(chǎ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'<<"預(yù)備"<<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'<<"規(guī)約"<<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'<<"規(guī)約"<<endl;
}
else
{
flag=false;
break;
}
}
if(flag==true)
{
cout<<"恭喜你,你的句子沒有問題。"<<endl;
}
else if(flag==false)
{
cout<<"算符優(yōu)先分析表中沒有這倆非終結(jié)符的對應(yīng)關(guān)系,匹配失敗。"<<endl;
}
}
int main()
{
cout<<"請使用英文輸入法輸入文法,輸入#代表結(jié)束。另:此程序?qū)ξ姆ㄓ也繜o檢錯功能。"<<endl;
int n;
while(1)
{
int i=0;
do
{
cin>>wenfa[i];
i++;
} while (wenfa[i-1][0]!='#');
n=i-1;//文法數(shù)量
// 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<<"非終結(jié)符有:VN={";
for(int i=0;i<strlen(VN);i++)
{
cout<<VN[i];
if(i!=strlen(VN)-1)
{
cout<<',';
}
}
cout<<'}'<<endl<<"終結(jié)符有: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<<"算符優(yōu)先分析表如下:"<<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;
}
運行結(jié)果如下:
輸入幾個例子的結(jié)果如下:
說明一下,我的代碼把所有數(shù)字和小寫字母都看作了i。
eg1:1+2
eg2:(1+2)/3+4-(5+6/7) (其實就是我舉的例子,我為了簡單全部換成了i)
eg3:((1-2)/3+4 (錯誤的例子)
最后只要輸入#結(jié)束運行就行了。
好了,拜拜,祝大家生活愉快。文章來源:http://www.zghlxwxcb.cn/news/detail-495986.html
有什么錯誤的地方歡迎評論區(qū)指正。文章來源地址http://www.zghlxwxcb.cn/news/detail-495986.html
到了這里,關(guān)于編譯原理:算符優(yōu)先分析算法的設(shè)計與實現(xiàn)(含代碼)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!