SLR文法分析表构造详解 - C#代码实现
SLR文法分析表构造详解 - C#代码实现
本文详细介绍了如何使用C#代码构造SLR文法分析表,包括SLRAnaly()函数的修改、follow集和first1集的构造函数,以及调用相关函数的代码示例。
SLRAnaly()函数的修改
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++)//归约项目
{
for (int j = 0; j < Echar.Count; j++)//遍历终结符集合
{
char curChar = Echar[j];
if (follow[LRobjNum[proitemset[Gy_itemset[i]].Container[0]].Left].Contains(curChar))
{
if (SLRAna[Gy_itemset[i]][j].error)//如果是ERROR状态
{
tnode = new Table('r', Find_pro(LRobjNum[proitemset[Gy_itemset[i]].Container[0]]));//添加状态r
SLRAna[Gy_itemset[i]][j] = tnode;
}
else//如果是移进状态
{
Console.WriteLine('移进-归约冲突');
}
}
}
}
for (int i = 0; i < proitemset.Count; i++)//移进项目
{
for (int j = 0; j < Echar.Count; j++)//遍历终结符集合
{
char curChar = Echar[j];
if (SLRAna[i][j].error)//如果是ERROR状态
{
int Goto = GotoTable(i, curChar);//获取GOTO状态
if (Goto != -1)
{
tnode = new Table('S', Goto);//添加状态S
SLRAna[i][j] = tnode;
}
}
else//如果是归约状态
{
Console.WriteLine('归约-移进冲突');
}
}
}
for (int i = 0; i < Gy_obj.Count; i++)//其他归约项目
{
for (int j = 0; j < Echar.Count; j++)//遍历终结符集合
{
char curChar = Echar[j];
if (follow[LRproNum[Gy_obj[i]].Left].Contains(curChar))
{
if (SLRAna[Gy_itemset[Gy_obj[i]]][j].error)//如果是ERROR状态
{
tnode = new Table('r', Gy_obj[i]);//添加状态r
SLRAna[Gy_itemset[Gy_obj[i]]][j] = tnode;
}
else//如果是移进状态或归约状态
{
Console.WriteLine('移进-归约或归约-移进冲突');
}
}
}
}
}
follow集和first1集的构造函数
private void GetFollow()
{
foreach (char c in Nchar)
{
follow[c] = new HashSet<char>();
}
follow[SLRproNum[0].Left].Add('#');//将#加入开始符号的follow集
bool flag = true;
while (flag)
{
flag = false;
foreach (SLRNode node in SLRproNum)
{
int len = node.Right.Length;
for (int i = 0; i < len; i++)
{
if (isNonterminal(node.Right[i]))//当前字符是非终结符
{
HashSet<char> tmp = new HashSet<char>();
if (i == len - 1)//当前字符是产生式右部的最后一个字符
{
tmp.UnionWith(follow[node.Left]);//将左部符号的follow集加入tmp
}
else
{
tmp.UnionWith(first1[node.Right[i + 1]]);//将右部下一个字符的first集加入tmp
if (first1[node.Right[i + 1]].Contains('ε'))//如果右部下一个字符的first集中包含ε
{
tmp.ExceptWith(new HashSet<char> { 'ε' });//将tmp中的ε删除
tmp.UnionWith(follow[node.Left]);//将左部符号的follow集加入tmp
}
}
if (follow[node.Right[i]].UnionWith(tmp))//将tmp加入当前字符的follow集
{
flag = true;//如果当前字符的follow集发生变化,则继续循环
}
}
}
}
}
}
private void GetFirst1()
{
foreach (char c in Nchar)
{
first1[c] = new HashSet<char>();
}
foreach (char c in Echar)
{
first1[c] = new HashSet<char> { c };//将终结符的first集设为自己
}
first1['ε'] = new HashSet<char> { 'ε' };//将ε的first集设为自己
bool flag = true;
while (flag)
{
flag = false;
foreach (SLRNode node in SLRproNum)
{
HashSet<char> tmp = new HashSet<char>();
if (isTerminal(node.Right[0]))//如果产生式右部第一个字符是终结符
{
if (first1[node.Left].Add(node.Right[0]))//将终结符加入左部符号的first集
{
flag = true;//如果左部符号的first集发生变化,则继续循环
}
}
else//如果产生式右部第一个字符是非终结符
{
tmp.UnionWith(first1[node.Right[0]]);//将右部第一个字符的first集加入tmp
for (int i = 1; i < node.Right.Length; i++)
{
if (isNonterminal(node.Right[i - 1]) && first1[node.Right[i - 1]].Contains('ε'))//如果前一个字符是非终结符且它的first集中包含ε
{
tmp.UnionWith(first1[node.Right[i]]);//将当前字符的first集加入tmp
}
else//如果前一个字符不是非终结符或它的first集中不包含ε
{
break;//退出循环
}
}
if (first1[node.Left].UnionWith(tmp))//将tmp加入左部符号的first集
{
flag = true;//如果左部符号的first集发生变化,则继续循环
}
}
}
}
}
调用相关函数的代码
public Table[][] GET_ANA()
{
SLRAnaly();
RStr_ANA += '\r\nSLR分析表:\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 += 'ACC' + ' ';
}
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;
}
注意:
isTerminal()和isNonterminal()函数用来判断字符是否为终结符或非终结符,需要根据具体的语法定义实现。FindID()函数用来查找字符在对应集合中的序号,需要根据具体的语法定义实现。GotoTable()函数用来计算GOTO状态,需要根据具体的语法定义实现。follow和first1是字典,用来存储每个符号的follow集和first1集。SLRproNum和SLRobjNum分别是产生式列表和项目列表,proitemset是项目集合列表,需要根据具体的语法定义初始化。Gy_obj和Gy_itemset分别是归约项目序号集合和含有归约项目的集合的序号集合,需要根据具体的语法定义初始化。
总结
本文提供了使用C#代码构造SLR文法分析表的详细步骤和代码示例,希望能够帮助读者理解SLR文法分析表的构造过程。需要注意的是,具体的实现代码需要根据具体的语法定义进行调整。
原文地址: https://www.cveoy.top/t/topic/f0u9 著作权归作者所有。请勿转载和采集!