编译原理-算符优先
来源:互联网 发布:工业设计所需软件 编辑:程序博客网 时间:2024/05/18 13:47
一、实验目的
根据文法求出FirstVT和LastVT,构造算法优先表,根据输入二元组判断正确与否
二、实验内容
2.1任务一:构造FIRSTVT,LASTVT
FIRSTVT计算过程:
(1)若有产生式P->a…或者P->Qa…,则a∈FIRSTVT(P);
(2)若a∈FIRSTVT(Q),且有产生式P->Q…,则a∈FIRSTVT(P);
LASTVT计算过程:
(1)若有产生式P->…a或者P->…aQ,则a∈LASTVT(P);
(2)若a∈LASTVT(Q),且有产生式P->…Q,则a∈LASTVT(P);
2.2任务二:构造算符优先表
(1)对形如 P→…ab…和形如P→…aQb…,有a=b;
(2)对形如 P→…aR…,而b∈FIRSTVT(R),有a
2.3任务三:根据输入判断结果
(1)读入当前输入符号
(2)若输入符号为数字,则输入符号进OPND,输入指针后移,转第(1)步
(3)若当前输入符号为终结符,则比较当前字符和符号栈栈顶字符的优先级
(4)若输入符号和栈顶的优先级相同,则输入指针后移,符号栈出栈
(5)若输入符号优先级小于栈顶的优先级,则输入符号入符号栈,输入指针后移
(6)若输入符号优先级大于栈顶的优先级,则从数据栈中弹出两个数,符号栈中弹出符号进行计算,结果压入数据栈。继续判断符号栈栈顶和输入符号的优先级
(7)若输入符号为“#”且符号栈只剩一个“#”时,表示判断成功。
三、实验过程
3.1 开发环境
使用Visual Studio 2015开发win32控制台程序
3.2 数据结构设计
3.2.1 使用的宏定义
#define MAXSIZE 10
#define NUM_VT 7
#define NUM_VN 5
3.2.2 定义的结构体
//栈操作
typedef struct Stack
{
char data[MAXSIZE];
int top;
};
3.3 测试数据设计
3.3.1 文法文件“nick.txt”
S->E
E->E+T
E->T
T->T*F
T->F
F->P^F
F->P
P->(E)
P->i
3.3.2 输入文件“Input.txt”
(i,1)
(+,)
(i,2)
(*,)
(i,3)
(#,)
/**功能:算符优先*作者:王文堃*创建时间:2016/5/15*/#include <iostream>#include <malloc.h>#include <stack>using namespace std;/**任务一:构造FIRSTVT,LASTVT*任务开始时间:2016/5/15*任务结束时间:2016/5/16*//**任务二:构造算符优先表*任务开始时间:2016/5/17*任务完成时间:2016/5/17*//**任务三:根据输入判断结果*任务开始时间:2016/5/17*任务完成时间:2016/5/17*/#define MAXSIZE 10#define NUM_VT 7#define NUM_VN 5char WenFa[MAXSIZE][MAXSIZE]; //存放从文件中读取的文法int g_num_wenfa = 0; //存放文法的个数,初值为0char vt[NUM_VT] = {'+','*','^','i','(',')','#'}; //所有终结符char vn[NUM_VN] = {'E','T','F','P','S'}; //存放所有非终结符int firstvt[NUM_VN][NUM_VT]; //存放每一个非终结符的firstvtint lastvt[NUM_VN][NUM_VT]; //存放每一个非终结符的lastvtint labelofch[MAXSIZE]; //存放已ch打头的所有文法的标号char OPT[NUM_VT][NUM_VT]; //算符优先表char Input[MAXSIZE][MAXSIZE]; //保存输入int g_num_input = 0; //存放输入的个数stack <char> OPTR; //符号栈stack <char> OPND; //数据栈/*-----------------------------------------计算FIRSTVT----------------------------------------*///读取文法bool readfromfile(char* str){ FILE* fp = fopen(str, "r"); if (fp) //succeed { while (EOF != fscanf(fp, "%s", WenFa[g_num_wenfa])) { g_num_wenfa++; } fclose(fp); return true; } else { printf("error to open the file\n"); return false; }}//判断文法中字符是否为终结符int isVt(char ch){ for (int i = 0; i < NUM_VT; i++) { if (ch == vt[i]) { return true; } } return false;}//判断文法中字符是否为非终结符int isVn(char ch){ for (int i = 0; i < NUM_VN; i++) { if (ch == vn[i]) { return true; } } return false;}//找到以ch开头的文法的下标int findit(char ch){ int num = 0; for (int i = 0; i < g_num_wenfa; i++) { if (WenFa[i][0] == ch) labelofch[num++] = i; } return num; //返回以ch开头文法的个数}//将非终结符转换成下标int Vn2num(char ch){ switch (ch) { case 'E': return 0; break; case 'T': return 1; break; case 'F': return 2; break; case 'P': return 3; break; case 'S': return 4; break; default: return -1; }}//将终结符转换成下标int Vt2num(char ch){ switch (ch) { case '+': return 0; break; case '*': return 1; break; case '^': return 2; break; case 'i': return 3; break; case '(': return 4; break; case ')': return 5; break; case '#': return 6; break; default: return -1; }}//求FIRSTVT(ch)void get_firstvt(char ch){ if (isVn(ch)) //对终非结符ch { int firstnum = Vn2num(ch); //ch所对应的编号 int num = findit(ch); //找到以该非终结符开头文法的下标 for (int i = 0; i < num; i++) { char rightfirst = WenFa[labelofch[i]][3]; //取出文法推到的第一个字符 if (isVt(rightfirst)) //该文法推出的第一个字符是终结符 { firstvt[firstnum][Vt2num(rightfirst)] = 1; } else //该文法推出的第一个字符是非终结符 { char rightsc = WenFa[labelofch[i]][4]; if (isVt(rightsc)) //判断该非终结符之后的符号是不是终结符 { firstvt[firstnum][Vt2num(rightsc)] = 1; } if (ch != rightfirst) { get_firstvt(rightfirst); //计算这个非终结符的firstvt集 int newvn = Vn2num(rightfirst); for (int j = 0; j < NUM_VT; j++) { if (firstvt[newvn][j] == 1) { firstvt[firstnum][j] = 1; } } } } } }}//计算所有firstvtvoid do_firstvt(){ for (int i = 0; i < NUM_VN; i++) { get_firstvt(vn[i]); }}//输出firstvt表void output_firstvt(){ int i = 0; printf("---------------firstvt----------------\n"); printf(" "); for (i = 0; i < NUM_VT; i++) { printf("%5c", vt[i]); } printf("\n"); for (i = 0; i < NUM_VN; i++) { printf("%c", vn[i]); for (int j = 0; j < NUM_VT; j++) { printf("%5d", firstvt[i][j]); } printf("\n"); } printf("--------------------------------------\n"); printf("\n");}/*-----------------------------------------计算LASTVT----------------------------------------*///找到下标为num的文法的最后一个字符的下标int get_last(int num){ for (int i = 0; i < MAXSIZE; i++) { if (WenFa[num][i] == '\0') { return (i-1); } }}//求LASTVT(ch)void get_lastvt(char ch){ if (isVn(ch)) //对终非结符ch { int lastnum = Vn2num(ch); //ch所对应的编号 int num = findit(ch); //找到以该非终结符开头文法的下标 for (int i = 0; i < num; i++) { int ilast = get_last(labelofch[i]); char rightlast = WenFa[labelofch[i]][ilast]; //获得文法的最后一个字符 if (isVt(rightlast)) //该文法推出的最后一个字符是终结符 { lastvt[lastnum][Vt2num(rightlast)] = 1; } else //该文法推出的最后一个字符是非终结符 { char rightlastsc = WenFa[labelofch[i]][ilast -1]; //文法倒数第二个字符 if (isVt(rightlastsc)) //判断倒数第二个字符是不是终结符 { lastvt[lastnum][Vt2num(rightlastsc)] = 1; } if (ch != rightlast) { get_lastvt(rightlast); //计算这个非终结符的lastvt集 int newvn = Vn2num(rightlast); for (int j = 0; j < NUM_VT; j++) { if (lastvt[newvn][j] == 1) { lastvt[lastnum][j] = 1; } } } } } }}//计算所有lastvtvoid do_lastvt(){ for (int i = 0; i < NUM_VN; i++) { get_lastvt(vn[i]); }}//输出lastvt表void output_lastvt(){ int i = 0; printf("----------------lastvt----------------\n"); printf(" "); for (i = 0; i < NUM_VT; i++) { printf("%5c", vt[i]); } printf("\n"); for (i = 0; i < NUM_VN; i++) { printf("%c", vn[i]); for (int j = 0; j < NUM_VT; j++) { printf("%5d", lastvt[i][j]); } printf("\n"); } printf("--------------------------------------\n"); printf("\n");}/*----------------------------------------构造算符优先表---------------------------------------*///处理小于的情况,a<FIRSTVT(R)void do_less(char vtch1, char vnch2){ int x = Vt2num(vtch1); //a int i = Vn2num(vnch2); //firstvt表中的行 for (int j = 0; j < NUM_VT; j++) //遍历firstvt表 { if (firstvt[i][j] == 1) OPT[x][j] = '<'; }}//处理大于的情况,LASTVT(R)>avoid do_more(char vnch1, char vtch2){ int y = Vt2num(vtch2); int i = Vn2num(vnch1); for (int j = 0; j < NUM_VT; j++) //遍历LASTVT表 { if (lastvt[i][j] == 1) { OPT[j][y] = '>'; } }}//处理#号void dosharp(){ //添加“#=#” int temp = Vt2num('#'); OPT[temp][temp] = '='; //添加'#'<FIRSTVT(S)、LASTVT(S)>'#' for (int i = 0; i < NUM_VT; i++) { int x = Vn2num('S'); int j = Vt2num('#'); if (firstvt[x][i] == 1) { OPT[j][i] = '<'; } if (lastvt[x][i] == 1) { OPT[i][j] = '>'; } }}//构造算法优先表void OperatorPrecedence(){ int i = 0; //循环变量 for (i = 0; i < g_num_wenfa; i++) //对所有的文法 { int j = 3; //内部循环变量,从推出来的第一个字符开始 while (WenFa[i][j] != '\0') //该文法没有完 { char ch = WenFa[i][j]; if (isVt(ch)) //判断当前字符是不是终结符 { //判断下一个字符是不是终结符 if (isVt(WenFa[i][j + 1])) { //若是,则这两个终结符的优先级相等 OPT[Vt2num(ch)][Vt2num(WenFa[i][j + 1])] = '='; } else { //做小于 do_less(ch, WenFa[i][j + 1]); //继续判断下一个字符是不是终结符 if (isVt(WenFa[i][j + 2])) { //若是,则这两个终结符的优先级依然相等 OPT[Vt2num(ch)][Vt2num(WenFa[i][j + 2])] = '='; } } } else //当前是非终结符 { if (isVt(WenFa[i][j + 1])) //判断下一个字符 { //大于 do_more(ch, WenFa[i][j + 1]); } } j++; } } dosharp(); //处理#}//输出算符优先表void output_OPT(){ int i = 0; printf("------------------OPT-----------------\n"); printf(" "); for (i = 0; i < NUM_VT; i++) { printf("%5c", vt[i]); } printf("\n"); for (i = 0; i < NUM_VT; i++) { printf("%c", vt[i]); for (int j = 0; j < NUM_VT; j++) { printf("%5c", OPT[i][j]); } printf("\n"); } printf("--------------------------------------\n"); printf("\n");}/*---------------------------------------处理输入判断结果---------------------------------------*///从文件中读取输入bool inputformfile(char* str){ FILE* fp = fopen(str, "r"); if (fp) //succeed { while (EOF != fscanf(fp, "%s", Input[g_num_input])) { g_num_input++; } fclose(fp); return true; } else { printf("error to open the file\n"); return false; }}//判断输入字符的类型int judge(char ch){ switch (ch) { case 'i': return 0; //表示数字 break; case '+': return 1; //表示'+'号 break; case '*': return 2; //表示'*'号 break; default: return -1; }}//将int行数字传化成char型int char2int(char ch){ if (ch >= 48 && ch <= 57) //数字 { return ch - 48; }}//处理输入bool doinput(){ int iInput = 0; //指向输入下标 //#入符号栈 OPTR.push('#'); while (iInput != (g_num_input-1) || OPTR.size() != 0) //将输入遍历完 { char* str = Input[iInput]; //取出第一个输入 int result = judge(str[1]); if (result == 0) //数字 { OPND.push(str[3]); } else //是符号 { //判断符号栈顶的符号和当前符号的优先级 int topofstack = Vt2num(OPTR.top()); int topofinput = Vt2num(str[1]); if (OPT[topofstack][topofinput] == '<') //栈顶小于输入就入栈 { OPTR.push(str[1]); } else if (OPT[topofstack][topofinput] == '>')//否则运算 { int i = char2int(OPND.top()); OPND.pop(); int j = char2int(OPND.top()); OPND.pop(); int vtnum = Vt2num(OPTR.top()); if (vtnum == 0) //+ { OPND.push(i + j); OPTR.pop(); } else if (vtnum == 1) //* { OPND.push(i*j); OPTR.pop(); } } else //如果相等就出栈 { OPTR.pop(); } } if (iInput != (g_num_input-1)) { iInput++; } } //判断 if (OPTR.size() == 0) { return true; } else { return false; }}int main(){ if (readfromfile("nick.txt")) { do_firstvt(); //构造firstvt output_firstvt(); //输出firstvt do_lastvt(); //构造lastvt output_lastvt(); //输出lastvt OperatorPrecedence(); //构造算符优先表 output_OPT(); //输出算符优先表 //--- inputformfile("input.txt"); bool result = doinput(); if (result != 0) { printf("最终结果正确\n"); } else { printf("最终结果错误\n"); } } getchar(); return 0;}
最终的运算结果是:
- 编译原理-算符优先
- 编译原理算符优先分析算法
- 编译原理-算符运算优先
- 编译原理——算符优先分析
- 编译原理实验——算符优先算法
- 编译原理实验3-算符优先分析法
- [编译原理]算符优先文法分析与实现
- 简单算符优先文法分析程序(编译原理)
- 编译原理之算符优先分析语法程序
- 编译原理(八) 算符优先分析法-分析过程
- 编译原理(七) 算符优先分析法-构造算符优先关系表算法
- 编译原理(七) 算符优先分析法(构造算符优先关系表算法及C++实现)
- 编译原理(七) 算符优先分析法(构造算符优先关系表算法及C++实现)
- 编译原理(七) 算符优先分析法(构造算符优先关系表算法及C++实现)
- 编译原理实验四——算符优先文法语法分析
- 编译原理上机作业3——算符优先算法
- 编译原理(八) 算符优先分析法(分析过程的算法和C++实现)
- 编译原理实验之语法分析(算符优先分析算法(C语言))
- 初识WPF
- TCP中的MSS解读
- 跨站脚本攻击(Cross-site scripting,通常简称为XSS)阿里云防护
- bootstrap--栅格系统
- Android中Strings资源一些冷门用法
- 编译原理-算符优先
- JAVA并发编程:线程池Executors
- 网站渗透思路(一)
- HTTP协议的特点
- Flink Runtime 1.0 Notes: Plan 2 Task
- maven镜像配置
- chrome浏览器ctrl+f5强刷仍然显示from cache的实现
- 买卖股票的最佳时机
- linux字符cdev和inode的联系