(原創) 如何用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方式。

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

  1/* 
  2(C) OOMusou 2007 http://oomusou.cnblogs.com
  3
  4Filename    : eval.cpp
  5Compiler    : Visual C++ 8.0 / ISO C++
  6Description : Demo how to implement eval() by C++
  7Release     : 01/06/2007 1.0
  8*/

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

 60
 61// constructor
 62Expression::Expression() {
 63
 64}

 65
 66// constructor
 67Expression::Expression(const char *val) {
 68  this->infix = string(val); // fill infix by constructor
 69  this->toSuffix();          // convert infix to suffix
 70}

 71
 72// convert char to string
 73string Expression::char2str(const char &c) {
 74  stringstream ss;
 75  ss << c;
 76
 77  return ss.str();
 78}

 79
 80// convert double to string
 81string Expression::dbl2str(const double &d) {
 82  stringstream ss;
 83  ss << d;
 84  
 85  return ss.str();
 86}

 87
 88// convert string to double
 89double Expression::str2dbl(const string &s) {
 90  stringstream ss(s);
 91  double d;
 92  ss >> d;
 93
 94  return d;
 95}

 96
 97// identify whether it is an operator
 98bool Expression::isoperator(const char &c) {
 99  switch(c) {
100    case '(' :
101    case ')' :
102    case '+' :
103    case '-' :
104    case '*' :
105    case '/' : return true;
106    default  : return false;
107  }

108}

109
110// parse operand to operandStack
111void Expression::parseOperand(const double &dOperand) {
112  suffix.push_back(make_pair(OPERAND, dbl2str(dOperand)));
113}

114
115// parse operator to operatorStack
116void Expression::parseOperator(const char &cOperator) {
117  if (operatorStack.empty() || cOperator == '('{
118    operatorStack.push(cOperator);
119  }

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

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

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

139      operatorStack.push(cOperator);
140    }

141  }

142}

143
144// define operator priority
145int Expression::operatorPriority(const char &cOperator) {
146  switch(cOperator) {
147    case '*' :
148    case '/' : return 3;
149    case '+' :
150    case '-' : return 2;
151    case '(' : return 1;
152    default  : return 0;
153  }

154}

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

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

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

185}

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

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

215    else if (iter->first == OPERAND) {
216      operandStack.push(str2dbl(iter->second));
217    }

218  }

219
220  return operandStack.top();
221}


執行結果

x1=519.75
x2
=19.6667
請按任意鍵繼續 . . .

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

posted on 2007-01-06 01:36  真 OO无双  阅读(6978)  评论(0编辑  收藏  举报

导航