计算器小程序

本文介绍了使用C++实现的一个数学表达式解析器,包括Token、ExprToken等类的设计,以及parse和compile函数,用于处理和计算输入的算式。
摘要由CSDN通过智能技术生成
#include <iostream>
#include <string>
#include <sstream>
#include <vector>

const int NumType = 0;
const int OperatorType = 1;
const int LeftBracket = 2;
const int RightBracket = 3;
const int ExprType = 4;

class Visitor;
class PrintVistor;
class Token;
class NumToken;
class OperatorToken;
class BracketToken;
class ExprToken;

// 将字符转为数字
float helpStringToNum(const std::string& text)
{
    float ret;
    std::stringstream ss;
    ss << text;
    ss >> ret;
    return ret;
}

// 访问对象 抽象类
class Visitor
{
public:
    virtual void apply(Token* token) = 0;
};

// 读取 虚基类
class Token
{
public:
    const std::string text;     // 读取的文本
    const int type;             // 文本类型

    virtual void visit(Visitor* visitor)//
    {
        visitor->apply(this);
    };
protected:
    Token(std::string text, const int type)
        :text(text), type(type) {}

    virtual ~Token() {}
};



// 读取数字
class NumToken : public Token
{
public:
    const float value;

    NumToken(std::string text)
        :Token(text, NumType)
        , value(helpStringToNum(text))
    { }
};

//读取运算符
class OperatorToken : public Token
{
public:
    const char op;

    OperatorToken(const char op)
        :Token(std::string(1, op), OperatorType)
        , op(op) { }
};

// 读取括号
class BracketToken : public Token
{
public:
    BracketToken(const char op)
        :Token(std::string(1, op), op == '(' ? LeftBracket : RightBracket)
    { }
};

// 读入一个式子
class ExprToken : public Token
{
private:
    NumToken* num;
    OperatorToken* op;
    ExprToken* lhs, * rhs;
    bool bracket;

    float calc()
    {
        if (op)
        {
            float l(lhs->value), r(rhs->value);
            switch (op->op)
            {
            case '+': return l + r;
            case '-': return l - r;
            case '*': return l * r;
            case '/': return l / r;
            }
        }
        else
            return num->value;
        return 0;
    }

public:
    const float value;

    ExprToken(NumToken* num)
        :Token(num->text, ExprType), num(num),
        op(NULL), lhs(NULL), rhs(NULL), value(calc()) {}

    ExprToken(ExprToken* lhs, OperatorToken* op_, ExprToken* rhs)
        :Token(lhs->text + op_->text + rhs->text, ExprType),
        num(NULL), op(op_), lhs(lhs), rhs(rhs), value(calc()) {}

    ExprToken(BracketToken* lb, ExprToken* expr, BracketToken* rb)
        :Token(lb->text + expr->text + rb->text, ExprType),
        num(NULL), op(NULL), lhs(expr), rhs(NULL),
        value(expr->value)
    {
        bracket = true;
    }

    virtual void visit(Visitor* visitor)
    {
        if (lhs) lhs->visit(visitor);
        if (rhs) rhs->visit(visitor);
        visitor->apply(this);
    }

    virtual ~ExprToken()
    {
        delete num;
        delete op;
        delete lhs;
        delete rhs;
    }
};

// 输出访问对象
class PrintVistor : public Visitor
{
private:
    int line;
public:
    PrintVistor() : line(0) {}

    virtual void apply(Token* token)
    {
        if (token->type == ExprType)
        {
            ExprToken* expr = dynamic_cast<ExprToken*>(token);
            std::cout << '#' << ++line << ": "
                << token->text << " = ";
            if (expr)
                std::cout << expr->value;
            else
                std::cout << "NaN";
            std::cout << std::endl;
        }
    }
};

// 将算式存入vector 匹配类型
std::vector<Token*> parse(std::string text)
{
    std::vector<Token*> vec;
    for (int i = 0; i < text.length(); ++i)
    {
        switch (text[i])
        {
        case ' ':
            break;
        case '+':
        case '-':
        case '*':
        case '/':
            vec.push_back(new OperatorToken(text[i]));
            break;
        case '(':
        case ')':
            vec.push_back(new BracketToken(text[i]));
            break;
        default:
        {
            int r;
            for (r = i; r < text.length() && text[r] >= '0'
                && text[r] <= '9'; ++r);
            vec.push_back(new NumToken(text.substr(i, r - i)));
            i = r - 1;
        }
        }
    }
    return vec;
}

