qt c++ 计算器

qt 写的 c++ 计算器

#include <QCoreApplication>
#include <QDebug>
#include <QVector>
#include <QRegularExpression>
#include <QMap>
#include <QStack>

using namespace std;

enum MatchType{
    Match_None,
    Match_Begin,
    Match_Full,
};

enum TokenType
{
    Token_None,
    Token_Start,
    Token_End,
    Token_Add,
    Token_Sub,
    Token_Mul,
    Token_Div,

    Token_LBkt,
    Token_RBkt,    
    Token_Space,
    Token_Comma,

    Token_Number,
    Token_Var,
    Token_Func,
};

int opPri(TokenType type)
{
    if(type == Token_Add || type == Token_Sub)
        return 0;
    else if(type == Token_Mul || type == Token_Div)
        return 1;
    else if(type == Token_LBkt || type == Token_RBkt)
        return 100;
    else
        return -1;
}

class Token
{
public:
    bool isOp()
    {
        return type >= Token_Add && type <= Token_Div;
    }

    TokenType type;
    QString text;
};

class TokenInfo
{
public:
    struct SubToken
    {
        int index;
        QRegularExpression exp;


    };

    MatchType match(QString text,Token &tk)
    {
        MatchType t = Match_None;
        for(int i = 0; i < tokens.size(); i++)
        {
            QRegularExpressionMatch match = tokens[i].exp.match(text,0,QRegularExpression::PartialPreferCompleteMatch);
            if(match.hasMatch())
            {
                t = Match_Full;
                tk.type = type;
                tk.text = text;
                return t;
            }
            else if(match.hasPartialMatch())
                t = Match_Begin;
        }

        return t;
    }

    TokenType type;
    QVector<SubToken> tokens;
};

TokenInfo makeTokenInfo(TokenType type,QStringList exprs)
{
    TokenInfo ret;
    ret.type = type;
    for(int i = 0; i < exprs.size(); i++)
    {
        TokenInfo::SubToken sub;
        sub.index = 0;
        sub.exp = QRegularExpression("^" + exprs[i] + "$");
        ret.tokens.push_back(sub);
    }
    return ret;
}

class Calculator
{
public:
    Calculator()
    {
        //tokenInfo
        TokenInfo tk_number = makeTokenInfo(Token_Number,{"-?[0-9]+(\\.[0-9]+)?","0x[0-9]+"});
        TokenInfo tk_add = makeTokenInfo(Token_Add,{"\\+"});
        TokenInfo tk_sub = makeTokenInfo(Token_Sub,{"-"});
        TokenInfo tk_mul = makeTokenInfo(Token_Mul,{"\\*"});
        TokenInfo tk_div = makeTokenInfo(Token_Div,{"/"});
        TokenInfo tk_lbkt = makeTokenInfo(Token_LBkt,{"\\("});
        TokenInfo tk_rbkt = makeTokenInfo(Token_RBkt,{"\\)"});
        TokenInfo tk_space = makeTokenInfo(Token_Space,{" "});
        m_tokenInfos.push_back(tk_number);
        m_tokenInfos.push_back(tk_add);
        m_tokenInfos.push_back(tk_sub);
        m_tokenInfos.push_back(tk_mul);
        m_tokenInfos.push_back(tk_div);
        m_tokenInfos.push_back(tk_rbkt);
        m_tokenInfos.push_back(tk_lbkt);
        m_tokenInfos.push_back(tk_space);

        //m_tokenMap
        m_tokenMap[Token_Start] << Token_LBkt << Token_Number << Token_Var << Token_Space << Token_Func;

        m_tokenMap[Token_Add] << Token_LBkt << Token_Number << Token_Var << Token_Func << Token_Space;
        m_tokenMap[Token_Sub] << Token_LBkt << Token_Number << Token_Var << Token_Func << Token_Space;
        m_tokenMap[Token_Mul] << Token_LBkt << Token_Number << Token_Var << Token_Func << Token_Space;
        m_tokenMap[Token_Div] << Token_LBkt << Token_Number << Token_Var << Token_Func << Token_Space;

        m_tokenMap[Token_LBkt] << Token_LBkt << Token_Number << Token_Var << Token_Func << Token_Space;
        m_tokenMap[Token_RBkt] << Token_Add << Token_Sub << Token_Mul << Token_Div << Token_Space << Token_End;
        m_tokenMap[Token_Comma] << Token_LBkt << Token_Number << Token_Var << Token_Space;

        m_tokenMap[Token_Number] << Token_Add << Token_Sub << Token_Mul << Token_Div << Token_RBkt << Token_Space << Token_End;
        m_tokenMap[Token_Var] << Token_Add << Token_Sub << Token_Mul << Token_Div << Token_Space << Token_End;
        m_tokenMap[Token_Func] << Token_Add << Token_Sub << Token_Mul << Token_Div << Token_Space << Token_End;
    }

    Token readToken()
    {
        Token tkNone;
        tkNone.type = Token_None;

        while(m_index < m_expr.size())
        {
            QVector<Token> preToken;
            QVector<Token> curToken;
            QVector<TokenInfo*> current;
            QVector<TokenInfo*> next;

            for(int token_idx = 0; token_idx < m_tokenInfos.size(); token_idx++)
                current.push_back(&m_tokenInfos[token_idx]);

            QString word;
            while(m_index < m_expr)
            {
                curToken.clear();
                next.clear();

                word.push_back(m_expr[m_index]);
                for(int token_idx = 0; token_idx < current.size(); token_idx++)
                {
                    if(!m_tokenMap[m_preType].contains(current[token_idx]->type))
                        continue;

                    Token tk;
                    MatchType matchType = current[token_idx]->match(word,tk);
                    if(matchType != Match_None)
                        next.push_back(current[token_idx]);
                    if(matchType == Match_Full)
                        curToken.push_back(tk);
                }

                if(next.size() == 0 || m_index == m_expr.size() - 1)
                {
                    if(m_index == m_expr.size() - 1 && curToken.size() != 0)
                    {
                        preToken = curToken;
                        m_index++;
                    }

                    if(preToken.size() == 0)
                    {
                        m_error = "no match";
                        return tkNone;
                    }

                    auto tk = preToken[0];
                    if(tk.type != Token_Space)
                        return tk;
                    else
                        break;
                }

                current = next;
                preToken = curToken;
                m_index++;
            }
        }
        return tkNone;
    }

