编译原理 实验三 逆波兰式的生成及计算程序
源代码仓库:CompilePrincipleLearning/experiment_3 · yusixian/CompilePrincipleLearning (github)
一. 实验目的
将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。
二. 实验内容及要求
将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。
程序输入/输出示例:
输出的格式如下:
(1)逆波兰式的生成及计算程序,编制人:姓名,学号,班级
(2)输入一以#结束的中缀表达式(包括+—/()数字#):在此位置输入符号串如(28+68)2#
(3)逆波兰式为:28&68+2
(4)逆波兰式28&68+2计算结果为192
备注:
(1) 在生成的逆波兰式中如果两个数相连则用&分隔,如28和68,中间用&分隔
(2)在此位置输入符号串为用户自行输入的符号串。
注意
- 表达式中允许使用运算符(±*/)、分割符(括号)、数字,结束符#
- 如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好)
- 对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照
三. 实验过程
1、功能描述
读取文件exp.txt中每一行表达式,输出其逆波兰表达式以及根据逆波兰表达式求值。
2、采用的数据结构
class ReversePolishExp {private:int len;string exp;vector<string> postfixExp;stack<string> s;public:ReversePolishExp(string exp) {this->exp = exp;this->len = exp.length();this->postfixExp = getPostfixExp(exp);}// 判断是否为数字bool isDigit(char c) {return c >= '0' && c <= '9';}// 判断是否为+-*/bool isOperate(char c) {return op.find(c) != string::npos;}// 将字符串转换为整数int s2i(string s) {int res = 0;for (auto i : s)res = res * 10 + (i - '0');return res;}// 读入一个完整的整数。string readNum(string exp, int& idx) {string res = "";while(idx < len && isDigit(exp[idx])) {res += exp[idx];idx++;}--idx;return res;}// 根据中缀计算后缀表达式vector<string> getPostfixExp(string exp) {vector<string> res;for(int i = 0; i < len; ++i) {char nowChar = exp[i];if(isDigit(nowChar)) { res.push_back(readNum(exp, i));} else if(isOperate(nowChar)) { string temp = string(1, nowChar);if(opMap[temp] == 1) { // + -while(!s.empty() && s.top() != "(") {res.push_back(s.top());s.pop();}} else { // * /while(!s.empty() && (s.top() == "*" || s.top() == "/")) {res.push_back(s.top());s.pop();}}s.push(temp);} else if(nowChar == '(') { s.push("(");} else if(nowChar == ')') { while(!s.empty() && s.top() != "(") {res.push_back(s.top());s.pop();}s.pop(); }}while(!s.empty()) { res.push_back(s.top());s.pop();}return res;}// 计算后缀表达式的值double compute() {stack<double> s2;for(auto item: postfixExp) {if(isDigit(item[0])) { // 是数字的话 直接入栈s2.push(s2i(item)*1.0);} else {double b = s2.top();s2.pop();double a = s2.top();s2.pop();switch(item[0]) {case '+': s2.push(a + b); break;case '-': s2.push(a - b); break;case '*': s2.push(a * b); break;case '/': if(b == 0) {cout << "Error: denominator is 0!" << endl;return Error;}s2.push(a / b); break;}}}return s2.top();}void printPostfixExp() {if(this->postfixExp.empty()) {cout << "postfixExp is empty" << endl;return;}cout << "输出的逆波兰表达式为: ";for (auto i : this->postfixExp)cout << i << " ";cout << endl;}void printExp() {if(this->exp.empty()) {cout << "exp is empty" << endl;return;}cout << "输入的中缀表达式为: " << this->exp << endl;}
};
3、头文件声明和全局变量定义
如下。
/** @Author: cos* @Date: 2022-04-18 00:46:57* @LastEditTime: 2022-04-18 20:40:38* @LastEditors: cos* @Description: 编译原理实验三 逆波兰表达式计算及求值* @FilePath: \CompileTheory\experiment_3\demo\main.cpp*/
#include <iostream>
#include <vector>
#include <stack>
#include <map>
#include <string>
#include <fstream>
using namespace std;
const int Error = -1;
const string ExpFileName = "./exp.txt";
const string existChars = "+-*/()0123456789";
const string op = "+-*/";
map <string, int> opMap = {{"+", 1},{"-", 1},{"*", 2},{"/", 2},
};
4、函数汇总
(1)函数汇总表
函数名称 | 功能简述 |
---|---|
readFile
|
读取文件函数,返回一个string动态数组,以行数分割 |
isValid
|
判断表达式是否有效(只能包含+-* /()数字 )
|
isDigit
|
判断字符是否为数字 |
isOperate
|
判断是否为 + - * / |
s2i
|
字符串转数字 |
readNum
|
读取连续的数字构成整数返回 |
getPostfixExp
|
中缀表达式转逆波兰表达式 |
compute
|
计算逆波兰表达式的值 |
printExp
|
输出中缀表达式 |
printPostfixExp
|
输出逆波兰表达式 |
(2)函数的调用关系
(3)流程图
5、实验结果
输入
exp.txt
(28+68)*2
(12-10+10*2)/2
32+12/(42-4*10)
12/0+12
(1+1)+1)
hauihd1@!
输出
读取的文件名为:./exp.txt------------------样例1: (28+68)*2--------------------
第1行输入的表达式合法,开始计算
输入的中缀表达式为: (28+68)*2
第2行输入的表达式合法,开始计算
输入的中缀表达式为: (12-10+10*2)/2
输出的逆波兰表达式为: 12 10 - 10 2 * + 2 /
./../x86_64-w64-mingw32/lib/../lib/libmingw32.a(lib64_libmingw32_a-crt0_c.o):crt0_c.c:(.text+0x46): undefined reference to `WinMain'
collect2.exe: error: ld returned 1 exit status
PS C:\Users\34504\OneDrive - nahcox\Programming\CS\CompileTheory\experiment_3\demo> cd "c:\Users\34504\OneDrive - nahcox\Programming\CS\CompileTheory\experiment_3\demo\" ; if ($?) { g++ main.cpp -o main } ; if ($?) { .\main }
逆波兰式的生成及计算程序,编制人: 201916010728 余思娴 计科F1901班
读取的文件名为:./exp.txt------------------样例1: (28+68)*2--------------------
第1行输入的表达式合法,开始计算
输入的中缀表达式为: (28+68)*2
输出的逆波兰表达式为: 28 68 + 2 *
该逆波兰表达式的计算值为:192------------------样例2: (12-10+10*2)/2--------------------
第2行输入的表达式合法,开始计算
输入的中缀表达式为: (12-10+10*2)/2
输出的逆波兰表达式为: 12 10 - 10 2 * + 2 /
该逆波兰表达式的计算值为:11------------------样例3: 32+12/(42-4*10)--------------------
第3行输入的表达式合法,开始计算
输入的中缀表达式为: 32+12/(42-4*10)
输出的逆波兰表达式为: 32 12 42 4 10 * - / +
该逆波兰表达式的计算值为:38------------------样例4: 12/0+12--------------------
第4行输入的表达式合法,开始计算
输入的中缀表达式为: 12/0+12
输出的逆波兰表达式为: 12 0 / 12 +
该逆波兰表达式的计算值为:Error: denominator is 0!
-1------------------样例5: (1+1)+1)--------------------
Error: ) without (!------------------样例6: hauihd1@!--------------------
Error:输入的表达式不合法(只能包含+—*/()数字)!
完整代码
/** @Author: cos* @Date: 2022-04-18 00:46:57* @LastEditTime: 2022-04-18 20:40:38* @LastEditors: cos* @Description: 编译原理实验三 逆波兰表达式计算及求值* @FilePath: \CompileTheory\experiment_3\demo\main.cpp*/
#include <iostream>
#include <vector>
#include <stack>
#include <map>
#include <string>
#include <fstream>
using namespace std;
const int Error = -1;
const string ExpFileName = "./exp.txt";
const string existChars = "+-*/()0123456789";
const string op = "+-*/";
map <string, int> opMap = {{"+", 1},{"-", 1},{"*", 2},{"/", 2},
};
// 读文件
vector<string> readFile(string fileName) {vector<string> res;try {ifstream fin;fin.open(fileName);string temp;while (getline(fin, temp))res.push_back(temp);return res;} catch(const exception& e) {cerr << e.what() << '\n';return res;}
}bool isValid(string exp) {if(exp.find_first_not_of(existChars) != string::npos){cout << "Error:输入的表达式不合法(只能包含+—*/()数字)!" << endl;return false;}stack<char> s; // ()???for (auto i : exp) {if(i == '(')s.push(i);else if(i == ')') {if(s.empty()){cout << "Error: ) without (!\n";return false;}s.pop();}}return true;
}
class ReversePolishExp {private:int len;string exp;vector<string> postfixExp;stack<string> s;public:ReversePolishExp(string exp) {this->exp = exp;this->len = exp.length();this->postfixExp = getPostfixExp(exp);}// 判断是否为数字bool isDigit(char c) {return c >= '0' && c <= '9';}// 判断是否为+-*/bool isOperate(char c) {return op.find(c) != string::npos;}// 将字符串转换为整数int s2i(string s) {int res = 0;for (auto i : s)res = res * 10 + (i - '0');return res;}// 读入一个完整的整数。string readNum(string exp, int& idx) {string res = "";while(idx < len && isDigit(exp[idx])) {res += exp[idx];idx++;}--idx;return res;}// 根据中缀计算后缀表达式vector<string> getPostfixExp(string exp) {vector<string> res;for(int i = 0; i < len; ++i) {char nowChar = exp[i];if(isDigit(nowChar)) { res.push_back(readNum(exp, i));} else if(isOperate(nowChar)) { string temp = string(1, nowChar);if(opMap[temp] == 1) { // + -while(!s.empty() && s.top() != "(") {res.push_back(s.top());s.pop();}} else { // * /while(!s.empty() && (s.top() == "*" || s.top() == "/")) {res.push_back(s.top());s.pop();}}s.push(temp);} else if(nowChar == '(') { s.push("(");} else if(nowChar == ')') { while(!s.empty() && s.top() != "(") {res.push_back(s.top());s.pop();}s.pop(); }}while(!s.empty()) { res.push_back(s.top());s.pop();}return res;}// 计算后缀表达式的值double compute() {stack<double> s2;for(auto item: postfixExp) {if(isDigit(item[0])) { // 是数字的话 直接入栈s2.push(s2i(item)*1.0);} else {double b = s2.top();s2.pop();double a = s2.top();s2.pop();switch(item[0]) {case '+': s2.push(a + b); break;case '-': s2.push(a - b); break;case '*': s2.push(a * b); break;case '/': if(b == 0) {cout << "Error: denominator is 0!" << endl;return Error;}s2.push(a / b); break;}}}return s2.top();}void printPostfixExp() {if(this->postfixExp.empty()) {cout << "postfixExp is empty" << endl;return;}cout << "输出的逆波兰表达式为: ";for (auto i : this->postfixExp)cout << i << " ";cout << endl;}void printExp() {if(this->exp.empty()) {cout << "exp is empty" << endl;return;}cout << "输入的中缀表达式为: " << this->exp << endl;}
};
int main(){cout << "读取的文件名为:" << ExpFileName << endl; vector<string> exps = readFile(ExpFileName);int len = exps.size();for(int i = 0; i < len; i++) {string exp = exps[i];cout << "\n------------------样例" << i+1 << ": "<< exp << "--------------------" << endl;if(!isValid(exp)) continue;cout << "第"<< i+1 << "行输入的表达式合法,开始计算" << endl;ReversePolishExp res(exp);res.printExp();res.printPostfixExp();cout << "该逆波兰表达式的计算值为:" << res.compute() << endl;}return 0;
}
编译原理 实验三 逆波兰式的生成及计算程序相关推荐
- 编译原理实验二-逆波兰式生成程序
一.实验目的和要求: 1. 掌握语法分析的基本思想,并用高级语言编写逆波兰式生成程序 2. 要求利用逆波兰式生成算法编写程序,将从键盘上输入的算术表达式 (中缀表达式)转化成逆波兰式 二.实验平台: ...
- 编译原理 | 实验四 | 逆波兰式
目录 一.问题分析 二.算法思想 1.关于分词器 2.关于逆波兰式分析器: 三.实现代码 1.头文件 & 类视图 2.预处理部分 3.逆波兰分析过程 4.计算,输出部分 四.总结 一.问题 ...
- 编译原理逆波兰式实验java_逆波兰式算法的编译原理实验过程.doc
逆波兰式算法的编译原理实验过程 实验目的 深入理解算符优先分析法 掌握FirstVt和LastVt集合的求法有算符优先关系表的求法 掌握利用算符优先分析法完成中缀表达式到逆波兰式的转化 实验内容及要求 ...
- 合工大 编译原理 实验三
合工大 编译原理 实验三 LR(1) 分析法 本项目使用c++实现,利用Windows API制作了简易的UI界面. 具体功能如下: 支持查看文法,项目族,LR(1) 分析表,句子归约过程. 可使用包 ...
- 编译原理实验-LL1语法分析器(自动生成First集、Follow集求法)java实现
编译原理实验-LL1语法分析器(自动生成First.Follow)java 博主在做实验时,参考众多他人代码,发现bug众多,在@moni_mm代码基础上,与伙伴把能看到的BUG都做出修正,同时增添了 ...
- 编译原理实验三 语义分析程序设计与实现
一.实验目的 在实现词法.语法分析程序的基础上,编写相应的语义子程序,进行语义处理,加深对语法制导翻译原理的理解,进一步掌握将语法分析所识别的语法范畴变换为某种中间代码(四元式)的语义分析方法,并完成 ...
- java编程实现算符优先分析法,编译原理实验三-算符优先分析法
编译原理实验3-算符优先分析法 #include #include #include #include #define SIZE 128 char priority[6][6]; //算符优先关系表数 ...
- 编译原理实验三 LR(1)分析法
实验三 LR(1)分析法 构造 LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文 法识别的句子,了解 LR(K)分析方法是严格的从左向右扫描,和自底向上的 语法分析方法. 二.实验内 ...
- 编译原理实验三:对完整程序进行词法分析并输出对应的二元组
实验要求 [任务介绍]根据给定源语言的构词规则,从任意字符串中识别出该语言所有的合法的单词符号,并以等长的二元组形式输出. [输入]字符串形式的源程序. [输出]单词符号所构成的串(流),单词以等长的 ...
- 编译原理 - 实验三 - 递归下降语法分析器的调试及扩展
一. 语法分析介绍 语法分析是编译过程的核心部分,它的主要任务是按照程序语言的语法规则,从由词法分析输出的源程序符号串中识别出各类语法成分,同时进行语法检查,为语义分析和代码生成做准备.执行语法分析任 ...
最新文章
- 双链表(删除节点操作)
- oracle体系结构-内存管理
- 致力云安全服务模式 安全狗获近5000万融资
- android频繁点击ui崩溃,android easeui 集成 启动崩溃
- Android Shape Drawable Resources
- 科技与我:在数字时代成长
- caffeine 时间轮的实现
- 空间统计分析_CDA 数据分析师 Level 1 备考系列之推断性统计分析概述
- vswatch窗口怎么出来_学会这6个打印小技巧,表格想怎么打就怎么打,让工作效率翻倍...
- dfmea文件_技术干货合集「失效分析、PFMEA DFMEA关系、文件结果化」
- Tomcat最大线程数的设置
- # 淘宝客导购小程序最新版本
- 在注册表里删除没用的服务
- 数据结构——计算节点个数和二叉树高度(C语言版)
- SEGGER RTT printf 的移植和浮点数处理
- 消息事件管理(游戏人工智能编程案例精粹)
- 快手、抖音等短视频营销模式
- svn 锁死解除方案
- 室内定位系统算法--无线时钟同步的比较
- FRM1 P1B1P1B2 整理笔记
热门文章
- 学会如何学习 - 成为更好的终身学习者
- 你评论,我赠书~【TFS-CLUB社区 第11期赠书活动】〖Unity手机游戏开发:从搭建到发布上线全流程实战〗等你来拿,参与评论,即可有机获得
- 将图片公式快速转为word可编辑的方法(windows和mac都支持)
- 中小型企业网络规划设计方案_深圳线尚网络:中小型企业网站建设方案包含哪些内容?...
- 奇迹服务器断开怎么修复,奇迹挂机怎么总是掉线?
- 计算机视觉论文-2021-07-19
- SQL教程之使用 dbt 和 SQLfluff 整理 SQL
- java 登录12306_请教java尝试模拟登录12306时遇到的一个问题
- IE下使用VLC网页播放视频Demo
- 微信支付的appid,appsecret,商户号mchid,微信交易支付密钥在哪里