LL1 句法分析器:SELECT 集的计算 (C# 代码示例)
public class Select
{
LL1Item LL1Item;
First first;
Follow follow;
Dictionary<string, Dictionary<string, List<string>>> selects;
public Select(LL1Item LL1Item, First first, Follow follow)
{
this.LL1Item = LL1Item;
this.first = first;
this.follow = follow;
selects = new Dictionary<string, Dictionary<string, List<string>>>();
GetSelect();
}
public void GetSelect()
{
var production = LL1Item.getproduction();
foreach (var nofinal in LL1Item.nofinal)
{
selects.Add(nofinal, new Dictionary<string, List<string>>());
//对非终结符的每个产生式获取select值
foreach (var f in production[nofinal])
{
selects[nofinal].Add(f, new List<string>());
for (int i = 0; i < f.Length; i++)
{
//如果该产生式第一个字符为终结符
if (IsTerminal(f[i]))
{
if (f[i].Equals('#'))
{
foreach (var fol in follow.getfollows()[nofinal])
selects[nofinal][f].Add(fol);
}
else if (!selects[nofinal][f].Contains(f[i].ToString()))
selects[nofinal][f].Add(f[i].ToString());
break;
}
//如果该产生式第一个字符为非终结符
else
{
int flag = 0;
foreach (var fir in first.getfirsts()[f[i].ToString()])
{
if (fir.Equals('#'))
flag = 1;
else
{
if (!selects[nofinal][f].Contains(fir))
selects[nofinal][f].Add(fir);
}
}
if (flag == 0) break;
}
if (i == f.Length - 1)
{
foreach (var fol in follow.getfollows()[nofinal])
if (!selects[nofinal][f].Contains(fol))
selects[nofinal][f].Add(fol);
}
}
}
}
}
static bool IsTerminal(char symbol)
{
return !char.IsUpper(symbol);
}
public Dictionary<string, Dictionary<string, List<string>>> getselects()
{
return selects;
}
}
// 计算 SELECT 集的函数 (不使用 LL1Item)
private Dictionary<string, List<string>> GetSelect(Dictionary<string, List<string>> production1, Dictionary<string, List<string>> firsts1, Dictionary<string, List<string>> follows1)
{
// 初始化 SELECT 集
Dictionary<string, List<string>> selects1 = new Dictionary<string, List<string>>();
foreach (var item in production1)
selects1.Add(item.Key, new List<string>());
// 遍历每个产生式,计算对应的 SELECT 集
foreach (var nonterm in production1.Keys)
{
foreach (var prod in production1[nonterm])
{
List<string> select = new List<string>();
bool flag = true;
// 对于产生式中的每个符号,计算其 FIRST 集
foreach (var s in prod)
{
if (IsTerminal(s))
{
select.Add(s.ToString());
flag = false;
break;
}
else
{
GetFirst(s.ToString(), production1, firsts1);
foreach (var f in firsts1[s.ToString()])
{
if (!f.Equals('#') && !select.Contains(f))
select.Add(f);
}
if (!IsReachEmpty(s.ToString(), production1))
{
flag = false;
break;
}
}
}
// 如果产生式中所有符号的 FIRST 集都包含空串,则将 FOLLOW 集加入 SELECT 集中
if (flag)
{
GetFollow(nonterm, production1, firsts1, follows1);
foreach (var f in follows1[nonterm])
{
if (!select.Contains(f))
select.Add(f);
}
}
selects1[nonterm].Add(string.Join("", select.ToArray()));
}
}
return selects1;
}
// 获取符号的 FIRST 集 (需根据具体情况补充)
private void GetFirst(string symbol, Dictionary<string, List<string>> production1, Dictionary<string, List<string>> firsts1)
{
// ...
}
// 判断符号是否能推导出空串 (需根据具体情况补充)
private bool IsReachEmpty(string symbol, Dictionary<string, List<string>> production1)
{
// ...
}
// 获取非终结符的 FOLLOW 集 (需根据具体情况补充)
private void GetFollow(string nonterm, Dictionary<string, List<string>> production1, Dictionary<string, List<string>> firsts1, Dictionary<string, List<string>> follows1)
{
// ...
}
代码说明:
-
GetSelect函数接受三个参数:production1: 产生式集合,表示每个非终结符可以推导出的所有产生式。firsts1: FIRST 集集合,表示每个符号的 FIRST 集。follows1: FOLLOW 集集合,表示每个非终结符的 FOLLOW 集。
-
GetSelect函数首先初始化一个新的字典selects1,用于存储 SELECT 集。 -
然后,函数遍历所有非终结符
nonterm和其对应的产生式prod。 -
对于每个产生式,函数初始化一个新的列表
select用于存储当前产生式的 SELECT 集。 -
函数使用一个
flag变量来判断当前产生式的所有符号的 FIRST 集是否都包含空串。 -
对于产生式中的每个符号
s,函数判断其是否为终结符。- 如果是终结符,直接将该终结符加入
select列表。 - 如果不是终结符,则调用
GetFirst函数获取该非终结符的 FIRST 集,并将其加入select列表,如果该非终结符的 FIRST 集包含空串,则将flag设置为false。
- 如果是终结符,直接将该终结符加入
-
如果
flag仍然为true,表示当前产生式的所有符号的 FIRST 集都包含空串,则调用GetFollow函数获取当前非终结符的 FOLLOW 集,并将其加入select列表。 -
最后,将
select列表中的所有元素拼接成字符串,并加入selects1中。
补充说明:
GetFirst、IsReachEmpty和GetFollow函数需要根据具体的语法规则进行实现,本文示例中并未给出具体的实现代码。- 该代码示例仅供参考,实际应用中需要根据具体的语法规则进行调整。
注意:
- 该代码示例仅包含
GetSelect函数的实现,其他辅助函数需要根据具体需求进行补充。 - 该代码示例中的
IsTerminal函数用于判断字符是否为终结符,实际应用中可能需要根据具体的语法规则进行调整。 - 该代码示例中的
GetSelect函数需要使用预先计算好的 FIRST 集和 FOLLOW 集,实际应用中需要根据具体的语法规则进行计算。
建议:
- 在学习 LL1 句法分析器时,建议先理解 FIRST 集、FOLLOW 集和 SELECT 集的概念,以及如何计算它们。
- 在编写代码时,建议使用一些辅助工具或库来帮助你进行语法分析,例如 ANTLR 或 Yacc。
- 建议使用测试用例来验证你的代码是否正确。
原文地址: http://www.cveoy.top/t/topic/ox8D 著作权归作者所有。请勿转载和采集!