编译原理 LL(1)预测分析技术识别字符串

  • 实验名称

LL(1)分析技术识别字符串

  • 实验目的
  1. 掌握自顶向下语法分析方法的原理
  2. 编程完成预测分析法
  • 实验内容和要求

用LL(1)分析技术对输入串进行句型分析

  • 实验环境

VS 2022

  • 算法设计思想

主函数由两个函数语句和一个简单的用户交互组成。LL_creat函数负责接收非终结符集和终结符集以及LL表的元素,然后创建LL表。接下来进行分析,分析函数为Analysis函数。

分析过程首先创建一个char类栈,通过for循环,对每个待分析字符进行分析,每次分析涉及多个分支,分支判断用到vn_vt_or_no()函数,是#号返回标记3,是终结符返回标记,是非终结符返回标记2,错误返回标记0,通过对不同的返回值,做相应的处理。详解都在附件代码里,自请看注释。

  • 主要问题与解决方法

问题:对字符栈path栈顶元素的处理

解决:不同的元素类型做不同的标记,是#号返回标记3,是终结符返回标记,是非终结符返回标记2,错误返回标记0。返回不同的标记供分析时做不同的处理。

  • 实验结果

匹配成功与失败:

编译原理 LL(1)预测分析技术识别字符串_第1张图片

  • 体会、质疑、建议

代码中的奥妙,其乐无穷!!!

  • 源代码
