110448Snilay@cs.wisc.edu/* Copyright (c) 2012 Massachusetts Institute of Technology 210448Snilay@cs.wisc.edu * 310448Snilay@cs.wisc.edu * Permission is hereby granted, free of charge, to any person obtaining a copy 410448Snilay@cs.wisc.edu * of this software and associated documentation files (the "Software"), to deal 510448Snilay@cs.wisc.edu * in the Software without restriction, including without limitation the rights 610448Snilay@cs.wisc.edu * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 710448Snilay@cs.wisc.edu * copies of the Software, and to permit persons to whom the Software is 810448Snilay@cs.wisc.edu * furnished to do so, subject to the following conditions: 910448Snilay@cs.wisc.edu * 1010448Snilay@cs.wisc.edu * The above copyright notice and this permission notice shall be included in 1110448Snilay@cs.wisc.edu * all copies or substantial portions of the Software. 1210448Snilay@cs.wisc.edu * 1310448Snilay@cs.wisc.edu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1410448Snilay@cs.wisc.edu * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1510448Snilay@cs.wisc.edu * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1610448Snilay@cs.wisc.edu * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1710448Snilay@cs.wisc.edu * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1810448Snilay@cs.wisc.edu * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 1910448Snilay@cs.wisc.edu * THE SOFTWARE. 2010448Snilay@cs.wisc.edu */ 2110448Snilay@cs.wisc.edu 2210447Snilay@cs.wisc.edu#include "Calculator.h" 2310447Snilay@cs.wisc.edu 2410447Snilay@cs.wisc.edu#include <cctype> 2510447Snilay@cs.wisc.edu#include <iostream> 2610447Snilay@cs.wisc.edu 2710447Snilay@cs.wisc.edunamespace LibUtil 2810447Snilay@cs.wisc.edu{ 2910447Snilay@cs.wisc.edu using std::cout; 3010447Snilay@cs.wisc.edu using std::endl; 3110447Snilay@cs.wisc.edu using std::scientific; 3210447Snilay@cs.wisc.edu 3310447Snilay@cs.wisc.edu Calculator::Calculator() 3410447Snilay@cs.wisc.edu { 3510447Snilay@cs.wisc.edu m_reserved_chars_ = "+-*/;=()\\"; 3610447Snilay@cs.wisc.edu } 3710447Snilay@cs.wisc.edu 3810447Snilay@cs.wisc.edu Calculator::~Calculator() 3910447Snilay@cs.wisc.edu {} 4010447Snilay@cs.wisc.edu 4110447Snilay@cs.wisc.edu void Calculator::reset() 4210447Snilay@cs.wisc.edu { 4310447Snilay@cs.wisc.edu m_var_.clear(); 4410447Snilay@cs.wisc.edu return; 4510447Snilay@cs.wisc.edu } 4610447Snilay@cs.wisc.edu 4710448Snilay@cs.wisc.edu void Calculator::evaluateString(const String& str_, 4810448Snilay@cs.wisc.edu const map<String, String> &config, 4910448Snilay@cs.wisc.edu DSENT::Model *ms_model, 5010448Snilay@cs.wisc.edu map<string, double> &outputs) 5110447Snilay@cs.wisc.edu { 5210447Snilay@cs.wisc.edu istringstream ist(str_); 5310448Snilay@cs.wisc.edu 5410447Snilay@cs.wisc.edu while(ist) 5510447Snilay@cs.wisc.edu { 5610447Snilay@cs.wisc.edu getToken(ist); 5710447Snilay@cs.wisc.edu if(m_curr_token_ == END) break; 5810447Snilay@cs.wisc.edu if(m_curr_token_ == SEP) continue; 5910447Snilay@cs.wisc.edu if((m_curr_token_ == NAME) && (m_value_string_ == "print")) 6010447Snilay@cs.wisc.edu { 6110447Snilay@cs.wisc.edu getToken(ist); 6210447Snilay@cs.wisc.edu 6310447Snilay@cs.wisc.edu if(m_curr_token_ == STRING) 6410447Snilay@cs.wisc.edu { 6510447Snilay@cs.wisc.edu String print_str = m_value_string_; 6610447Snilay@cs.wisc.edu 6710447Snilay@cs.wisc.edu getToken(ist); 6810447Snilay@cs.wisc.edu if(m_curr_token_ == SEP) 6910447Snilay@cs.wisc.edu { 7010448Snilay@cs.wisc.edu outputs[print_str] = 0; 7110447Snilay@cs.wisc.edu cout << print_str << endl; 7210447Snilay@cs.wisc.edu } 7310447Snilay@cs.wisc.edu else 7410447Snilay@cs.wisc.edu { 7510448Snilay@cs.wisc.edu double v = expr(ist, false, config, ms_model); 7610448Snilay@cs.wisc.edu outputs[print_str] = v; 7710448Snilay@cs.wisc.edu cout << print_str << v << endl; 7810447Snilay@cs.wisc.edu } 7910447Snilay@cs.wisc.edu } 8010447Snilay@cs.wisc.edu else 8110447Snilay@cs.wisc.edu { 8210448Snilay@cs.wisc.edu double v = expr(ist, false, config, ms_model); 8310448Snilay@cs.wisc.edu outputs["Missing Expression"] = v; 8410448Snilay@cs.wisc.edu cout << v << endl; 8510447Snilay@cs.wisc.edu } 8610447Snilay@cs.wisc.edu } 8710447Snilay@cs.wisc.edu else 8810447Snilay@cs.wisc.edu { 8910448Snilay@cs.wisc.edu expr(ist, false, config, ms_model); 9010447Snilay@cs.wisc.edu } 9110447Snilay@cs.wisc.edu } 9210447Snilay@cs.wisc.edu } 9310447Snilay@cs.wisc.edu 9410447Snilay@cs.wisc.edu Calculator::Token Calculator::getToken(istringstream& ist_) 9510447Snilay@cs.wisc.edu { 9610447Snilay@cs.wisc.edu char ch; 9710447Snilay@cs.wisc.edu do 9810447Snilay@cs.wisc.edu { 9910447Snilay@cs.wisc.edu ist_.get(ch); 10010447Snilay@cs.wisc.edu if(!ist_) 10110447Snilay@cs.wisc.edu { 10210447Snilay@cs.wisc.edu m_curr_token_ = END; 10310447Snilay@cs.wisc.edu return m_curr_token_; 10410447Snilay@cs.wisc.edu } 10510447Snilay@cs.wisc.edu } 10610447Snilay@cs.wisc.edu while(ch != '\n' && isspace(ch)); 10710447Snilay@cs.wisc.edu 10810447Snilay@cs.wisc.edu switch(ch) 10910447Snilay@cs.wisc.edu { 11010447Snilay@cs.wisc.edu case '\n': 11110447Snilay@cs.wisc.edu m_curr_token_ = END; 11210447Snilay@cs.wisc.edu return m_curr_token_; 11310447Snilay@cs.wisc.edu case ';': 11410447Snilay@cs.wisc.edu m_curr_token_ = SEP; 11510447Snilay@cs.wisc.edu return m_curr_token_; 11610447Snilay@cs.wisc.edu case '*': 11710447Snilay@cs.wisc.edu case '/': 11810447Snilay@cs.wisc.edu case '+': 11910447Snilay@cs.wisc.edu case '-': 12010447Snilay@cs.wisc.edu case '(': 12110447Snilay@cs.wisc.edu case ')': 12210447Snilay@cs.wisc.edu case '=': 12310447Snilay@cs.wisc.edu m_curr_token_ = Token(ch); 12410447Snilay@cs.wisc.edu return m_curr_token_; 12510447Snilay@cs.wisc.edu case '0': case '1': case '2': case '3': case '4': 12610447Snilay@cs.wisc.edu case '5': case '6': case '7': case '8': case '9': 12710447Snilay@cs.wisc.edu case '.': 12810447Snilay@cs.wisc.edu ist_.putback(ch); 12910447Snilay@cs.wisc.edu ist_ >> m_value_number_; 13010447Snilay@cs.wisc.edu m_curr_token_ = NUMBER; 13110447Snilay@cs.wisc.edu return m_curr_token_; 13210447Snilay@cs.wisc.edu case '"': 13310447Snilay@cs.wisc.edu ist_.get(ch); 13410447Snilay@cs.wisc.edu m_value_string_ = ""; 13510447Snilay@cs.wisc.edu while(ist_ && ('"' != ch)) 13610447Snilay@cs.wisc.edu { 13710447Snilay@cs.wisc.edu m_value_string_ += String(1, ch); 13810447Snilay@cs.wisc.edu ist_.get(ch); 13910447Snilay@cs.wisc.edu } 14010447Snilay@cs.wisc.edu m_curr_token_ = STRING; 14110447Snilay@cs.wisc.edu return m_curr_token_; 14210447Snilay@cs.wisc.edu case '$': 14310447Snilay@cs.wisc.edu ist_.get(ch); 14410447Snilay@cs.wisc.edu ASSERT((ch == '('), "[Error] Bad token: '(' expected"); 14510447Snilay@cs.wisc.edu ist_.get(ch); 14610447Snilay@cs.wisc.edu m_value_string_ = ""; 14710447Snilay@cs.wisc.edu while(ist_ && (!isspace(ch)) && (')' != ch)) 14810447Snilay@cs.wisc.edu { 14910447Snilay@cs.wisc.edu m_value_string_ += String(1, ch); 15010447Snilay@cs.wisc.edu ist_.get(ch); 15110447Snilay@cs.wisc.edu } 15210447Snilay@cs.wisc.edu m_curr_token_ = NAME2; 15310447Snilay@cs.wisc.edu return m_curr_token_; 15410447Snilay@cs.wisc.edu default: 15510447Snilay@cs.wisc.edu if(isalpha(ch)) 15610447Snilay@cs.wisc.edu { 15710447Snilay@cs.wisc.edu m_value_string_ = ch; 15810447Snilay@cs.wisc.edu ist_.get(ch); 15910447Snilay@cs.wisc.edu while(ist_ && (isalnum(ch) || ('_' == ch))) 16010447Snilay@cs.wisc.edu { 16110447Snilay@cs.wisc.edu m_value_string_ += String(1, ch); 16210447Snilay@cs.wisc.edu ist_.get(ch); 16310447Snilay@cs.wisc.edu } 16410447Snilay@cs.wisc.edu ist_.putback(ch); 16510447Snilay@cs.wisc.edu m_curr_token_ = NAME; 16610447Snilay@cs.wisc.edu return m_curr_token_; 16710447Snilay@cs.wisc.edu } 16810447Snilay@cs.wisc.edu else 16910447Snilay@cs.wisc.edu { 17010447Snilay@cs.wisc.edu String error_msg = "[Error] Bad token: '" + String(ch) + "'"; 17110447Snilay@cs.wisc.edu throw Exception(error_msg); 17210447Snilay@cs.wisc.edu } 17310447Snilay@cs.wisc.edu } 17410447Snilay@cs.wisc.edu } 17510447Snilay@cs.wisc.edu 17610448Snilay@cs.wisc.edu double Calculator::prim(istringstream& ist_, bool is_get_, 17710448Snilay@cs.wisc.edu const map<String, String> &config, 17810448Snilay@cs.wisc.edu DSENT::Model *ms_model) 17910447Snilay@cs.wisc.edu { 18010447Snilay@cs.wisc.edu if(is_get_) 18110447Snilay@cs.wisc.edu { 18210447Snilay@cs.wisc.edu getToken(ist_); 18310447Snilay@cs.wisc.edu } 18410447Snilay@cs.wisc.edu 18510447Snilay@cs.wisc.edu double v; 18610447Snilay@cs.wisc.edu switch(m_curr_token_) 18710447Snilay@cs.wisc.edu { 18810447Snilay@cs.wisc.edu case NUMBER: 18910447Snilay@cs.wisc.edu v = m_value_number_; 19010447Snilay@cs.wisc.edu getToken(ist_); 19110447Snilay@cs.wisc.edu return v; 19210447Snilay@cs.wisc.edu case NAME: 19310447Snilay@cs.wisc.edu if(getToken(ist_) == ASSIGN) 19410447Snilay@cs.wisc.edu { 19510447Snilay@cs.wisc.edu String var_name = m_value_string_; 19610448Snilay@cs.wisc.edu v = expr(ist_, true, config, ms_model); 19710447Snilay@cs.wisc.edu m_var_.set(var_name, v); 19810447Snilay@cs.wisc.edu } 19910447Snilay@cs.wisc.edu else 20010447Snilay@cs.wisc.edu { 20110447Snilay@cs.wisc.edu v = m_var_.get(m_value_string_); 20210447Snilay@cs.wisc.edu } 20310447Snilay@cs.wisc.edu return v; 20410447Snilay@cs.wisc.edu case NAME2: 20510448Snilay@cs.wisc.edu v = getEnvVar(m_value_string_, config, ms_model); 20610447Snilay@cs.wisc.edu getToken(ist_); 20710447Snilay@cs.wisc.edu return v; 20810447Snilay@cs.wisc.edu case MINUS: 20910448Snilay@cs.wisc.edu return -prim(ist_, true, config, ms_model); 21010447Snilay@cs.wisc.edu case LP: 21110448Snilay@cs.wisc.edu v = expr(ist_, true, config, ms_model); 21210447Snilay@cs.wisc.edu ASSERT((m_curr_token_ == RP), "[Error] ')' expected"); 21310447Snilay@cs.wisc.edu getToken(ist_); 21410447Snilay@cs.wisc.edu return v; 21510447Snilay@cs.wisc.edu default: 21610447Snilay@cs.wisc.edu ASSERT(0, "[Error] primary expected, get: '" + String(int(m_curr_token_)) + "'"); 21710447Snilay@cs.wisc.edu } 21810447Snilay@cs.wisc.edu } 21910447Snilay@cs.wisc.edu 22010448Snilay@cs.wisc.edu double Calculator::term(istringstream& ist_, bool is_get_, 22110448Snilay@cs.wisc.edu const map<String, String> &config, 22210448Snilay@cs.wisc.edu DSENT::Model *ms_model) 22310447Snilay@cs.wisc.edu { 22410448Snilay@cs.wisc.edu double left = prim(ist_, is_get_, config, ms_model); 22510447Snilay@cs.wisc.edu 22610447Snilay@cs.wisc.edu while(1) 22710447Snilay@cs.wisc.edu { 22810447Snilay@cs.wisc.edu double d; 22910447Snilay@cs.wisc.edu switch(m_curr_token_) 23010447Snilay@cs.wisc.edu { 23110447Snilay@cs.wisc.edu case MUL: 23210448Snilay@cs.wisc.edu left *= prim(ist_, true, config, ms_model); 23310447Snilay@cs.wisc.edu break; 23410447Snilay@cs.wisc.edu case DIV: 23510448Snilay@cs.wisc.edu d = prim(ist_, true, config, ms_model); 23610447Snilay@cs.wisc.edu ASSERT(d, "[Error] divided by 0"); 23710447Snilay@cs.wisc.edu left /= d; 23810447Snilay@cs.wisc.edu break; 23910447Snilay@cs.wisc.edu default: 24010447Snilay@cs.wisc.edu return left; 24110447Snilay@cs.wisc.edu } 24210447Snilay@cs.wisc.edu } 24310447Snilay@cs.wisc.edu } 24410447Snilay@cs.wisc.edu 24510448Snilay@cs.wisc.edu double Calculator::expr(istringstream& ist_, bool is_get_, 24610448Snilay@cs.wisc.edu const map<String, String> &config, 24710448Snilay@cs.wisc.edu DSENT::Model *ms_model) 24810447Snilay@cs.wisc.edu { 24910448Snilay@cs.wisc.edu double left = term(ist_, is_get_, config, ms_model); 25010447Snilay@cs.wisc.edu 25110447Snilay@cs.wisc.edu while(1) 25210447Snilay@cs.wisc.edu { 25310447Snilay@cs.wisc.edu switch(m_curr_token_) 25410447Snilay@cs.wisc.edu { 25510447Snilay@cs.wisc.edu case PLUS: 25610448Snilay@cs.wisc.edu left += term(ist_, true, config, ms_model); 25710447Snilay@cs.wisc.edu break; 25810447Snilay@cs.wisc.edu case MINUS: 25910448Snilay@cs.wisc.edu left -= term(ist_, true, config, ms_model); 26010447Snilay@cs.wisc.edu break; 26110447Snilay@cs.wisc.edu default: 26210447Snilay@cs.wisc.edu return left; 26310447Snilay@cs.wisc.edu } 26410447Snilay@cs.wisc.edu } 26510447Snilay@cs.wisc.edu } 26610447Snilay@cs.wisc.edu 26710448Snilay@cs.wisc.edu double Calculator::getEnvVar(const String& var_name_, 26810448Snilay@cs.wisc.edu const map<String, String> &config, 26910448Snilay@cs.wisc.edu DSENT::Model *ms_model) const 27010447Snilay@cs.wisc.edu { 27110447Snilay@cs.wisc.edu return m_var_.get(var_name_); 27210447Snilay@cs.wisc.edu } 27310447Snilay@cs.wisc.edu} // namespace LibUtil 274