SLR(1)方法的出現,解決了大部分的移進和規約沖突、規約和規約的沖突。並且SLR(1)其優點是狀態數目少,造表算法簡單,大多數程序設計語言基本上都可用SLR(1)文法來描述。
但是仍然有一些文法,不能用SLR(1)解決。
例如:
S->BB;
B->aB;
B->b;
該文法我們可以看到,在S->BB中,第一個B和第二個B的follow集是不同的。為了解決這個問題,於是誕生了LR(1)分析方法。
解決辦法是在每個項目集的產生式后加上follow集。比如:
S-> ·BB, #
B-> · aB, a/b
B-> · b ,a/b
這樣就是是同一個非終結符,但是仍舊可以根據不同狀態集內的產生式的follow集進行不沖突的規約和移進。
目前LR(1)分析法仍舊是應用非常廣泛,是當前最一般的分析方法,幾乎所有的上下文無關文法描述的程序設計語言都可以通過LR(1)分析法分析。
為了解決LR(1)分析法狀態過多的問題,於是提出了LALR(1)分析法,將“心”相同的狀態合並,從而減少狀態數。
具體例子如下:
文法G[E]
(0)S’->S
(1)S->BB
(2)B->Ab
(3)B->b
1、構造項目集
2、構造LR(分析表)
狀態 |
a |
b |
# |
S |
B |
0 |
S3 |
S4 |
|
1 |
2 |
1 |
|
|
Acc |
|
|
2 |
S6 |
S7 |
|
|
5 |
3 |
S3 |
S4 |
|
|
8 |
4 |
R3 |
R3 |
|
|
|
5 |
|
|
R1 |
|
|
6 |
S6 |
S7 |
|
|
9 |
7 |
|
|
R3 |
|
|
8 |
R2 |
R2 |
|
|
|
9 |
|
|
R2 |
|
|
3、編程
1 #include<bits/stdc++.h> 2 #define ROW 11 3 #define COLUMN 6 4 using namespace std; 5 //產生式 6 string products[4][2]={ 7 {"S'","S"}, 8 {"S","BB"}, 9 {"B","aB"}, 10 {"B","b"} 11 }; 12 //分析表 13 string actiontable[ROW][COLUMN]={ 14 {"","a","b","#","S","B"}, 15 {"0","s3","s4","","1","2"}, 16 {"1","","","acc","",""}, 17 {"2","s6","s7","","","5"}, 18 {"3","s3","s4","","","8"}, 19 {"4","r3","r3","","",""}, 20 {"5","","","r1","",""}, 21 {"6","s6","s7","","","9"}, 22 {"7","","","r3","",""}, 23 {"8","r2","r2","","",""}, 24 {"9","","","r2","",""} 25 }; 26 stack<int> sstatus; //狀態棧 27 stack<char> schar; //符號棧 28 struct Node{ 29 char type; 30 int num; 31 }; 32 //打印步驟 33 void print_step(int times){ 34 stack<char> tmp2; 35 cout<<times<<setw(4); 36 while(!schar.empty()){ 37 char t=schar.top(); 38 schar.pop(); 39 tmp2.push(t); 40 cout<<t; 41 } 42 while(!tmp2.empty()){ 43 int t=tmp2.top(); 44 tmp2.pop(); 45 schar.push(t); 46 } 47 } 48 //查表 49 Node Action_Goto_Table(int status,char a){ 50 int row=status+1; 51 string tmp; 52 for(int j=1;j<COLUMN;j++){ 53 if(a==actiontable[0][j][0]){ 54 tmp=actiontable[row][j]; 55 } 56 } 57 Node ans; 58 if(tmp[0]>='0'&&tmp[0]<='9'){ 59 int val=0; 60 for(int i=0;i<tmp.length();i++){ 61 val=val*10+(tmp[i]-'0'); 62 } 63 ans.num=val; 64 ans.type=' '; 65 }else if(tmp[0]=='s'){ 66 int val=0; 67 for(int i=1;i<tmp.length();i++){ 68 val=val*10+(tmp[i]-'0'); 69 } 70 ans.type='s'; 71 ans.num=val; 72 }else if(tmp[0]=='r'){ 73 int val=0; 74 for(int i=1;i<tmp.length();i++){ 75 val=val*10+(tmp[i]-'0'); 76 } 77 ans.type='r'; 78 ans.num=val; 79 }else if(tmp[0]=='a'){ 80 ans.type='a'; 81 }else{ 82 ans.type=' '; 83 } 84 return ans; 85 } 86 //LR(1)分析法 87 bool LR1(string input){ 88 while(!sstatus.empty()){ 89 sstatus.pop(); 90 } 91 while(!schar.empty()){ 92 schar.pop(); 93 } 94 int times=0; 95 bool flag=true; 96 int st=0; 97 sstatus.push(st); 98 schar.push('#'); 99 int i=0; 100 char a=input[i]; 101 while(true){ 102 Node action=Action_Goto_Table(st,a); 103 if(action.type=='s'){ 104 st=action.num; 105 sstatus.push(st); 106 schar.push(a); 107 a=input[++i]; 108 print_step(++times); 109 cout<<setw(10)<<'s'<<st<<endl; 110 111 }else if(action.type=='r'){ 112 int n=action.num; 113 string ls=products[n][0]; 114 string rs=products[n][1]; 115 for(int j=0;j<rs.length();j++){ 116 sstatus.pop(); 117 schar.pop(); 118 } 119 schar.push(ls[0]); 120 st=sstatus.top(); 121 action =Action_Goto_Table(st,ls[0]); 122 st=action.num; 123 sstatus.push(st); 124 print_step(++times); 125 cout<<setw(10)<<'r'<<" "<<ls<<"->"<<rs<<endl; 126 127 }else if(action.type=='a'){ 128 flag=true; 129 break; 130 }else{ 131 flag=false; 132 break; 133 } 134 } 135 return flag; 136 } 137 int main(){ 138 string input; 139 while(cin>>input){ 140 if(LR1(input)){ 141 cout<<"syntax correct"<<endl; 142 }else{ 143 cout<<"syntax error"<<endl; 144 } 145 } 146 return 0; 147 }