南华大学
计算机学院/软件学院
实 验 报 告
( 2017 ~2018 学年度 大二 第 二 学期 )
课程名称 |
程序设计与编译原理 |
实验名称 |
算符优先分析法设计与实现 |
姓名 |
LFY |
学号 |
2016 |
专业 |
|
班级 |
|
地点 |
|
教师 |
|
1、实验目的及要求
实验目的:
加深对语法分析器工作过程的理解;加强对算符优先分析法实现语法分析程序的掌握;能够采用一种编程语言实现简单的语法分析程序;能够使用自己编写的分析程序对简单的程序段进行语法翻译。
掌握 FirstVT和 LastVT集的算法,算符优先分析表的构造算法及其分析过程,并掌握中间代码产生过程。
掌握算符优先分析法的原理,利用算符优先分析法将赋值语句进行语法分析,翻译成等价的四元式表示。
实验要求:
实验内容:
在实验1的基础上,用算符优先分析法编制语法分析程序,语法分析程序的实现可以采用任何一种编程语言和工具。
1.算术表达式的文法可以是(你可以根据需要适当改变):
E→E+E | E-E | E*E | E/E |(E)| i
2.根据算符优先分析法,将表达式进行语法分析,判断一个表达式是否正确。
3.将赋值语句进行语法分析,翻译成等价的一组基本操作,每一基本操作用四元式表示。
软件、硬件环境
软件:VisualStudio编写、调试并执行实验代码
硬件:普通笔记本电脑,windows10(OS系统)
2.实验步骤
1.定义目标语言的语法规则;
例如:E->E+T|T
T->T*F|F
F->(E)|i
2.求解预测分析方法需要的符号集和分析表;
终极符集合为:{+,*,(,i,)}
非终极符集为:{E,T,F}
算符优先分析表为:
|
+ |
* |
i |
( |
) |
# |
+ |
> |
< |
< |
< |
> |
> |
* |
> |
> |
< |
< |
> |
> |
i |
> |
> |
|
|
> |
> |
( |
< |
< |
< |
< |
= |
|
) |
> |
> |
|
|
> |
> |
# |
< |
< |
< |
< |
|
= |
3.依次读入实验一的分析结果,根据预测分析的方法进行语法分析,直到源程序结束;
4.对遇到的语法错误做出错误处理。
3. 实验内容
流程图 、程序 注意函数思想流程图:
程序:
#include
#include "stdio.h"
#include "stdlib.h"
#include
using namespace std;
char Data[20][20]; //算符优先关系
char s[100]; //模拟符号栈s
char lable[20]; //文法终极符集
char input[100]; //文法输入符号串
char In_str[20][10]; //用于输入串的分析
int k;
char a;
int j;
char q;
int r; //文法规则个数
int r1; //转化后文法规则个数
char st[10][30]; //用来存储文法规则
char first[10][10]; //文法非终结符FIRSTVT集
char last[10][10]; //文法非终结符LASTVT集
int fflag[10] = { 0 }; //标志第i个非终结符的FIRSTVT集是否已求出
int lflag[10] = { 0 }; //标志第i个非终结符的LASTVT集是否已求出
int deal(); //对输入串的分析
int Terminator(char c); //判断字符c是否是终极符
int getIndex(char c); //求字符c在算符优先关系表中的下标
void out(int j, int k, char *s); //打印s栈
void firstvt(char c); //求非终结符c的FIRSTVT集
void lastvt(char c); //求非终结符c的LASTVT集
void table(); //创建文法优先关系表
int main()
{
int i, j, k = 0;
printf("请输入文法规则数:");
cin >> r;
printf("请输入文法规则:\n");
for (i = 0; i> st[i]; //存储文法规则,初始化FIRSTVT集和LASTVT集*/
first[i][0] = 0; /*first[i][0]和last[i][0]分别表示st[i][0]非终极
符的FIRSTVT集和LASTVT集中元素的个数*/
last[i][0] = 0;
}
for (i = 0; i'Z')
{
printf("不是算符文法!\n");
exit(-1);
}
if (st[i][j] >= 'A'&&st[i][j] <= 'Z')
{
if (st[i][j + 1] >= 'A'&&st[i][j + 1] <= 'Z')//两非终结符不能相邻
{
printf("不是算符文法!\n");
exit(-1);
}
}
}
}
for (i = 0; i'Z') && st[i][j] != '-'&&st[i][j] != '>'&&st[i][j] != '|')
lable[k++] = st[i][j];
}
}
lable[k] = '#';//把井号终结符加入到终结符集合里面
lable[k + 1] = '\0';
table();
printf("每个非终结符的FIRSTVT集为:\n"); //输出每个非终结符的FIRSTVT集
for (i = 0; i> input && input != "exit") {
deal();
printf("请输入文法输入符号串以#结束:");
}
system("pause");
}
void table()
{
char text[20][10];
int i, j, k, t, l, x = 0, y = 0;
int m, n;
x = 0;
//求firstvt集和lastvt集
for (i = 0; i';
}
else
{
text[x][y] = st[i][j];
y++;
}
}
text[x][y] = '\0';
x++;
y = 0;
}
r1 = x;//更改转换后文法的数目
printf("转化后的文法为:\n");
for (i = 0; i"
后的转化文法,用于最后的规约)*/
for (i = 0; i';
}
}
}
}
//将#E#开始文法也加上去求出其对应的firstvt和lastvt集。
m = getIndex('#');
for (t = 0; t';
}
Data[n][n] = '=';
}
void firstvt(char c) //求FIRSTVT集
{
int i, j, k, m, n;
for (i = 0; i')//归约
{
out(1, k, s);
printf("%c", a);
out(i + 1, z, input);
printf("规约\n");
do
{
q = s[j];
if (Terminator(s[j - 1]))
j = j - 1;
else j = j - 2;
x = getIndex(s[j]);
y = getIndex(q);
} while (Data[x][y] != '<');
int m, n, N;
for (m = j + 1; m <= k; m++)
{
for (N = 0; N
4.实验结果
书上文法例子
输入串不是文法的句子的情况
其他句子输入情况
5. 实验总结分析
这次的实验花费了我不少时间,但也从中学到了很多,从最初的第一个模块一路走来,也遇到许多挫折,特别是明明逻辑都对却找不到错误的原因的时候,多亏了调试工具。编写这个程序一部分来自于学习的课程要求,另一部分也来自于自己对编程的喜爱,或许正是这种感觉一直支持我到现在吧。代码虽然写完了,可是毕竟也有它的局限性。即便如此,编译原理的处理问题的思想,思考问题的角度,都让我大受启发。对于我们理解编译的过程和具体的实现都是很有帮助的。当然,编译原理博大精深,比如说对于数组的处理、中间代码的生成等很多方面,都值得我们认真揣摩。
虽然实验要求基本达到,但我也知道此实验代码并不是完全个人撰写,也有借鉴网上代码,但我不是抄袭,是看懂之后才仿照的。
虽然用文件读取对照输出比较好,但我这个小程序功能不是很完善,只能实现输入文法规则,输入句子,判断是否是合法句子,所以我还是选择了控制台输入。这样老师就可以直接打开源代码运行,而不会因为打开文件路径不存在而报错了。方便老师检查运行情况。