编译原理--实验3-基于-LR(0)方法的语法分析

文章目录

  • 前言
  • 1.1实验目的
  • 1.2 实验任务
  • 1.3 实验内容
      • 1.3.1 输入格式:
      • 1.3.2 输出格式:
      • 1.3.3 样例
  • 1.4 程序
      • 1.4.1 程序流程图
      • 1.4.2 算法描述
      • 1.4.3 程序源码

前言

编译原理课程实验的实验课内容—构造自底向上LR(0)的语法分析程序。通过本次实验,可以熟练掌握对于LR(0)分析表的构造方法。

1.1实验目的

(1)掌握 LR(0)分析表的构造方法。

(2)掌握设计、编制和调试典型的语法分析程序,进一步掌握常用的语法分析方法。

(3)理解语法分析在编译程序中的作用。

1.2 实验任务

编写一个程序对输入的源代码进行语法分析,并打印分析结果。

自己编写一个基于 LR(0)方法的语法分析程序。语言不限,文法不限。 此时可根据自己的实际情况,选择以下一项实现分析算法中分析表的构造: 

(1)直接输入根据已知文法构造的 LR(0)分析表;

(2)输入已知文法的项目集规范族和转换函数,由程序自动生成 LR(0)分析表;

(3)输入已知文法,由程序自动生成 LR(0)分析表。

1.3 实验内容

1.3.1 输入格式:

你的程序输入是一个包含待分析词法单元序列的文本 文件,程序需要能够接收一个输入文件名作为参数,以获得相应的输出结果。

1.3.2 输出格式:

你的程序需要输出语法分析过程(包括 LR(0)分析表和分析过程表,并能够保 存 LR(0)分析表)和相应的分析结果(即此串是否为 LR(0)文法的句子)

1.3.3 样例

编译原理--实验3-基于-LR(0)方法的语法分析_第1张图片

编译原理--实验3-基于-LR(0)方法的语法分析_第2张图片

编译原理--实验3-基于-LR(0)方法的语法分析_第3张图片

对输入串的分析:

编译原理--实验3-基于-LR(0)方法的语法分析_第4张图片

1.4 程序

1.4.1 程序流程图

编译原理--实验3-基于-LR(0)方法的语法分析_第5张图片

1.4.2 算法描述

本次LR(0)分析表采用的是课本P136页表6.3的LR(0)分析表。程序的整体设计思路上,首先分为几个主要的函数来实现查找LR(0)分析表,对确定的输入串进行LR(0)分析过程。 同时,还要有出错判断的提示,这个我计划放在对输入串的分析过程中一并实现,另一个是保存当前的LR(0)分析表,这个功能放在输出LR(0)分析表的函数中实现。

1.4.3 程序源码

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
//本次LR(0)的文法样例采用课本P136页表6.3的LR(0)分析表
///表格数组                a       b        c       d       #      E      A       B
char LR0[50][50][100] = { {"S2"   ,"S3"   ,"null", "null" ,"null" ,"1"    ,"null" ,"null"},//0
						 {"null" ,"null" ,"null", "null" ,"acc " ,"null" ,"null" ,"null"},//1
						 {"null" ,"null" ,"S4"  , "S10"  ,"null" ,"null" ,"6"    ,"null"},//2
						 {"null" ,"null" ,"S5"  , "S11"  ,"null" ,"null" ,"null" ,"7"   },//3
						 {"null" ,"null" ,"S4"  , "S10"  ,"null" ,"null" ,"8"    ,"null"},//4
						 {"null" ,"null" ,"S5"  , "S11"  ,"null" ,"null" ,"null" ,"9"   },//5
						 {"r1"   ,"r1"   ,"r1"  , "r1"   ,"r1"   ,"null" ,"null" ,"null"},//6
						 {"r2"   ,"r2"   ,"r2"  , "r2"   ,"r2"   ,"null" ,"null" ,"null"},//7
						 {"r3"   ,"r3"   ,"r3"  , "r3"   ,"r3"   ,"null" ,"null" ,"null"},//8
						 {"r5"   ,"r5"   ,"r5"  , "r5"   ,"r5"   ,"null" ,"null" ,"null"},//9
						{"r4"   ,"r4"   ,"r4"  , "r4"   ,"r4"   ,"null" ,"null" ,"null"},//10
						{"r6"   ,"r6"   ,"r6"  , "r6"   ,"r6"   ,"null" ,"null" ,"null"},//11
//单个容量是100的字符串,总共50行,50列
};
char L[200] = "abcd#EAB";    ///列判断依据
int  del[10] = { 0,2,2,2,1,2,1 };//0-6号文法每个文法长度
char head[20] = { 'S','E','E','A','A','B','B' };
stack<int>con;    ///状态栈
stack<char>cmp;   ///符号栈
char cod[300] = "0";///初始状态栈对应输出数组
int cindex = 0;
char sti[300] = "#"; ///初始符号栈对应输出数组
int sindex = 0;
int findL(char b)///对应列寻找
{
	for (int i = 0; i <= 7; i++)
	{
		if (b == L[i])
		{
			return i;
		}
	}
	return -1;
}
void error(int x, int y)       //报错输出
{
	printf("第%d行%c列为空!", x, L[y]);
}

