c++详细实现:读取固定位置的文件中的文法,并对文法实现以下具体功能: 1、检测左递归,如果有则进行消除; 2、求解FIRST集和FOLLOW集; 3、构建LL(1)分析表; 4、构建LL分析程序,对于用户输入的句子,能够利用所构造的分析程序进行分析,并显示出分析过程。

时间: 2024-03-25 07:36:32 浏览: 20
好的,我来一步步为您解答。 首先,我们需要读取文件中的文法。假设我们的文法存储在文件 grammar.txt 中,则可以使用以下代码读取: ```c++ #include <fstream> #include <string> #include <vector> using namespace std; vector<string> grammar; void readGrammar() { ifstream inFile("grammar.txt"); string line; while (getline(inFile, line)) { grammar.push_back(line); } inFile.close(); } ``` 接下来,我们需要实现检测左递归并进行消除。以下是一个简单的左递归消除算法: ```c++ void eliminateLeftRecursion() { for (int i = 0; i < grammar.size(); i++) { string left = grammar[i].substr(0, grammar[i].find("->")); vector<string> right; string tmp = grammar[i].substr(grammar[i].find("->") + 2); int pos = 0; while ((pos = tmp.find("|")) != -1) { right.push_back(tmp.substr(0, pos)); tmp = tmp.substr(pos + 1); } right.push_back(tmp); for (int j = 0; j < i; j++) { string prev_left = grammar[j].substr(0, grammar[j].find("->")); if (prev_left != left) continue; vector<string> prev_right; tmp = grammar[j].substr(grammar[j].find("->") + 2); pos = 0; while ((pos = tmp.find("|")) != -1) { prev_right.push_back(tmp.substr(0, pos)); tmp = tmp.substr(pos + 1); } prev_right.push_back(tmp); vector<string> new_right; for (int k = 0; k < right.size(); k++) { if (right[k][0] == prev_left) { for (int l = 0; l < prev_right.size(); l++) { new_right.push_back(right[k].substr(1) + prev_right[l]); } } else { new_right.push_back(right[k]); } } right = new_right; } vector<string> new_grammar; bool flag = false; for (int j = 0; j < right.size(); j++) { if (right[j][0] == left[0]) { flag = true; string new_left = left + "'"; new_grammar.push_back(new_left + "->" + right[j].substr(1) + new_left); } else { new_grammar.push_back(left + "->" + right[j]); } } if (flag) { new_grammar.push_back(left + "'->" + "epsilon"); for (int j = 0; j < i; j++) { string prev_left = grammar[j].substr(0, grammar[j].find("->")); if (prev_left == left) continue; new_grammar.push_back(grammar[j]); } grammar = new_grammar; eliminateLeftRecursion(); return; } } } ``` 现在我们需要求解 FIRST 集和 FOLLOW 集。以下是一个简单的算法: ```c++ #include <map> #include <set> using namespace std; map<string, set<string>> first_set; map<string, set<string>> follow_set; void calculateFirst() { for (int i = 0; i < grammar.size(); i++) { string left = grammar[i].substr(0, grammar[i].find("->")); if (left == "S") first_set[left].insert("$"); vector<string> right; string tmp = grammar[i].substr(grammar[i].find("->") + 2); int pos = 0; while ((pos = tmp.find("|")) != -1) { right.push_back(tmp.substr(0, pos)); tmp = tmp.substr(pos + 1); } right.push_back(tmp); for (int j = 0; j < right.size(); j++) { string cur = right[j]; if (cur[0] >= 'a' && cur[0] <= 'z') { first_set[left].insert(cur.substr(0, 1)); } else { int k = 0; while (k < cur.size()) { if (cur[k] >= 'a' && cur[k] <= 'z') { first_set[left].insert(cur.substr(k, 1)); break; } else { string next = cur.substr(k, 1); set<string> next_first = first_set[next]; first_set[left].insert(next_first.begin(), next_first.end()); if (next_first.find("epsilon") == next_first.end()) break; k++; } } if (k == cur.size()) { first_set[left].insert("epsilon"); } } } } } void calculateFollow() { follow_set["S"].insert("$"); for (int i = 0; i < grammar.size(); i++) { string left = grammar[i].substr(0, grammar[i].find("->")); vector<string> right; string tmp = grammar[i].substr(grammar[i].find("->") + 2); int pos = 0; while ((pos = tmp.find("|")) != -1) { right.push_back(tmp.substr(0, pos)); tmp = tmp.substr(pos + 1); } right.push_back(tmp); for (int j = 0; j < right.size(); j++) { string cur = right[j]; for (int k = 0; k < cur.size(); k++) { if (cur[k] >= 'a' && cur[k] <= 'z') continue; string cur_sym = cur.substr(k, 1); if (k == cur.size() - 1) { set<string> follow_left = follow_set[left]; follow_set[cur_sym].insert(follow_left.begin(), follow_left.end()); } else { int l = k + 1; bool flag = true; while (l < cur.size()) { if (cur[l] >= 'a' && cur[l] <= 'z') { follow_set[cur_sym].insert(cur.substr(l, 1)); flag = false; break; } else { set<string> next_first = first_set[cur.substr(l, 1)]; if (next_first.find("epsilon") == next_first.end()) { follow_set[cur_sym].insert(next_first.begin(), next_first.end()); flag = false; break; } else { next_first.erase("epsilon"); follow_set[cur_sym].insert(next_first.begin(), next_first.end()); l++; } } } if (flag) { set<string> follow_left = follow_set[left]; follow_set[cur_sym].insert(follow_left.begin(), follow_left.end()); } } } } } } ``` 接下来,我们需要构建 LL(1) 分析表。以下是一个简单的算法: ```c++ #include <map> #include <string> #include <vector> using namespace std; map<string, map<string, vector<string>>> ll1_table; void buildLL1Table() { for (int i = 0; i < grammar.size(); i++) { string left = grammar[i].substr(0, grammar[i].find("->")); vector<string> right; string tmp = grammar[i].substr(grammar[i].find("->") + 2); int pos = 0; while ((pos = tmp.find("|")) != -1) { right.push_back(tmp.substr(0, pos)); tmp = tmp.substr(pos + 1); } right.push_back(tmp); for (int j = 0; j < right.size(); j++) { set<string> first = first_set[right[j].substr(0, 1)]; for (set<string>::iterator it = first.begin(); it != first.end(); it++) { if (*it == "epsilon") { set<string> follow = follow_set[left]; for (set<string>::iterator it2 = follow.begin(); it2 != follow.end(); it2++) { ll1_table[left][*it2].push_back(right[j]); } } else { ll1_table[left][*it].push_back(right[j]); } } } } } ``` 最后,我们需要构建 LL 分析程序,对于用户输入的句子,能够利用所构造的分析程序进行分析,并显示出分析过程。以下是一个简单的算法: ```c++ #include <iostream> #include <stack> #include <string> using namespace std; void llParse() { while (true) { cout << "请输入要分析的句子(以 $ 结尾):" << endl; string sentence; cin >> sentence; if (sentence == "$") break; stack<string> stk; stk.push("$"); stk.push("S"); int pos = 0; string cur_sym = sentence.substr(pos, 1); while (!stk.empty()) { string top_sym = stk.top(); if (top_sym == cur_sym) { stk.pop(); pos++; if (pos >= sentence.size()) { cout << "分析成功!" << endl; break; } cur_sym = sentence.substr(pos, 1); } else if (top_sym[0] >= 'A' && top_sym[0] <= 'Z') { vector<string> rule = ll1_table[top_sym][cur_sym]; if (rule.empty()) { cout << "无法匹配 " << cur_sym << endl; break; } stk.pop(); for (int i = rule[0].size() - 1; i >= 0; i--) { stk.push(rule[0].substr(i, 1)); } } else { cout << "无法匹配 " << cur_sym << endl; break; } } } } ``` 完整的代码如下:

