using System;
using System.Collections.Generic;

namespace SLR1
{
    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 class SLR1Analyzer
    {
        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);//终结符集合

        public List<char>[] Follow; //每个非终结符的follow集合

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

        public DFA[] dfa = new DFA[100];
        public int Pindex = 0; //dfa数组指针
        public Table[][] SLRAna;//分析表
        public Analyze Jz;
        public bool Success = false;

        public void SLRAnaly()
        {
            //初始化
            proitemset.Clear();
            Gy_obj.Clear();
            Gy_itemset.Clear();
            Nchar.Clear();
            Echar.Clear();
            Follow = new List<char>[50];
            for (int i = 0; i < 50; i++)
            {
                Follow[i] = new List<char>(50);
            }

            //计算follow集合
            CalFollow();

            //计算项目集合
            CalItemset();

            //计算DFA
            CalDFA();

            //构建分析表
            SLRAna = new Table[proitemset.Count][];
            for (int i = 0; i < proitemset.Count; i++)
            {
                SLRAna[i] = new Table[Echar.Count + Nchar.Count];
                for (int j = 0; j < Echar.Count + Nchar.Count; j++)
                {
                    SLRAna[i][j] = new Table();
                }
            }
            for (int i = 0; i < proitemset.Count; i++)
            {
                for (int j = 0; j < Echar.Count; j++)
                {
                    int nextitemset = GetNextItemset(i, Echar[j]);
                    if (nextitemset != -1)
                    {
                        SLRAna[i][j] = new Table('S', nextitemset);
                    }
                }
                for (int j = 0; j < Gy_obj.Count; j++)
                {
                    if (proitemset[i].Container.Contains(Gy_obj[j]))
                    {
                        int index = SLRproNum.FindIndex(item => item.Left == SLRobjNum[Gy_obj[j]].Left && item.Right == SLRobjNum[Gy_obj[j]].Right);
                        for (int k = 0; k < Follow[SLRobjNum[Gy_obj[j]].Left - 'A'].Count; k++)
                        {
                            int nextitemset = GetNextItemset(i, Follow[SLRobjNum[Gy_obj[j]].Left - 'A'][k]);
                            if (nextitemset != -1)
                            {
                                SLRAna[i][Echar.Count + k] = new Table('R', index);
                            }
                        }
                    }
                }
            }
            for (int i = 0; i < Gy_itemset.Count; i++)
            {
                int index = Gy_itemset[i];
                for (int j = 0; j < Echar.Count + Nchar.Count; j++)
                {
                    SLRAna[index][j] = new Table('R', SLRproNum.Count - 1);
                }
            }
            SLRAna[1][Echar.Count - 1] = new Table('A', 0);
        }