int calculate(int l, char s[])  //计算移入或者归约的数字
{
	int num = 0;
	for (int i = 1; i < l; i++)
	{
		num = num * 10 + (s[i] - '0');
	}
	return num;
}
void analyze(string str, int len) //分析主体过程,第一个参数为要分析的字符串,第二个参数为字符串长度
{
	int cnt = 1;
	printf("步骤      状态栈    符号栈    输入串    ACTION    GOTO\n");
	int LR = 0;
	while (LR <= len)  //还没有分析到结尾
	{
		printf("(%d)       %-10s%-10s", cnt, cod, sti);  //步骤,状态栈,符号栈输出
		cnt++;
		for (int i = LR; i < len; i++)  //输入串输出,只输出目前没有分析的部分
		{
			cout << str[i];
		}
		for (int i = len - LR; i < 10; i++)cout<<" ";

		int x = con.top();   //状态栈栈顶
		int y = findL(str[LR]);  //待判断当前串的串首元素

		if (strcmp(LR0[x][y], "null") != 0)  //当前状态不为空,进入下一步分析
		{
			int l = strlen(LR0[x][y]);  //当前Ri或Si的长度

			if (LR0[x][y][0] == 'a')  //acc,归约结束,返回
			{
				printf("acc        \n"); ///ACTION与GOTO
				return;
			}
			else if (LR0[x][y][0] == 'S')  //Si,移入操作
			{
				printf("%-10s \n", LR0[x][y]);  //ACTION与GOTO
				int t = calculate(l, LR0[x][y]);  //计算移入的是状态几的操作
				con.push(t);     //将移入的状态入栈
				sindex++;		//符号栈指针加1
				sti[sindex] = str[LR];		//新字符移入符号栈
				cmp.push(str[LR]);		
				if (t < 10)    
				{
					cindex++;   
					cod[cindex] = LR0[x][y][1];   //输出状态栈,移入几
				}
				else  //t是两位数
				{
					int k = 1;
					cindex++;
					cod[cindex] = '(';
					while (k < l)  //k小于L
					{
						cindex++;
						cod[cindex] = LR0[x][y][k];
						k++;
					}
					cindex++;
					cod[cindex] = ')';
				}
				LR++;
			}
			else if (LR0[x][y][0] == 'r') ///ri,退栈,ACTION和GOTO
			{
				printf("%-10s", LR0[x][y]);
				int t = calculate(l, LR0[x][y]);
				int g = del[t];  //要回退多少个符号
				while (g--)
				{
					con.pop();
					cmp.pop();
					sti[sindex] = '\0';
					sindex--;
				}
				g = del[t];
				while (g > 0)
				{
					if (cod[cindex] == ')')
					{
						cod[cindex] = '\0';
						cindex--;
						for (;;)
						{
							if (cod[cindex] == '(')
							{
								cod[cindex] = '\0';
								cindex--;
								break;
							}
							else
							{
								cod[cindex] = '\0';
								cindex--;
							}
						}
						g--;
					}
					else
					{
						cod[cindex] = '\0';
						cindex--;
						g--;
					}
				}///
				cmp.push(head[t]);
				sindex++;
				sti[sindex] = head[t];
				x = con.top();
				y = findL(cmp.top());
				t = LR0[x][y][0] - '0';
				con.push(t);
				cindex++;
				cod[cindex] = LR0[x][y][0];
				printf("%-10d\n", t);
			}
			
		}
		else  //当前状态为空,出错处理
		{
			error(x, y);
			cout << endl;
			cout << "程序分析结束,遇到语法错误!" << endl;
			exit(0);
			///报错
		}
	}

}
void chart()///测试表函数
{
	string file = ("文法.txt");
	ifstream input(file);
	string grammar;
	cout << "文法如下:" << endl;
	while (!input.eof())
	{
		getline(input, grammar);
		cout << grammar << endl;
	}
	input.close();
	cout << endl;
	file = ("LR(0).txt");
	ofstream output(file, ios::trunc);
	cout << "LR(0)分析表:" << endl;
	output << "LR(0)分析表:" << endl;
	cout << "---------------------------------------------------------------------" << endl;
	printf("-\ta\tb\tc\td\t#\tE\tA\tB\n");
	output << "-\ta\tb\tc\td\t#\tE\tA\tB\n";
	for (int i = 0; i <= 11; i++)
	{
		cout << "---------------------------------------------------------------------" << endl;
		printf("%d", i);
		output << i;
		for (int j = 0; j <= 8; j++)
		{
			printf("\t%s", LR0[i][j]);
			output << "\t" << LR0[i][j];
		}
		cout << endl;
		output << endl;
	}
	cout <<"---------------------------------------------------------------------"<< endl;
	output.close();
}
int main()
{
	chart(); //先构造分析表,采取直接构造的方式
	con.push(0);  //0进入状态栈
	cmp.push('#');  //#句首符号进入状态栈
	string str; //输入串
	cout << "读取的字符串为:" << endl;
	string file = ("测试样例1.txt");
	ifstream input(file);
	input >> str;
	cout << str << endl;
	input.close();
	int len = str.length();
	analyze(str, len);
	return 0;
}

(寒假打算发一下的,结果后来一直拖到现在,忽然想起,还是赶快发一下)

参考博客:https://blog.csdn.net/wys5wys/article/details/85128812

你可能感兴趣的:(编译原理)