语法分析程序的设计与实现
环境
- win10
- vscode
- mingw
综述
共实现了三种语法分析程序,即LL1、SLR1和LR1语法分析程序,对满足条件的输入文法能够自动的生成该文法的语法分析程序并执行分析过程,输出所采用的产生式。源代码
对于LL1语法分析程序有以下功能(要求输入文法为LL1文法)
- 自动构建FIRST集
- 自动构建FOLLOW集
- 自动构建预测分析表
- 执行分析程序分析输入串
- 输出所采用的产生式
对于SLR1分析程序有以下功能(要求输入文法为SLR1文法)
- 自动构建FIRST集
- 自动构建FOLLOW集
- 自动构建有效项目集规范族和DFA
- 自动构建SLR1分析表
- 执行分析程序分析输入串
- 输出所采用的产生式
对于LR1分析程序有以下功能(要求输入文法为LR1文法)
- 自动构建FIRST集
- 自动构建有效项目集规范族和DFA
- 自动构建LR1分析表
- 执行分析程序分析输入串
- 输出所采用的产生式
三种语法分析程序均要求输入的文法符号为单个字符,请将原文法符号不是单个字符自行更换为单文法符号,如S’更换为A,id更换为n,以此类推。具体输入格式见每个程序测试部分的输入样例。
LL1语法分析程序
数据结构
/* 产生式结构体 */
struct Production {
char left; // 左部符号
vector<char> rigths; // 右部符号串
};
/* 文法结构体 */
struct Grammar {
int num; // 产生式数量
vector<char> T; // 终结符集
vector<char> N; // 非终结符集
vector<Production> prods; //产生式集
} grammar;
/* FIRST集和FOLLOW集 */
map<char, set<char> > first;
map<char, set<char> > follow;
/* 分析栈 */
stack<char> ST;
/* 待分析串 */
string str;
/* 预测分析表 */
vector<char> M[50][50];
辅助函数
/* 判断ch是否是终结符, 若是返回所在位置 */
int isInT(char ch);
/* 判断ch是否是非终结符, 若是返回所在位置 */
int isInN(char ch);
/* 读入并初始化语法 */
void initGrammar();
/* 把生成式插入到预测分析表对应的项中 */
void insertTOForecastAnalysisTable(char A, char a, Production &P);
/* 取出预测分析表对应的项中的产生式 */
void getFromForecastAnalysisTable(char A, char a, vector<char> &s);
构建FIRST集和FOLLOW集
求单个文法符号的FIRST集
/* 求(T U N)的FIRST集 */
void getFirstSet()
{
/* 终结符的FIRST集是其本身 */
for (int i = 0; i < grammar.T.size(); i++) {
char X = grammar.T[i];
set<char> tmp;
tmp.insert(X);
first[X] = tmp;
}
/* 当非终结符的FIRST集发生变化时循环 */
bool change = true;
while (change) {
change = false;
/* 枚举每个产生式 */
for (int i = 0; i < grammar.prods.size(); i++) {
Production &P = grammar.prods[i];
char X = P.left;
set<char> &FX = first[X];
/* 如果右部第一个符号是空或者是终结符,则加入到左部的FIRST集中 */
if (isInT(P.rigths[0]) || P.rigths[0] == '&') {
/* 查找是否FIRST集是否已经存在该符号 */
auto it = FX.find(P.rigths[0]);
/* 不存在 */
if (it == FX.end()) {
change = true; // 标注FIRST集发生变化,循环继续
FX.insert(P.rigths[0]);
}
} else {
/* 当前符号是非终结符,若当前符号可以推出空,则还需判断下一个符号 */
bool next = true;
/* 待判断符号的下标 */
int idx = 0;
while (next && idx < P.rigths.size()) {
next = false;
char Y = P.rigths[idx];
set<char> &FY = first[Y];
for (auto it = FY.begin(); it != FY.end(); it++) {
/* 把当前符号的FIRST集中非空元素加入到左部符号的FIRST集中 */
if (*it != '&') {
auto itt = FX.find(*it);
if (itt == FX.end()) {
change = true;
FX.insert(*it);
}
}
}
/* 当前符号的FIRST集中有空, 标记next为真,idx下标+1 */
auto it = FY.find('&');
if (it != FY.end()) {
next = true;
idx = idx + 1;
}
}
}
}
}
}
求一串文法符号的FIRST集
要求FIRST( α \alpha α),先将 α \alpha α的第一个文法符号的FIRST集加入到加入到FIRST( α \alpha α),若当前符号的FIRST集含空,则继续将下一个文法符号的FIRST加入到FIRST( α \alpha α)中,直至末尾。
/* 产找alpha串的FIRST集, 保存到FS集合中 */
void getFirstByAlphaSet(vector<char> &alpha, set<char> &FS)
{
/* 当前符号是非终结符,若当前符号可以推出空,则还需判断下一个符号 */
bool next = true;
int idx = 0;
while (idx < alpha.size() && next) {
next = false;
/* 当前符号是终结符或空,加入到FIRST集中 */
if (isInT(alpha[idx]) || alpha[idx] == '&') {
/* 判断是否已经在FIRST集中 */
auto itt = FS.find(alpha[idx]);
if (itt == FS.end()) {
FS.insert(alpha[idx]);
}
} else {
char B = alpha[idx];
set<char> &FB = first[B];
for (auto it = first[B].begin