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;

}

注意:

  1. isTerminal()isNonterminal() 函数用来判断字符是否为终结符或非终结符,需要根据具体的语法定义实现。
  2. FindID() 函数用来查找字符在对应集合中的序号,需要根据具体的语法定义实现。
  3. GotoTable() 函数用来计算GOTO状态,需要根据具体的语法定义实现。
  4. followfirst1 是字典,用来存储每个符号的follow集和first1集。
  5. SLRproNumSLRobjNum 分别是产生式列表和项目列表,proitemset 是项目集合列表,需要根据具体的语法定义初始化。
  6. Gy_objGy_itemset 分别是归约项目序号集合和含有归约项目的集合的序号集合,需要根据具体的语法定义初始化。

总结

本文提供了使用C#代码构造SLR文法分析表的详细步骤和代码示例,希望能够帮助读者理解SLR文法分析表的构造过程。需要注意的是,具体的实现代码需要根据具体的语法定义进行调整。

SLR文法分析表构造详解 - C#代码实现

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

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