【C++】手动编写语法分析器(LR分析表)

已知文法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;
} 
  • 测试
    在这里插入图片描述
发布了55 篇原创文章 · 获赞 30 · 访问量 9827

猜你喜欢

转载自blog.csdn.net/chaifang0620/article/details/103501511
今日推荐