编译原理 实验三 逆波兰式的生成及计算程序

本文介绍了如何将非后缀式算术表达式转换为逆波兰式,并演示了实现过程,包括读取文件、表达式验证、逆波兰式生成和错误处理。通过实例展示了程序的运行和计算结果,适用于编译原理学习者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源代码仓库: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. 表达式中允许使用运算符(±*/)、分割符(括号)、数字,结束符#
  2. 如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好)
  3. 对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照

三. 实验过程

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)函数的调用关系

function3.drawio.png

(3)流程图

main.drawio.png

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;
}

#define maxbuffer 64 void main() { char display_out(char out_ch[maxbuffer], char ch[32]); //int caculate_array(char out_ch[32]); static int i=0; static int j=0; char ch[maxbuffer],s[maxbuffer],out[maxbuffer]; cout<>ch; for(i=0;i<maxbuffer;i++) {out[i]=ch[i];} cout<<"请确认您输入的表达: "; while(out[j]!='#') { cout<<out[j]; j++; } cout<<'#'<<endl; display_out(s,out); //caculate_array; } char display_out(char out_ch[32],char ch[]) { int top=-1; int i=0,data[maxbuffer],n; int j=0; char sta[20]; while(ch[i]!='#') { if(isalnum(ch[i])) { while(isalnum(ch[i])) { out_ch[j]=ch[i]; j++; i++; }out_ch[j]=' ';j++; } else{ switch(ch[i]) { case '+': case '-': if(sta[top]=='('||top==-1) { top++; sta[top]=ch[i]; i++; } else { //j--; out_ch[j]=sta[top]; j++; top--; //i++; } break; //break; case '*': case '/':if(sta[top]=='*'&&sta[top]=='/') { out_ch[j]=sta[top]; j++; //i++; top--; } else { top++; sta[top]=ch[i]; i++; } break ; //break; case '(':top++; sta[top]=ch[i]; i++; break; case ')':if(sta[top]=='(') { top--; i++; } if(top==-1) { cout<<"错误: 第"<<j<<"个位置的“)”没有找到与之匹配的“(”"; ch[i]='#';j=0; } else { //while(sta[top]!='('){ out_ch[j]=sta[top]; top--; j++; //}break; } break; /*case '#': out_ch[j]='#'; j++; break;*/ default: cout<<" your input is error"<<endl; ch[i]='#'; j=0; break; } } }while(top!=-1) { out_ch[j]=sta[top];j++; top--; } out_ch[j]='#'; n=0; cout<<"波兰表达为: "; while(out_ch[n]!='#') { cout<<out_ch[n]; n++; } cout<<endl; j=0; /*while(ch[j]!='#') { top++; data[top]=ch[j]; } cout<<data[top]; */ return out_ch[maxbuffer]; } 波兰
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

余cos

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值