如何用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
 17 using   namespace  std;
 18
 19 //  define const variable for readability
 20 const   int  OPERATOR  =   0
 21 const   int  OPERAND   =   1 ;
 22
 23 class  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
 53 int  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
 62 Expression::Expression()  {
 63
 64}

 65
 66 //  constructor
 67 Expression::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
 73 string  Expression::char2str( const   char   & c)  {
 74  stringstream ss;
 75  ss << c;
 76
 77  return ss.str();
 78}

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

 87
 88 //  convert string to double
 89 double  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
 98 bool  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
111 void  Expression::parseOperand( const   double   & dOperand)  {
112  suffix.push_back(make_pair(OPERAND, dbl2str(dOperand)));
113}

114
115 //  parse operator to operatorStack
116 void  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
145 int  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.
162 void  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
188 double  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
202 double  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, 洪錦魁, 文魁出版社

你可能感兴趣的:(c/c++)