代码清单
1 // calculator.h 2 #ifndef CALCULATOR_H 3 #define CALCULATOR_H 4 5 #include <stack> 6 #include <string> 7 #include <iostream> 8 #include <cassert> 9 10 using namespace std; 11 12 typedef enum { 13 BEGIN, 14 NUMBER, 15 OPERATOR, 16 LEFT_BRAC, 17 RIGHT_BRAC 18 } TokenType; 19 20 class Calculator 21 { 22 public: 23 double calculate(string expression) throw(string); 24 25 private: 26 stack<double> _stkNumbers; 27 stack<char> _stkOperators; 28 29 static int priority(char op); 30 static double calculate(double d1, char op, double d2) throw(string); 31 32 void calculateStack() throw(string); 33 void dealWithNumber(char *&pToken) throw(string); 34 void dealWithOperator(char *&pToken) throw(string); 35 void dealWithLeftBrac(char *&pToken) throw(string); 36 void dealWithRightBrac(char *&pToken) throw(string); 37 }; 38 39 #endif // CALCULATOR_H 40 41 // calculator.cpp 42 #include "calculator.h" 43 44 int Calculator::priority(char op) { 45 assert(op == '+' || op == '-' || op == '*' || op == '/' || op == '('); 46 47 if (op == '+' || op == '-') { 48 return 1; 49 } else if (op == '*' || op == '/') { 50 return 2; 51 } else { 52 return 0; 53 } 54 } 55 56 double Calculator::calculate(double d1, char op, double d2) throw (string) { 57 assert(op == '+' || op == '-' || op == '*' || op == '/'); 58 59 cout << d1 << op << d2 << endl; 60 61 if (op == '+') { 62 return d1 + d2; 63 } else if (op == '-') { 64 return d1 - d2; 65 } else if (op == '*') { 66 return d1 * d2; 67 } else { 68 if (!d2) { 69 throw string("divided by 0"); 70 } 71 return d1 / d2; 72 } 73 } 74 75 void Calculator::calculateStack() throw (string) { 76 double d2 = _stkNumbers.top(); 77 _stkNumbers.pop(); 78 double d1 = _stkNumbers.top(); 79 _stkNumbers.pop(); 80 char op = _stkOperators.top(); 81 _stkOperators.pop(); 82 _stkNumbers.push(calculate(d1, op, d2)); 83 } 84 85 double Calculator::calculate(string expression) throw (string) { 86 while (!_stkNumbers.empty()) { 87 _stkNumbers.pop(); 88 } 89 while (!_stkOperators.empty()) { 90 _stkOperators.pop(); 91 } 92 TokenType lastToken = BEGIN; 93 94 char * pToken = &expression[0]; 95 while (*pToken) { 96 switch (lastToken) { 97 case BEGIN: 98 if (*pToken == '(') { 99 // an expression begin with a left bracket 100 dealWithLeftBrac(pToken); 101 lastToken = LEFT_BRAC; 102 } else { 103 // or a number 104 dealWithNumber(pToken); 105 lastToken = NUMBER; 106 } 107 break; 108 case NUMBER: 109 // after a number 110 if (*pToken == ')') { 111 // it may be a right bracket 112 dealWithRightBrac(pToken); 113 lastToken = RIGHT_BRAC; 114 } else { 115 // it may be an operator 116 dealWithOperator(pToken); 117 lastToken = OPERATOR; 118 } 119 break; 120 case OPERATOR: 121 case LEFT_BRAC: 122 // after an operator or a left bracket 123 if (*pToken == '(') { 124 // it may be a left bracket 125 dealWithLeftBrac(pToken); 126 lastToken = LEFT_BRAC; 127 } else { 128 // it may be a number 129 dealWithNumber(pToken); 130 lastToken = NUMBER; 131 } 132 break; 133 case RIGHT_BRAC: 134 // after a right bracket 135 if (*pToken == ')') { 136 // it may be another right bracket 137 dealWithRightBrac(pToken); 138 lastToken = RIGHT_BRAC; 139 } else { 140 // it may be an operator 141 dealWithOperator(pToken); 142 lastToken = OPERATOR; 143 } 144 break; 145 } 146 } 147 148 while (!_stkOperators.empty()) { 149 if (_stkOperators.top() == '(') { 150 throw string("bad token '('"); 151 } 152 calculateStack(); 153 } 154 155 assert(!_stkNumbers.empty()); 156 return _stkNumbers.top(); 157 } 158 159 void Calculator::dealWithNumber(char *&pToken) throw (string) { 160 if (!isdigit(*pToken) && *pToken != '-') { 161 throw string("bad token '") + *pToken + "'"; 162 } 163 _stkNumbers.push(strtod(pToken, &pToken)); 164 } 165 166 void Calculator::dealWithOperator(char *&pToken) throw (string) { 167 if (*pToken != '+' && *pToken != '-' && *pToken != '*' && *pToken != '/') { 168 throw string("bad token '") + *pToken + "'"; 169 } 170 if (!_stkOperators.empty() 171 && priority(_stkOperators.top()) >= priority(*pToken)) { 172 calculateStack(); 173 } 174 _stkOperators.push(*pToken); 175 pToken++; 176 } 177 178 void Calculator::dealWithLeftBrac(char *&pToken) throw (string) { 179 if (*pToken != '(') { 180 throw string("bad token '") + *pToken + "'"; 181 } 182 _stkOperators.push(*pToken); 183 pToken++; 184 } 185 186 void Calculator::dealWithRightBrac(char *&pToken) throw (string) { 187 if (*pToken != ')') { 188 throw string("bad token '") + *pToken + "'"; 189 } 190 while (!_stkOperators.empty() && _stkOperators.top() != '(') { 191 calculateStack(); 192 if (_stkOperators.empty()) { 193 throw string("bad token ')'"); 194 } 195 } 196 _stkOperators.pop(); 197 pToken++; 198 } 199 200 // main.cpp 201 #include "calculator.h" 202 203 int main(int argc, char *argv[]) 204 { 205 Calculator calculator; 206 207 if (argc > 1) { 208 if (argc == 2) { 209 cout << calculator.calculate(string(argv[1])) << endl; 210 } else { 211 cout << "too many arguments" << endl; 212 return -1; 213 } 214 } else { 215 while (1) { 216 string expression; 217 cout << ">" << flush; 218 cin >> expression; 219 if (expression == "quit;") { 220 cout << "Bye." << endl; 221 return 0; 222 } 223 try { 224 cout << calculator.calculate(expression) << endl; 225 } catch (string ex) { 226 cout << ex << endl; 227 } 228 } 229 } 230 }