已知文法G[E]:
E → E + T | T
T → (E) | id | id[E]
设计LR分析表,使用用C++编写语法分析器。
需要构造LR分析表,因此首先写出DFA:
根据DFA,可以看出如果使用LR(0),会产生冲突
,使用SLR(1).
构造SLR(1)分析表:
- 增广文法
0:S → E
1:E → E + T
2:E → T
3:T → (E)
4:T → id
5:T → id[E]
-
DFA
图画得好丑,将就看一下
由图所知,使用LR(0)将会有冲突,求出冲突的FOLLOW集,没有交集,所以可以使用SLR(0)。 -
SLR(1)分析表
0
:表示error,使用16
代表acc
状态 | id | + | ( | ) | [ | ] | # | T | E |
---|---|---|---|---|---|---|---|---|---|
0 | S4 | 0 | S3 | 0 | 0 | 0 | 0 | 2 | 1 |
1 | 0 | S5 | 0 | 0 | 0 | 0 | acc | 0 | 0 |
2 | 0 | R2 | 0 | R2 | 0 | R2 | R2 | 0 | 0 |
3 | S4 | 0 | S3 | 0 | 0 | 0 | 0 | 2 | 6 |
4 | 0 | R4 | 0 | R4 | S7 | R4 | R4 | 0 | 0 |
5 | S4 | 0 | S3 | 0 | 0 | 0 | 0 | 8 | 0 |
6 | 0 | S5 | 0 | S9 | 0 | 0 | 0 | 0 | 0 |
7 | S4 | 0 | S3 | 0 | 0 | 0 | 0 | 2 | 10 |
8 | 0 | R1 | 0 | R1 | 0 | R1 | R1 | 0 | 0 |
9 | S8 | R3 | 0 | R3 | 0 | R3 | R3 | 0 | 0 |
10 | 0 | S5 | 0 | 0 | 0 | S11 | 0 | 0 | 0 |
11 | 0 | R5 | 0 | R5 | 0 | R5 | R5 | 0 | 0 |
- 源代码
#include<iostream>
#include<cstring>
#include<stack>
#include<regex>
using namespace std;
string terminal="@+()[]#";
string nonterminal="TE";
int action[12][7]={ //负数表示规约,正数表示移入,0表示error,16代表acc
4,0,3,0,0,0,0,
0,5,0,0,0,0,16,
0,-2,0,-2,0,-2,-2,
4,0,3,0,0,0,0,
0,-4,0,-4,7,-4,-4,
4,0,3,0,0,0,0,
0,5,0,9,0,0,0,
4,0,3,0,0,0,0,
0,-1,0,-1,0,-1,-1,
8,-3,0,-3,0,-3,-3,
0,5,0,0,0,11,0,
0,-5,0,-5,0,-5,-5};
int go[12][2]={ //goto状态
2,1,
0,0,
0,0,
2,6,
0,0,
8,0,
0,0,
2,10,
0,0,
0,0,
0,0,
0,0,
};
int move(char c,int status) { //action表
int index=terminal.find_first_of(c);
return action[status][index];
}
int reduction(char c,int status) { //goto表
int index=nonterminal.find_first_of(c);
return go[status][index];
}
bool parser(string s) {
int status=0,temp=1,i=0;
stack<int> ss;
stack<char> symbol;
ss.push(status);
char word=s[i];
while(1) {
status=ss.top();
temp=move(word,status);
if(temp==16) {
return true;
}
else if(temp>0) { //移入
ss.push(temp);
symbol.push(word);
word=s[++i];
}
else if(temp<0) { //规约
switch(-temp) {
case 1:
printf("E->E+T.\n");
ss.pop();
ss.pop();
ss.pop();
symbol.pop();
symbol.pop();
symbol.pop();
symbol.push('E');
break;
case 2:
printf("E->T.\n");
ss.pop();
symbol.pop();
symbol.push('E');
break;
case 3:
printf("T->(E).\n");
ss.pop();
ss.pop();
ss.pop();
symbol.pop();
symbol.pop();
symbol.pop();
symbol.push('T');
break;
case 4:
printf("T->id.\n");
ss.pop();
symbol.pop();
symbol.push('T');
break;
case 5:
printf("T->id[E].\n");
ss.pop();
ss.pop();
ss.pop();
ss.pop();
symbol.pop();
symbol.pop();
symbol.pop();
symbol.pop();
symbol.push('T');
break;
default://Error
return false;
}
int r=reduction(symbol.top(), ss.top());
if(r!=0) {
ss.push(r);
} else {
return false;
}
}
else {
return false;
}
}
return false;
}
int main() {
string ss;
regex rule("[a-z][1-9]"); //变量匹配的正则表达式,做得比较单一
// cout<<"输入句子:"<<endl;
while(1) {
getline(cin, ss);
ss=regex_replace(ss,rule,"@"); //变量统一命名
ss.append("#");
size_t n=0;
for(size_t i=0;ss[i];i++) { //去掉空格
if(ss[i]!=' ') {
ss[n++]=ss[i];
}
}
ss=ss.substr(0,n); //去掉字符串后面多余的
bool isparser=parser(ss);
if(isparser)
cout<<"Syntax analysis is right"<<endl;
else
cout<<"Error on syntax analysis"<<endl;
}
return 0;
}
- 测试