(原創) 如何用C++實作eval()? (C/C++)

C/C++都是靜態語言,所以都沒有eval()這個函數,C#也沒有,在.NET語言中,只有JScript.NET有eval(),連VB也沒有,事實上,eval()是很好用的,以前在寫VFP時,常常利用字串湊程式,然後用eval()去執行,來到C#,一直想用eval(),若真的想在C#用,可以偷用JScript.NET的,有時間會另外討論這個主題。

在此程式我們試著用C++寫一個eval(),不過這個eval()功能有限,只能處理四則運算加上括號而已,在很多資料結構講stack的地方,會用C語言利用stack來寫,事實上,本程式也是參考『看程式實例學資料結構 使用Turbo C』的範例加以修改成C++和STL,以及OOP方式。

本程式的演算法是,先將人類習慣的『中序運算式』表示法先改成『後序運算式』表示法,因為後序式不需考慮括號的處理,比較簡單,然後再加以運算。

  1ExpandedBlockStart.gifContractedBlock.gif/**//* 
  2InBlock.gif(C) OOMusou 2007 http://oomusou.cnblogs.com
  3InBlock.gif
  4InBlock.gifFilename    : eval.cpp
  5InBlock.gifCompiler    : Visual C++ 8.0 / ISO C++
  6InBlock.gifDescription : Demo how to implement eval() by C++
  7InBlock.gifRelease     : 01/06/2007 1.0
  8ExpandedBlockEnd.gif*/

  9None.gif
 10None.gif#include <iostream> // cout
 11None.gif#include <string>   // string
 12None.gif#include <sstream>  // stringstream
 13None.gif#include <stack>    // stack
 14None.gif#include <vector>   // vector
 15None.gif#include <cctype>   // isdigit()
 16None.gif
 17None.gifusing namespace std;
 18None.gif
 19None.gif// define const variable for readability
 20None.gifconst int OPERATOR = 0
 21None.gifconst int OPERAND  = 1;
 22None.gif
 23ExpandedBlockStart.gifContractedBlock.gifclass Expression dot.gif{
 24InBlock.gif// constructor
 25InBlock.gifpublic
 26InBlock.gif  Expression();
 27InBlock.gif  Expression(const char*);
 28InBlock.gif
 29InBlock.gif// public member function
 30InBlock.gifpublic:
 31InBlock.gif  double eval(); // get eval result
 32InBlock.gif
 33InBlock.gif// private data member
 34InBlock.gifprivate
 35InBlock.gif  stack<double> operandStack; // stack to store operand
 36InBlock.gif  stack<char> operatorStack;  // stack to store operator
 37InBlock.gif  string infix;               // string to hold infix expression
 38InBlock.gif  vector<pair<intstring> > suffix; // vector to hold suffix expression
 39InBlock.gif
 40InBlock.gif// private member function
 41InBlock.gifprivate:
 42InBlock.gif  string char2str(const char &);      // convert char to string
 43InBlock.gif  string dbl2str(const double &);     // convert double to string
 44InBlock.gif  double str2dbl(const string &);     // convert string to double
 45InBlock.gif  bool isoperator(const char &);      // identify whether it is an operator
 46InBlock.gif  void parseOperand(const double &);  // parse operand to operandStack
 47InBlock.gif  void parseOperator(const char &);   // parse operator to operatorStack
 48InBlock.gif  int operatorPriority(const char&); // define operator priority
 49InBlock.gif  void toSuffix(void);        // convert infix to suffix
 50InBlock.gif  double calculate(const string &const double &const double &); // calculate result by operator and operand
 51ExpandedBlockEnd.gif}
