该代码实现了构建 SLR(1) 分析器所需的各个功能函数,包括:

  1. SLRNode 类:用于存储产生式和项目。

  2. SLRitemsets 类:用于存储项目集。

  3. DFA 结构体:用于存储 DFA 中的一条边。

  4. Table 类:用于存储分析表中的一个结点。

  5. Analyze 类:用于存储分析过程中的状态栈、符号栈、输入串和所用产生式。

  6. Buildprod 函数:用于读入文法并构建产生式和项目。

  7. Creteitemsets 函数:用于构建项目集和 DFA。

  8. Closure 函数:用于求一个项目集的闭包。

  9. Go 函数:用于求一个项目集在某个符号下的转移。

其中,Buildprod 函数读入文法并构建产生式和项目,具体实现如下:

  1. 将拓广文法开始符号 S' 加入产生式列表 SLRproNum 中。

  2. 遍历文法中的每一行,对于每一行的产生式,将其左部非终结符加入非终结符集合 Nchar 中,将其右部加入产生式列表 SLRproNum 中。

  3. 对于每个产生式,构造其所有可能的项目,并加入项目列表 SLRobjNum 中。

  4. 将项目集合的第一个项目集初始化为包含拓广文法开始符号的闭包,然后循环遍历项目集合中的每个项目集,对于每个项目集,遍历所有终结符和非终结符,求出它们的 Go 函数,并判断该函数是否已经在项目集合中出现过,如果出现过,则直接使用该项目集的序号,否则新建一个项目集,并将该函数加入项目集合中。同时,将该函数作为 DFA 中的一条边加入 DFA 数组中。

Creteitemsets 函数用于构建项目集和 DFA,具体实现如下:

  1. 将项目集合的第一个项目集初始化为包含拓广文法开始符号的闭包。

  2. 循环遍历项目集合中的每个项目集,对于每个项目集,求出其所有可能的 Go 函数,并判断该函数是否已经在项目集合中出现过,如果出现过,则直接使用该项目集的序号,否则新建一个项目集,并将该函数加入项目集合中。同时,将该函数作为 DFA 中的一条边加入 DFA 数组中。

Closure 函数用于求一个项目集的闭包,具体实现如下:

  1. 将该项目集中的所有项目加入闭包中。

  2. 循环遍历闭包中的每个项目,对于每个项目,如果其后面的符号为非终结符,则将该非终结符对应的所有产生式的所有可能的项目加入闭包中。

Go 函数用于求一个项目集在某个符号下的转移,具体实现如下:

  1. 遍历该项目集中的每个项目,对于每个项目,如果其后面的符号为给定符号,则将其下一个项目加入转移结果中。

  2. 对转移结果求闭包。

public class SLRNode
{
    public string Left;
    public string Right;
    public SLRNode(string Left, string Right)
    {
        this.Left = Left;
        this.Right = Right;
    }
}
//项目集类
public class SLRitemsets
{
    public List<int> Container
        = new List<int>(100);
    //记录项目在项目集合中的序号
}

//DFA结点
public struct DFA
{
    public int from;
    public char symbol;
    public int to;
    public DFA(int from, char symbol, int to)
    {
        this.from = from;
        this.symbol = symbol;
        this.to = to;
    }
}

//分析表 结点
public class Table
{
    public bool error;//是否为ERROR
    public char type;//结点类型
    public int id;//数值
    public Table()
    {
        this.error = true;
    }
    public Table(char type, int id)
    {
        this.type = type;
        this.id = id;
        this.error = false;
    }
}

//分析句子
public class Analyze
{
    public List<string> stack_state = new List<string>(100);//记录状态栈
    public List<string> stack_symbol = new List<string>(100);//记录符号栈
    public List<string> Input_str = new List<string>(100);//记录输入串
    public List<string> Tran_pro = new List<string>(100);//记录所用产生式
}

