合工大 编译原理 实验二 LL1 自动生成M[A,a]

2023-11-15

实验目的
通过完成预测分析法的语法分析程序,了解预测分析法和递归子程序法的区
别和联系。使学生了解语法分析的功能,掌握语法分析程序设计的原理和构造方
法,训练学生掌握开发应用程序的基本方法。有利于提高学生的专业素质,为培
养适应社会多方面需要的能力。
实验截图
在这里插入图片描述

#include <iostream>
#include <stack>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
using namespace std;

bool isVN(char a) {
	if (a >= 'A' && a <= 'Z')
		return true;
	else return false;
}

int LL_1(string grammar, string stc) {
	char start = grammar[0];          //记录开始符
	int a[10][10] = { 0 };
	vector<char> vn;
	vector<string> drived;
	vector<char> vt;
	int i = 0;
	while (i < grammar.length()) {          //获取非终结符
		if (isVN(grammar[i])) {
			vn.push_back(grammar[i]);
		}
		i++;
	}
	i = 0;
	while (i < grammar.length()) {          //获取所有推导式
		string tmp = "";
		while (grammar[i] != '\n' && i < grammar.length()) {
			tmp += grammar[i];
			i++;
		}
		i++;
		drived.push_back(tmp);
	}
	i = 0;
	while (i < grammar.length()) {          //获取zhongjiefu
		if (grammar[i] != '\n' && !isVN(grammar[i]) && grammar[i] != '|' && grammar[i] != '?' && grammar[i] != ' ') {
			vt.push_back(grammar[i]);
		}
		i++;
	}

	sort(vn.begin(), vn.end());          //非终结符去重
	auto pos = unique(vn.begin(), vn.end());
	vn.erase(pos, vn.end());

	sort(vt.begin(), vt.end());          //非终结符去重
	auto pos2 = unique(vt.begin(), vt.end());
	vt.erase(pos2, vt.end());

	int f_size = vn.size();   //sizeof FIRST and FOLLOW
	//初始化first集合
	set<char> first[10];
	for (int i = 0; i < f_size; i++) {               //init first[]
		for (int j = 0; j < drived.size(); j++) {
			for (int k = 2; k < drived[j].size(); k++) {
				if (vn[i] == drived[j][0]) {
					if ((drived[j][k - 1] == '|' && !isVN(drived[j][k])) || (drived[j][k - 1] == ' ' && !isVN(drived[j][k]))) {
						first[i].insert(drived[j][k]);
					}
				}
			}
		}
	}

	for (int j = 0; j < drived.size(); j++) {           //用矩阵记录形如E->T T->S的非终结符通路
		for (int k = 0; k < f_size; k++) {
			if (drived[j][0] == vn[k]) {
				for (int l = 2; l < drived[j].size(); l++) {
					if (isVN(drived[j][l])) {
						for (int m = 0; m < f_size; m++) {
							if (drived[j][l] == vn[m] && (drived[j][l - 1] == '|' || drived[j][l - 1] == ' ')) {
								a[k][m] = 1;

							}

						}
					}
				}
				break;
			}

		}
	}
	//初始化标志数组 记录first的改变
	int flag[10] = { 0 };
	for (int j = 0; j < 10; j++) {
		flag[j] = first[j].size();
	}
	int sig = 0;
	for (int j = 0; j < f_size; j++) {
		for (int k = 0; k < f_size; k++) {
			if (a[j][k] == 1) {
				for (set<char>::iterator it = first[k].begin(); it != first[k].end(); it++) {
					first[j].insert(*it);
				}
			}
		}
	}
	do {
		for (int j = 0; j < f_size; j++) {
			for (int k = 0; k < f_size; k++) {
				if (a[j][k] == 1) {
					for (set<char>::iterator it = first[k].begin(); it != first[k].end(); it++) {
						first[j].insert(*it);
					}
				}
			}
		}
		for (int j = 0; j < 10; j++) {
			if (flag[j] != first[j].size()) {           //当first集合发生改变时,就得执行循环,直到不改变为止
				sig = 1;
				flag[j] = first[j].size();
				break;
			}
			if (j == 9) {
				sig = 0;
			}
		}
	} while (sig);

	set<char> follow[10];
	for (int j = 0; j < f_size; j++) {
		if (vn[j] == start) {
			follow[j].insert('#');
			break;
		}
	}

	//遍历推导式从二位开始 1遇到两个大写连着 后面的first加入前面的follow 2遇到大写后面跟着终结符,加入其follow
	for (int j = 0; j < drived.size(); j++) {
		for (int k = 2; k < drived[j].size() - 1; k++) {
			if (isVN(drived[j][k]) && isVN(drived[j][k + 1])) {         //对应条件1
				for (int l = 0; l < f_size; l++) {
					if (drived[j][k + 1] == vn[l]) {
						for (int m = 0; m < f_size; m++) {
							if (drived[j][k] == vn[m]) {
								for (set<char>::iterator it = first[l].begin(); it != first[l].end(); it++) {
									if (*it != '?') {
										follow[m].insert(*it);
									}

								}
								break;
							}
						}
						break;
					}
				}
			}
			if (isVN(drived[j][k]) && !isVN(drived[j][k + 1]) && drived[j][k + 1] != '|' && drived[j][k + 1] != '?') {    //对应条件2
				for (int l = 0; l < f_size; l++) {
					if (drived[j][k] == vn[l]) {
						follow[l].insert(drived[j][k + 1]);
						break;
					}
				}
			}
		}
	}
	int flag2[10] = { 0 };
	for (int j = 0; j < 10; j++) {
		flag2[j] = follow[j].size();
	}
	sig = 0;
	//follow第三条规则 E->anyH follow E = follow H
	do {
		for (int j = 0; j < drived.size(); j++) {
			for (int k = 2; k < drived[j].size() - 1; k++) {
				if (k == drived[j].size() - 2 && isVN(drived[j][k + 1])) {
					for (int l = 0; l < f_size; l++) {
						if (drived[j][k + 1] == vn[l]) {
							for (int m = 0; m < f_size; m++) {
								if (drived[j][0] == vn[m]) {
									for (set<char>::iterator it = follow[l].begin(); it != follow[l].end(); it++) {
										follow[m].insert(*it);
									}
									for (set<char>::iterator it = follow[m].begin(); it != follow[m].end(); it++) {
										follow[l].insert(*it);
									}
									break;
								}
							}
							break;
						}
					}
				}
				if (isVN(drived[j][k]) && drived[j][k + 1] == '|') {
					for (int l = 0; l < f_size; l++) {
						if (drived[j][k] == vn[l]) {
							for (int m = 0; m < f_size; m++) {
								if (drived[j][0] == vn[m]) {
									for (set<char>::iterator it = follow[l].begin(); it != follow[l].end(); it++) {
										follow[m].insert(*it);
									}
									for (set<char>::iterator it = follow[m].begin(); it != follow[m].end(); it++) {
										follow[l].insert(*it);
									}
									break;
								}
							}
							break;
						}
					}
				}
			}
		}
		for (int j = 0; j < 10; j++) {
			if (flag2[j] != follow[j].size()) {           //当follow集合发生改变时,就得执行循环,直到不改变为止
				sig = 1;
				flag2[j] = follow[j].size();
				break;
			}
			if (j == 9) {
				sig = 0;
			}
		}
	} while (sig);
	
	// 构造M[A,a]
	string m[10][10];
	for (int i = 0; i < vt.size(); i++) {
		string tmp = "";
		tmp += vt[i];
		m[0][i + 1] = tmp;
	}
	for (int i = 0; i < vn.size(); i++) {
		string tmp = "";
		tmp += vn[i];
		m[i + 1][0] = tmp;
	}
	
	for (int i = 1; i < vt.size() + 1; i++) {
		for (int j = 1; j < vn.size() + 1; j++) {
			auto pos = first[j - 1].find(m[0][i][0]); 
			auto pos2 = first[j - 1].find('?');
			if (pos != first[j - 1].end()) {
				m[j][i] = "o";
				for (int k = 0; k < drived.size(); k++) {
					if (drived[k][0] == m[j][0][0]) {
						if (drived[k][2] == m[0][i][0]) {
							m[j][i] = drived[k];
						}
					}
				}
				
			}
			else if (pos2 != first[j - 1].end()) {
				auto pos3 = follow[j - 1].find(m[0][i][0]);
				if (pos3 != follow[j - 1].end()) {
					m[j][i] = "?";
				}
				else m[j][i] = "$";
			}
			else m[j][i] = "$";
		}
	}
	for (int i = 1; i < vt.size() + 1; i++) {
		for (int j = 1; j < vn.size() + 1; j++) {
			if (m[j][i][0] == 'o') {
				for (int k = 0; k < drived.size(); k++) {
					if (drived[k][0] == m[j][0][0]) {
						if (isVN(drived[k][2])) {
							m[j][i] = drived[k];
						}
					}
				}
			}
		}
	}

	//至此 查找表构造完成
	string st = "";
	st += start;
	st += '#';
	while (stc.length() > 1) {
		char a, b;
		a = stc[0];
		b = st[0];
		int flag = 0;
		if (a == b) {
			cout << "当前两个字符串顶相同,删去" << a << endl;
			stc.erase(0, 1);
			st.erase(0, 1);
			cout << endl;

		}
		else {
			for (int i = 1; i < vt.size() + 1; i++) {
				if (flag)
					break;
				for (int j = 1; j < vn.size() + 1; j++) {
					if (a == m[0][i][0] && b == m[j][0][0]) {
						string tmp = m[j][i];
						flag = 1;
						if (tmp[0] == '?') {
							cout << "匹配式:  " << st<<'	';
							cout << "语句:  " << stc<<'	';
							st.erase(0, 1);
							cout << "用:  ->?" ;
							cout << endl; cout << endl;
						}
						else {
							cout << "匹配式:  " << st << '	';
							cout << "语句:  " << stc << '	';
							tmp.insert(1, "->");
							cout << "用公式:  " << tmp << '	';
							tmp.erase(0, 4);
							st.erase(0, 1);
							st.insert(0, tmp);
							
							cout << endl; cout << endl;
						}
						break;
					}
					
				}
			}
		}

	}
	while (st.length() > 1) {
		cout << "用->?消除" << st[0] << endl;
		st.erase(0, 1);
	}

	return 0;
}