;
 52None.gif
 53ExpandedBlockStart.gifContractedBlock.gifint main(voiddot.gif{
 54InBlock.gif  Expression x1("123/4+123*4-3");
 55InBlock.gif  cout << "x1=" << x1.eval() << endl;
 56InBlock.gif
 57InBlock.gif  Expression x2("1+(6+8)*4/3");
 58InBlock.gif  cout << "x2=" << x2.eval() << endl;
 59ExpandedBlockEnd.gif}

 60None.gif
 61None.gif// constructor
 62ExpandedBlockStart.gifContractedBlock.gifExpression::Expression() dot.gif{
 63InBlock.gif
 64ExpandedBlockEnd.gif}

 65None.gif
 66None.gif// constructor
 67ExpandedBlockStart.gifContractedBlock.gifExpression::Expression(const char *val) dot.gif{
 68InBlock.gif  this->infix = string(val); // fill infix by constructor
 69InBlock.gif  this->toSuffix();          // convert infix to suffix
 70ExpandedBlockEnd.gif}

 71None.gif
 72None.gif// convert char to string
 73ExpandedBlockStart.gifContractedBlock.gifstring Expression::char2str(const char &c) dot.gif{
 74InBlock.gif  stringstream ss;
 75InBlock.gif  ss << c;
 76InBlock.gif
 77InBlock.gif  return ss.str();
 78ExpandedBlockEnd.gif}

 79None.gif
 80None.gif// convert double to string
 81ExpandedBlockStart.gifContractedBlock.gifstring Expression::dbl2str(const double &d) dot.gif{
 82InBlock.gif  stringstream ss;
 83InBlock.gif  ss << d;
 84InBlock.gif  
 85InBlock.gif  return ss.str();
 86ExpandedBlockEnd.gif}

 87None.gif
 88None.gif// convert string to double
 89ExpandedBlockStart.gifContractedBlock.gifdouble Expression::str2dbl(const string &s) dot.gif{
 90InBlock.gif  stringstream ss(s);
 91InBlock.gif  double d;
 92InBlock.gif  ss >> d;
 93InBlock.gif
 94InBlock.gif  return d;
 95ExpandedBlockEnd.gif}

 96None.gif
 97None.gif// identify whether it is an operator
 98ExpandedBlockStart.gifContractedBlock.gifbool Expression::isoperator(const char &c) dot.gif{
 99ExpandedSubBlockStart.gifContractedSubBlock.gif  switch(c) dot.gif{
100InBlock.gif    case '(' :
101InBlock.gif    case ')' :
102InBlock.gif    case '+' :
103InBlock.gif    case '-' :
104InBlock.gif    case '*' :
105InBlock.gif    case '/' : return true;
106InBlock.gif    default  : return false;
107ExpandedSubBlockEnd.gif  }

108ExpandedBlockEnd.gif}

109None.gif
110None.gif// parse operand to operandStack
111ExpandedBlockStart.gifContractedBlock.gifvoid Expression::parseOperand(const double &dOperand) dot.gif{
112InBlock.gif  suffix.push_back(make_pair(OPERAND, dbl2str(dOperand)));
113ExpandedBlockEnd.gif}

114None.gif
115None.gif// parse operator to operatorStack
116ExpandedBlockStart.gifContractedBlock.gifvoid Expression::parseOperator(const char &cOperator) dot.gif{
117ExpandedSubBlockStart.gifContractedSubBlock.gif  if (operatorStack.empty() || cOperator == '('dot.gif{
118InBlock.gif    operatorStack.push(cOperator);
119ExpandedSubBlockEnd.gif  }

120ExpandedSubBlockStart.gifContractedSubBlock.gif  else dot.gif{
121ExpandedSubBlockStart.gifContractedSubBlock.gif    if (cOperator == ')'dot.gif{
122ExpandedSubBlockStart.gifContractedSubBlock.gif      while(operatorStack.top() != '('dot.gif{
123InBlock.gif        suffix.push_back(make_pair(OPERATOR, char2str(operatorStack.top())));
124InBlock.gif        operatorStack.pop();
125InBlock.gif
126InBlock.gif        if (operandStack.empty()) break;
127ExpandedSubBlockEnd.gif      }

128InBlock.gif      // Remove '('
129InBlock.gif      operatorStack.pop();
130ExpandedSubBlockEnd.gif    }

131ExpandedSubBlockStart.gifContractedSubBlock.gif    else dot.gif// not ')'
132ExpandedSubBlockStart.gifContractedSubBlock.gif      while(operatorPriority(cOperator) <= operatorPriority(operatorStack.top()) && !operatorStack.empty()) dot.gif{
133InBlock.gif        suffix.push_back(make_pair(OPERATOR, char2str(operatorStack.top())));
134InBlock.gif        operatorStack.pop();
135InBlock.gif
136InBlock.gif        if (operatorStack.empty()) 
137InBlock.gif          break;
138ExpandedSubBlockEnd.gif      }

139InBlock.gif      operatorStack.push(cOperator);
140ExpandedSubBlockEnd.gif    }

141ExpandedSubBlockEnd.gif  }

142ExpandedBlockEnd.gif}

143None.gif
144None.gif// define operator priority
145ExpandedBlockStart.gifContractedBlock.gifint Expression::operatorPriority(const char &cOperator) dot.gif{
146ExpandedSubBlockStart.gifContractedSubBlock.gif  switch(cOperator) dot.gif{
147InBlock.gif    case '*' :
148InBlock.gif    case '/' : return 3;
149InBlock.gif    case '+' :
150InBlock.gif    case '-' : return 2;
151InBlock.gif    case '(' : return 1;
152InBlock.gif    default  : return 0;
153ExpandedSubBlockEnd.gif  }

154ExpandedBlockEnd.gif}

155None.gif
156None.gif// Convert infix to suffix
157None.gif// Algorithm : Parse infix string one char by one char. If char 
158None.gif//             is operator, check if _operand is "", if not, let 
159None.gif//             _operand to operandStack, and make _operand string 
160None.gif//             clear, then let operator to operatorStack. If char 
161None.gif//             is digit, concatenate to _operand string.
162ExpandedBlockStart.gifContractedBlock.gifvoid Expression::toSuffix(voiddot.gif{
163InBlock.gif  string _operand;
164ExpandedSubBlockStart.gifContractedSubBlock.gif  for(string::iterator p = infix.begin(); p != infix.end(); ++p) dot.gif{
165ExpandedSubBlockStart.gifContractedSubBlock.gif    if (isoperator(*p)) dot.gif{
166ExpandedSubBlockStart.gifContractedSubBlock.gif      if (_operand != ""dot.gif{
167InBlock.gif        parseOperand(str2dbl(_operand));
168InBlock.gif        _operand.clear();
169ExpandedSubBlockEnd.gif      }

170InBlock.gif      parseOperator(*p);
171ExpandedSubBlockEnd.gif    }
 else if (isdigit(*p)) 
172InBlock.gif      _operand.push_back(*p);
173ExpandedSubBlockEnd.gif  }

174InBlock.gif
175InBlock.gif  // If _operand is not "", let _operand to operandStack.
176InBlock.gif  if (_operand != "")
177InBlock.gif    parseOperand(str2dbl(_operand));
178InBlock.gif
179InBlock.gif  // If operatorStack is not empty, push it to suffix vector until
180InBlock.gif  // operatorStack is empty.
181ExpandedSubBlockStart.gifContractedSubBlock.gif  while(!operatorStack.empty()) dot.gif{
182InBlock.gif    suffix.push_back(make_pair(OPERATOR,char2str(operatorStack.top())));
183InBlock.gif    operatorStack.pop();
184ExpandedSubBlockEnd.gif  }

185ExpandedBlockEnd.gif}

186None.gif
187None.gif// calculate result by operator and operand
188ExpandedBlockStart.gifContractedBlock.gifdouble Expression::calculate(const string &op, const double &operand1, const double &operand2) dot.gif{
189InBlock.gif  if (op == "+"
190InBlock.gif    return operand2 + operand1;
191InBlock.gif  else if (op == "-"
192InBlock.gif    return operand2 - operand1;
193InBlock.gif  else if (op == "*")
194InBlock.gif    return operand2 * operand1;
195InBlock.gif  else if (op == "/")
196InBlock.gif    return operand2 / operand1;
197InBlock.gif  else
198InBlock.gif    return 0;
199ExpandedBlockEnd.gif}

200None.gif
201None.gif// get eval result
202ExpandedBlockStart.gifContractedBlock.gifdouble Expression::eval(voiddot.gif{
203InBlock.gif  // Clear OperandStack
204InBlock.gif  while(!operandStack.empty())
205InBlock.gif    operandStack.pop();
206InBlock.gif
207ExpandedSubBlockStart.gifContractedSubBlock.gif  for(vector<pair<intstring> >::iterator iter = suffix.begin(); iter != suffix.end(); ++iter) dot.gif{
208ExpandedSubBlockStart.gifContractedSubBlock.gif    if (iter->first == OPERATOR) dot.gif{
209InBlock.gif      double operand1 = operandStack.top();
210InBlock.gif      operandStack.pop();
211InBlock.gif      double operand2 = operandStack.top();
212InBlock.gif      operandStack.pop();
213InBlock.gif      operandStack.push(calculate(iter->second, operand1, operand2));
214ExpandedSubBlockEnd.gif    }

215ExpandedSubBlockStart.gifContractedSubBlock.gif    else if (iter->first == OPERAND) dot.gif{
216InBlock.gif      operandStack.push(str2dbl(iter->second));
217ExpandedSubBlockEnd.gif    }

218ExpandedSubBlockEnd.gif  }

219InBlock.gif
220InBlock.gif  return operandStack.top();
221ExpandedBlockEnd.gif}


執行結果

None.gifx1=519.75
None.gifx2
=19.6667
None.gif請按任意鍵繼續 . . .

Reference
看程式實例學資料結構 使用Turbo C P.5-25 ~ P.5-54, 洪錦魁, 文魁出版社
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值