{ "title": "C# LL(1) 语法分析器实现 - 句法分析功能", "description": "本文介绍了使用 C# 实现 LL(1) 语法分析器的代码,并展示了如何通过按钮操作进行句法分析,并以步骤的形式在 ListView 中显示分析过程。", "keywords": "LL(1) 语法分析, C# 实现, 句法分析, 预测分析表, 分析过程展示", "content": "```csharp private void button7_Click(object sender, EventArgs e) { string text = textBox1.Text; analyze();

// 在界面第二行之后展示步骤、分析串、剩余输入串、推导所用产生式或匹配
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 analyze() { // 获取产生式、非终结符、终结符、FIRST集、FOLLOW集、预测分析表 Dictionary<string, List> production = getProduction(); List nonterminals = getNonTerminals(); List terminals = getTerminals(); Dictionary<string, List> firsts = getFirsts(production); Dictionary<string, List> follows = getFollows(production, firsts, nonterminals); Dictionary<string, Dictionary<string, string>> table = getTable(production, firsts, follows, nonterminals, terminals);

// 初始化分析栈和输入栈
Stack<char> analyseStack = new Stack<char>();
Stack<char> inputStack = new Stack<char>();
analyseStack.Push('#');
inputStack.Push('#');
for (int i = text.Length - 1; i >= 0; i--)
{
    inputStack.Push(text[i]);
}

// 初始化分析结果列表
List<string> resultAnalyse = new List<string>();
List<string> resultInput = new List<string>();
List<string> resultParse = new List<string>();

// 将开始符号加入分析栈
analyseStack.Push(nonterminals[0][0]);

// 进行LL(1)语法分析
while (true)
{
    // 如果分析栈栈顶元素为终结符
    if (IsTerminal(analyseStack.Peek()))
    {
        // 当两个栈都只剩下#时,说明匹配成功
        if (analyseStack.Peek() == inputStack.Peek() && analyseStack.Count() == 1 && inputStack.Count() == 1)
        {
            resultParse.Add("成功");
            break;
        }
        if (analyseStack.Peek() == inputStack.Peek())
        {
            resultParse.Add('"' + analyseStack.Peek() + '"' + "匹配");
            analyseStack.Pop();
            inputStack.Pop();
            resultAnalyse.Add(analyseStack.getString());
            resultInput.Add(inputStack.getString());
            continue;
        }
        else
        {
            resultParse.Add("失败");
            break;
        }
    }

    string nonterminal = analyseStack.Peek().ToString();
    string terminal = inputStack.Peek().ToString();

    // 如果分析表中没有该产生式,则匹配失败
    if (!table.ContainsKey(nonterminal) || !table[nonterminal].ContainsKey(terminal))
    {
        resultParse.Add("失败");
        break;
    }

    // 获取推导产生式
    string production = table[nonterminal][terminal];
    resultParse.Add(nonterminal + "->" + production);

    // 将推导产生式中的符号压入分析栈
    analyseStack.Pop();
    if (!production.Equals("#"))
    {
        for (int i = production.Length - 1; i >= 0; i--)
            analyseStack.Push(production[i]);
    }

    // 更新分析栈和输入栈的变化
    resultAnalyse.Add(analyseStack.getString());
    resultInput.Add(inputStack.getString());
}

// 将分析结果添加到 ListView 中
for (int i = 0; i < resultAnalyse.Count; i++)
{
    ListViewItem item = new ListViewItem(new string[] { (i + 1).ToString(), resultAnalyse[i], resultInput[i], resultParse[i] });
    listView4.Items.Add(item);
}

}


**按钮功能说明:**

* **button7:** 触发分析过程,将 textBox1 中输入的字符串进行 LL(1) 语法分析,并将分析结果显示在 listView4 中。
* **button8:** 单步显示分析信息,点击一次按钮,在 listView4 中显示一个分析步骤。
* **button9:** 一键显示分析信息,点击按钮,将所有分析步骤一次性显示在 listView4 中。

**分析函数:**

```csharp
private void analyze()
{
    // 获取产生式、非终结符、终结符、FIRST集、FOLLOW集、预测分析表
    Dictionary<string, List<string>> production = getProduction();
    List<string> nonterminals = getNonTerminals();
    List<string> terminals = getTerminals();
    Dictionary<string, List<string>> firsts = getFirsts(production);
    Dictionary<string, List<string>> follows = getFollows(production, firsts, nonterminals);
    Dictionary<string, Dictionary<string, string>> table = getTable(production, firsts, follows, nonterminals, terminals);

    // 初始化分析栈和输入栈
    Stack<char> analyseStack = new Stack<char>();
    Stack<char> inputStack = new Stack<char>();
    analyseStack.Push('#');
    inputStack.Push('#');
    for (int i = text.Length - 1; i >= 0; i--)
    {
        inputStack.Push(text[i]);
    }

    // 初始化分析结果列表
    List<string> resultAnalyse = new List<string>();
    List<string> resultInput = new List<string>();
    List<string> resultParse = new List<string>();

    // 将开始符号加入分析栈
    analyseStack.Push(nonterminals[0][0]);

    // 进行LL(1)语法分析
    while (true)
    {
        // 如果分析栈栈顶元素为终结符
        if (IsTerminal(analyseStack.Peek()))
        {
            // 当两个栈都只剩下#时,说明匹配成功
            if (analyseStack.Peek() == inputStack.Peek() && analyseStack.Count() == 1 && inputStack.Count() == 1)
            {
                resultParse.Add("成功");
                break;
            }
            if (analyseStack.Peek() == inputStack.Peek())
            {
                resultParse.Add('"' + analyseStack.Peek() + '"' + "匹配");
                analyseStack.Pop();
                inputStack.Pop();
                resultAnalyse.Add(analyseStack.getString());
                resultInput.Add(inputStack.getString());
                continue;
            }
            else
            {
                resultParse.Add("失败");
                break;
            }
        }

        string nonterminal = analyseStack.Peek().ToString();
        string terminal = inputStack.Peek().ToString();

        // 如果分析表中没有该产生式,则匹配失败
        if (!table.ContainsKey(nonterminal) || !table[nonterminal].ContainsKey(terminal))
        {
            resultParse.Add("失败");
            break;
        }

        // 获取推导产生式
        string production = table[nonterminal][terminal];
        resultParse.Add(nonterminal + "->" + production);

        // 将推导产生式中的符号压入分析栈
        analyseStack.Pop();
        if (!production.Equals("#"))
        {
            for (int i = production.Length - 1; i >= 0; i--)
                analyseStack.Push(production[i]);
        }

        // 更新分析栈和输入栈的变化
        resultAnalyse.Add(analyseStack.getString());
        resultInput.Add(inputStack.getString());
    }

    // 将分析结果添加到 ListView 中
    for (int i = 0; i < resultAnalyse.Count; i++)
    {
        ListViewItem item = new ListViewItem(new string[] { (i + 1).ToString(), resultAnalyse[i], resultInput[i], resultParse[i] });
        listView4.Items.Add(item);
    }
}

注意:

  • 需要将 getProduction()getNonTerminals()getTerminals()getFirsts()getFollows()getTable() 等函数实现,以获取产生式、非终结符、终结符、FIRST 集、FOLLOW 集和预测分析表。
  • getString() 函数是 Stack 类的一个扩展方法,用于将栈中的元素转换为字符串。
  • 为了实现单步显示功能,需要在 analyze() 函数中添加判断语句,根据按钮的状态来控制分析过程的执行。

代码示例:

// 获取产生式
private Dictionary<string, List<string>> getProduction()
{
    // 在这里定义产生式
    // 例如:
    Dictionary<string, List<string>> production = new Dictionary<string, List<string>>
    {
        { "S", new List<string> { "A", "B", "C" } },
        { "A", new List<string> { "a", "S" } },
        { "B", new List<string> { "b", "A" } },
        { "C", new List<string> { "c", "B" } }
    };
    return production;
}

// 获取非终结符
private List<string> getNonTerminals()
{
    // 在这里定义非终结符
    // 例如:
    List<string> nonterminals = new List<string> { "S", "A", "B", "C" };
    return nonterminals;
}

// 获取终结符
private List<string> getTerminals()
{
    // 在这里定义终结符
    // 例如:
    List<string> terminals = new List<string> { "a", "b", "c", "#" };
    return terminals;
}

// 计算 FIRST 集
private Dictionary<string, List<string>> getFirsts(Dictionary<string, List<string>> production)
{
    // 在这里实现计算 FIRST 集的逻辑
    // 例如:
    Dictionary<string, List<string>> firsts = new Dictionary<string, List<string>>();
    // ...
    return firsts;
}

// 计算 FOLLOW 集
private Dictionary<string, List<string>> getFollows(Dictionary<string, List<string>> production, Dictionary<string, List<string>> firsts, List<string> nonterminals)
{
    // 在这里实现计算 FOLLOW 集的逻辑
    // 例如:
    Dictionary<string, List<string>> follows = new Dictionary<string, List<string>>();
    // ...
    return follows;
}

// 获取预测分析表
private Dictionary<string, Dictionary<string, string>> getTable(Dictionary<string, List<string>> production, Dictionary<string, List<string>> firsts, Dictionary<string, List<string>> follows, List<string> nonterminals, List<string> terminals)
{
    // 在这里实现获取预测分析表的逻辑
    // 例如:
    Dictionary<string, Dictionary<string, string>> table = new Dictionary<string, Dictionary<string, string>>();
    // ...
    return table;
}

通过以上代码示例和说明,您可以根据自己的需要调整和完善 LL(1) 语法分析器的实现。


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

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