一、題目
對下列文法,用SLR(1)分析法對任意輸入的符號串進行分析:
(1)S->E
(2)E->E+T
(3)E->T
(4)T->T*F
(5)T->F
(6)F->(E)
(7)F->i
二、設計思路
(1)總控程序,也可以稱為驅動程序。對所有的LR分析器總控程序都是相同的。
(2)分析表或分析函數,不同的文法分析表將不同,同一個文法采用的LR分析器不同時,分析表將不同,分析表又可以分為動作表(ACTION)和狀態轉換(GOTO)表兩個部分,它們都可用二維數組表示。
(3)分析棧,包括文法符號棧和相應的狀態棧,它們均是先進后出棧。
分析器的動作就是由棧頂狀態和當前輸入符號所決定。
LR分析器由三個部分組成:
其中:SP為棧指針,S[i]為狀態棧,X[i]為文法符號棧。狀態轉換表用GOTO[i,X]=j表示,規定當棧頂狀態為i,遇到當前文法符號為X時應轉向狀態j,X為終結符或非終結符。
ACTION[i,a]規定了棧頂狀態為i時遇到輸入符號a應執行。動作有四種可能:
(1)移進:
action[i,a]= Sj:狀態j移入到狀態棧,把a移入到文法符號棧,其中i,j表示狀態號。
(2)歸約:
action[i,a]=rk:當在棧頂形成句柄時,則歸約為相應的非終結符A,即文法中有A- B的產生式,若B的長度為R(即|B|=R),則從狀態棧和文法符號棧中自頂向下去掉R個符號,即棧指針SP減去R,並把A移入文法符號棧內,j=GOTO[i,A]移進狀態棧,其中i為修改指針后的棧頂狀態。
(3)接受acc:
當歸約到文法符號棧中只剩文法的開始符號S時,並且輸入符號串已結束即當前輸入符是'#',則為分析成功。
(4)報錯:
當遇到狀態棧頂為某一狀態下出現不該遇到的文法符號時,則報錯,說明輸入端不是該文法能接受的符號串。
三、源代碼

#include<bits/stdc++.h> using namespace std; char vt[6] = { 'i', '+', '*', '(', ')', '#' }; //終結符 char vn[3] = { 'E', 'T', 'F' }; //非終結符 //文法 string wf[7] = { "S->E", "E->E+T", "E->T", "T->T*F", "T->F", "F->(E)", "F->i" }; //action表 string action[12][6] = { "s5", "^", "^", "s4", "^", "^", "^", "s6", "^", "^", "^", "acc", "^", "r2", "s7", "^", "r2", "r2", "^", "r4", "r4", "^", "r4", "r4", "s5", "^", "^", "s4", "^", "^", "^", "r6", "r6", "^", "r6", "r6", "s5", "^", "^", "s4", "^", "^", "s5", "^", "^", "s4", "^", "^", "^", "s6", "^", "^", "s11", "^", "^", "r1", "s7", "^", "r1", "r1", "^", "r3", "r3", "^", "r3", "r3", "^", "r5", "r5", "^", "r5", "r5" }; //goto表 int goto_[12][3] = { 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 2, 3, 0, 0, 0, 0, 9, 3, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //當前狀態 string nowcout="0"; //輸入串的游標 int com = 0; int num = 1; int t=0; //輸入串 string input = ""; stack <char> symbols;//創建一個符號棧 stack <int> status;//創建一個狀態棧 void show(string statuA,int statuG); void init() { cout<<"輸入的文法"<<endl; for (int j = 0; j < 6; j++) { cout << wf[j] << endl; } cout << "VT:"; for (int i = 0; i < 6; i++) { cout << vt[i] << "\t"; } cout << endl<< "VN:"; for (int i = 0; i <3; i++) { cout << vn[i] << "\t"; } cout << endl; symbols.push('#'); status.push(0); } //獲取非終結符所在下標 int getVtNowIndex(char now) { for(int i=0;i<6;i++) { if(now==vt[i]) { return i; } } return -1; } //獲取終結符所在下標 int getVnNowIndex(char now) { for(int i=0;i<3;i++) { if(now==vn[i]) { return i; } } return -1; } //輸出棧中元素但是不破壞棧的結構 int showStack(stack<int >&s){ stack <int> temp; int num=s.size(); for(int i=0;i<num;i++) { temp.push(s.top()); s.pop(); } for(int i=0;i<num;i++) { cout<<temp.top(); s.push(temp.top()); temp.pop(); } } //輸出棧中元素但是不破壞棧的結構 char showStack(stack<char >&s){ stack <char> temp; int num=s.size(); for(int i=0;i<num;i++) { temp.push(s.top()); s.pop(); } for(int i=0;i<num;i++) { cout<<temp.top(); s.push(temp.top()); temp.pop(); } } //格式化輸出 void show(string statuA,int statuG) { showStack(status); cout<<"\t"; showStack(symbols); cout<<"\t"; cout<<input.substr(com); cout<<"\t\t"<<nowcout<<"\t"<<statuG<<endl; } //移進 void yj(int statu,char symbol) { symbols.push(symbol); status.push(statu); string statuA = "s"+statu; show(statuA,0); com++; } //規約 void gy(int index) { int n = wf[index].length()-3; for(int i=0;i<n;i++) { symbols.pop(); status.pop(); } symbols.push(wf[index][0]); int indexj = getVnNowIndex(wf[index][0]); int indexi = status.top(); status.push(goto_[indexi][indexj]); string statuA = "r"+index; show(statuA,goto_[indexi][indexj]); } //分析 void analysis(string s) { while(com<input.size()) { int i = status.top(); char ch = s[com]; t=getVtNowIndex(ch); nowcout=action[i][t]; if (action[i][t][0] == 's') { int t1 = action[i][t][1]-'0'; yj(t1, ch); } else if (action[i][t][0] == 'r') { gy(action[i][t][1]-'0'); } else if (action[i][t] == "^") { cout << "\tError" << endl; break; } else if (action[i][t] == "acc") { show("",0); //cout << "acc" << "\t 分析成功" << endl; break; } } } int main() { init(); cout<<"輸入的文法:"<<endl; cin>>input; cout<<"狀態棧\t符號棧\t輸入串\t\tACTION\tGOTO\n"; show("0",0); analysis(input); return 0; }
四、運行結果