// 判断类型 
bool is_expr(Token* lhs, Token* op, Token* rhs, bool priority = false)
{
    if (lhs->type != ExprType
        || op->type != OperatorType
        || rhs->type != ExprType)
        return false;
    OperatorToken* _op = dynamic_cast<OperatorToken*>(op);//将基类指针转化为派生类指针
    return _op && (!priority ^ ((_op->op == '*') || (_op->op == '/')));
}

// 计算
void compile(std::vector<Token*>& vec)
{
    for (int i = 0; i < vec.size(); ++i)
        if (vec[i]->type == NumType)
        {
            NumToken* num = dynamic_cast<NumToken*>(vec[i]);
            if (num)//如果为数字则将其转为初始expr
                vec[i] = new ExprToken(num);
            else
                vec[i] = new ExprToken(new NumToken("0"));
        }
    while (vec.size() > 1)
    {
        bool flag = false;
        // 先计算= '(' expr ')'
        for (int i = 0; i < vec.size() - 2; ++i)
        {
            if (vec[i]->type == LeftBracket && vec[i + 2]->type == RightBracket
                && vec[i + 1]->type == ExprType)
            {
                flag = true;
                ExprToken* expr = new ExprToken(
                    dynamic_cast<BracketToken*>(vec[i]),
                    dynamic_cast<ExprToken*>(vec[i + 1]),
                    dynamic_cast<BracketToken*>(vec[i + 2]));
                vec.erase(vec.begin() + i + 1, vec.begin() + i + 3);
                vec[i] = expr;
            }
            if (flag) break;
        }
        if (flag) continue;
        // 再计算expr '*' expr
        // 再计算 expr '/' expr
        for (int i = 0; i < vec.size() - 2; ++i)
        {
            if (is_expr(vec[i], vec[i + 1], vec[i + 2], true))
            {
                flag = true;
                ExprToken* expr = new ExprToken(
                    dynamic_cast<ExprToken*>(vec[i]),
                    dynamic_cast<OperatorToken*>(vec[i + 1]),
                    dynamic_cast<ExprToken*>(vec[i + 2]));
                vec.erase(vec.begin() + i + 1, vec.begin() + i + 3);
                vec[i] = expr;
            }
            if (flag) break;
        }
        if (flag) continue;
        // 计算expr '+' expr
        // 计算 expr '-' expr
        for (int i = 0; i < vec.size() - 2; ++i)
        {
            if (is_expr(vec[i], vec[i + 1], vec[i + 2]))
            {
                if (i > 0 && vec[i - 1]->type == OperatorType
                    && (dynamic_cast<OperatorToken*>(vec[i - 1])->op == '*'
                        || dynamic_cast<OperatorToken*>(vec[i - 1])->op == '/'))
                    continue;
                if (i + 3 < vec.size() && vec[i + 3]->type == OperatorType
                    && (dynamic_cast<OperatorToken*>(vec[i + 3])->op == '*'
                        || dynamic_cast<OperatorToken*>(vec[i + 3])->op == '/'))
                    continue;
                flag = true;
                ExprToken* expr = new ExprToken(
                    dynamic_cast<ExprToken*>(vec[i]),
                    dynamic_cast<OperatorToken*>(vec[i + 1]),
                    dynamic_cast<ExprToken*>(vec[i + 2]));
                vec.erase(vec.begin() + i + 1, vec.begin() + i + 3);
                vec[i] = expr;
            }
            if (flag) break;
        }
        if (!flag)
        {
            std::cout << "error" << std::endl;
            return;
        }
    }

    PrintVistor v;
    vec[0]->visit(&v);
}



int main(int argc, char* argv[])
{
    std::string s;
    std::cin >> s;
    std::vector<Token*> vec = parse(s);
    compile(vec);
    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值