// 刚开始代码中用的是 Ne,现在改为 toEpsilon Dictionary<char, bool> toEpsilon = new Dictionary<char, bool>(); // 是否能推出 epsilon void ComputeEpsilon() { // 第一步求出能推出 epsilon 的非终结符 Dictionary<char, List> curr = LR.ToDictionary(entry => entry.Key, entry => entry.Value.ToList()); Dictionary<char, int> record2 = new Dictionary<char, int>(record); // 记录以某一非终结符为左部的产生式的数量 foreach (KeyValuePair<char, List> s in curr) { // 产生式: A->BC, s1:BC s2:A List s1 = s.Value; char s2 = s.Key; for (int i = 0; i < s1.Count; i++) { if (s1[i].Length == 1 && s1[i][0] == '=') { // 如果产生式右侧只有 epsilon toEpsilon[s2] = true; curr[s2] = new List() { '' }; // 将所有此非终结符的产生式置空 break; } for (int j = 0; j < s1[i].Length; j++) { if (VT.Contains(s1[i][j])) { // 为非终结符 curr[s2][i] = ''; // 此产生式删除 record2[s2]--; // s2 的产生式减 1 if (record2[s2] == 0) { // 如果 s2 的产生式都被删除,则为 false toEpsilon[s2] = false; } } } } } int judge = 0; while (judge <= 20) { // 第三步, 迭代 20 次 foreach (KeyValuePair<char, List> s in curr) { List s1 = s.Value; char s2 = s.Key; for (int i = 0; i < s1.Count; i++) { int len = s1[i].Length; // 用 len 来记录该产生式右部剩下的字符数 for (int j = 0; j < s1[i].Length; j++) { if (toEpsilon.ContainsKey(s1[i][j]) && VN.Contains(s1[i][j])) { // 为非终结符 if (toEpsilon[s1[i][j]]) { len--; // 删去该终结符,右部字符数 - 1 if (len == 0) { // 全部删了, 则为 true toEpsilon[s2] = true; break; } } else { curr[s2][i] = ''; // 删去该产生式 record2[s2]--; if (record2[s2] == 0) { toEpsilon[s2] = false; break; } } } } } } judge++; } }

C++ 代码转 C#:计算能推出 Epsilon 的非终结符

原文地址: https://www.cveoy.top/t/topic/n7xn 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录