int main() {
	string s = "E#";
	string wenfa = "E TG\nG +TG\nG -TG\nG ?\nT FS\nS *FS\nS /FS\nS ?\nF (E)\nF i"; //文法输入
	string s_in = "i/i-i+i*i#";            //待解析语句
	LL_1(wenfa, s_in);
	return 0;
}

https://download.csdn.net/download/qq_45205060/18212579?spm=1001.2014.3001.5503
带界面的qt文件

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

合工大 编译原理 实验二 LL1 自动生成M[A,a] 的相关文章

  • 如何从字符串中提取子字符串直到遇到第二个空格?

    我有一个像这样的字符串 o1 1232 5467 1232 5467 1232 5467 1232 5467 1232 5467 1232 5467 如何仅提取 o1 1232 5467 要提取的字符数并不总是相同 因此 我只想提取直到遇到
  • 是否可以使用 http url 作为 DirectShow .Net 中源过滤器的源位置?

    我正在使用 DirectShow Net 库创建一个过滤器图 该过滤器图通过使用 http 地址和 WM Asf Writer 来流式传输视频 然后 在网页上 我可以使用对象元素在 Windows Media Player 对象中呈现视频源
  • 关于逻辑/算法的想法以及如何防止线程写入 Sql Server 中的竞争

    我有以下逻辑 public void InQueueTable DataTable Table int incomingRows Table Rows Count if incomingRows gt RowsThreshold async
  • EntityHydrate 任务失败

    我最近安装了 Visual Studio 11 Beta 和 Visual Studio 2010 之后 我无法在 Visual Studio 2010 中构建依赖于 PostSharp 的项目 因此我卸载了 Visual Studio 1
  • Boost ASIO 串行写入十六进制值

    我正在使用 ubuntu 通过串行端口与设备进行通信 所有消息都必须是十六进制值 我已经在 Windows 环境中使用白蚁测试了通信设置 并得到了我期望的响应 但在使用 Boost asio 时我无法得到任何响应 以下是我设置串口的方法 b
  • 2个对象,完全相同(除了命名空间)c#

    我正在使用第三方的一组网络服务 但遇到了一个小障碍 在我手动创建将每个属性从源复制到目标的方法之前 我想我应该在这里寻求更好的解决方案 我有 2 个对象 一个是 Customer CustomerParty 类型 另一个是 Appointm
  • 使用 C# 和 ASP.NET 在电子邮件附件中发送 SQL 报告

    我正在尝试使用 ASP NET 和 C 从 sql reportserver 2008 作为电子邮件附件发送报告 到目前为止我学会了如何获取 PDF 格式的报告 http weblogs asp net srkirkland archive
  • 混合模型优先和代码优先

    我们使用模型优先方法创建了一个 Web 应用程序 一名新开发人员进入该项目 并使用代码优先方法 使用数据库文件 创建了一个新的自定义模型 这 这是代码第一个数据库上下文 namespace WVITDB DAL public class D
  • 如何向 Mono.ZeroConf 注册服务?

    我正在尝试测试 ZeroConf 示例http www mono project com Mono Zeroconf http www mono project com Mono Zeroconf 我正在运行 OpenSuse 11 和 M
  • 为什么这个 makefile 在“make clean”上执行目标

    这是我当前的 makefile CXX g CXXFLAGS Wall O3 LDFLAGS TARGET testcpp SRCS main cpp object cpp foo cpp OBJS SRCS cpp o DEPS SRCS
  • Libev,如何将参数传递给相关回调

    我陷入了 libev 中争论的境地 通常 libev 在类似的函数中接收包 接收回调 没关系 但是实际操作中 我们需要派遣一个亲戚 写回调 根据收到的包裹处理具体工作 例如 S RECV MSG pstRecvMsg S RECV MSG
  • 测量进程消耗的 CPU 时钟

    我用 C 语言编写了一个程序 它是作为研究结果创建的程序 我想计算程序消耗的确切 CPU 周期 精确的循环次数 知道我怎样才能找到它吗 The valgrind tool cachegrind valgrind tool cachegrin
  • 条件类型定义

    如果我有一小段这样的代码 template
  • 让网络摄像头在 OpenCV 中工作

    我正在尝试让我的网络摄像头在 Windows 7 64 位中的 OpenCV 版本 2 2 中捕获视频 但是 我遇到了一些困难 OpenCV 附带的示例二进制文件都无法检测到我的网络摄像头 最近我发现这篇文章表明答案在于重新编译一个文件 o
  • ASP.NET Core 中间件与过滤器

    在阅读了 ASP NET Core 中间件之后 我对何时应该使用过滤器以及何时应该使用中间件感到困惑 因为它们似乎实现了相同的目标 什么时候应该使用中间件而不是过滤器 9频道有一个关于此的视频 ASP NET 怪物 91 中间件与过滤器 h
  • Unity3D - 将 UI 对象移动到屏幕中心,同时保持其父子关系

    我有一个 UI 图像 它的父级是 RectTransform 容器 该容器的父级是 UI 面板 而 UI 面板的父级是 Canvas 我希望能够将此 UI 图像移动到屏幕中心 即画布 同时保留父级层次结构 我的目标是将 UI 图像从中心动画
  • 如何高效计算连续数的数字积?

    我正在尝试计算数字序列中每个数字的数字乘积 例如 21 22 23 98 99 将会 2 4 6 72 81 为了降低复杂性 我只会考虑 连续的数字 http simple wikipedia org wiki Consecutive in
  • 如何组合两个 lambda [重复]

    这个问题在这里已经有答案了 可能的重复 在 C 中组合两个 lambda 表达式 https stackoverflow com questions 1717444 combining two lamba expressions in c
  • 从后面的代码添加外部 css 文件

    我有一个 CSS 文件 例如 SomeStyle css 我是否可以将此样式表文档从其代码隐藏应用到 aspx 页面 您可以将文字控件添加到标头控件中 Page Header Controls Add new System Web UI L
  • 如何在 ASP.NET Core 中注入泛型的依赖关系

    我有以下存储库类 public class TestRepository Repository