    bool parse(QString expr,QVector<Token> &tokens)
    {
        expr = expr.simplified();                                        

        m_index = 0;
        m_preType = Token_Start;
        m_expr = expr;
        while(m_index < m_expr.size())
        {
            Token tk = readToken();
            if(tk.type == Token_None)
                return false;

            m_preType = tk.type;
            tokens.push_back(tk);
        }

        if(!m_tokenMap[m_preType].contains(Token_End))
        {
            m_error = "error end";
            return false;
        }

        int bkt = 0;
        for(int i = 0; i < tokens.size(); i++)
        {
            if(tokens[i].type == Token_LBkt)
                bkt++;
            else if(tokens[i].type == Token_RBkt)
                bkt--;
            if(bkt < 0)
                break;
        }
        if(bkt != 0)
        {
            m_error = "bracket error";
            return false;
        }

        return true;
    }

    void trans(QVector<Token> &tokens)
    {
        m_tokenExprs.clear();

        QStack<Token> stack;
        for(int i = 0; i < tokens.size(); i++)
        {
            auto &tk = tokens[i];
            if(tk.isOp())
            {
                int pri = opPri(tk.type);
                int top_pri = stack.size() > 0? opPri(stack.top().type): -1;
                if(pri <= top_pri)
                {
                    while(stack.size() > 0 && stack.top().isOp())
                    {
                        top_pri = opPri(stack.top().type);
                        if(pri <= top_pri)
                            m_tokenExprs.push_back(stack.pop());
                        else
                            break;
                    }
                }
                stack.push(tk);
            }
            else if(tk.type == Token_LBkt)
            {
                stack.push(tk);
            }
            else if(tk.type == Token_RBkt)
            {
                while(stack.size() > 0)
                {
                    Token tk = stack.pop();
                    if(tk.type == Token_LBkt)
                        break;
                    else
                        m_tokenExprs.push_back(tk);
                }
            }
            else
                m_tokenExprs.push_back(tk);
        }

        while(stack.size() > 0)
        {
            m_tokenExprs.push_back(stack.pop());
        }
    }

    double calc()
    {
        QStack<Token> stack;
        for(int i = 0; i < m_tokenExprs.size(); i++)
        {
            if(m_tokenExprs[i].isOp())
            {
                auto b = stack.pop().text.toDouble();
                auto a = stack.pop().text.toDouble();
                double c = 0;
                auto op = m_tokenExprs[i].type;
                if(op == Token_Add)
                    c = a + b;
                else if(op == Token_Sub)
                    c = a - b;
                else if(op == Token_Mul)
                    c = a * b;
                else
                    c = a / b;

                Token ret;
                ret.type = Token_Number;
                ret.text = QString::number(c);
                stack.push(ret);
            }
            else
                stack.push(m_tokenExprs[i]);
        }

        return stack.pop().text.toDouble();
    }

    double eval(QString expr)
    {
        QVector<Token> tokens;
        if(!parse(expr,tokens))
            return 0;

        trans(tokens);
        return calc();
    }

    QString toString()
    {
        QString ret;
        for(int i = 0; i < m_tokenExprs.size(); i++)
            ret += m_tokenExprs[i].text;
        return ret;
    }

    QVector<Token> m_tokenExprs;
    QVector<TokenInfo> m_tokenInfos;
    QMap<TokenType,QVector<TokenType>> m_tokenMap;
    QString m_expr;
    QString m_error;
    TokenType m_preType;
    int m_index;
};

#define DOUBLE_EQU(a,b) (((a) + 0.000001 > (b)) && ((a) - 0.000001 < (b)))
#define CHECK_EXPR(expr) do{ qDebug() << c.eval(#expr) << expr; }while(0)


int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    Calculator c;
    CHECK_EXPR(1+1);
    CHECK_EXPR(1 + 2);
    CHECK_EXPR((1 + 1));
    CHECK_EXPR(1 + 2 + 3);
    CHECK_EXPR(1 + (2 + 3));
    CHECK_EXPR(1 + 1 / 8.0);
    CHECK_EXPR((1 + 1) / 8.0);
    CHECK_EXPR(1 + 1/(8 + 10 * 1.0 - 200));
    CHECK_EXPR(1 + 1/2000.0 * 500 / 80);
    CHECK_EXPR(1.0 + 1.0 * (8 + 100));
    CHECK_EXPR(1 + 2 * 3.0 - 4.0 * 5);
    CHECK_EXPR((1 + 2.3) * (3.0 - 4.0) * 5);
    CHECK_EXPR(1 + 2.0 * 3.0 - 4.0 * 5);
    CHECK_EXPR(1 / 2.0 - 3.0 + 4.0 * 5);
    CHECK_EXPR(1 / 2.0 * 3.0 - 4.0 * 5);
    CHECK_EXPR(-100 + (-100));
    CHECK_EXPR(-100 + (-100 - 5 - -100));

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值