(原創) 如何用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
4
Filename : eval.cpp
5
Compiler : Visual C++ 8.0 / ISO C++
6
Description : Demo how to implement eval() by C++
7
Release : 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
25
public:
26
Expression();
27
Expression(const char*);
28
29
// public member function
30
public:
31
double eval(); // get eval result
32
33
// private data member
34
private:
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
41
private:
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<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.com3

4
Filename : eval.cpp5
Compiler : Visual C++ 8.0 / ISO C++6
Description : Demo how to implement eval() by C++7
Release : 01/06/2007 1.08
*/9

10
#include <iostream> // cout11
#include <string> // string12
#include <sstream> // stringstream13
#include <stack> // stack14
#include <vector> // vector15
#include <cctype> // isdigit()16

17
using namespace std;18

19
// define const variable for readability20
const int OPERATOR = 0; 21
const int OPERAND = 1;22

23
class Expression {24
// constructor25
public: 26
Expression();27
Expression(const char*);28

29
// public member function30
public:31
double eval(); // get eval result32

33
// private data member34
private: 35
stack<double> operandStack; // stack to store operand36
stack<char> operatorStack; // stack to store operator37
string infix; // string to hold infix expression38
vector<pair<int, string> > suffix; // vector to hold suffix expression39

40
// private member function41
private:42
string char2str(const char &); // convert char to string43
string dbl2str(const double &); // convert double to string44
double str2dbl(const string &); // convert string to double45
bool isoperator(const char &); // identify whether it is an operator46
void parseOperand(const double &); // parse operand to operandStack47
void parseOperator(const char &); // parse operator to operatorStack48
int operatorPriority(const char&); // define operator priority49
void toSuffix(void); // convert infix to suffix50
double calculate(const string &, const double &, const double &); // calculate result by operator and operand51
};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
// constructor62
Expression::Expression() {63

64
}65

66
// constructor67
Expression::Expression(const char *val) {68
this->infix = string(val); // fill infix by constructor69
this->toSuffix(); // convert infix to suffix70
}71

72
// convert char to string73
string Expression::char2str(const char &c) {74
stringstream ss;75
ss << c;76

77
return ss.str();78
}79

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

88
// convert string to double89
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 operator98
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 operandStack111
void Expression::parseOperand(const double &dOperand) {112
suffix.push_back(make_pair(OPERAND, dbl2str(dOperand)));113
}114

115
// parse operator to operatorStack116
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 priority145
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 suffix157
// 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 until180
// 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 operand188
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
else198
return 0;199
}200

201
// get eval result202
double Expression::eval(void) {203
// Clear OperandStack204
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
請按任意鍵繼續 . . .Reference
看程式實例學資料結構 使用Turbo C P.5-25 ~ P.5-54, 洪錦魁, 文魁出版社


浙公网安备 33010602011771号