zoukankan      html  css  js  c++  java
  • LR分析-demo2

    0.LR分析

    用一个栈来保存文法符号和状态的信息,一个字符串保存输入信息。

    使用栈顶的状态符号和当前的输入符号来检索分析表,来决定移进-归约分析的动作。

    1.样例文法

    "E>E+T",
    "E>T",
    "T>T*F",
    "T>F",
    "F>(E)",
    "F>id",
    

    2.分析表(未全部列出)

    3.code

    //LR分析-demo2
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<string>
    #include<stack>
    #include<map>
    using namespace std;
    
    stack<string>stk, tmp, com;		//stk是存入s0x1,即状态和符号的栈,tmp是用来输出的栈,
    								//com是在归约时确定归约式子的栈(防止错误弹出元素)
    string input;			//输入串
    string slr[15][15];		//slr表
    string action[] = {		//slr表横轴动作+转换
    	"id","+","*","(",")","$","E","T","F"
    };
    //i就是id
    string handle[] = {   //文法
    	" ",
    	"E>E+T",
    	"E>T",
    	"T>T*F",
    	"T>F",
    	"F>(E)",
    	"F>id",
    };
    map<string, int> act, status;		//转移表
    map<string, int>::iterator it_act, it_trans;
    string transfer[] = {
    	"E","T","F"
    };
    bool flag = false;		//accept状态
    int now = 0;			//当前扫描字符位置
    int handle_index = 0;	//选中的规约式序号
    void init() {			//初始化,
    	int i = 0;
    	for (i = 0; i < 9;i++) {
    		act.insert(make_pair(action[i], i));	//建立分析表
    	}
    	int j = 0;
    	while (j<12) {
    		int i = j;
    		string t;
    		if (i < 10)
    			t = '0' + i;
    		else {
    			t = ('0' + (i / 10));
    			t += ('0' + i % 10);
    		}
    			status.insert(make_pair(t, j));		//将状态和数字对应
    		j++;
    	}
    	slr[0][0] = slr[4][0] = slr[6][0] = slr[7][0] = "s5";		//保存slr表
    	slr[1][1] = slr[8][1] = "s6";
    	slr[2][1] = slr[2][4] = slr[2][5] = "r2";
    	slr[2][2] = slr[9][2] ="s7";
    	slr[0][3] = slr[6][3] = slr[4][3] = slr[7][3] = "s4";
    	slr[1][5] = "acc";
    	slr[3][1] = slr[3][2] = slr[3][4] = slr[3][5] = "r4";
    	slr[5][1] = slr[5][2] = slr[5][4] = slr[5][5] = "r6";
    	slr[9][1] = slr[9][4] = slr[9][5] = "r1";
    	slr[8][4] = "s11";
    	slr[10][1] = slr[10][2] = slr[10][4] = slr[10][5] = "r3";
    	slr[11][1] = slr[11][2] = slr[11][4] = slr[11][5] = "r5";
    	slr[0][6] = "1";
    	slr[0][7] = slr[4][7] = "2";
    	slr[0][8] = slr[4][8] = slr[6][8] = "3";
    	slr[4][6] = "8";
    	slr[6][7] = "9";
    	slr[7][8] = "10";
    }
    void show() {				
    	int count_two_char = 0;		//数栈中超过两个字符的元素
    	while (!stk.empty()) {		//用两个栈来回倒,输出字符
    		tmp.push(stk.top());
    		stk.pop();
    	}
    	while (!tmp.empty()) {
    		cout << tmp.top();
    		if (tmp.top().size()>1)
    			count_two_char++;
    		stk.push(tmp.top());
    		tmp.pop();
    	}
    	cout.setf(ios::right);
    	cout.width(11 - stk.size()- count_two_char);
    	cout << "|";
    }
    
    
    //参数1是状态,参数2是符号,符号包括终结符和非终结符,作用是找到slr表中项目
    string slrFind(string stat,string ActionAndTransfer) {		
    	string s = stat, a = ActionAndTransfer;				
    	//cout << s + " " + a << endl;
    	int t1 = status[s];	//取出状态对应下标
    	int t2 = act[a];	//取出符号对应下标
    	string tmp;
    	if (slr[t1][t2] != "") //如果slr表中存在此项
    		tmp = slr[t1][t2];	
    	else
    		tmp = "";
    	//cout << tmp << endl;
    	return tmp;			//返回slr表中的项目
    }
    
    //参数1和2同slrFind函数,index是选中的规约式子序号
    bool judge(string stat, string Transfer,int &index) {		
    	string judg = slrFind(stat, Transfer);		//得到slr表中项目
    	if (judg[0] != 'r')							//如果这个项不是r开头,就不是归约
    		return false;							//非归约直接返回
    	int i = judg[1] - '0';						//如果是归约,得到归约式子序号
    	index = i;
    	return true;								//可以发起归约
    }
    
    
    void analysis(string s) {				
    	string w = s;
    	//cout.setf(ios::right);	//设置字符对其方式
    	//cout.width(10);			//设置字符宽度
    	printf("----------|----------|----------
    ");
    	printf("    栈    |   输入   |    动作  
    ");
    	printf("----------|----------|----------
    ");
    	while (!flag) {						//处于非接受状态
    		now = 0;						//正在处理的输入串中的字符
    		if (stk.empty()) {	//一开始栈为空,直接移进符号
    			stk.push("0");
    			cout << "0         |";
    			cout.setf(ios::right);	//设置字符对其方式
    			cout.width(10);			//设置字符宽度
    			cout << w;
    			cout << "|移进" << endl;
    			printf("----------|----------|----------
    ");
    			string t1, t2;
    			t1 = stk.top();
    			if (w[now] == 'i') {	//移进符号为id
    				t2 = "id";
    				now = 2;
    			}
    			else {					//移进符号不为id
    				t2 = w[now];
    				now = 1;
    			}
    			stk.push(t2);						//将符号压入栈
    			w = w.substr(now, w.size() - now);	//丢弃已扫描的字符	
    			string lr = slrFind(t1, t2);		//找到对应的动作
    			if (lr[0] == 's')					//此时是移进
    				lr = lr.substr(1, lr.size() - 1);
    				stk.push(lr);
    			continue;
    		}
    		show();
    		string serach;
    		if(w[0]!='i')		//获取输入串的开头符号
    			serach =w.substr(0,1);
    		else
    			serach = w.substr(0, 2);
    		//cout << w[0]+""<< endl;		//转换字符串不能这么做
    		if(judge(stk.top(), serach, handle_index)) {	//归约,优先级最高
    			cout.setf(ios::right);	//设置字符对其方式
    			cout.width(10);			//设置字符宽度
    			cout << w;
    			cout << "|";
    			cout.setf(ios::left);
    			cout.width(10);
    			cout << "按" + handle[handle_index] + "归约" << endl;
    			printf("----------|----------|----------
    ");
    			string ttt = handle[handle_index].substr(2, handle[handle_index].size() - 2);  //得到产生式右部符号
    			while (ttt != "") {		
    				if (ttt[0] == 'i'){			//将产生式右部所有非终结符暂时压入一个栈中
    					com.push("id");
    					ttt=ttt.substr(2, ttt.size() - 2);
    				}
    				else
    				{
    					string t5;
    					t5 = ttt[0];
    					com.push(t5);
    					ttt=ttt.substr(1, ttt.size() - 1);
    				}
    			}
    			while (!com.empty()) {		//用这个有产生式右部所有非终结符的栈和当前栈比对,确定归约式正确
    				stk.pop();
    				string cmp1 = stk.top();
    				if (com.top()==cmp1) {
    					stk.pop();
    					com.pop();
    				}
    			}
    			string t3 = handle[handle_index];
    			t3 = t3[0];		//得到归约式的左部符号
    			string t4 = slrFind(stk.top(),t3);		//用此时左部符号和当前栈顶来确认下一个动作
    			stk.push(t3);
    			stk.push(t4);
    			continue;
    		}
    		else {  //移进操作--或者acc
    			cout.setf(ios::right);	//设置字符对其方式
    			cout.width(10);			//设置字符宽度
    			cout << w;
    			cout << "|";
    			cout.setf(ios::left);
    			cout.width(10);
    			string t1, t2;
    			t1 = stk.top();
    			if (w[now] == 'i') {	//移进符号为id
    				t2 = "id";
    				now = 2;
    			}
    			else {					//移进符号不为id
    				t2 = w[now];
    				now = 1;
    			}
    			stk.push(t2);			//将符号压入栈
    			w = w.substr(now, w.size() - now);	//丢弃已扫描的字符	
    			string lr = slrFind(t1, t2);	//找到对应的动作
    			if (lr[0] == 's'){				//如果是移进操作
    				lr = lr.substr(1, lr.size() - 1);
    				cout << "移进" << endl;
    			}
    			else if (lr == "acc") {			//或者是接受状态
    				cout << "接受" << endl;
    				flag = true;
    			}
    			stk.push(lr);
    			printf("----------|----------|----------
    ");
    			continue;
    		}
    	}
    }
    int main(void) {
    	init();
    	input = "id*id+id";		//输入串
    	input += "$";
    	analysis(input);
    	return 0;
    }
    
    

    4.样例输出

    5. To be continued.

  • 相关阅读:
    Hybrid APP基础篇(三)->Hybrid APP之Native和H5页面交互原理
    Hybrid APP基础篇(二)->Native、Hybrid、React Native、Web App方案的分析比较
    Hybrid APP基础篇(一)->什么是Hybrid App
    JavaScript筑基篇(一)->变量、值与对象
    深入Node.js的进程与子进程:从文档到实践
    深入Node模块Buffer-学会操作二进制
    深入Nodejs模块fs
    刷《一年半经验,百度、有赞、阿里面试总结》·手记
    Asp.Net Core 轻松学-被低估的过滤器
    css精灵图&字体图标
  • 原文地址:https://www.cnblogs.com/FlyerBird/p/10013050.html
Copyright © 2011-2022 走看看