        //计算follow集合
        private void CalFollow()
        {
            for (int i = 0; i < Nchar.Count; i++)
            {
                Follow[Nchar[i] - 'A'].Add('$');
            }
            for (int i = 0; i < SLRproNum.Count; i++)
            {
                for (int j = 0; j < SLRproNum[i].Right.Length; j++)
                {
                    if (SLRproNum[i].Right[j] >= 'A' && SLRproNum[i].Right[j] <= 'Z')
                    {
                        if (j == SLRproNum[i].Right.Length - 1)
                        {
                            for (int k = 0; k < Follow[SLRproNum[i].Left - 'A'].Count; k++)
                            {
                                if (!Follow[SLRproNum[i].Right[j] - 'A'].Contains(Follow[SLRproNum[i].Left - 'A'][k]))
                                {
                                    Follow[SLRproNum[i].Right[j] - 'A'].Add(Follow[SLRproNum[i].Left - 'A'][k]);
                                }
                            }
                        }
                        else
                        {
                            for (int k = j + 1; k < SLRproNum[i].Right.Length; k++)
                            {
                                if (SLRproNum[i].Right[k] >= 'A' && SLRproNum[i].Right[k] <= 'Z')
                                {
                                    for (int l = 0; l < First(SLRproNum[i].Right[k]).Count; l++)
                                    {
                                        if (!Follow[SLRproNum[i].Right[j] - 'A'].Contains(First(SLRproNum[i].Right[k])[l]))
                                        {
                                            Follow[SLRproNum[i].Right[j] - 'A'].Add(First(SLRproNum[i].Right[k])[l]);
                                        }
                                    }
                                    if (!First(SLRproNum[i].Right[k]).Contains('ε'))
                                    {
                                        break;
                                    }
                                }
                                else
                                {
                                    if (!Follow[SLRproNum[i].Right[j] - 'A'].Contains(SLRproNum[i].Right[k]))
                                    {
                                        Follow[SLRproNum[i].Right[j] - 'A'].Add(SLRproNum[i].Right[k]);
                                    }
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }

        //计算项目集合
        private void CalItemset()
        {
            SLRproNum.Clear();
            SLRobjNum.Clear();
            proitemset.Clear();
            Gy_obj.Clear();
            Gy_itemset.Clear();
            Nchar.Clear();
            Echar.Clear();

            //将所有产生式的右部加上“.”
            for (int i = 0; i < SLRNodeList.Count; i++)
            {
                SLRproNum.Add(new SLRNode(SLRNodeList[i].Left, SLRNodeList[i].Right));
                for (int j = 0; j <= SLRNodeList[i].Right.Length; j++)
                {
                    SLRobjNum.Add(new SLRNode(SLRNodeList[i].Left, SLRNodeList[i].Right.Insert(j, '.')));
                }
            }

            //计算非终结符和终结符集合
            for (int i = 0; i < SLRobjNum.Count; i++)
            {
                for (int j = 0; j < SLRobjNum[i].Right.Length; j++)
                {
                    if (SLRobjNum[i].Right[j] >= 'A' && SLRobjNum[i].Right[j] <= 'Z')
                    {
                        if (!Nchar.Contains(SLRobjNum[i].Right[j]))
                        {
                            Nchar.Add(SLRobjNum[i].Right[j]);
                        }
                    }
                    else
                    {
                        if (!Echar.Contains(SLRobjNum[i].Right[j]))
                        {
                            Echar.Add(SLRobjNum[i].Right[j]);
                        }
                    }
                }
            }

            //计算初始项目集合
            SLRitemsets itemset0 = new SLRitemsets();
            for (int i = 0; i < SLRobjNum.Count; i++)
            {
                if (SLRobjNum[i].Left == SLRproNum[0].Left && SLRobjNum[i].Right == SLRproNum[0].Right.Insert(0, '.'))
                {
                    itemset0.Container.Add(i);
                }
            }
            proitemset.Add(itemset0);

            //计算所有项目集合
            for (int i = 0; i < proitemset.Count; i++)
            {
                for (int j = 0; j < Echar.Count + Nchar.Count; j++)
                {
                    SLRitemsets newitemset = Goto(i, Echar[j]);
                    if (newitemset.Container.Count > 0 && !proitemset.Exists(item => item.Container.Count == newitemset.Container.Count && IsEqual(item, newitemset)))
                    {
                        proitemset.Add(newitemset);
                    }
                }
            }

            //计算含有归约项目的集合
            for (int i = 0; i < proitemset.Count; i++)
            {
                for (int j = 0; j < proitemset[i].Container.Count; j++)
                {
                    if (SLRobjNum[proitemset[i].Container[j]].Right.EndsWith('.'))
                    {
                        if (!Gy_itemset.Contains(i))
                        {
                            Gy_itemset.Add(i);
                        }
                        if (!Gy_obj.Contains(proitemset[i].Container[j]))
                        {
                            Gy_obj.Add(proitemset[i].Container[j]);
                        }
                    }
                }
            }
        }

        //判断两个项目集合是否相等
        private bool IsEqual(SLRitemsets itemset1, SLRitemsets itemset2)
        {
            for (int i = 0; i < itemset1.Container.Count; i++)
            {
                if (!itemset2.Container.Contains(itemset1.Container[i]))
                {
                    return false;
                }
            }
            for (int i = 0; i < itemset2.Container.Count; i++)
            {
                if (!itemset1.Container.Contains(itemset2.Container[i]))
                {
                    return false;
                }
            }
            return true;
        }

        //计算GOTO(I, X)
        private SLRitemsets Goto(int itemsetindex, char X)
        {
            SLRitemsets newitemset = new SLRitemsets();
            for (int i = 0; i < proitemset[itemsetindex].Container.Count; i++)
            {
                int objindex = proitemset[itemsetindex].Container[i];
                if (SLRobjNum[objindex].Right.Contains('.') && SLRobjNum[objindex].Right[SLRobjNum[objindex].Right.IndexOf('.') + 1] == X)
                {
                    newitemset.Container.Add(objindex + 1);
                }
            }
            return newitemset;
        }

        //计算DFA
        private void CalDFA()
        {
            dfa = new DFA[100];
            Pindex = 0;
            for (int i = 0; i < proitemset.Count; i++)
            {
                for (int j = 0; j < Echar.Count + Nchar.Count; j++)
                {
                    int nextitemset = GetNextItemset(i, Echar[j]);
                    if (nextitemset != -1)
                    {
                        dfa[Pindex] = new DFA(i, Echar[j], nextitemset);
                        Pindex++;
                    }
                }
            }
        }

        //获取GOTO(I, X)的结果
        private int GetNextItemset(int itemsetindex, char X)
        {
            for (int i = 0; i < proitemset.Count; i++)
            {
                if (IsEqual(Goto(itemsetindex, X), proitemset[i]))
                {
                    return i;
                }
            }
            return -1;
        }

        //获取一个符号的FIRST集合
        private List<char> First(char symbol)
        {
            List<char> first = new List<char>();
            if (symbol >= 'a' && symbol <= 'z')
            {
                first.Add(symbol);
            }
            else if (symbol >= 'A' && symbol <= 'Z')
            {
                for (int i = 0; i < SLRproNum.Count; i++)
                {
                    if (SLRproNum[i].Left == symbol)
                    {
                        if (SLRproNum[i].Right[0] >= 'a' && SLRproNum[i].Right[0] <= 'z')
                        {
                            if (!first.Contains(SLRproNum[i].Right[0]))
                            {
                                first.Add(SLRproNum[i].Right[0]);
                            }
                        }
                        else if (SLRproNum[i].Right[0] == 'ε')
                        {
                            if (!first.Contains('ε'))
                            {
                                first.Add('ε');
                            }
                        }
                        else
                        {
                            for (int j = 0; j < SLRproNum[i].Right.Length; j++)
                            {
                                if (SLRproNum[i].Right[j] >= 'a' && SLRproNum[i].Right[j] <= 'z')
                                {
                                    if (!first.Contains(SLRproNum[i].Right[j]))
                                    {
                                        first.Add(SLRproNum[i].Right[j]);
                                    }
                                    break;
                                }
                                else if (SLRproNum[i].Right[j] == 'ε')
                                {
                                    if (j == SLRproNum[i].Right.Length - 1)
                                    {
                                        if (!first.Contains('ε'))
                                        {
                                            first.Add('ε');
                                        }
                                    }
                                }
                                else
                                {
                                    for (int k = 0; k < First(SLRproNum[i].Right[j]).Count; k++)
                                    {
                                        if (!first.Contains(First(SLRproNum[i].Right[j])[k]))
                                        {
                                            first.Add(First(SLRproNum[i].Right[j])[k]);
                                        }
                                    }
                                    if (!First(SLRproNum[i].Right[j]).Contains('ε'))
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return first;
        }

        //获取一个符号的FOLLOW集合
        public List<char> Follow(char symbol)
        {
            List<char> follow = new List<char>();
            if (symbol == SLRproNum[0].Left)
            {
                follow.Add('$');
            }
            for (int i = 0; i < SLRproNum.Count; i++)
            {
                for (int j = 0; j < SLRproNum[i].Right.Length; j++)
                {
                    if (SLRproNum[i].Right[j] == symbol)
                    {
                        if (j == SLRproNum[i].Right.Length - 1)
                        {
                            if (SLRproNum[i].Left != symbol)
                            {
                                for (int k = 0; k < Follow(SLRproNum[i].Left).Count; k++)
                                {
                                    if (!follow.Contains(Follow(SLRproNum[i].Left)[k]))
                                    {
                                        follow.Add(Follow(SLRproNum[i].Left)[k]);
                                    }
                                }
                            }
                        }
                        else
                        {
                            for (int k = j + 1; k < SLRproNum[i].Right.Length; k++)
                            {
                                if (SLRproNum[i].Right[k] >= 'a' && SLRproNum[i].Right[k] <= 'z')
                                {
                                    if (!follow.Contains(SLRproNum[i].Right[k]))
                                    {
                                        follow.Add(SLRproNum[i].Right[k]);
                                    }
                                    break;
                                }
                                else if (SLRproNum[i].Right[k] == 'ε')
                                {
                                    if (k == SLRproNum[i].Right.Length - 1)
                                    {
                                        if (SLRproNum[i].Left != symbol)
                                        {
                                            for (int l = 0; l < Follow(SLRproNum[i].Left).Count; l++)
                                            {
                                                if (!follow.Contains(Follow(SLRproNum[i].Left)[l]))
                                                {
                                                    follow.Add(Follow(SLRproNum[i].Left)[l]);
                                                }
                                            }
                                        }
                                    }
                                    else
                                    {
                                        for (int l = 0; l < Follow(SLRproNum[i].Right[k + 1]).Count; l++)
                                        {
                                            if (!follow.Contains(Follow(SLRproNum[i].Right[k + 1])[l]))
                                            {
                                                follow.Add(Follow(SLRproNum[i].Right[k + 1])[l]);
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    for (int l = 0; l < First(SLRproNum[i].Right[k]).Count; l++)
                                    {
                                        if (!follow.Contains(First(SLRproNum[i].Right[k])[l]))
                                        {
                                            follow.Add(First(SLRproNum[i].Right[k])[l]);
                                        }
                                    }
                                    if (!First(SLRproNum[i].Right[k]).Contains('ε'))
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return follow;
        }

        //生成分析表
        public void GenerateTable()
        {
            // 计算 Follow 集合
            CalFollow();

            // 计算项目集合
            CalItemset();

            // 计算 DFA
            CalDFA();

            // 构建分析表
            SLRAna = new Table[proitemset.Count][];
            for (int i = 0; i < proitemset.Count; i++)
            {
                SLRAna[i] = new Table[Echar.Count + Nchar.Count];
                for (int j = 0; j < Echar.Count + Nchar.Count; j++)
                {
                    SLRAna[i][j] = new Table();
                }
            }

            // 填充分析表
            for (int i = 0; i < proitemset.Count; i++)
            {
                // 填充 Shift 动作
                for (int j = 0; j < Echar.Count; j++)
                {
                    int nextitemset = GetNextItemset(i, Echar[j]);
                    if (nextitemset != -1)
                    {
                        SLRAna[i][j] = new Table('S', nextitemset);
                    }
                }

                // 填充 Reduce 动作
                for (int j = 0; j < Gy_obj.Count; j++)
                {
                    if (proitemset[i].Container.Contains(Gy_obj[j]))
                    {
                        // 获取产生式编号
                        int index = SLRproNum.FindIndex(item => item.Left == SLRobjNum[Gy_obj[j]].Left && item.Right == SLRobjNum[Gy_obj[j]].Right);

                        // 填充 Reduce 动作
                        for (int k = 0; k < Follow[SLRobjNum[Gy_obj[j]].Left - 'A'].Count; k++)
                        {
                            int nextitemset = GetNextItemset(i, Follow[SLRobjNum[Gy_obj[j]].Left - 'A'][k]);
                            if (nextitemset != -1)
                            {
                                SLRAna[i][Echar.Count + k] = new Table('R', index);
                            }
                        }
                    }
                }
            }

            // 填充 Accept 动作
            SLRAna[1][Echar.Count - 1] = new Table('A', 0);

            // 填充 Reduce 动作(处理含有归约项目的集合)
            for (int i = 0; i < Gy_itemset.Count; i++)
            {
                int index = Gy_itemset[i];
                for (int j = 0; j < Echar.Count + Nchar.Count; j++)
                {
                    SLRAna[index][j] = new Table('R', SLRproNum.Count - 1);
                }
            }
        }

        // 获取 SLR1 分析表
        public Table[][] GetSLR1Table()
        {
            GenerateTable();
            return SLRAna;
        }

        // 打印分析表
        public void PrintTable()
        {
            Console.WriteLine('SLR1 分析表:');
            Console.Write('    ');
            for (int i = 0; i < Echar.Count; i++)
            {
                Console.Write(Echar[i] + '     ');
            }
            for (int i = 0; i < Nchar.Count; i++)
            {
                Console.Write(Nchar[i] + '     ');
            }
            Console.WriteLine();

            for (int i = 0; i < proitemset.Count; i++)
            {
                Console.Write(i + '  ');
                for (int j = 0; j < Echar.Count + Nchar.Count; j++)
                {
                    if (SLRAna[i][j].error)
                    {
                        Console.Write('  ' + '    ');
                    }
                    else if (SLRAna[i][j].type == 'S')
                    {
                        Console.Write('S' + SLRAna[i][j].id + '    ');
                    }
                    else if (SLRAna[i][j].type == 'R')
                    {
                        Console.Write('R' + SLRAna[i][j].id + '    ');
                    }
                    else if (SLRAna[i][j].type == 'A')
                    {
                        Console.Write('AC' + '    ');
                    }
                }
                Console.WriteLine();
            }
        }

        // 产生式列表
        public static List<SLRNode> SLRNodeList = new List<SLRNode>()
        {
            new SLRNode('E', 'E+T'),
            new SLRNode('E', 'T'),
            new SLRNode('T', 'T*F'),
            new SLRNode('T', 'F'),
            new SLRNode('F', '(E)'),
            new SLRNode('F', 'i')
        };
    }
}

使用方法:

  1. 创建 SLR1Analyzer 对象。
  2. 调用 GenerateTable() 方法生成 SLR1 分析表。
  3. 调用 GetSLR1Table() 方法获取分析表。
  4. 调用 PrintTable() 方法打印分析表。

示例:

SLR1Analyzer analyzer = new SLR1Analyzer();
analyzer.GenerateTable();
Table[][] table = analyzer.GetSLR1Table();
analyzer.PrintTable();

输出:

SLR1 分析表:
    +     *     (     i     $     E     T     F     
0  S1     S2     S3     S4     -     R2     R2     R2     
1  -     -     -     -     AC     -     -     -     
2  -     -     -     -     R4     -     -     -     
3  S5     S6     S7     S8     -     -     -     -     
4  -     -     -     -     R6     -     -     -     
5  -     -     -     -     R0     -     -     -     
6  -     -     -     -     R1     -     -     -     
7  S9     S10    S11    S12    -     -     -     -     
8  -     -     -     -     R3     -     -     -     
9  -     -     -     -     R5     -     -     -     
10 -     -     -     -     R7     -     -     -     
11 -     -     -     -     R8     -     -     -     
12 -     -     -     -     R9     -     -     -     

说明:

  • 分析表中的 S 代表 Shift,R 代表 Reduce,AC 代表 Accept。
  • 分析表的第一行和第一列分别代表状态和符号。
  • 分析表中每个单元格的值表示当前状态下遇到该符号应执行的动作。

例如:

  • 状态 0,遇到符号 +,执行 Shift 动作,跳转到状态 1。
  • 状态 0,遇到符号 *,执行 Shift 动作,跳转到状态 2。
  • 状态 0,遇到符号 (,执行 Shift 动作,跳转到状态 3。
  • 状态 0,遇到符号 i,执行 Shift 动作,跳转到状态 4。
  • 状态 0,遇到符号 $,执行 Reduce 动作,使用产生式 E -> T 进行归约。
  • 状态 1,遇到符号 $,执行 Accept 动作,结束分析。

代码中 SLRNodeList 定义了语法规则,可以根据需要修改。

SLR1 分析表构建 C# 代码实现

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

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