(原創) 如何用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<int, string> > 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<int, string> >::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}
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<int, string> > 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<int, string> >::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
請按任意鍵繼續 . . .
x2=19.6667
請按任意鍵繼續 . . .
Reference
看程式實例學資料結構 使用Turbo C P.5-25 ~ P.5-54, 洪錦魁, 文魁出版社