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 }