public DFA[] dfa = new DFA[100];
public int Pindex = 0; //dfa数组指针
public Table[][] SLRAna;//分析表
public Analyze Jz;
public bool Success = false;
public List<SLRNode> SLRproNum = new List<SLRNode>(50);//产生式 列表
public List<SLRNode> SLRobjNum = new List<SLRNode>(50);//项目 列表
public List<SLRitemsets> proitemset = new List<SLRitemsets>(100);//项目集合
public List<int> Gy_obj = new List<int>(50);//归约项目序号集合
public List<int> Gy_itemset = new List<int>(50);//含有归约项目的集合的序号 的集合
public List<char> Nchar = new List<char>(50);//非终结符集合
public List<char> Echar = new List<char>(50);//终结符集合

Dictionary<char, HashSet<char>> follow = new Dictionary<char, HashSet<char>>();//非终结符的Follow集

public string RStr = '';
public string RStr_obitemset = '';//输出返回
public string RStr_DFA = '';
public string RStr_ANA = '';

public void Buildprod(string str)
{
    SLRNode Lr;
    int i = 0;
    string left = '';
    string right = '';
    left += 'S';
    right += str[0];
    Lr = new SLRNode(left, right);//拓广文法开始
    SLRproNum.Add(Lr);
    while (i < str.Length)
    {
        left = right = '';//还原
        int j = i;
        while (i < str.Length && str[i] != '\r' && str[i] != '\n')//换行符‘\r\n’
        {
            if (str[i] == ' ')
            {
                i++;
                continue;
            }
            if (str[i] == '|')                 //  遇到'|'可构造一条产生式
            {
                Lr = new SLRNode(left, right);
                SLRproNum.Add(Lr);
                right = '';                    //产生式左边相同 右边重新积累
                i++;                           //跳过'|'
                continue;
            }
            if ((i - j) == 0)
            {
                if (!exist(Nchar, str[i]))//如果非终结符集合中不存在str[i],加入Nchar  产生式左边 只有非终结符 不必判断终结符
                    Nchar.Add(str[i]);
                left += str[i++];
            }
            else if (i - j <= 2)
                i++;
            else
            {
                if (isFinalsymbol(str[i]) && !exist(Nchar, str[i]))//如果非终结符集合中不存在str[i],加入Nchar  isfinalsymbol 非终结符返回T 终结符返回F
                    Nchar.Add(str[i]);
                else if (!isFinalsymbol(str[i]) && !exist(Echar, str[i]))//产生式右边 需要判断终结符
                    Echar.Add(str[i]);
                right += str[i++];
            }
        }//while

        i++;//跳过换行符
        if (left != '' && right != '')
        {
            Lr = new SLRNode(left, right);//构造每一行最后一个产生式,不存在'|'时就是该行产生式本身
            SLRproNum.Add(Lr);
        }
    }//while
    Echar.Add('#');

    //构造项目 对产生式集合SLRproNum中的所有产生式都循环插'.'
    SLRNode Lobj;
    for (i = 0; i < SLRproNum.Count; i++)
    {
        left = '';
        right = '';
        for (int j = 0; j <= SLRproNum[i].Right.Length; j++)//j可以等于length  项目共length+1个
        {
            left = SLRproNum[i].Left;
            right = CreObj(SLRproNum[i].Right, j);//在第j个位置插入'.'
            if (j == SLRproNum[i].Right.Length && SLRobjNum.Count != 1)
            {
                //在产生式最后的位置插入. 即为归约项目   项目集中1号位置为接受项目
                Gy_obj.Add(SLRobjNum.Count);//归约项目在项目集中的序号 不用+1 本身就是从0开始的
            }
            Lobj = new SLRNode(left, right);
            SLRobjNum.Add(Lobj);
            left = '';//还原
            right = '';
        }
    }
    Creteitemsets();//项目集
    RStr_obitemset += '\r\n项目集构建:\r\n';
    for (int j = 0; j < proitemset.Count; j++)
    {
        RStr_obitemset += 'I' + j.ToString() + ':' + '\r\n';
        for (i = 0; i < proitemset[j].Container.Count; i++)
        {
            RStr_obitemset += SLRobjNum[proitemset[j].Container[i]].Left.ToString() + '->' + SLRobjNum[proitemset[j].Container[i]].Right.ToString() + '\r\n';
        }
    }
    //return RStr_obitemset;
}

