| /* Copyright (c) 2012 Massachusetts Institute of Technology | |
| * | |
| * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| * of this software and associated documentation files (the "Software"), to deal | |
| * in the Software without restriction, including without limitation the rights | |
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| * copies of the Software, and to permit persons to whom the Software is | |
| * furnished to do so, subject to the following conditions: | |
| * | |
| * The above copyright notice and this permission notice shall be included in | |
| * all copies or substantial portions of the Software. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| * THE SOFTWARE. | |
| */ | |
| #include "Calculator.h" | |
| #include <cctype> | |
| #include <iostream> | |
| namespace LibUtil | |
| { | |
| using std::cout; | |
| using std::endl; | |
| using std::scientific; | |
| Calculator::Calculator() | |
| { | |
| m_reserved_chars_ = "+-*/;=()\\"; | |
| } | |
| Calculator::~Calculator() | |
| {} | |
| void Calculator::reset() | |
| { | |
| m_var_.clear(); | |
| return; | |
| } | |
| void Calculator::evaluateString(const String& str_, | |
| const map<String, String> &config, | |
| DSENT::Model *ms_model, | |
| map<string, double> &outputs) | |
| { | |
| istringstream ist(str_); | |
| while(ist) | |
| { | |
| getToken(ist); | |
| if(m_curr_token_ == END) break; | |
| if(m_curr_token_ == SEP) continue; | |
| if((m_curr_token_ == NAME) && (m_value_string_ == "print")) | |
| { | |
| getToken(ist); | |
| if(m_curr_token_ == STRING) | |
| { | |
| String print_str = m_value_string_; | |
| getToken(ist); | |
| if(m_curr_token_ == SEP) | |
| { | |
| outputs[print_str] = 0; | |
| cout << print_str << endl; | |
| } | |
| else | |
| { | |
| double v = expr(ist, false, config, ms_model); | |
| outputs[print_str] = v; | |
| cout << print_str << v << endl; | |
| } | |
| } | |
| else | |
| { | |
| double v = expr(ist, false, config, ms_model); | |
| outputs["Missing Expression"] = v; | |
| cout << v << endl; | |
| } | |
| } | |
| else | |
| { | |
| expr(ist, false, config, ms_model); | |
| } | |
| } | |
| } | |
| Calculator::Token Calculator::getToken(istringstream& ist_) | |
| { | |
| char ch; | |
| do | |
| { | |
| ist_.get(ch); | |
| if(!ist_) | |
| { | |
| m_curr_token_ = END; | |
| return m_curr_token_; | |
| } | |
| } | |
| while(ch != '\n' && isspace(ch)); | |
| switch(ch) | |
| { | |
| case '\n': | |
| m_curr_token_ = END; | |
| return m_curr_token_; | |
| case ';': | |
| m_curr_token_ = SEP; | |
| return m_curr_token_; | |
| case '*': | |
| case '/': | |
| case '+': | |
| case '-': | |
| case '(': | |
| case ')': | |
| case '=': | |
| m_curr_token_ = Token(ch); | |
| return m_curr_token_; | |
| case '0': case '1': case '2': case '3': case '4': | |
| case '5': case '6': case '7': case '8': case '9': | |
| case '.': | |
| ist_.putback(ch); | |
| ist_ >> m_value_number_; | |
| m_curr_token_ = NUMBER; | |
| return m_curr_token_; | |
| case '"': | |
| ist_.get(ch); | |
| m_value_string_ = ""; | |
| while(ist_ && ('"' != ch)) | |
| { | |
| m_value_string_ += String(1, ch); | |
| ist_.get(ch); | |
| } | |
| m_curr_token_ = STRING; | |
| return m_curr_token_; | |
| case '$': | |
| ist_.get(ch); | |
| ASSERT((ch == '('), "[Error] Bad token: '(' expected"); | |
| ist_.get(ch); | |
| m_value_string_ = ""; | |
| while(ist_ && (!isspace(ch)) && (')' != ch)) | |
| { | |
| m_value_string_ += String(1, ch); | |
| ist_.get(ch); | |
| } | |
| m_curr_token_ = NAME2; | |
| return m_curr_token_; | |
| default: | |
| if(isalpha(ch)) | |
| { | |
| m_value_string_ = ch; | |
| ist_.get(ch); | |
| while(ist_ && (isalnum(ch) || ('_' == ch))) | |
| { | |
| m_value_string_ += String(1, ch); | |
| ist_.get(ch); | |
| } | |
| ist_.putback(ch); | |
| m_curr_token_ = NAME; | |
| return m_curr_token_; | |
| } | |
| else | |
| { | |
| String error_msg = "[Error] Bad token: '" + String(ch) + "'"; | |
| throw Exception(error_msg); | |
| } | |
| } | |
| } | |
| double Calculator::prim(istringstream& ist_, bool is_get_, | |
| const map<String, String> &config, | |
| DSENT::Model *ms_model) | |
| { | |
| if(is_get_) | |
| { | |
| getToken(ist_); | |
| } | |
| double v; | |
| switch(m_curr_token_) | |
| { | |
| case NUMBER: | |
| v = m_value_number_; | |
| getToken(ist_); | |
| return v; | |
| case NAME: | |
| if(getToken(ist_) == ASSIGN) | |
| { | |
| String var_name = m_value_string_; | |
| v = expr(ist_, true, config, ms_model); | |
| m_var_.set(var_name, v); | |
| } | |
| else | |
| { | |
| v = m_var_.get(m_value_string_); | |
| } | |
| return v; | |
| case NAME2: | |
| v = getEnvVar(m_value_string_, config, ms_model); | |
| getToken(ist_); | |
| return v; | |
| case MINUS: | |
| return -prim(ist_, true, config, ms_model); | |
| case LP: | |
| v = expr(ist_, true, config, ms_model); | |
| ASSERT((m_curr_token_ == RP), "[Error] ')' expected"); | |
| getToken(ist_); | |
| return v; | |
| default: | |
| ASSERT(0, "[Error] primary expected, get: '" + String(int(m_curr_token_)) + "'"); | |
| } | |
| } | |
| double Calculator::term(istringstream& ist_, bool is_get_, | |
| const map<String, String> &config, | |
| DSENT::Model *ms_model) | |
| { | |
| double left = prim(ist_, is_get_, config, ms_model); | |
| while(1) | |
| { | |
| double d; | |
| switch(m_curr_token_) | |
| { | |
| case MUL: | |
| left *= prim(ist_, true, config, ms_model); | |
| break; | |
| case DIV: | |
| d = prim(ist_, true, config, ms_model); | |
| ASSERT(d, "[Error] divided by 0"); | |
| left /= d; | |
| break; | |
| default: | |
| return left; | |
| } | |
| } | |
| } | |
| double Calculator::expr(istringstream& ist_, bool is_get_, | |
| const map<String, String> &config, | |
| DSENT::Model *ms_model) | |
| { | |
| double left = term(ist_, is_get_, config, ms_model); | |
| while(1) | |
| { | |
| switch(m_curr_token_) | |
| { | |
| case PLUS: | |
| left += term(ist_, true, config, ms_model); | |
| break; | |
| case MINUS: | |
| left -= term(ist_, true, config, ms_model); | |
| break; | |
| default: | |
| return left; | |
| } | |
| } | |
| } | |
| double Calculator::getEnvVar(const String& var_name_, | |
| const map<String, String> &config, | |
| DSENT::Model *ms_model) const | |
| { | |
| return m_var_.get(var_name_); | |
| } | |
| } // namespace LibUtil |