1/* Copyright (c) 2012 Massachusetts Institute of Technology 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to deal 5 * in the Software without restriction, including without limitation the rights 6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 * copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 * THE SOFTWARE. 20 */ 21 22#include "Calculator.h" 23 24#include <cctype> 25#include <iostream> 26 27namespace LibUtil 28{ 29 using std::cout; 30 using std::endl; 31 using std::scientific; 32 33 Calculator::Calculator() 34 { 35 m_reserved_chars_ = "+-*/;=()\\"; 36 } 37 38 Calculator::~Calculator() 39 {} 40 41 void Calculator::reset() 42 { 43 m_var_.clear(); 44 return; 45 } 46 47 void Calculator::evaluateString(const String& str_, 48 const map<String, String> &config, 49 DSENT::Model *ms_model, 50 map<string, double> &outputs) 51 { 52 istringstream ist(str_); 53 54 while(ist) 55 { 56 getToken(ist); 57 if(m_curr_token_ == END) break; 58 if(m_curr_token_ == SEP) continue; 59 if((m_curr_token_ == NAME) && (m_value_string_ == "print")) 60 { 61 getToken(ist); 62 63 if(m_curr_token_ == STRING) 64 { 65 String print_str = m_value_string_; 66 67 getToken(ist); 68 if(m_curr_token_ == SEP) 69 { 70 outputs[print_str] = 0; 71 cout << print_str << endl; 72 } 73 else 74 { 75 double v = expr(ist, false, config, ms_model); 76 outputs[print_str] = v; 77 cout << print_str << v << endl; 78 } 79 } 80 else 81 { 82 double v = expr(ist, false, config, ms_model); 83 outputs["Missing Expression"] = v; 84 cout << v << endl; 85 } 86 } 87 else 88 { 89 expr(ist, false, config, ms_model); 90 } 91 } 92 } 93 94 Calculator::Token Calculator::getToken(istringstream& ist_) 95 { 96 char ch; 97 do 98 { 99 ist_.get(ch); 100 if(!ist_) 101 { 102 m_curr_token_ = END; 103 return m_curr_token_; 104 } 105 } 106 while(ch != '\n' && isspace(ch)); 107 108 switch(ch) 109 { 110 case '\n': 111 m_curr_token_ = END; 112 return m_curr_token_; 113 case ';': 114 m_curr_token_ = SEP; 115 return m_curr_token_; 116 case '*': 117 case '/': 118 case '+': 119 case '-': 120 case '(': 121 case ')': 122 case '=': 123 m_curr_token_ = Token(ch); 124 return m_curr_token_; 125 case '0': case '1': case '2': case '3': case '4': 126 case '5': case '6': case '7': case '8': case '9': 127 case '.': 128 ist_.putback(ch); 129 ist_ >> m_value_number_; 130 m_curr_token_ = NUMBER; 131 return m_curr_token_; 132 case '"': 133 ist_.get(ch); 134 m_value_string_ = ""; 135 while(ist_ && ('"' != ch)) 136 { 137 m_value_string_ += String(1, ch); 138 ist_.get(ch); 139 } 140 m_curr_token_ = STRING; 141 return m_curr_token_; 142 case '$': 143 ist_.get(ch); 144 ASSERT((ch == '('), "[Error] Bad token: '(' expected"); 145 ist_.get(ch); 146 m_value_string_ = ""; 147 while(ist_ && (!isspace(ch)) && (')' != ch)) 148 { 149 m_value_string_ += String(1, ch); 150 ist_.get(ch); 151 } 152 m_curr_token_ = NAME2; 153 return m_curr_token_; 154 default: 155 if(isalpha(ch)) 156 { 157 m_value_string_ = ch; 158 ist_.get(ch); 159 while(ist_ && (isalnum(ch) || ('_' == ch))) 160 { 161 m_value_string_ += String(1, ch); 162 ist_.get(ch); 163 } 164 ist_.putback(ch); 165 m_curr_token_ = NAME; 166 return m_curr_token_; 167 } 168 else 169 { 170 String error_msg = "[Error] Bad token: '" + String(ch) + "'"; 171 throw Exception(error_msg); 172 } 173 } 174 } 175 176 double Calculator::prim(istringstream& ist_, bool is_get_, 177 const map<String, String> &config, 178 DSENT::Model *ms_model) 179 { 180 if(is_get_) 181 { 182 getToken(ist_); 183 } 184 185 double v; 186 switch(m_curr_token_) 187 { 188 case NUMBER: 189 v = m_value_number_; 190 getToken(ist_); 191 return v; 192 case NAME: 193 if(getToken(ist_) == ASSIGN) 194 { 195 String var_name = m_value_string_; 196 v = expr(ist_, true, config, ms_model); 197 m_var_.set(var_name, v); 198 } 199 else 200 { 201 v = m_var_.get(m_value_string_); 202 } 203 return v; 204 case NAME2: 205 v = getEnvVar(m_value_string_, config, ms_model); 206 getToken(ist_); 207 return v; 208 case MINUS: 209 return -prim(ist_, true, config, ms_model); 210 case LP: 211 v = expr(ist_, true, config, ms_model); 212 ASSERT((m_curr_token_ == RP), "[Error] ')' expected"); 213 getToken(ist_); 214 return v; 215 default: 216 ASSERT(0, "[Error] primary expected, get: '" + String(int(m_curr_token_)) + "'"); 217 } 218 } 219 220 double Calculator::term(istringstream& ist_, bool is_get_, 221 const map<String, String> &config, 222 DSENT::Model *ms_model) 223 { 224 double left = prim(ist_, is_get_, config, ms_model); 225 226 while(1) 227 { 228 double d; 229 switch(m_curr_token_) 230 { 231 case MUL: 232 left *= prim(ist_, true, config, ms_model); 233 break; 234 case DIV: 235 d = prim(ist_, true, config, ms_model); 236 ASSERT(d, "[Error] divided by 0"); 237 left /= d; 238 break; 239 default: 240 return left; 241 } 242 } 243 } 244 245 double Calculator::expr(istringstream& ist_, bool is_get_, 246 const map<String, String> &config, 247 DSENT::Model *ms_model) 248 { 249 double left = term(ist_, is_get_, config, ms_model); 250 251 while(1) 252 { 253 switch(m_curr_token_) 254 { 255 case PLUS: 256 left += term(ist_, true, config, ms_model); 257 break; 258 case MINUS: 259 left -= term(ist_, true, config, ms_model); 260 break; 261 default: 262 return left; 263 } 264 } 265 } 266 267 double Calculator::getEnvVar(const String& var_name_, 268 const map<String, String> &config, 269 DSENT::Model *ms_model) const 270 { 271 return m_var_.get(var_name_); 272 } 273} // namespace LibUtil 274