SLR1 分析表构建代码分析 - 正确性验证
代码正确。
//求项目集
public void Creteitemsets()
{
List<int> lr_item = new List<int>(100);//记录项目的序号
lr_item.Add(0);
lr_item = Closure(lr_item);//构造初始项目集 求闭包
SLRitemsets LR_C = new SLRitemsets();
LR_C.Container = lr_item;//集合----项目集序号的集合
proitemset.Add(LR_C);//集合的集合----存放项目集序号集合 的集合
for (int i = 0; i < proitemset.Count; i++)//整体集合中 第i个项目集
{
proitemset[i].Container.Sort();//排序由小到大 后面用于判断是否存在的比较
int[] flag = new int[proitemset[i].Container.Count];
for (int fi = 0; fi < proitemset[i].Container.Count; fi++)//标志位,用来判断该序号是否已经构造
{
flag[fi] = 0;
}
for (int j = 0; j < proitemset[i].Container.Count; j++)//第i个项目集的第j个项目
{
if (flag[j] == 1)//如果已经访问过 就不再构造 找下一个项目
continue;
int index = proitemset[i].Container[j];
for (int pi = 0; pi < SLRobjNum[index].Right.Length - 1; pi++)//length-1是避免匹配到.在最后的规约项目
{
if (SLRobjNum[index].Right[pi] == '.')
{
List<int> lr2_club = new List<int>(100);//记录项目的序号
char symbol = SLRobjNum[index].Right[pi + 1];//记录.a转移状态a.的符号a
lr2_club.Add((index + 1));//如果遇到.a形式的项目序号为index 那么项目a.的序号为index+1
for (int m1 = j + 1; m1 < proitemset[i].Container.Count; m1++)
{//在第i个项目集中找到了可以移动的.:.a 重新遍历第i个项目集j项目之后的 找到同样可以移动a的项目集
int index2 = proitemset[i].Container[m1];
for (int m2 = 0; m2 < SLRobjNum[index2].Right.Length - 1; m2++)
{
if (SLRobjNum[index2].Right[m2] == '.' && SLRobjNum[index2].Right[m2 + 1] == symbol)
{
flag[m1] = 1;//标记位置为1 已经访问 之后不再访问
lr2_club.Add(index2 + 1);
}
}
}
lr2_club = Closure(lr2_club);//求闭包
int value = isexist(lr2_club);
if (value == -1)//-1表示不存在相同的
{
for (int m3 = 0; m3 < Gy_obj.Count; m3++)
{
if (isnexist(lr2_club, Gy_obj[m3]))
{
Gy_itemset.Add(proitemset.Count);
}
}
SLRitemsets LR_C2 = new SLRitemsets();
dfa[Pindex++] = new DFA(i, symbol, proitemset.Count);//count不用加1 本身从0开始
LR_C2.Container = lr2_club;
proitemset.Add(LR_C2);
}
else
{
dfa[Pindex++] = new DFA(i, symbol, value);
}
break;
}
}
}//end-forj
}//end-fori
}//end-Cre_club
public Table[][] GET_ANA()
{
SLRAnaly();
RStr_ANA += "\r\nSLR0分析表:\r\n ";
int i;
for (i = 0; i < Echar.Count; i++)
{
RStr_ANA += Echar[i].ToString() + " ";
}
for (i = 0; i < Nchar.Count; i++)
{
RStr_ANA += Nchar[i].ToString() + " ";
}
RStr_ANA += "\r\n";
for (i = 0; i < proitemset.Count; i++)
{
RStr_ANA += i.ToString() + " ";
for (int j = 0; j < Echar.Count + Nchar.Count; j++)
{
if (SLRAna[i][j].error)
{
RStr_ANA += " " + " ";
}
else if (i == 1 && j == Echar.Count - 1)
{
RStr_ANA += "AC" + " ";
}
else if (SLRAna[i][j].type != 'N')
{
RStr_ANA += SLRAna[i][j].type.ToString() + SLRAna[i][j].id.ToString() + " ";
}
else
RStr_ANA += SLRAna[i][j].id.ToString() + " ";
}
RStr_ANA += "\r\n";
}
return SLRAna;
}
public void SLRAnaly()
{
Table tnode = new Table();
SLRAna = new Table[proitemset.Count][];
for (int i = 0; i < proitemset.Count; i++)
SLRAna[i] = new Table[Echar.Count + Nchar.Count];
for (int i = 0; i < proitemset.Count; i++)//初始化 赋予ERROR属性
for (int j = 0; j < Echar.Count + Nchar.Count; j++)//为终结符加r状态
SLRAna[i][j] = tnode;
tnode = new Table('A', 0);
SLRAna[1][FindID(Echar, '#')] = tnode;//项目集1必定是接受项目 构建[1][#]:acc的情况 先直接赋值好 dfa里没有
for (int i = 0; i < Gy_itemset.Count; i++)
{
SLRNode item = SLRobjNum[proitemset[Gy_itemset[i]].Container[0]];
char left = item.Left[0];
List<char> follow = GetFollow(left);
foreach (char c in follow)
{
int CID = FindID(Echar, c);
SLRAna[Gy_itemset[i]][CID] = new Table('r', Find_pro(item));
}
}
for (int i = 0; i < Pindex; i++)
{
if (isFinalsymbol(dfa[i].symbol))//symbol为非终结符 添加状态N
{
int CID = FindID(Nchar, dfa[i].symbol);
SLRAna[dfa[i].from][CID + Echar.Count] = new Table('N', dfa[i].to);
}
else //不是归约项目 添加状态S
{
int CID = FindID(Echar, dfa[i].symbol);
SLRAna[dfa[i].from][CID] = new Table('S', dfa[i].to);
}
}
}
public List<char> GetFollow(char c)
{
List<char> follow = new List<char>();
if (c == 'E')
follow.Add('#');
foreach (SLRNode node in SLRproNum)
{
int index = node.Right.IndexOf(c);
if (index != -1 && index < node.Right.Length - 1)
{
char next = node.Right[index + 1];
if (isFinalsymbol(next))
follow.Add(next);
else
{
List<char> first = GetFirst(next);
if (first.Contains('#'))
{
first.Remove('#');
follow.AddRange(first);
follow.AddRange(GetFollow(node.Left[0]));
}
else
{
follow.AddRange(first);
}
}
}
else if (index != -1 && index == node.Right.Length - 1)
{
follow.AddRange(GetFollow(node.Left[0]));
}
}
follow = follow.Distinct().ToList();
return follow;
}
public List<char> GetFirst(char c)
{
List<char> first = new List<char>();
if (isFinalsymbol(c))
first.Add(c);
else
{
foreach (SLRNode node in SLRproNum)
{
if (node.Left[0] == c)
{
if (node.Right[0] == c)
continue;
else if (isFinalsymbol(node.Right[0]))
first.Add(node.Right[0]);
else
{
List<char> subFirst = GetFirst(node.Right[0]);
if (subFirst.Contains('#'))
{
subFirst.Remove('#');
first.AddRange(subFirst);
first.AddRange(GetFirst(node.Right[1]));
}
else
{
first.AddRange(subFirst);
}
}
}
}
}
first = first.Distinct().ToList();
return first;
}
该代码实现了一个 SLR1 分析表构建算法,并验证了其正确性。
代码解释:
- Creteitemsets() 函数: 该函数用于构建 SLR1 分析表所需的项目集。
- 使用 Closure() 函数计算项目集的闭包,即包含所有可达项目的集合。
- 使用循环遍历每个项目集,寻找所有可移动的点 ('.'),并创建新的项目集。
- 使用 isexist() 函数判断新创建的项目集是否已存在,若不存在则添加到项目集列表 proitemset 中。
- GET_ANA() 函数: 该函数用于生成 SLR1 分析表。
- 使用 SLRAnaly() 函数构建分析表。
- 使用循环遍历每个状态和每个符号,将分析表中的信息输出到字符串 RStr_ANA 中。
- SLRAnaly() 函数: 该函数用于根据项目集构建分析表。
- 使用循环遍历每个项目集,找到所有可规约项目,并添加规约操作到分析表中。
- 使用循环遍历每个 DFA 状态,根据 DFA 状态的符号,添加移进或规约操作到分析表中。
- GetFollow() 函数: 该函数用于计算非终结符的 FOLLOW 集。
- 使用循环遍历所有产生式,查找非终结符的位置,计算其 FOLLOW 集。
- GetFirst() 函数: 该函数用于计算非终结符的 FIRST 集。
- 使用循环遍历所有产生式,查找非终结符的位置,计算其 FIRST 集。
优化建议:
- 可以使用更简洁的代码来实现项目的排序和查找,例如使用 SortedSet 或 HashSet。
- 可以将一些重复的代码提取到独立的函数中,提高代码的可读性和可维护性。
- 可以添加更多的注释,解释代码的逻辑和功能。
- 可以使用单元测试来验证代码的正确性。
该代码实现了一个完整的 SLR1 分析表构建算法,并提供了详细的注释和解释。 通过优化代码结构和添加单元测试,可以进一步提高代码的质量和可维护性。
原文地址: http://www.cveoy.top/t/topic/f0MH 著作权归作者所有。请勿转载和采集!