C# LL(1) 语法分析器实现 - 句法分析功能
{ "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
// 初始化分析栈和输入栈
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 著作权归作者所有。请勿转载和采集!