相关推荐

最新推荐

recommend-type

C++使用递归和非递归算法实现的二叉树叶子节点个数计算方法

主要介绍了C++使用递归和非递归算法实现的二叉树叶子节点个数计算方法,涉及C++二叉树的定义、遍历、统计相关操作技巧,需要的朋友可以参考下
recommend-type

java递归实现复制一个文件夹下所有文件功能

主要介绍了java递归实现复制一个文件夹下所有文件功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
recommend-type

MyBatis之自查询使用递归实现 N级联动效果(两种实现方式)

主要介绍了MyBatis之自查询使用递归实现 N级联动效果,本文给大家分享两种实现方式,需要的的朋友参考下吧
recommend-type

C++ 数据结构二叉树(前序/中序/后序递归、非递归遍历)

主要介绍了C++ 数据结构二叉树(前序/中序/后序递归、非递归遍历)的相关资料,这里提供实例代码来帮助大家理解掌握二叉树,需要的朋友可以参考下
recommend-type

C++递归算法实例代码

主要介绍了C++递归算法实例代码,还是比较不错的,运用了递归算法解决相关问题,这里分享给大家,需要的朋友可以参考下。
recommend-type

zigbee-cluster-library-specification

最新的zigbee-cluster-library-specification说明文档。
recommend-type

管理建模和仿真的文件

管理Boualem Benatallah引用此版本:布阿利姆·贝纳塔拉。管理建模和仿真。约瑟夫-傅立叶大学-格勒诺布尔第一大学,1996年。法语。NNT:电话:00345357HAL ID:电话:00345357https://theses.hal.science/tel-003453572008年12月9日提交HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire
recommend-type

MATLAB柱状图在信号处理中的应用:可视化信号特征和频谱分析

![matlab画柱状图](https://img-blog.csdnimg.cn/3f32348f1c9c4481a6f5931993732f97.png) # 1. MATLAB柱状图概述** MATLAB柱状图是一种图形化工具,用于可视化数据中不同类别或组的分布情况。它通过绘制垂直条形来表示每个类别或组中的数据值。柱状图在信号处理中广泛用于可视化信号特征和进行频谱分析。 柱状图的优点在于其简单易懂,能够直观地展示数据分布。在信号处理中,柱状图可以帮助工程师识别信号中的模式、趋势和异常情况,从而为信号分析和处理提供有价值的见解。 # 2. 柱状图在信号处理中的应用 柱状图在信号处理
recommend-type

解释这行代码 c = ((double)rand() / RAND_MAX) * (a + b - fabs(a - b)) + fabs(a - b);

这行代码是用于生成 a 和 b 之间的随机数。首先,它使用 rand() 函数生成一个 [0,1) 之间的随机小数,然后将这个小数乘以 a、b 范围内的差值,再加上 a 和 b 中的较小值。这可以确保生成的随机数大于等于 a,小于等于 b,而且不会因为 a 和 b 之间的差距过大而导致难以生成足够多的随机数。最后,使用 fabs() 函数来确保计算结果是正数。
recommend-type

JSBSim Reference Manual

JSBSim参考手册,其中包含JSBSim简介,JSBSim配置文件xml的编写语法,编程手册以及一些应用实例等。其中有部分内容还没有写完,估计有生之年很难看到完整版了,但是内容还是很有参考价值的。