一、实验目的

将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式, 并计算用逆波兰式来表示的算术表达式的值。

二、实验原理

三、实验代码

main.cpp

#define _CRT_SECURE_NO_WARNINGS
#include"stdio.h"
#include "stdlib.h"
#include<iostream>
using namespace std;
#include <stack>
#include "OPG.h"//逆波兰表达式变量和函数的声明
stack<float> s2;          //s2作为数字栈
char arr[80] = { 0 };  //存储中缀表达式
char str1[80] = { 0 }; //存储初始后缀表达式
char str2[80] = { 0 }; //存储最终后缀表达式
int num[80] = { 0 };       //存储后缀表达式中的数字
void deal();                //由中缀生成后缀
void number(char str[]);    //实现逆波兰表达式的计算void main()
{init();deal();number(str2);
}//算符优先关系表已经有了,开始生成逆波兰式
void deal()
{//清空缓冲区char c;while ((c = getchar()) != '\n' && c != EOF);printf("请输入中缀表达式,以'#'结尾:");gets_s(arr);
//  printf("test1 arr=%s\n", arr);//测试打印arrint i, j = 0;stack <char>s;s.push('#');      //初始化栈//从左至右依次扫描字符串for (i = 0; arr[i] != 0; i++){  char sym = arr[i];if (sym >= '0' && sym <= '9'){int k = 0;str1[j] = sym;j++;//向后看一位,如果不是数字,则加分隔符&if (arr[i + 1] > '9' || arr[i + 1] < '0'){str1[j] = '&';j++;}}else{for (;;){int x = xiabiao(s.top());int y = xiabiao(sym);if (dat[x][y] == '<'){s.push(sym);break;}else{if (dat[x][y] == '='){if (s.top() == '(' && sym == ')'){s.pop();break;}elsebreak;}else{str1[j] = s.top();j++;s.pop();}}}}}//打印出初始逆波兰表达式
//  printf("%s\n",str1);//再次处理逆波兰表达式for (i=0,k=0;str1[i]!=0;i++){//如果是分隔符&,向后看一位,如果下一个不是数字,则不需要分隔符&if(! (str1[i] == '&'&&(str1[i+1]>'9'||str1[i+1]<'0'))){str2[k] = str1[i];k++;}}printf("逆波兰表达式:%s\n", str2);
}//实现逆波兰表达式的计算
void number(char str[])
{int k = 0, p = 1;float a = 0, b = 0, c = 0;for (int i = 0; str[i] != 0; i++){//如果是数字,将逆波兰式的数字串处理成数字if (str[i] <= '9' && str[i] >= '0'){//如果下一个不是数字if (str[i + 1] > '9' || str[i + 1] < '0'){num[k] = str[i] - '0';}//如果下一个也是数字if (str[i + 1] <= '9' && str[i + 1] >= '0'){num[k] = str[i] - '0';for (p = 1; str[i + p] != 0; p++){if (str[i + p] <= '9' && str[i + p] >= '0'){num[k] = num[k] * 10 + str[i + p] - '0';}elsebreak;}//k+1是数组元素个数//相当于读入了p个字符,i需要跳过p-1  i = i + p - 1;}k++;//每循环一次,得到一个数字,则数字入栈s2.push(num[k - 1]);}//如果是运算符,则将栈顶两个元素弹出栈,并进入当前符号运算,将运算结果再压入数字栈if (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/'){a = s2.top();s2.pop();b = s2.top();s2.pop();if (str[i] == '+')c = b + a;if (str[i] == '-')c = b - a;if (str[i] == '*')c = b * a;if (str[i] == '/')c = b / a;s2.push(c);}}printf("逆波兰式%s=计算结果为%.2f\n", str2, c);}

OPG.h

//算符优先文法全局变量和函数的声明
char dat[20][20];//算符优先关系
char s[200];//模拟符号栈
char lable[20];//文法终极符集
char input[100];//文法输入符号串
char str[20][10];//用于输入串的分析
int k;
char a;
int j;
char q;
int r;//文法规则个数
int r1;
int m, n, N;//转化后文法规则个数
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 zhongjie(char c);//判断字符c是否是终结符
int xiabiao(char c);//求字符c在算符优先关系表中的下标
void firstvt(char c);//求非终结符c的FIRSTVT集
void lastvt(char c);//求非终结符c的LASTVT集
void table();//创建文法优先关系表
void init();void init()
{int i, j, k = 0;printf("请输入文法规则数:");scanf("%d", &r);printf("请输入文法规则:\n");for (i = 0; i < r; i++){scanf("%s", 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 < r; i++){for (j = 0; st[i][j] != '\0'; j++){if (st[i][0] < 'A' || st[i][0]>'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 < r; i++){for (j = 0; st[i][j] != '\0'; j++)if ((st[i][j] < 'A' || st[i][j]>'Z') && st[i][j] != '=' && st[i][j] != '>' && st[i][j] != '|')lable[k++] = st[i][j];}lable[k] = '#';lable[k + 1] = '\0';table();}void table()
{char text[20][10] = { 0 };int i, j, k, t, l, x = 0, y = 0;int m, n;x = 0;for (i = 0; i < r; i++){firstvt(st[i][0]);lastvt(st[i][0]);}//文法转化for (i = 0; i < r; i++){text[x][y] = st[i][0];y++;for (j = 1; st[i][j] != '\0'; j++){if (st[i][j] == '|'){text[x][y] = '\0';x++;y = 0;text[x][y] = st[i][0];y++;text[x][y++] = '-';text[x][y++] = '>';}else{text[x][y] = st[i][j];y++;}}text[x][y] = '\0';x++;y = 0;}r1 = x;for (i = 0; i < x; i++)//求每个终结符的推导结果(去掉"->"后的转化文法,用于最后的规约){str[i][0] = text[i][0];for (j = 3, l = 1; text[i][j] != '\0'; j++, l++)str[i][l] = text[i][j];str[i][l] = '\0';}for (i = 0; i < x; i++){for (j = 1; text[i][j + 1] != '\0'; j++){if (zhongjie(text[i][j]) && zhongjie(text[i][j + 1])){m = xiabiao(text[i][j]);n = xiabiao(text[i][j + 1]);dat[m][n] = '=';}if (text[i][j + 2] != '\0' && zhongjie(text[i][j]) && zhongjie(text[i][j + 2]) && !zhongjie(text[i][j + 1])){m = xiabiao(text[i][j]);n = xiabiao(text[i][j + 2]);dat[m][n] = '=';}if (zhongjie(text[i][j]) && !zhongjie(text[i][j + 1])){for (k = 0; k < r; k++){if (st[k][0] == text[i][j + 1])break;}m = xiabiao(text[i][j]);for (t = 0; t < first[k][0]; t++){n = xiabiao(first[k][t + 1]);dat[m][n] = '<';}}if (!zhongjie(text[i][j]) && zhongjie(text[i][j + 1])){for (k = 0; k < r; k++){if (st[k][0] == text[i][j])break;}n = xiabiao(text[i][j + 1]);for (t = 0; t < last[k][0]; t++){m = xiabiao(last[k][t + 1]);dat[m][n] = '>';}}}}m = xiabiao('#');for (t = 0; t < first[0][0]; t++){n = xiabiao(first[0][t + 1]);dat[m][n] = '<';}n = xiabiao('#');for (t = 0; t < last[0][0]; t++){m = xiabiao(last[0][t + 1]);dat[m][n] = '>';}dat[n][n] = '=';
}void firstvt(char c)//求firstvt集
{int i, j, k, m, n;for (i = 0; i < r; i++){if (st[i][0] == c)break;}if (fflag[i] == 0){n = first[i][0] + 1;m = 0;do {if (m == 2 || st[i][m] == '|'){if (zhongjie(st[i][m + 1])){first[i][n] = st[i][m + 1];n++;}else{if (zhongjie(st[i][m + 2])){first[i][n] = st[i][m + 2];n++;}if (st[i][m + 1] != c){firstvt(st[i][m + 1]);for (j = 0; j < r; j++){if (st[j][0] == st[i][m + 1])break;}for (k = 0; k < first[j][0]; k++){int t;for (t = 0; t < n; t++){if (first[i][t] == first[j][k + 1])break;}if (t == n){first[i][n] = first[j][k + 1];n++;}}}}}m++;} while (st[i][m] != '\0');first[i][n] = '\0';first[i][0] = --n;fflag[i] = 1;}
}void lastvt(char c)//求LASTVT集
{int i, j, k, m, n;for (i = 0; i < r; i++){if (st[i][0] == c)break;}if (lflag[i] == 0){n = last[i][0] + 1;m = 0;do {if (st[i][m + 1] == '\0' || st[i][m + 1] == '|'){if (zhongjie(st[i][m])){last[i][n] = st[i][m];n++;}else{if (zhongjie(st[i][m - 1])){last[i][n] = st[i][m - 1];n++;}if (st[i][m] != c){lastvt(st[i][m]);for (j = 0; j < r; j++){if (st[j][0] == st[i][m])break;}for (k = 0; k < last[j][0]; k++){int t;for (t = 0; t < n; t++){if (last[i][t] == last[j][k + 1])break;}if (t == n){last[i][n] = last[j][k + 1];n++;}}}}}m++;} while (st[i][m] != '\0');last[i][n] = '\0';last[i][0] = --n;lflag[i] = 1;}
}int xiabiao(char c)//求字符c在算符优先关系表中的下标
{int i;for (i = 0; lable[i] != '\0'; i++){if (c == lable[i])return i;}return -1;
}int zhongjie(char c)//判断字符c是否是终结符
{int i;for (i = 0; lable[i] != '\0'; i++){if (c == lable[i])return 1;}return 0;
}

四、实验总结

1、数据结构:在生成逆波兰表达式时,主要用了符号栈;在计算逆波兰表达式时,主要用了数字栈。

2、本实验是算符优先文法的一个应用,所以我直接将中缀表达式对应的算符文法的优先分析表拿过来用。
该文法能识别带有+,-,,/,(,)的中缀表达式。
E=>E+T|E-T|T
T=>T
P|T/P|P
P=>(E)|i
(注:由于涉及减法” - ”的运算,所以->改为=>)
得到算符优先关系后,用其限定符号栈(栈顶符号优先级最高)。

3、在生成逆波兰表达式时,在deal( )函数中,需要体现数字串,通过“向后看一位,如果不是数字,则加分隔符&”,可以在每个数字串后面跟上一个分隔符,再通过“如果是分隔符&,向后看一位,如果下一个不是数字,则不需要分隔符&”,可以实现只在连续数字之间有分隔符;在计算逆波兰表达式时,在number( )函数中,从左向右读入逆波兰表达式,通过如“num[k] = str[i] - ‘0’;”实现字符转化为数字,然后将数字符号串转化为数字。

4、清空输入缓冲区
//清空缓冲区
char c;
while ((c = getchar()) != ‘\n’ && c != EOF);

5、待改进:本实验尚未实现一目运算符如负号的运算;遇到错误没有尽可能地显示错误信息。

基于算符优先文法的逆波兰表达式及计算相关推荐

  1. 算符优先文法,中缀式求值,栈的典型应用

    栈,是比较基础,应用比较广的一种数据结构,栈和队列都可以看成是比较特殊的一些链表,其最突出的特性就是先进后出.虾米阿尼是一个比较常见的中缀表达式求值的应用,当然中缀式到后缀式的转化也是可以实现的. 中 ...

  2. 数据结构 - 栈 (逆波兰计算器)(栈的三种表达式)(前缀、中缀和后缀表达式,后缀也叫逆波兰表达式)(中缀表达式转后缀表达式实现步骤及完整代码)

    栈的三种表达式:前缀.中缀和后缀表达式,后缀也叫逆波兰表达式 前缀(波兰表达式) 中缀(对人来讲很好理解,对于计算机来讲就方便了,一般会把中缀表达式转换成后缀表达式) 后缀(逆波兰表达式) 计算过程 ...

  3. nyoj35——逆波兰表达式

    逆波兰表达式又称作后缀表达式,在四则混合运算的程序设计中用到. 例如: 1+2写成后缀表达式就是12+ 4+5*(3-2)的后缀表达式就是4532-*+ 后缀表达式在四则运算中带来了意想不到的方便,在 ...

  4. 前缀表达式后缀表达式_你知道波兰表达式和逆波兰表达式吗

    什么是波兰表达式 我们日常的运算表达式通常是如下形式,这种成为中缀表达式,也就是运算符在运算数的中间.这种表达式人类很容易识别,并根据其进行计算,但计算机识别这种表达式非常困难. a + b * (c ...

  5. 调度场算法与逆波兰表达式

    本文的主要内容是如何求一个给定的表达式的值,具体思路就是先将普通算术的中缀表达式转化为后缀表达式,这一步用到的算法叫做调度场算法.然后对后缀表达式,也就是逆波兰表达式求值. 题目:http://acm ...

  6. php逆波兰表达式,PHP实现逆波兰式 - 计算工资时用

    近期一个小项目需要用到公式运算, 所以就进行一些了解,以下内容均属于个人经验. 在PHP中实现公式表达式四则运算大概有两种方法: 1)使用系统函数eval 2)将表达式转换成逆波兰表达式进行计算. / ...

  7. 算符优先文法编写java语法分析器,编译原理课程设计实验报告——基于算符优先分析方法的表达式语法分析器...

    内容简介: 一.设计目的 了解用算符优先法对表达进行语法分析的方法,掌握自顶向下的预测语法分析程序的手工构造方法. 二.设计内容 对简单表达式文法构造算符优先分析器. 三.设计要求 1.对下列简单表达 ...

  8. 栈、波兰表达式、逆波兰表达式

    一.栈的简介及其基本操作 栈的介绍 1)栈的英文为(stack) 2)栈是一个先入后出(FILO-First In Last Out)的有序列表 3)栈(stack)是限制线性表中元素的插入和删除只能 ...

  9. JavaScript逆波兰表达式求值

    逆波兰表达式简介 逆波兰表达式又叫做后缀表达式.逆波兰表示法是波兰逻辑学家J・卢卡西维兹(J・ Lukasiewicz)于1929年首先提出的一种表达式的表示方法 .后来,人们就把用这种表示法写出的表 ...

  10. 算符优先分析法实现给定表达式的分析识别(Python)

    给定类C语言中简单算术表达式文法G[E]:     E→E+T | E-T | T     T→T*F | T/F | F     F→(E) | id 根据该文法,编写算符优先分析器. 1)输入:任 ...

最新文章

  1. python使用TSNE为影像组学(radiomics)数据进行降维可视化分析
  2. Java 8 Stream Api 中的 map和 flatMap 操作
  3. golang select
  4. tensorflow教程 开始——数据集:快速了解 tf.data
  5. 《UML中的六大关系》和《Eclipse中如何使用UML方便查看项目框架》
  6. go+cookie+angular踩过的坑
  7. c++ stack 遍历_C/C++内存分配!
  8. dht11温湿度传感器_Arduino不调用库实现DHT11数据读取
  9. 03-树1 树的同构 (25 分)
  10. 通过自己的项目实际经验,阐述为什么“恶心玩技术”?玩Java开源B/S的教训(三)...
  11. Java 并发编程之 CopyOnWriteArrayList
  12. android程序的建立,创建第一个Android程序 HelloWorld
  13. Redis 最大客户端连接数,你了解吗?
  14. Python编程——函数
  15. linux 项目文件管理,VS2017开发Linux程序之管理已有的makefile工程
  16. JB的Python之旅-爬虫篇--requestsScrapy
  17. 酷狗.kgtemp文件加密算法逆向
  18. 雷锋科普:小米M2之芯高通APQ8064芯片组解析
  19. 2022年王道数据结构考研复习指导习题代码(排序)
  20. rstp 小米网络摄像头_小米哪个家庭摄像头好用?

热门文章

  1. Rust:字符串数组的拼接、与 String 、 str的选择
  2. (转)新金融的魔幻IPO:都在讲科技,但最终还是靠现金贷上岸
  3. Julia: DataFrame最大的好处是对NA的处理和对象化操作!
  4. 技术人 | 我在支付宝体验技术部这四年学到了什么?
  5. 基于HBR的云上统一备份最佳实践
  6. Linux基金会发布开源Hypervisor项目ACRN支持物联网设备开发
  7. 【优化算法】帝国主义竞争优化算法(ICA)【含Matlab源码 1635期】
  8. 【物理应用】基于matlab非序贯蒙特卡洛法评估风电系统【含matlab源码 766期】
  9. 【语音识别】基于matlab动态时间规整(DTW)孤立字语音识别【含Matlab源码 573期】
  10. 【数字信号调制】基于matlab GUI PCM编码调制【含Matlab源码 453期】