c++实现: 1、检测左递归,如果有则进行消除; 2、求解FIRST集和FOLLOW集; 3、构建LL(1)分析表; 4、构建LL分析程序,对于用户输入的句子,能够利用所构造的分析程序进行分析,并显示出分析过程。

时间: 2024-03-25 11:36:05 浏览: 17
以下是一个简单的 C++ 实现,包括检测和消除左递归,求解FIRST和FOLLOW集,构建LL(1)分析表,以及利用所构造的分析程序对用户输入的句子进行分析并显示出分析过程。 ```c++ #include <iostream> #include <vector> #include <map> #include <set> #include <string> #include <sstream> #include <algorithm> using namespace std; // 定义产生式结构体 struct Production { char left; // 产生式左部 vector<string> right; // 产生式右部 }; // 检测左递归 void eliminate_left_recursion(vector<Production>& productions) { for (int i = 0; i < productions.size(); i++) { Production& p = productions[i]; vector<string> new_right; vector<string> old_right = p.right; bool has_left_recursion = false; for (string& s : old_right) { if (s[0] == p.left) { has_left_recursion = true; break; } } if (!has_left_recursion) { continue; } char new_left = p.left + 1; while (find_if(productions.begin(), productions.end(), [&](const Production& p) { return p.left == new_left; }) != productions.end()) { new_left++; } // 消除左递归 for (string& s : old_right) { if (s[0] == p.left) { new_right.push_back(s.substr(1) + new_left); } else { new_right.push_back(s + new_left); } } new_right.push_back("$"); // 生成新的产生式 p.right.clear(); for (string& s : new_right) { p.right.push_back(s); } Production new_p = {new_left, {}}; for (string& s : old_right) { if (s[0] != p.left) { new_p.right.push_back(s + new_left); } } new_p.right.push_back("$"); productions.push_back(new_p); } } // 求解FIRST集 void compute_first_sets(vector<Production>& productions, map<char, set<char>>& first_sets) { bool changed = true; while (changed) { changed = false; for (Production& p : productions) { char left = p.left; vector<string>& right = p.right; for (string& s : right) { if (s.empty()) { // 空产生式 if (first_sets[left].insert('@').second) { changed = true; } } else if (islower(s[0])) { // 终结符 if (first_sets[left].insert(s[0]).second) { changed = true; } } else { // 非终结符 bool has_epsilon = true; for (char& c : s) { if (first_sets[c].find('@') == first_sets[c].end()) { has_epsilon = false; if (first_sets[left].insert(*first_sets[c].begin()).second) { changed = true; } break; } } if (has_epsilon && first_sets[left].insert('@').second) { changed = true; } } } } } } // 求解FOLLOW集 void compute_follow_sets(vector<Production>& productions, map<char, set<char>>& first_sets, map<char, set<char>>& follow_sets) { bool changed = true; while (changed) { changed = false; for (Production& p : productions) { char left = p.left; vector<string>& right = p.right; for (int i = 0; i < right.size(); i++) { string& s = right[i]; for (int j = 0; j < s.length(); j++) { if (!isupper(s[j])) { // 终结符 continue; } bool has_epsilon = true; for (int k = j + 1; k < s.length(); k++) { if (first_sets[s[k]].find('@') == first_sets[s[k]].end()) { has_epsilon = false; if (follow_sets[s[j]].insert(*first_sets[s[k]].begin()).second) { changed = true; } break; } } if (has_epsilon && follow_sets[s[j]].insert(follow_sets[left].begin(), follow_sets[left].end()).second) { changed = true; } if (has_epsilon && i == right.size() - 1 && follow_sets[s[j]].insert(follow_sets[left].begin(), follow_sets[left].end()).second) { changed = true; } } } } } } // 构建LL(1)分析表 void build_ll1_table(vector<Production>& productions, map<char, set<char>>& first_sets, map<char, set<char>>& follow_sets, map<pair<char, char>, vector<string>> &ll1_table) { for (Production& p : productions) { char left = p.left; vector<string>& right = p.right; for (int i = 0; i < right.size(); i++) { string& s = right[i]; set<char> first; if (s.empty() || first_sets[s[0]].find('@') != first_sets[s[0]].end()) { // 空产生式或以非终结符开头的产生式 first = follow_sets[left]; } else { first = first_sets[s[0]]; } for (char& c : first) { ll1_table[{left, c}].push_back(s); } } } } // 执行LL分析 vector<string> ll_analyze(map<pair<char, char>, vector<string>>& ll1_table, string input) { vector<string> output; input += "$"; vector<char> stack = {'$', 'S'}; int i = 0; while (!stack.empty()) { char c = stack.back(); stack.pop_back(); if (c == input[i]) { output.push_back(string("match: ") + c); i++; } else if (isupper(c)) { auto it = ll1_table.find({c, input[i]}); if (it == ll1_table.end()) { output.push_back("error"); break; } else { vector<string>& s = it->second; output.push_back(string("predict: ") + s[0]); stack.insert(stack.end(), s[0].rbegin(), s[0].rend()); } } else { output.push_back("error"); break; } } return output; } int main() { // 输入文法 vector<Production> productions = { {'S', {"aBC"}}, {'B', {"bB", "@"}}, {'C', {"cC", "@"}} }; // 消除左递归 eliminate_left_recursion(productions); // 求解FIRST集 map<char, set<char>> first_sets; compute_first_sets(productions, first_sets); // 求解FOLLOW集 map<char, set<char>> follow_sets; follow_sets['S'].insert('$'); compute_follow_sets(productions, first_sets, follow_sets); // 构建LL(1)分析表 map<pair<char, char>, vector<string>> ll1_table; build_ll1_table(productions, first_sets, follow_sets, ll1_table); // 执行LL分析 vector<string> output = ll_analyze(ll1_table, "abccc$"); // 输出分析过程 for (string& s : output) { cout << s << endl; } return 0; } ``` 这个实现只是一个简单的例子,实际应用中可能需要更复杂的算法和数据结构来处理更复杂的语法。