随机推荐

  • mock方法常用框架_Mock框架Mockito入门教程

    在开发中 我们经常会依赖同事或者第三方提供的接口 如果该接口无法正常工作 比如接口正在修复 或者网络异常等 那么便会对需要依赖该接口的开发造成很大影响 遇到这种情况 我们可能会想到模拟该接口以提供正常的返回值 用来继续当前的工作 使用Moc
  • Qt信号槽进阶及误区

    lambda写法 Qt 中信号槽lambda表达式优缺点 好处 代码更加紧凑 不用特意费力去定义一个常规的函数 坏处 一旦写的过长 臃肿 代码可读性会变差 C 中lambda表达式构成 capture parameters mutable
  • 数据模型及E-R模型

    数据模型的基本概念 模型就是对现实世界特征的模拟和抽象 数据模型是对现实世界数据特征的抽象 对于具体的模型人们并不陌生 如航模飞机 地图和建筑设计沙盘等都是具体的模型 最常用的数据模型分为概念数据模型和基本数据模型 1 概念数据模型 概念数
  • 不拼花哨,只拼实用:unittest指南,干货为王!

    Python为开发者提供了内置的单元测试框架 unittest 它是一种强大的工具 能够有效地编写和执行单元测试 unittest 提供了完整的测试结构 支持自动化测试的执行 能够对测试用例进行组织 并且提供了丰富的断言方法 最终 unit
  • 网络编程基础

    目录 一 网络的概念 1 认识网络 2 网络的发展 二 协议 1 网络问题的产生 2 什么是协议 3 网络协议 三 协议分层 1 协议分层的概念 2 OSI七层模型 3 TCP IP四层 五层 模型 1 物理层 2 数据链路层 网卡层 3
  • 宝塔面板获取默认账号密码

    bt default
  • 安装ssl证书后报错Caused by: java.io.IOException: DerInputStream.getLength(): lengthTag=109, too big.

    刚刚安装完ssl证书后 报错 org apache catalina LifecycleException Protocol handler start failed at org apache catalina connector Con
  • 物联网毕设 -- 智能热水器(GPRS+APP+OneNET)

    目录 前言 一 连线图 1 原理图 2 PCB效果 3 实物效果 4 功能概括 1 硬件端 2 APP端 3 云平台端 演示视频 二 底层代码使用方式 1 使用说明 2 下载程序 3 查看云平台 三 APP使用方式 1 下载APP 1 操作
  • 【XGBoost】第 5 章:XGBoost 揭幕

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • 增益带宽积 压摆率

    带宽 它指的是电路可以保持稳定工作的频率范围 选高速运放能减少对贷款的影响 只要能够完美再现方波 就是高带宽电路 带宽与压摆率同时变化 高频下 增益就缩小了 说明增益是有带宽的 在一定频率内增益才稳定 一倍放大 与 10倍放大输出用1 10
  • AntDesign-vue-Tree组件-拖动排序

  • c++primer plus第一章复习题和编程练习答案

    复习题 c 程序的模块是 函数 include
  • MATLAB —— 低通滤波器设计与信号滤波

    百度百科 简介 低通滤波器是容许低于截止频率的信号通过 但高于截止频率的信号不能通过的电子滤波装置 1 提取滤波器 系数矩阵 打开工具 MATLAB APP Filter Designer 参数设置 滤波器类型 Response Type
  • 爬虫实例——某翻译网站参数sign的构造

    1 网页分析 该翻译网站为进行Ajax加载的网站 针对这种网页的爬取 一般有两种方式 使用Selenium等模拟浏览器的方式进行爬取 这种方式实现起来较为简单 但是爬取速度相对较慢 直接对网站的接口进行请求 爬取速度相对较快 但是某些网站的
  • 7 125 kHz RFID技术

    ATA5577C应答器芯片 芯片性能和电路组成 主要技术性能 低功耗 低工作电压 非接触能量供给和读 写数据 工作频率范围为100 150 kHz EEPROM存储器容量为363位 分为11块 每块33位 具有7块用户数据 每块32位 共2
  • 算法分析02--分治法

    3 分治法 3 1递归 递归是指子程序 或函数 直接调用自己或通过一系列调用语句间接调用自己 是一种描述问题和解决问题的常用方法 使用递归技术往往使函数的定义和算法的描述简洁且易千理解 递归有两个基本要素 边界条件 即确定递归到何时终止 也
  • FASTAI and Fine-Tuning BERT with FastAI

    这是一篇笔记类型文章 主要是从新学习一下fastai 和实践 pytorch pretrained BERT 和 pytorch transformers 对接fastai 后简洁快速实现bert模型的训练和执行任务 我还是一个小白 大佬看
  • python Elasticsearch 排序

    sort 与query是同级的 Elasticsearch python sort sort score order desc query function score query match all script score lang p
  • 接口报错之number值过大问题

    number的最大的值为2的53次方 9007199254740992 16位 当你传入的参数为Number类型时候超过16位 js就识别不了 接口会出现错误的情况 可以直接改成字符串就好了 1 JavaScript中所有的数字 无论是整数
  • 合工大 编译原理 实验二 LL1 自动生成M[A,a]

    实验目的 通过完成预测分析法的语法分析程序 了解预测分析法和递归子程序法的区 别和联系 使学生了解语法分析的功能 掌握语法分析程序设计的原理和构造方 法 训练学生掌握开发应用程序的基本方法 有利于提高学生的专业素质 为培 养适应社会多方面需