diff options
Diffstat (limited to 'ext/dsent/libutil/Calculator.cc')
-rw-r--r-- | ext/dsent/libutil/Calculator.cc | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/ext/dsent/libutil/Calculator.cc b/ext/dsent/libutil/Calculator.cc new file mode 100644 index 000000000..e78e67287 --- /dev/null +++ b/ext/dsent/libutil/Calculator.cc @@ -0,0 +1,239 @@ +#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_) + { + 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) + { + cout << print_str << endl; + } + else + { + double v = expr(ist, false); + cout << scientific << print_str << v << endl; + } + } + else + { + double v = expr(ist, false); + cout << scientific << v << endl; + } + } + else + { + expr(ist, false); + } + } + return; + } + + 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_) + { + 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); + m_var_.set(var_name, v); + } + else + { + v = m_var_.get(m_value_string_); + } + return v; + case NAME2: + v = getEnvVar(m_value_string_); + getToken(ist_); + return v; + case MINUS: + return -prim(ist_, true); + case LP: + v = expr(ist_, true); + 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_) + { + double left = prim(ist_, is_get_); + + while(1) + { + double d; + switch(m_curr_token_) + { + case MUL: + left *= prim(ist_, true); + break; + case DIV: + d = prim(ist_, true); + ASSERT(d, "[Error] divided by 0"); + left /= d; + break; + default: + return left; + } + } + } + + double Calculator::expr(istringstream& ist_, bool is_get_) + { + double left = term(ist_, is_get_); + + while(1) + { + switch(m_curr_token_) + { + case PLUS: + left += term(ist_, true); + break; + case MINUS: + left -= term(ist_, true); + break; + default: + return left; + } + } + } + + double Calculator::getEnvVar(const String& var_name_) const + { + return m_var_.get(var_name_); + } +} // namespace LibUtil + |