#include
#include
#include
#define N 100
#include
#define error()  {cout << endl<<"Sorry!!!  The string can not be analysed.Try it again!" << endl;return;}
using namespace std;
/***************************************定义LL(1)表*******************************************/
struct LL
{
	string production;//利用结构体,节点里存储一个string字符串production
}LL[N][N];
/***************************************函数声明**********************************************/
void LL_craet();
int vn_vt_or_no(char elem);
void Printf_path(stackpath, string& p);
void Analysis();
/***************************************定义全局字符串****************************************/
string VN;
string VT;
/***************************************函数模块区********************************************/
int main()
{
	/***********************************主函数实现********************************************/
	int choice = 0;
	LL_craet();
	Analysis();
	while (1) {
		cout << "1.Try to analyse new string/2.Exit" << endl << "Press which:";
		cin >> choice;
		if (choice == 1)Analysis();
		else exit(1);
	}
	return 0;
}
int vn_vt_or_no(char elem)
{
	/*********************判断栈顶元素属于非终结符还是终结符还是#号***************************************/
	if (elem == '#')return 3;                            //是#号返回标记3
	if (VT.find(elem) < VT.size())return 1;                //是终结符返回标记1
	if (VN.find(elem) < VN.size())return 2;                //是非终结符返回标记2
	return 0;                                            //错误返回标记0
}
void Printf_path(stackpath, string& p)
{
	/*********************栈无法直接输出,通过处理传引用复制到字符串,用string类输出**********************/
	p.clear();                              //第一步将p清空,才能存东西
	while (!path.empty()) {					//path.empty()判断栈是否为空,empty是bool类型,空返回true,非空返回false
		p.insert(0, 1, path.top());			//利用插入方式,达到将栈元素存至p中,p.insert(0,1,path.top())表示,“0”位置,插入“1”个“path.top()”元素
		path.pop();						//插完之后栈顶移除一个元素
	}
}
void LL_craet()
{
	/******************************************终结和非终结字符输入***************************************/
	cout << "Please input the VN:" << endl;
	cin >> VN;
	cout << "Please input the VT:" << endl;
	cin >> VT;
	VT.push_back('#');                             //终结符需加入#号
	/******************************************LL(1)文法输入*********************************************/
	cout << "Please input LL rule:" << endl;
	for (int i = 0;i < VN.size();i++)
		for (int j = 0;j < VT.size();j++)
			cin >> LL[i][j].production;
	/******************************************LL(1)文法输出*********************************************/
	cout << "The LL(1) analyse table is as followed:" << endl << ' ';
	for (auto i : VT)cout << right << setw(10) << i;// 先将第一行终结符输出
	cout << endl;
	for (int i = 0;i < VN.size();i++) {            //而后逐行输出首位非终结符和LL表
		cout << VN.at(i);
		for (int j = 0;j < VT.size();j++) {
			if (LL[i][j].production == "-")cout << right << setw(11) << "ε";
			else cout << right << setw(10) << LL[i][j].production;
		}
		cout << endl;
	}
}
void Analysis()
{
	stack path;              //创建栈
	string str, production;         //创建字符串str,production
	/********************************读取要分析的字符串*************************************************/
	cout << "Please input the string ready to be analysed:" << endl;
	cin >> str;
	str.push_back('#');            //待分析字符串末尾加上#号
	/******************************入栈初始化***********************************************************/
	path.push('#');
	path.push(VN.front());
	/*******************************LL(1)分析过程输出***************************************************/
	cout << "The analysis process is as follows:" << endl;
	cout << left << setw(14) << "步骤" << setw(16) << "分析栈" << setw(20) << "剩余字符串" << "所用产生式" << endl;
	for (int step = 1;;step++) {            //通过for循环
		Printf_path(path, production);      //利用此函数处理,得到production,以此将栈输出
		cout << left << setw(14) << step << setw(16) << production << right << setw(10) << str << setw(10) << ' ';
		switch (vn_vt_or_no(path.top())) {              //分支,按返回,做相应处理,返回值看vn_vt_or_no函数内部分析
		case 0:             //返回0,意味着出错,直接退出系统
			cout << endl << "Wrong!!!" << endl;
			exit(1);
		case 1:           //返回1,path.top()栈顶元素为终结符
			if (path.top() == str.front()) {     //如果栈顶元素path.top()和待分析字符串首字符str.front()相等
				cout << path.top() << "匹配" << endl;  //相等即成功匹配
				str.erase(0, 1);                       //匹配已成功,移除待分析字符串首元素,str.erase(0,1)意思是删除str字符串“0”位置开始往后“1”个元素
				path.pop();                           //同样,匹配成功之后,栈也要移除栈顶元素
			}
			else error()                   //不相等则报错,并且return,退出当前Analysis函数
				break;
		case 2:            //返回2,path.top()栈顶元素为非终结符
			if (VT.find(str.front()) > VT.size()) error()                              //如果待分析字符出错,则报错
				production = LL[VN.find(path.top())][VT.find(str.front())].production;//取VN.find(path.top())行,VT.find(str.front())列,的LL[][]表中的字符串,赋值
			if (production == "-") {                                             //如果该字符串为“-”,则是产生式推空
				cout << path.top() << "->ε" << endl;                            //手动输出ε
				path.pop();                                                      //分析完,移除栈顶元素
			}
			else if (production == "NULL") error()                                  //如果该字符串是NULL,意味着LL表中无该产生式,同样报错处理,并退出Analysis函数
			else
			{                                                               //如果前两种情况都不是,则意味着正确,那么后面步骤即输出“分析产生式”即可
				cout << path.top() << "->" << production << endl;                //输出当前栈顶元素(因为当前正在分析该栈顶元素),然后->,然后production字符串,即产生式后半部分
				path.pop();                                                      //同样分析完之后,移除栈顶元素
				for (string::iterator i = production.end();i != production.begin();)path.push(*(--i));//移除完栈顶元素之后,需要将刚才产生式后半部分入栈,这里用到迭代器
			}
			break;
		case 3:            //返回3,path.top()栈顶元素为#号,意味着即将分析结束
			if (path.top() == str.front()) {             //此时栈顶元素已经是#号
				cout << "接受" << endl;                   //成功接收
				cout << endl << "Congratulation!!!  The string is analysed successfully!" << endl;
				return;                                  //接收完之后,return退出Analysis函数,进行后续操作
			}
			else error()                                     //如果不等于str.front(),则意味着str.front()不是#号,即待分析字符串还没分析完,出错
				break;
		}
	}
}
/*
* 案例一
SABC
abde
aA
bB
NULL
NULL
NULL
SBe
SBe
-
-
-
NULL
NULL
dC
e
NULL
NULL
bC
-
-
-
abede
* 案例二
STRD
abde
RT
RT
RT
eT
RT
DR
DR
NULL
NULL
-
-
-
dR
NULL
-
a
bd
NULL
NULL
NULL
ddbdd
*/

你可能感兴趣的:(c++,算法,开发语言)