C# LL(1) 语法分析器实现:按钮功能详解

本示例代码展示了使用 C# 实现 LL(1) 语法分析器的核心功能,并重点讲解了三个按钮的实现逻辑:

  1. button7_Click 函数: 实现对 textBox1 中输入字符的分析功能,判断其是否为该文法的句子。
  2. button8_Click 函数: 在界面第二行之后展示分析过程的每一步,包括步骤、分析串、剩余输入串、推导所用产生式或匹配。点击“下一步”按钮可以查看分析过程的下一步,直到分析结束。
  3. button9_Click 函数: 在界面第二行之后自动展示完整的分析过程,直到分析结束。

以下是代码示例:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace byyljxfzxt
{
    public partial class Form4 : Form
    {
        public Form4()
        {
            InitializeComponent();
        }

        //--------------------预处理
        Dictionary<string, List<string>> production;
        Dictionary<string, List<string>> firsts;
        Dictionary<string, List<string>> follows;
        Dictionary<string, List<string>> selects;
        Dictionary<string, Dictionary<string, string>> table;
        List<string> terminals;
        List<string> nonterminals;

        Stack<char> analyse; // 分析栈
        Stack<char> input; // 输入栈
        List<string> result_analys; // 分析栈的每一步变化
        List<string> result_input; // 输入栈的每一步变化
        List<string> result_parse; // 每一步分析的结果,包括推导所用产生式或匹配成功/失败的信息
        private int step = 0;

       

        private void button4_Click(object sender, EventArgs e)
        {
            string text = richTextBox1.Text;
            production = new Dictionary<string, List<string>>();
            string[] pro = text.Split('\n');
            foreach (string s in pro)
            {
                if (s == '') continue;

                Regex.Replace(s, ' ', '');
                string[] ga = Regex.Split(s, '->');
                if (ga.Length != 2) return;
                if (ga[0].Length == 0 || ga[1].Length == 0)
                    return;
                if (ga[0].Length != 1 || !char.IsUpper(ga[0][0])) return;

                string[] ga2 = Regex.Split(ga[1], '\|');
                if (!production.ContainsKey(ga[0]))
                    production.Add(ga[0], new List<string>());
                foreach (string s1 in ga2)
                    production[ga[0]].Add(s1);
            }

            firsts = new Dictionary<string, List<string>>();
            foreach (var item in production.Keys)
                GetFirst(item, production, firsts);

            follows = new Dictionary<string, List<string>>();
            foreach (var item in production.Keys)
                GetFollow(item, production, firsts, follows);


            if (JudgeLL1(production, firsts, follows))
            {
                MessageBox.Show('该文法是LL(1)文法\n');

            }
            else
            {
                MessageBox.Show('该文法不是LL(1)文法,存在左递归或者存在FIRST集合有交集的情况!\n');
            }
            button1.Enabled = true;
            button2.Enabled = true;
            button6.Enabled = true;
            button7.Enabled = true;

        }
private void button7_Click(object sender, EventArgs e)
        {
            // 判断输入是否为空
            if (string.IsNullOrWhiteSpace(textBox1.Text))
            {
                MessageBox.Show('输入为空,分析失败');
                return;
            }


            // 初始化分析器
            

            listView4.Columns.Clear();
            listView4.Items.Clear();
            listView4.View = View.Details;


            listView4.Columns.Add('步骤', 60, HorizontalAlignment.Center);
            listView4.Columns.Add('分析串', 60, HorizontalAlignment.Center);
            listView4.Columns.Add('剩余输入串', 80, HorizontalAlignment.Center);
            listView4.Columns.Add('推导所用产生式或匹配', 150, HorizontalAlignment.Center);

            button8.Enabled = true;
            button9.Enabled = true;
        }

        private void button8_Click(object sender, EventArgs e)
        {
            // 在界面第二行之后展示步骤、分析串、剩余输入串、推导所用产生式或匹配
            //点一下按钮对应出来一行结果


        }

        private void button9_Click(object sender, EventArgs e)
        {
            // 自动分析直到分析结束
            button8.Enabled = false;
            button9.Enabled = false;
        }

        // button7_Click 函数实现
        private void button7_Click(object sender, EventArgs e)
        {
            // 判断输入是否为空
            if (string.IsNullOrWhiteSpace(textBox1.Text))
            {
                MessageBox.Show('输入为空,分析失败');
                return;
            }

            // 初始化分析器
            analyse = new Stack<char>();
            input = new Stack<char>();
            result_analys = new List<string>();
            result_input = new List<string>();
            result_parse = new List<string>();

            // 将输入字符串压入输入栈
            string inputStr = textBox1.Text;
            for (int i = inputStr.Length - 1; i >= 0; i--)
            {
                input.Push(inputStr[i]);
            }
            // 将#和文法起始符号压入分析栈
            analyse.Push('#');
            analyse.Push(production.Keys.First()[0]);

            // 初始化ListView
            listView4.Columns.Clear();
            listView4.Items.Clear();
            listView4.View = View.Details;
            listView4.Columns.Add('步骤', 60, HorizontalAlignment.Center);
            listView4.Columns.Add('分析串', 60, HorizontalAlignment.Center);
            listView4.Columns.Add('剩余输入串', 80, HorizontalAlignment.Center);
            listView4.Columns.Add('推导所用产生式或匹配', 150, HorizontalAlignment.Center);

            // 启用自动分析按钮
            button9.Enabled = true;
        }

        // button8_Click 函数实现
        private void button8_Click(object sender, EventArgs e)
        {
            // 检查是否已经分析结束
            if (analyse.Count == 0)
            {
                MessageBox.Show('分析已结束');
                return;
            }

            // 获取当前分析栈和输入栈的状态
            string analysStr = new string(analyse.Reverse().ToArray());
            string inputStr = new string(input.Reverse().ToArray());

            // 获取当前步骤数
            int stepNum = result_analys.Count + 1;

            // 获取当前分析栈顶元素和输入栈顶元素
            char topAnalyse = analyse.Pop();
            char topInput = input.Pop();

            // 分析栈和输入栈的变化
            result_analys.Add(analysStr);
            result_input.Add(inputStr);

            // 判断当前分析栈顶元素是否为终结符
            if (terminals.Contains(topAnalyse))
            {
                // 如果是终结符,判断是否匹配输入栈顶元素
                if (topAnalyse == topInput)
                {
                    // 匹配成功,添加到分析结果中
                    result_parse.Add($'第{stepNum}步:{topAnalyse}匹配成功');
                }
                else
                {
                    // 匹配失败,添加到分析结果中,并结束分析
                    result_parse.Add($'第{stepNum}步:{topAnalyse}与{topInput}不匹配,分析失败');
                    listView4.Items.Add(new ListViewItem(new string[] { stepNum.ToString(), analysStr, inputStr, '分析失败' }));
                    button9.Enabled = false;
                    return;
                }
            }
            else
            {
                // 如果是非终结符,查找当前输入栈顶元素对应的产生式
                string select = table[topAnalyse.ToString()][topInput.ToString()];
                if (select == null)
                {
                    // 如果查找失败,添加到分析结果中,并结束分析
                    result_parse.Add($'第{stepNum}步:{topAnalyse}无法识别{topInput},分析失败');
                    listView4.Items.Add(new ListViewItem(new string[] { stepNum.ToString(), analysStr, inputStr, '分析失败' }));
                    button9.Enabled = false;
                    return;
                }
                else
                {
                    // 如果查找成功,将产生式反转并添加到分析结果中
                    string reverseSelect = new string(select.Reverse().ToArray());
                    result_parse.Add($'第{stepNum}步:{topAnalyse}->{reverseSelect}');

                    // 将产生式压入分析栈
                    foreach (char c in select)
                    {
                        analyse.Push(c);
                    }
                }
            }

            // 添加分析结果到ListView中
            listView4.Items.Add(new ListViewItem(new string[] { stepNum.ToString(), analysStr, inputStr, result_parse.Last() }));
        }

        // button9_Click 函数实现
        private void button9_Click(object sender, EventArgs e)
        {
            // 自动分析直到分析结束
            while (analyse.Count > 0)
            {
                button8_Click(sender, e);
            }
            // 禁用自动分析按钮
            button9.Enabled = false;
        }
    }
}

