Calculator.cc revision 10447:a465576671d4
1#include "Calculator.h" 2 3#include <cctype> 4#include <iostream> 5 6namespace LibUtil 7{ 8 using std::cout; 9 using std::endl; 10 using std::scientific; 11 12 Calculator::Calculator() 13 { 14 m_reserved_chars_ = "+-*/;=()\\"; 15 } 16 17 Calculator::~Calculator() 18 {} 19 20 void Calculator::reset() 21 { 22 m_var_.clear(); 23 return; 24 } 25 26 void Calculator::evaluateString(const String& str_) 27 { 28 istringstream ist(str_); 29 while(ist) 30 { 31 getToken(ist); 32 if(m_curr_token_ == END) break; 33 if(m_curr_token_ == SEP) continue; 34 if((m_curr_token_ == NAME) && (m_value_string_ == "print")) 35 { 36 getToken(ist); 37 38 if(m_curr_token_ == STRING) 39 { 40 String print_str = m_value_string_; 41 42 getToken(ist); 43 if(m_curr_token_ == SEP) 44 { 45 cout << print_str << endl; 46 } 47 else 48 { 49 double v = expr(ist, false); 50 cout << scientific << print_str << v << endl; 51 } 52 } 53 else 54 { 55 double v = expr(ist, false); 56 cout << scientific << v << endl; 57 } 58 } 59 else 60 { 61 expr(ist, false); 62 } 63 } 64 return; 65 } 66 67 Calculator::Token Calculator::getToken(istringstream& ist_) 68 { 69 char ch; 70 do 71 { 72 ist_.get(ch); 73 if(!ist_) 74 { 75 m_curr_token_ = END; 76 return m_curr_token_; 77 } 78 } 79 while(ch != '\n' && isspace(ch)); 80 81 switch(ch) 82 { 83 case '\n': 84 m_curr_token_ = END; 85 return m_curr_token_; 86 case ';': 87 m_curr_token_ = SEP; 88 return m_curr_token_; 89 case '*': 90 case '/': 91 case '+': 92 case '-': 93 case '(': 94 case ')': 95 case '=': 96 m_curr_token_ = Token(ch); 97 return m_curr_token_; 98 case '0': case '1': case '2': case '3': case '4': 99 case '5': case '6': case '7': case '8': case '9': 100 case '.': 101 ist_.putback(ch); 102 ist_ >> m_value_number_; 103 m_curr_token_ = NUMBER; 104 return m_curr_token_; 105 case '"': 106 ist_.get(ch); 107 m_value_string_ = ""; 108 while(ist_ && ('"' != ch)) 109 { 110 m_value_string_ += String(1, ch); 111 ist_.get(ch); 112 } 113 m_curr_token_ = STRING; 114 return m_curr_token_; 115 case '$': 116 ist_.get(ch); 117 ASSERT((ch == '('), "[Error] Bad token: '(' expected"); 118 ist_.get(ch); 119 m_value_string_ = ""; 120 while(ist_ && (!isspace(ch)) && (')' != ch)) 121 { 122 m_value_string_ += String(1, ch); 123 ist_.get(ch); 124 } 125 m_curr_token_ = NAME2; 126 return m_curr_token_; 127 default: 128 if(isalpha(ch)) 129 { 130 m_value_string_ = ch; 131 ist_.get(ch); 132 while(ist_ && (isalnum(ch) || ('_' == ch))) 133 { 134 m_value_string_ += String(1, ch); 135 ist_.get(ch); 136 } 137 ist_.putback(ch); 138 m_curr_token_ = NAME; 139 return m_curr_token_; 140 } 141 else 142 { 143 String error_msg = "[Error] Bad token: '" + String(ch) + "'"; 144 throw Exception(error_msg); 145 } 146 } 147 } 148 149 double Calculator::prim(istringstream& ist_, bool is_get_) 150 { 151 if(is_get_) 152 { 153 getToken(ist_); 154 } 155 156 double v; 157 switch(m_curr_token_) 158 { 159 case NUMBER: 160 v = m_value_number_; 161 getToken(ist_); 162 return v; 163 case NAME: 164 if(getToken(ist_) == ASSIGN) 165 { 166 String var_name = m_value_string_; 167 v = expr(ist_, true); 168 m_var_.set(var_name, v); 169 } 170 else 171 { 172 v = m_var_.get(m_value_string_); 173 } 174 return v; 175 case NAME2: 176 v = getEnvVar(m_value_string_); 177 getToken(ist_); 178 return v; 179 case MINUS: 180 return -prim(ist_, true); 181 case LP: 182 v = expr(ist_, true); 183 ASSERT((m_curr_token_ == RP), "[Error] ')' expected"); 184 getToken(ist_); 185 return v; 186 default: 187 ASSERT(0, "[Error] primary expected, get: '" + String(int(m_curr_token_)) + "'"); 188 } 189 } 190 191 double Calculator::term(istringstream& ist_, bool is_get_) 192 { 193 double left = prim(ist_, is_get_); 194 195 while(1) 196 { 197 double d; 198 switch(m_curr_token_) 199 { 200 case MUL: 201 left *= prim(ist_, true); 202 break; 203 case DIV: 204 d = prim(ist_, true); 205 ASSERT(d, "[Error] divided by 0"); 206 left /= d; 207 break; 208 default: 209 return left; 210 } 211 } 212 } 213 214 double Calculator::expr(istringstream& ist_, bool is_get_) 215 { 216 double left = term(ist_, is_get_); 217 218 while(1) 219 { 220 switch(m_curr_token_) 221 { 222 case PLUS: 223 left += term(ist_, true); 224 break; 225 case MINUS: 226 left -= term(ist_, true); 227 break; 228 default: 229 return left; 230 } 231 } 232 } 233 234 double Calculator::getEnvVar(const String& var_name_) const 235 { 236 return m_var_.get(var_name_); 237 } 238} // namespace LibUtil 239 240