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

前言

编译原理课程实验的实验课内容—构造自底向上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 样例

在这里插入图片描述

在这里插入图片描述

对输入串的分析:

1.4 程序

1.4.1 程序流程图

在这里插入图片描述

1.4.2 算法描述

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

1.4.3 程序源码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<stack>
#include<string>
#include<sstream>
#include<fstream>
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

  • 9
    点赞
  • 108
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
由于你没有提供文法,我这里以一个简单的算术表达式文法为例: ``` E -> E + T E -> E - T E -> T T -> T * F T -> T / F T -> F F -> ( E ) F -> num ``` LR分析需要先构建LR(1)自动机,然后进行分析。下面是该文法LR(1)自动机(省略了一些状态和转换): ``` state 0: E -> . E + T E -> . E - T E -> . T T -> . T * F T -> . T / F T -> . F F -> . ( E ) F -> . num ... state 1: E -> E . + T E -> E . - T ... state 2: E -> T . ... state 3: T -> T . * F T -> T . / F ... state 4: T -> F . ... state 5: F -> ( . E ) ... state 6: F -> num . ... ``` 接下来,我们可以通过栈的方式对输入的字符串进行语法分析。具体步骤如下: 1. 将起始状态(0)和结束符号$入栈。 2. 读入输入字符串的第一个符号,并将其入栈。 3. 从状态栈顶取出状态,从符号栈顶取出符号。 4. 如果符号是终结符号,则比较该符号和输入字符串当前位置的符号是否相同。如果相同,则将输入字符串的下一个符号入栈,否则出错并结束分析。 5. 如果符号是非终结符,则查找该符号和输入字符串当前位置的符号对应的转移状态,并将该状态入栈。 6. 如果栈顶符号是$,并且输入字符串已经全部读入,则分析成功,结束分析。 7. 如果栈为空,但输入字符串还没有全部读入,则分析失败,结束分析。 8. 重复步骤3-7,直到分析成功或失败。 通过以上步骤,我们可以完成对该文法语法分析

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨大熊的代码世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值