(原創) 如何用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 ExpandedBlockStart.gif ContractedBlock.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*/

  9 None.gif
 10 None.gif#include  < iostream >   //  cout
 11 None.gif #include  < string >     //  string
 12 None.gif #include  < sstream >    //  stringstream
 13 None.gif #include  < stack >      //  stack
 14 None.gif #include  < vector >     //  vector
 15 None.gif #include  < cctype >     //  isdigit()
 16 None.gif
 17 None.gif using   namespace  std;
 18 None.gif
 19 None.gif //  define const variable for readability
 20 None.gif const   int  OPERATOR  =   0
 21 None.gif const   int  OPERAND   =   1 ;
 22 None.gif
 23 ExpandedBlockStart.gifContractedBlock.gif class  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}
;
 52 None.gif
 53 ExpandedBlockStart.gifContractedBlock.gif int  main( void dot.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}

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

 65 None.gif
 66 None.gif //  constructor
 67 ExpandedBlockStart.gifContractedBlock.gif Expression::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}

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

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

 87 None.gif
 88 None.gif //  convert string to double
 89 ExpandedBlockStart.gifContractedBlock.gif double  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}

 96 None.gif
 97 None.gif //  identify whether it is an operator
 98 ExpandedBlockStart.gifContractedBlock.gif bool  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}

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

114 None.gif
115 None.gif //  parse operator to operatorStack
116 ExpandedBlockStart.gifContractedBlock.gif void  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}

143 None.gif
144 None.gif //  define operator priority
145 ExpandedBlockStart.gifContractedBlock.gif int  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}

155 None.gif
156 None.gif //  Convert infix to suffix
157 None.gif //  Algorithm : Parse infix string one char by one char. If char 
158 None.gif //              is operator, check if _operand is "", if not, let 
159 None.gif //              _operand to operandStack, and make _operand string 
160 None.gif //              clear, then let operator to operatorStack. If char 
161 None.gif //              is digit, concatenate to _operand string.
162 ExpandedBlockStart.gifContractedBlock.gif void  Expression::toSuffix( void dot.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}

186 None.gif
187 None.gif //  calculate result by operator and operand
188 ExpandedBlockStart.gifContractedBlock.gif double  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}

200 None.gif
201 None.gif //  get eval result
202 ExpandedBlockStart.gifContractedBlock.gif double  Expression::eval( void dot.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.gif x1 = 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、付费专栏及课程。

余额充值