public void Creteitemsets()
{
    //初始化项目集
    SLRitemsets itemset_0 = new SLRitemsets();
    itemset_0.Container.Add(0);
    proitemset.Add(itemset_0);

    //循环遍历项目集
    for (int i = 0; i < proitemset.Count; i++)
    {
        //获取该项目集中所有项目的闭包
        HashSet<int> closure = Closure(proitemset[i]);

        //遍历所有终结符和非终结符,获取它们的Go函数
        foreach (char c in Nchar.Concat(Echar))
        {
            HashSet<int> go = Go(closure, c);
            if (go.Count == 0) continue;

            //判断该Go函数是否已经在项目集中出现过,如果出现过,则直接使用该项目集的序号
            int index = -1;
            for (int j = 0; j < proitemset.Count; j++)
            {
                if (proitemset[j].Container.SetEquals(go))
                {
                    index = j;
                    break;
                }
            }
            if (index == -1)
            {
                //如果该Go函数没有在项目集中出现过,则新建一个项目集
                index = proitemset.Count;
                SLRitemsets itemset = new SLRitemsets();
                itemset.Container = go.ToList();
                proitemset.Add(itemset);
            }
            //添加DFA边
            dfa[Pindex++] = new DFA(i, c, index);
        }
    }
}

public HashSet<int> Closure(SLRitemsets itemset)
{
    HashSet<int> closure = new HashSet<int>(itemset.Container);

    bool flag = true;
    while (flag)
    {
        flag = false;
        foreach (int i in closure)
        {
            SLRNode node = SLRobjNum[i];
            int dotIndex = node.Right.IndexOf('.');
            if (dotIndex == node.Right.Length - 1) continue;

            char nextChar = node.Right[dotIndex + 1];
            if (!Nchar.Contains(nextChar)) continue;

            foreach (SLRNode prod in SLRproNum)
            {
                if (prod.Left == nextChar.ToString())
                {
                    SLRNode newNode = new SLRNode(nextChar.ToString(), '.' + prod.Right);
                    int index = SLRobjNum.IndexOf(newNode);
                    if (index == -1)
                    {
                        index = SLRobjNum.Count;
                        SLRobjNum.Add(newNode);
                    }
                    if (closure.Add(index)) flag = true;
                }
            }
        }
    }
    return closure;
}

public HashSet<int> Go(HashSet<int> itemset, char c)
{
    HashSet<int> go = new HashSet<int>();
    foreach (int i in itemset)
    {
        SLRNode node = SLRobjNum[i];
        int dotIndex = node.Right.IndexOf('.');
        if (dotIndex == node.Right.Length - 1) continue;

        char nextChar = node.Right[dotIndex + 1];
        if (nextChar == c) go.Add(i + 1);
    }
    return Closure(new SLRitemsets() { Container = go.ToList() });
}

// 补充函数:exist、isFinalsymbol、CreObj
private bool exist(List<char> list, char c)
{
    return list.Contains(c);
}
private bool isFinalsymbol(char c)
{
    // 这里需要根据你的语法定义判断是否是终结符,
    // 比如,字母可能是非终结符,其他字符可能是终结符
    return !Char.IsLetter(c);
}
private string CreObj(string str, int index)
{
    return str.Insert(index, '.');
}

注意:

  • 代码中 isFinalsymbol 函数需要根据你的具体文法进行调整,判断字符是否是终结符。
  • 代码中 CreObj 函数用于在给定字符串的指定位置插入'.'。
  • 代码中 Buildprod 函数将拓广文法开始符号加入产生式列表时,使用了 'S',你可以根据自己的文法修改为其他符号。
  • 代码中未实现 SLRAna 分析表的构建,需要根据 DFA 和项目集信息进行构建。
  • 代码中未实现分析句子部分,需要根据构建的分析表进行分析。

希望以上内容对你理解 SLR(1) 分析器的构建有所帮助。

SLR(1) 分析器构建代码解析与补充

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

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