C# 句法分析器 - LL(1) 文法分析
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;
private void button4_Click(object sender, EventArgs e)
{
string text = richTextBox1.Text;
production = new Dictionary<string, List<string>>();
string[] pro = text.Split('
');
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;
}
private void GetFirst(string symbol, Dictionary<string, List<string>> production1, Dictionary<string, List<string>> firsts1)
{
// 如果该非终结符的 FIRST 集已经被计算出,则直接返回
if (firsts1.ContainsKey(symbol))
{
return;
}
firsts1.Add(symbol, new List<string>());
// 遍历产生式,计算 FIRST 集
foreach (var prod in production1[symbol])
{
// 如果产生式首字符为终结符,则直接将其加入 FIRST 集中
if (prod.Length > 0 && IsTerminal(prod[0]))
{
if (!firsts1[symbol].Contains(prod[0].ToString()))
firsts1[symbol].Add(prod[0].ToString());
continue;
}
// 如果产生式首字符为非终结符,则计算该非终结符的 FIRST 集,并将结果加入首字符的 FIRST 集中
else if (prod.Length > 0 && !IsTerminal(prod[0]))
{
GetFirst(prod[0].ToString(), production1, firsts1);
foreach (var f in firsts1[prod[0].ToString()])
{
if (!firsts1[symbol].Contains(f) && !f.Equals('#'))
firsts1[symbol].Add(f);
}
}
//如果第一个非终结符能推出#
if (IsReachEmpty(prod[0].ToString(), production1))
{
// 递归计算第二个和后面的字符的 FIRST 集,并将结果加入该非终结符的 FIRST 集中
for (int j = 1; j < prod.Length; j++)
{
if (IsTerminal(prod[j]))
{
if (!firsts1[symbol].Contains(prod[j].ToString()))
firsts1[symbol].Add(prod[j].ToString());
break;
}
GetFirst(prod[j].ToString(), production1, firsts1);
foreach (var f in firsts1[prod[j].ToString()])
{
if (!firsts1[symbol].Contains(f) && !f.Equals('#'))
firsts1[symbol].Add(f);
}
// 如果该非终结符的 FIRST 集没有包含空串,则可以结束循环
if (!IsReachEmpty(prod[j].ToString(), production1))
{
break;
}
// 如果是最后一个字符且所有非终结符的 FIRST 集都含有空串,则将空串加入该非终结符的 FIRST 集中
if (j == prod.Length - 1)
{
if (!firsts1[symbol].Contains("#"))
firsts1[symbol].Add("#");
}
}
}
}
}
// 计算 FOLLOW 集
private void GetFollow(string symbol, Dictionary<string, List<string>> production1, Dictionary<string, List<string>> firsts1, Dictionary<string, List<string>> follows1)
{
// 如果该非终结符的 FOLLOW 集已经被计算出,则直接返回
if (follows1.ContainsKey(symbol))
{
return;
}
follows1.Add(symbol, new List<string>());
// 如果是起始符号,则将 # 加入 FOLLOW 集中
if (symbol.Equals(production1.Keys.First()))
{
if (!follows1[symbol].Contains("#"))
follows1[symbol].Add("#");
}
// 遍历产生式,计算 FOLLOW 集
foreach (var item in production1)
{
foreach (var prod in item.Value)
{
int index = prod.IndexOf(symbol);
if (index == -1)
continue;
// 如果该非终结符位于产生式末尾,则将产生式左部的 FOLLOW 集加入该非终结符的 FOLLOW 集中
if (index == prod.Length - 1)
{
GetFollow(item.Key, production1, firsts1, follows1);
foreach (var f in follows1[item.Key])
{
if (!follows1[symbol].Contains(f))
follows1[symbol].Add(f);
}
}
else
{
// 如果该非终结符后面是终结符,则将该终结符加入该非终结符的 FOLLOW 集中
if (IsTerminal(prod[index + 1]))
{
if (!follows1[symbol].Contains(prod[index + 1].ToString()))
follows1[symbol].Add(prod[index + 1].ToString());
}
// 如果该非终结符后面是非终结符,则将该非终结符的 FIRST 集加入该非终结符的 FOLLOW 集中
else
{
GetFirst(prod[index + 1].ToString(), production1, firsts1);
foreach (var f in firsts1[prod[index + 1].ToString()])
{
if (!f.Equals("#") && !follows1[symbol].Contains(f))
follows1[symbol].Add(f);
}
// 如果该非终结符后面的所有符号都能推出空串,则将产生式左部的 FOLLOW 集加入该非终结符的 FOLLOW 集中
if (IsReachEmpty(prod[index + 1].ToString(), production1))
{
GetFollow(item.Key, production1, firsts1, follows1);
foreach (var f in follows1[item.Key])
{
if (!follows1[symbol].Contains(f))
follows1[symbol].Add(f);
}
}
}
}
}
}
}
private void GetSelect(Dictionary<string, List<string>> production1, Dictionary<string, List<string>> firsts1, Dictionary<string, List<string>> follows1)
{
//对非终结符的每个产生式获取select值
//如果该产生式第一个字符为终结符
//如果该产生式第一个字符为非终结符
// 对每个非终结符进行操作
// 对每个非终结符进行遍历
foreach (var nonterm in nonterminals)
{
// 获取该非终结符的所有产生式
var productions = production1[nonterm];
// 遍历该非终结符的所有产生式
foreach (var prod in productions)
{
// 初始化该产生式的 select 值
List<string> select = new List<string>();
// 如果该产生式的第一个字符为终结符,直接将该字符加入 select
if (IsTerminal(prod[0]))
{
if (prod[0].Equals('#'))
{
// 如果该产生式的第一个字符为 #,将 follow(nonterm) 加入 select
select.AddRange(follows1[nonterm]);
}
else
{
// 如果该产生式的第一个字符为其他终结符,将该终结符加入 select
select.Add(prod[0].ToString());
}
}
else
{
// 如果该产生式的第一个字符为非终结符,将该非终结符的 first 集加入 select
select.AddRange(firsts1[prod[0].ToString()]);
// 如果该非终结符的 first 集中包含空串,将 follow(nonterm) 加入 select
if (select.Contains("#"))
{
select.Remove("#");
select.AddRange(follows1[nonterm]);
}
}
// 将该产生式的 select 值加入预测分析表中
foreach (var term in select)
{
table[nonterm][term] = prod;
}
}
}
}
private void button7_Click(object sender, EventArgs e)
{
// 获取输入的句子
string text = textBox1.Text;
// 创建分析器
analyse_sentence analyser = new analyse_sentence(text, select);
// 显示单步分析结果
for (int i = 0; i < analyser.result_analys.Count; i++)
{
listView4.Items.Add(new ListViewItem(new string[] { analyser.result_analys[i], analyser.result_input[i], analyser.result_parse[i] }));
}
}
private void button8_Click(object sender, EventArgs e)
{
// 获取输入的句子
string text = textBox1.Text;
// 创建分析器
analyse_sentence analyser = new analyse_sentence(text, select);
// 显示一键分析结果
for (int i = 0; i < analyser.result_analys.Count; i++)
{
listView4.Items.Add(new ListViewItem(new string[] { analyser.result_analys[i], analyser.result_input[i], analyser.result_parse[i] }));
}
// 显示最终结果
if (analyser.result_parse.Last() == "成功")
{
MessageBox.Show("该句子符合语法规则!");
}
else
{
MessageBox.Show("该句子不符合语法规则!");
}
}
private void button9_Click(object sender, EventArgs e)
{
// 获取输入的句子
string text = textBox1.Text;
// 创建分析器
analyse_sentence analyser = new analyse_sentence(text, select);
// 清空 listView4
listView4.Items.Clear();
// 显示一键分析结果
for (int i = 0; i < analyser.result_analys.Count; i++)
{
listView4.Items.Add(new ListViewItem(new string[] { analyser.result_analys[i], analyser.result_input[i], analyser.result_parse[i] }));
}
// 显示最终结果
if (analyser.result_parse.Last() == "成功")
{
MessageBox.Show("该句子符合语法规则!");
}
else
{
MessageBox.Show("该句子不符合语法规则!");
}
}
}
}
代码说明
- 预处理:
button4_Click事件处理函数负责读取文法规则,计算 FIRST 集合、FOLLOW 集合以及 SELECT 集合,并构建预测分析表。 - 分析:
analyse_sentence类负责进行句法分析,包含analyseresult方法用于执行分析过程,并记录分析步骤、输入栈和解析步骤。 - 显示结果:
button7_Click事件处理函数实现单步分析功能,button8_Click和button9_Click事件处理函数实现一键分析功能,并将分析结果显示在listView4中。
补充说明
- 代码中的
select是预测分析表,需要在代码中初始化。 - 代码中使用了
Stack和List数据结构,分别用于模拟分析栈和结果列表。 - 代码中的
IsTerminal方法用于判断字符是否为终结符,IsReachEmpty方法用于判断非终结符是否可以推导出空串。 - 为了完成功能,需要根据具体的需求和界面设计进行调整。
总结
该代码实现了一个基本的 LL(1) 句法分析器,可以根据输入的句子判断其是否符合语法规则,并显示分析过程。通过代码分析,可以了解 LL(1) 语法分析的原理和实现方法。
原文地址: https://www.cveoy.top/t/topic/fXKg 著作权归作者所有。请勿转载和采集!