代码解读:

  1. button7_Click 函数: 主要负责初始化分析器和 ListView,并将输入字符串压入输入栈。该函数调用后,button8 和 button9 按钮被启用,用户可以选择手动分析或自动分析。
  2. button8_Click 函数: 实现一步一步的分析过程,根据当前分析栈顶元素和输入栈顶元素进行匹配或推导。该函数会在 ListView 中添加一行新的分析结果,包括步骤、分析串、剩余输入串、推导所用产生式或匹配结果。如果分析失败,则停止分析过程。
  3. button9_Click 函数: 通过循环调用 button8_Click 函数,实现自动分析直到分析结束。该函数会禁用自动分析按钮,防止用户重复点击。

注意:

  • 本示例代码只包含了分析过程的核心逻辑,具体实现需要根据您的文法和需求进行修改和完善。
  • 建议您阅读相关编译原理书籍或资料,深入了解 LL(1) 语法分析器的原理和实现方法。
  • 您可以根据需要扩展功能,例如添加语法错误提示、错误恢复等功能。
  • 本示例代码使用了 C# 的基本语法和数据结构,您可以根据您的项目需求选择其他编程语言进行实现。

希望本示例代码能够帮助您更好地理解 LL(1) 语法分析器的实现过程。如果您有任何问题,请随时提出。

C# LL(1) 语法分析器实现:按钮功能详解

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

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