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