编译原理实验(三)

实验三 逆波兰式的产生及计算

一、实验目的

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

二、实验题目

如输入如下: 21 + ( ( 42 − 2 ) ∗ 15 + 6 ) − 18 21+((42-2)* 15+6)-18 21+((422)15+6)18 #

输出为:

原来表达式: 21 + ( ( 42 − 2 ) ∗ 15 + 6 ) − 18 21+((42-2)* 15+6)-18 21+((422)15+6)18

后缀表达式: 21   42   2   −   15   ∗   6   +   +   18   − 21\space 42 \space 2 \space - \space 15 \space *\space 6 \space +\space + \space18\space- 21 42 2  15  6 + + 18 

计算结果: 609 609 609

三、编码实现

源代码

#include <iostream>
#include <vector>
#include <string>
#include <stack>
#include <map>
#include <cmath>

std::vector<std::string> ans;
std::map<char, int> priority;     // define the prioritization
/*
 * these operators will be accept
 * . should not be seen as a opt here
*/
std::string opt = "+-*/()^%";

void trans(std::string str) {
    std::stack<char> ops;
    // insert a '#' in the rear side of stack symbolized the end
    ops.push('#');
    // storing opts temporarily
    std::string tempStr;
    std::string tempFlag;

读取数字

  • 对于由数字或符号开始的字符串,逐个字符读取以获取数字,直到下个符号不是数字 1 ∼ 9 1 \sim 9 19 或小数点 . . . 为止,从而实现对小数和负数的读取。

  • 对于负数,视作单目运算符 − - 与一个正数的复合,记作 @ @ @ @ @ @ 符号放入字符串尾部。

    for (int i = 0; i < str.size(); i++) {
        /*
         * check opt whether a true opt or a part of a number
         * if i equal to zero,the opt + & - should be seen as a part of number except this is the end
         */
        if (((str[i] == '-' || str[i] == '+' || str[i] == '.') &&
             (i == 0 || std::string("+-/*(^%").find(str[i - 1]) != std::string::npos)) ||
            isdigit(str[i])) { // is number

            tempStr = str[i] != '+' ? str.substr(i, 1) : "";

            while (i + 1 < str.size() && opt.find(str[i + 1]) == std::string::npos) { // border control and
                tempStr += str[++i];
            }
            if (tempStr[0] == '-') {
                tempStr.erase(0, 1);
                tempFlag = "@";
            } else {
                tempFlag = "";
            }
            ans.push_back(tempStr);
            if (!tempFlag.empty()) {
                ans.push_back(tempFlag);
                tempFlag.clear();
            }
        } else {
            // for operators
            if (str[i] == '(')
                ops.push(str[i]);
            else if (str[i] == ')') {
                while (ops.top() != '(') {
                    ans.emplace_back(1, ops.top());
                    ops.pop();
                }
                ops.pop();
            } else {
                while (priority[str[i]] <= priority[ops.top()] && str[i] != '^') {
                    ans.emplace_back(1, ops.top());
                    ops.pop();
                }
                ops.push(str[i]);
            }
        }
    }
    while (ops.size() > 1) {
        ans.emplace_back(1, ops.top());
        ops.pop();
    }
}

double cal() { //calculator
    std::stack<double> temp;
    for (const auto &i: ans) {
        try {
            // turn string to double
            temp.push(std::stod(i));
        } catch (...) {
            /*
             * exception occurred, which means this is not a num but opt
             * we can start cal here
             */
            char c = i[0];
            double res = 0;
            if (c == '@') {
                res = res - temp.top();
                temp.pop();
                temp.push(res);
            } else if (c == '+') {
                res = res + temp.top();
                temp.pop();
                res = res + temp.top();
                temp.pop();
                temp.push(res);
            } else if (c == '-') {
                res = res + temp.top();
                temp.pop();
                res = temp.top() - res;
                temp.pop();
                temp.push(res);
            } else if (c == '*') {
                res = res + temp.top();
                temp.pop();
                res = res * temp.top();
                temp.pop();
                temp.push(res);
            } else if (c == '/') {
                res = res + temp.top();
                temp.pop();
                res = temp.top() / res;
                temp.pop();
                temp.push(res);
            } else if (c == '^') {
                res = res + temp.top();
                temp.pop();
                res = pow(temp.top(), res);
                temp.pop();
                temp.push(res);
            } else if (c == '%') {
                res = res + temp.top();
                temp.pop();
                res = fmod(temp.top(), res);
                temp.pop();
                temp.push(res);
            }
        }
    }

    return temp.top();
}

加入乘方运算符号 ^,拥有最高优先级

加入取余符号 % \% %,优先级同乘除号

int main() {
    priority['^'] = 4;
    priority['*'] = priority['/'] = priority['%'] = 3;
    priority['+'] = priority['-'] = 2;
    priority['('] = 1;
    priority['#'] = 0;
    std::string str;
    getline(std::cin, str);
    trans(str);
    for (int i = 0; i < ans.size(); i++)
        std::cout << (i ? " " : "") << ans[i];
    std::cout << std::endl;
    double res_n = cal();
    std::cout << " " << '=' << " " << res_n << std::endl;
    return 0;
}

改进与提升小结

增加了对取余运算、乘方运算、负数(负号视作单目运算符,在此代码中记作 @ @ @ )的支持

四、运行测试

  • 基本要求(四则运算与括号)

    23 + ( 34 ∗ 5 / 2 − 1 ) 23+(34*5/2-1) 23+(345/21)

  • 含负数的处理

    − 34 + 7 ∗ 5 -34+7*5 34+75

  • 含乘方的处理

    4 3 2 4^{3^{2}} 432

  • 需取余的处理

    34 % 8 % 3 34\%8\%3 34%8%3

  • 综合测试

    ( − 34 + 3 2 2 / 9 % 4 ) + 8 ∗ ( 3.6 − 4 ) (-34+3^{2^2}/9 \%4)+8*(3.6-4) (34+322/9%4)+8(3.64)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值