相关推荐

最新推荐

recommend-type

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

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

C++递归算法实例代码

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

编译原理实验报告(含代码:状态转换图;DFA扫描;First集,follow集计算)

实验一:状态转换图 输入一串数据,利用状态转换图程序求出“关键字,标识符,整数,运算符,实数”。 实验二:DFA扫描 打开一个编写好的源...输入一个不含左递归的文法,由此程序求出该文法的first集和follow集。
recommend-type

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

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

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

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

实现实时数据湖架构:Kafka与Hive集成

![实现实时数据湖架构:Kafka与Hive集成](https://img-blog.csdnimg.cn/img_convert/10eb2e6972b3b6086286fc64c0b3ee41.jpeg) # 1. 实时数据湖架构概述** 实时数据湖是一种现代数据管理架构,它允许企业以低延迟的方式收集、存储和处理大量数据。与传统数据仓库不同,实时数据湖不依赖于预先定义的模式,而是采用灵活的架构,可以处理各种数据类型和格式。这种架构为企业提供了以下优势: - **实时洞察:**实时数据湖允许企业访问最新的数据,从而做出更明智的决策。 - **数据民主化:**实时数据湖使各种利益相关者都可
recommend-type

解释minorization-maximization (MM) algorithm,并给出matlab代码编写的例子

Minorization-maximization (MM) algorithm是一种常用的优化算法,用于求解非凸问题或含有约束的优化问题。该算法的基本思想是通过构造一个凸下界函数来逼近原问题,然后通过求解凸下界函数的最优解来逼近原问题的最优解。具体步骤如下: 1. 初始化参数 $\theta_0$,设 $k=0$; 2. 构造一个凸下界函数 $Q(\theta|\theta_k)$,使其满足 $Q(\theta_k|\theta_k)=f(\theta_k)$; 3. 求解 $Q(\theta|\theta_k)$ 的最优值 $\theta_{k+1}=\arg\min_\theta Q(
recommend-type

JSBSim Reference Manual

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