LL(1) 语法分析器实现
private void analyze()
{
while (true)
{
// 如果分析栈为空或者输入栈为空,则分析结束
if (analyseStack.Count == 0 || inputStack.Count == 0)
{
break;
}
// 获取分析栈的栈顶元素和输入栈的栈顶元素
char topAnalyse = analyseStack.Peek();
char topInput = inputStack.Peek();
// 如果分析栈的栈顶元素和输入栈的栈顶元素相同,则进行匹配
if (topAnalyse == topInput)
{
// 将匹配的元素从分析栈和输入栈中弹出
analyseStack.Pop();
inputStack.Pop();
// 在分析结果列表中添加匹配信息
resultAnalyse.Add(analyseStack.ToString());
resultInput.Add(inputStack.ToString());
resultParse.Add('"' + topAnalyse + '"' + " 匹配");
}
else
{
// 如果分析栈的栈顶元素为终结符,则出错
if (IsTerminal(topAnalyse))
{
resultParse.Add("出错");
break;
}
else
{
if (!table.ContainsKey(topAnalyse.ToString()) || !table[topAnalyse.ToString()].ContainsKey(topInput.ToString()))
{
resultParse.Add("出错");
break;
}
else
{
// 获取分析表中的产生式
string production = table[topAnalyse.ToString()][topInput.ToString()];
// 如果分析表中没有产生式,则出错
if (production == null)
{
resultParse.Add("出错");
break;
}
else
{
// 将产生式从分析栈中弹出
analyseStack.Pop();
// 如果产生式不是空串,则将产生式中的符号逆序压入分析栈中
if (production != "#" )
{
for (int i = production.Length - 1; i >= 0; i--)
{
analyseStack.Push(production[i]);
}
}
// 在分析结果列表中添加产生式信息
resultAnalyse.Add(analyseStack.ToString());
resultInput.Add(inputStack.ToString());
resultParse.Add(topAnalyse + " -> " + production);
}
}
}
}
}
// 如果分析栈和输入栈都为空,则分析成功
if (analyseStack.Count == 0 && inputStack.Count == 0)
{
resultParse.Add("成功");
}
}
// 预测分析表
private Dictionary<string, Dictionary<string, string>> table;
// 构造函数
public SyntaxAnalyzer(List<Production> productions, List<char> terminals, List<char> nonTerminals)
{
// 构造预测分析表
table = new Dictionary<string, Dictionary<string, string>>();
foreach (var nonTerminal in nonTerminals)
{
table.Add(nonTerminal.ToString(), new Dictionary<string, string>());
foreach (var terminal in terminals)
{
table[nonTerminal.ToString()].Add(terminal.ToString(), null);
}
table[nonTerminal.ToString()].Add("#", null);
}
foreach (var production in productions)
{
string nonTerminal = production.Left.ToString();
foreach (var terminal in production.First)
{
if (terminal != '#')
{
table[nonTerminal][terminal.ToString()] = production.Right;
}
else
{
foreach (var follow in production.Follow)
{
table[nonTerminal][follow.ToString()] = production.Right;
}
}
}
}
}
// 判断是否为终结符
static bool IsTerminal(char symbol)
{
return !char.IsUpper(symbol);
}
代码说明:
- 预测分析表: 代码使用
table字典来存储预测分析表,其中 key 为非终结符,value 为另一个字典,该字典的 key 为终结符,value 为对应的产生式。 - 分析过程: 代码使用
analyseStack和inputStack两个栈来模拟语法分析过程,并使用resultAnalyse、resultInput和resultParse列表来记录分析过程中的信息。 - 分析步骤:
- 获取分析栈和输入栈的栈顶元素。
- 如果两个栈顶元素相同,则进行匹配,并将元素从两个栈中弹出。
- 如果分析栈的栈顶元素为终结符,则出错。
- 如果分析栈的栈顶元素为非终结符,则根据预测分析表获取产生式,并将产生式中的符号逆序压入分析栈中。
- 分析结果: 代码最后会根据分析栈和输入栈的状态判断分析是否成功,并将分析结果记录到
resultParse列表中。
示例:
假设 LL(1) 文法为:
E -> T + E | T
T -> F * T | F
F -> id
预测分析表为:
| | id | + | * | # | | |-------|----|---|---|---|--| | E | T | T | T | T | | | T | F | F | F | F | | | F | id | | | | |
输入字符串为:id + id * id
分析过程:
- 初始化分析栈为
E,输入栈为id + id * id#。 - 根据预测分析表,
E可以推导出T,将T压入分析栈,分析栈变为TE,resultParse列表中添加E -> T。 - 继续根据预测分析表,
T可以推导出F,将F压入分析栈,分析栈变为TFE,resultParse列表中添加T -> F。 - 继续根据预测分析表,
F可以推导出id,将id压入分析栈,分析栈变为TFidE,resultParse列表中添加F -> id。 - 匹配
id,将id从分析栈和输入栈中弹出,分析栈变为TFE,resultParse列表中添加"id" 匹配。 - 继续分析,直到输入栈为空,分析成功。
结果:
resultParse 列表中包含以下内容:
E -> T
T -> F
F -> id
"id" 匹配
E -> T + E
T -> F
F -> id
"id" 匹配
"+" 匹配
T -> F * T
F -> id
"id" 匹配
"*" 匹配
F -> id
"id" 匹配
"#" 匹配
成功
总结:
该代码实现了基于 LL(1) 文法的语法分析器,能够根据预测分析表对输入字符串进行分析,并输出分析结果。代码结构清晰、易于理解,适用于学习和理解语法分析过程。
原文地址: https://www.cveoy.top/t/topic/oBP0 著作权归作者所有。请勿转载和采集!