编译原理课程实验的实验课内容—构造自底向上LR(0)的语法分析程序。通过本次实验,可以熟练掌握对于LR(0)分析表的构造方法。
(1)掌握 LR(0)分析表的构造方法。
(2)掌握设计、编制和调试典型的语法分析程序,进一步掌握常用的语法分析方法。
(3)理解语法分析在编译程序中的作用。
编写一个程序对输入的源代码进行语法分析,并打印分析结果。
自己编写一个基于 LR(0)方法的语法分析程序。语言不限,文法不限。 此时可根据自己的实际情况,选择以下一项实现分析算法中分析表的构造:
(1)直接输入根据已知文法构造的 LR(0)分析表;
(2)输入已知文法的项目集规范族和转换函数,由程序自动生成 LR(0)分析表;
(3)输入已知文法,由程序自动生成 LR(0)分析表。
你的程序输入是一个包含待分析词法单元序列的文本 文件,程序需要能够接收一个输入文件名作为参数,以获得相应的输出结果。
你的程序需要输出语法分析过程(包括 LR(0)分析表和分析过程表,并能够保 存 LR(0)分析表)和相应的分析结果(即此串是否为 LR(0)文法的句子)
对输入串的分析:
本次LR(0)分析表采用的是课本P136页表6.3的LR(0)分析表。程序的整体设计思路上,首先分为几个主要的函数来实现查找LR(0)分析表,对确定的输入串进行LR(0)分析过程。 同时,还要有出错判断的提示,这个我计划放在对输入串的分析过程中一并实现,另一个是保存当前的LR(0)分析表,这个功能放在输出LR(0)分析表的函数中实现。
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
//本次LR(0)的文法样例采用课本P136页表6.3的LR(0)分析表
///表格数组 a b c d # E A B
char LR0[50][50][100] = { {"S2" ,"S3" ,"null", "null" ,"null" ,"1" ,"null" ,"null"},//0
{"null" ,"null" ,"null", "null" ,"acc " ,"null" ,"null" ,"null"},//1
{"null" ,"null" ,"S4" , "S10" ,"null" ,"null" ,"6" ,"null"},//2
{"null" ,"null" ,"S5" , "S11" ,"null" ,"null" ,"null" ,"7" },//3
{"null" ,"null" ,"S4" , "S10" ,"null" ,"null" ,"8" ,"null"},//4
{"null" ,"null" ,"S5" , "S11" ,"null" ,"null" ,"null" ,"9" },//5
{"r1" ,"r1" ,"r1" , "r1" ,"r1" ,"null" ,"null" ,"null"},//6
{"r2" ,"r2" ,"r2" , "r2" ,"r2" ,"null" ,"null" ,"null"},//7
{"r3" ,"r3" ,"r3" , "r3" ,"r3" ,"null" ,"null" ,"null"},//8
{"r5" ,"r5" ,"r5" , "r5" ,"r5" ,"null" ,"null" ,"null"},//9
{"r4" ,"r4" ,"r4" , "r4" ,"r4" ,"null" ,"null" ,"null"},//10
{"r6" ,"r6" ,"r6" , "r6" ,"r6" ,"null" ,"null" ,"null"},//11
//单个容量是100的字符串,总共50行,50列
};
char L[200] = "abcd#EAB"; ///列判断依据
int del[10] = { 0,2,2,2,1,2,1 };//0-6号文法每个文法长度
char head[20] = { 'S','E','E','A','A','B','B' };
stack<int>con; ///状态栈
stack<char>cmp; ///符号栈
char cod[300] = "0";///初始状态栈对应输出数组
int cindex = 0;
char sti[300] = "#"; ///初始符号栈对应输出数组
int sindex = 0;
int findL(char b)///对应列寻找
{
for (int i = 0; i <= 7; i++)
{
if (b == L[i])
{
return i;
}
}
return -1;
}
void error(int x, int y) //报错输出
{
printf("第%d行%c列为空!", x, L[y]);
}
int calculate(int l, char s[]) //计算移入或者归约的数字
{
int num = 0;
for (int i = 1; i < l; i++)
{
num = num * 10 + (s[i] - '0');
}
return num;
}
void analyze(string str, int len) //分析主体过程,第一个参数为要分析的字符串,第二个参数为字符串长度
{
int cnt = 1;
printf("步骤 状态栈 符号栈 输入串 ACTION GOTO\n");
int LR = 0;
while (LR <= len) //还没有分析到结尾
{
printf("(%d) %-10s%-10s", cnt, cod, sti); //步骤,状态栈,符号栈输出
cnt++;
for (int i = LR; i < len; i++) //输入串输出,只输出目前没有分析的部分
{
cout << str[i];
}
for (int i = len - LR; i < 10; i++)cout<<" ";
int x = con.top(); //状态栈栈顶
int y = findL(str[LR]); //待判断当前串的串首元素
if (strcmp(LR0[x][y], "null") != 0) //当前状态不为空,进入下一步分析
{
int l = strlen(LR0[x][y]); //当前Ri或Si的长度
if (LR0[x][y][0] == 'a') //acc,归约结束,返回
{
printf("acc \n"); ///ACTION与GOTO
return;
}
else if (LR0[x][y][0] == 'S') //Si,移入操作
{
printf("%-10s \n", LR0[x][y]); //ACTION与GOTO
int t = calculate(l, LR0[x][y]); //计算移入的是状态几的操作
con.push(t); //将移入的状态入栈
sindex++; //符号栈指针加1
sti[sindex] = str[LR]; //新字符移入符号栈
cmp.push(str[LR]);
if (t < 10)
{
cindex++;
cod[cindex] = LR0[x][y][1]; //输出状态栈,移入几
}
else //t是两位数
{
int k = 1;
cindex++;
cod[cindex] = '(';
while (k < l) //k小于L
{
cindex++;
cod[cindex] = LR0[x][y][k];
k++;
}
cindex++;
cod[cindex] = ')';
}
LR++;
}
else if (LR0[x][y][0] == 'r') ///ri,退栈,ACTION和GOTO
{
printf("%-10s", LR0[x][y]);
int t = calculate(l, LR0[x][y]);
int g = del[t]; //要回退多少个符号
while (g--)
{
con.pop();
cmp.pop();
sti[sindex] = '\0';
sindex--;
}
g = del[t];
while (g > 0)
{
if (cod[cindex] == ')')
{
cod[cindex] = '\0';
cindex--;
for (;;)
{
if (cod[cindex] == '(')
{
cod[cindex] = '\0';
cindex--;
break;
}
else
{
cod[cindex] = '\0';
cindex--;
}
}
g--;
}
else
{
cod[cindex] = '\0';
cindex--;
g--;
}
}///
cmp.push(head[t]);
sindex++;
sti[sindex] = head[t];
x = con.top();
y = findL(cmp.top());
t = LR0[x][y][0] - '0';
con.push(t);
cindex++;
cod[cindex] = LR0[x][y][0];
printf("%-10d\n", t);
}
}
else //当前状态为空,出错处理
{
error(x, y);
cout << endl;
cout << "程序分析结束,遇到语法错误!" << endl;
exit(0);
///报错
}
}
}
void chart()///测试表函数
{
string file = ("文法.txt");
ifstream input(file);
string grammar;
cout << "文法如下:" << endl;
while (!input.eof())
{
getline(input, grammar);
cout << grammar << endl;
}
input.close();
cout << endl;
file = ("LR(0).txt");
ofstream output(file, ios::trunc);
cout << "LR(0)分析表:" << endl;
output << "LR(0)分析表:" << endl;
cout << "---------------------------------------------------------------------" << endl;
printf("-\ta\tb\tc\td\t#\tE\tA\tB\n");
output << "-\ta\tb\tc\td\t#\tE\tA\tB\n";
for (int i = 0; i <= 11; i++)
{
cout << "---------------------------------------------------------------------" << endl;
printf("%d", i);
output << i;
for (int j = 0; j <= 8; j++)
{
printf("\t%s", LR0[i][j]);
output << "\t" << LR0[i][j];
}
cout << endl;
output << endl;
}
cout <<"---------------------------------------------------------------------"<< endl;
output.close();
}
int main()
{
chart(); //先构造分析表,采取直接构造的方式
con.push(0); //0进入状态栈
cmp.push('#'); //#句首符号进入状态栈
string str; //输入串
cout << "读取的字符串为:" << endl;
string file = ("测试样例1.txt");
ifstream input(file);
input >> str;
cout << str << endl;
input.close();
int len = str.length();
analyze(str, len);
return 0;
}
(寒假打算发一下的,结果后来一直拖到现在,忽然想起,还是赶快发一下)
参考博客:https://blog.csdn.net/wys5wys/article/details/85128812