Calculator.cc revision 10447
110447Snilay@cs.wisc.edu#include "Calculator.h"
210447Snilay@cs.wisc.edu
310447Snilay@cs.wisc.edu#include <cctype>
410447Snilay@cs.wisc.edu#include <iostream>
510447Snilay@cs.wisc.edu
610447Snilay@cs.wisc.edunamespace LibUtil
710447Snilay@cs.wisc.edu{
810447Snilay@cs.wisc.edu    using std::cout;
910447Snilay@cs.wisc.edu    using std::endl;
1010447Snilay@cs.wisc.edu    using std::scientific;
1110447Snilay@cs.wisc.edu
1210447Snilay@cs.wisc.edu    Calculator::Calculator()
1310447Snilay@cs.wisc.edu    {
1410447Snilay@cs.wisc.edu        m_reserved_chars_ = "+-*/;=()\\";
1510447Snilay@cs.wisc.edu    }
1610447Snilay@cs.wisc.edu
1710447Snilay@cs.wisc.edu    Calculator::~Calculator()
1810447Snilay@cs.wisc.edu    {}
1910447Snilay@cs.wisc.edu
2010447Snilay@cs.wisc.edu    void Calculator::reset()
2110447Snilay@cs.wisc.edu    {
2210447Snilay@cs.wisc.edu        m_var_.clear();
2310447Snilay@cs.wisc.edu        return;
2410447Snilay@cs.wisc.edu    }
2510447Snilay@cs.wisc.edu
2610447Snilay@cs.wisc.edu    void Calculator::evaluateString(const String& str_)
2710447Snilay@cs.wisc.edu    {
2810447Snilay@cs.wisc.edu        istringstream ist(str_);
2910447Snilay@cs.wisc.edu        while(ist)
3010447Snilay@cs.wisc.edu        {
3110447Snilay@cs.wisc.edu            getToken(ist);
3210447Snilay@cs.wisc.edu            if(m_curr_token_ == END) break;
3310447Snilay@cs.wisc.edu            if(m_curr_token_ == SEP) continue;
3410447Snilay@cs.wisc.edu            if((m_curr_token_ == NAME) && (m_value_string_ == "print"))
3510447Snilay@cs.wisc.edu            {
3610447Snilay@cs.wisc.edu                getToken(ist);
3710447Snilay@cs.wisc.edu
3810447Snilay@cs.wisc.edu                if(m_curr_token_ == STRING)
3910447Snilay@cs.wisc.edu                {
4010447Snilay@cs.wisc.edu                    String print_str = m_value_string_;
4110447Snilay@cs.wisc.edu
4210447Snilay@cs.wisc.edu                    getToken(ist);
4310447Snilay@cs.wisc.edu                    if(m_curr_token_ == SEP)
4410447Snilay@cs.wisc.edu                    {
4510447Snilay@cs.wisc.edu                        cout << print_str << endl;
4610447Snilay@cs.wisc.edu                    }
4710447Snilay@cs.wisc.edu                    else
4810447Snilay@cs.wisc.edu                    {
4910447Snilay@cs.wisc.edu                        double v = expr(ist, false);
5010447Snilay@cs.wisc.edu                        cout << scientific << print_str << v << endl;
5110447Snilay@cs.wisc.edu                    }
5210447Snilay@cs.wisc.edu                }
5310447Snilay@cs.wisc.edu                else
5410447Snilay@cs.wisc.edu                {
5510447Snilay@cs.wisc.edu                    double v = expr(ist, false);
5610447Snilay@cs.wisc.edu                    cout << scientific << v << endl;
5710447Snilay@cs.wisc.edu                }
5810447Snilay@cs.wisc.edu            }
5910447Snilay@cs.wisc.edu            else
6010447Snilay@cs.wisc.edu            {
6110447Snilay@cs.wisc.edu                expr(ist, false);
6210447Snilay@cs.wisc.edu            }
6310447Snilay@cs.wisc.edu        }
6410447Snilay@cs.wisc.edu        return;
6510447Snilay@cs.wisc.edu    }
6610447Snilay@cs.wisc.edu
6710447Snilay@cs.wisc.edu    Calculator::Token Calculator::getToken(istringstream& ist_)
6810447Snilay@cs.wisc.edu    {
6910447Snilay@cs.wisc.edu        char ch;
7010447Snilay@cs.wisc.edu        do
7110447Snilay@cs.wisc.edu        {
7210447Snilay@cs.wisc.edu            ist_.get(ch);
7310447Snilay@cs.wisc.edu            if(!ist_)
7410447Snilay@cs.wisc.edu            {
7510447Snilay@cs.wisc.edu                m_curr_token_ = END;
7610447Snilay@cs.wisc.edu                return m_curr_token_;
7710447Snilay@cs.wisc.edu            }
7810447Snilay@cs.wisc.edu        }
7910447Snilay@cs.wisc.edu        while(ch != '\n' && isspace(ch));
8010447Snilay@cs.wisc.edu
8110447Snilay@cs.wisc.edu        switch(ch)
8210447Snilay@cs.wisc.edu        {
8310447Snilay@cs.wisc.edu            case '\n':
8410447Snilay@cs.wisc.edu                m_curr_token_ = END;
8510447Snilay@cs.wisc.edu                return m_curr_token_;
8610447Snilay@cs.wisc.edu            case ';':
8710447Snilay@cs.wisc.edu                m_curr_token_ = SEP;
8810447Snilay@cs.wisc.edu                return m_curr_token_;
8910447Snilay@cs.wisc.edu            case '*':
9010447Snilay@cs.wisc.edu            case '/':
9110447Snilay@cs.wisc.edu            case '+':
9210447Snilay@cs.wisc.edu            case '-':
9310447Snilay@cs.wisc.edu            case '(':
9410447Snilay@cs.wisc.edu            case ')':
9510447Snilay@cs.wisc.edu            case '=':
9610447Snilay@cs.wisc.edu                m_curr_token_ = Token(ch);
9710447Snilay@cs.wisc.edu                return m_curr_token_;
9810447Snilay@cs.wisc.edu            case '0': case '1': case '2': case '3': case '4':
9910447Snilay@cs.wisc.edu            case '5': case '6': case '7': case '8': case '9':
10010447Snilay@cs.wisc.edu            case '.':
10110447Snilay@cs.wisc.edu                ist_.putback(ch);
10210447Snilay@cs.wisc.edu                ist_ >> m_value_number_;
10310447Snilay@cs.wisc.edu                m_curr_token_ = NUMBER;
10410447Snilay@cs.wisc.edu                return m_curr_token_;
10510447Snilay@cs.wisc.edu            case '"':
10610447Snilay@cs.wisc.edu                ist_.get(ch);
10710447Snilay@cs.wisc.edu                m_value_string_ = "";
10810447Snilay@cs.wisc.edu                while(ist_ && ('"' != ch))
10910447Snilay@cs.wisc.edu                {
11010447Snilay@cs.wisc.edu                    m_value_string_ += String(1, ch);
11110447Snilay@cs.wisc.edu                    ist_.get(ch);
11210447Snilay@cs.wisc.edu                }
11310447Snilay@cs.wisc.edu                m_curr_token_ = STRING;
11410447Snilay@cs.wisc.edu                return m_curr_token_;
11510447Snilay@cs.wisc.edu            case '$':
11610447Snilay@cs.wisc.edu                ist_.get(ch);
11710447Snilay@cs.wisc.edu                ASSERT((ch == '('), "[Error] Bad token: '(' expected");
11810447Snilay@cs.wisc.edu                ist_.get(ch);
11910447Snilay@cs.wisc.edu                m_value_string_ = "";
12010447Snilay@cs.wisc.edu                while(ist_ && (!isspace(ch)) && (')' != ch))
12110447Snilay@cs.wisc.edu                {
12210447Snilay@cs.wisc.edu                    m_value_string_ += String(1, ch);
12310447Snilay@cs.wisc.edu                    ist_.get(ch);
12410447Snilay@cs.wisc.edu                }
12510447Snilay@cs.wisc.edu                m_curr_token_ = NAME2;
12610447Snilay@cs.wisc.edu                return m_curr_token_;
12710447Snilay@cs.wisc.edu            default:
12810447Snilay@cs.wisc.edu                if(isalpha(ch))
12910447Snilay@cs.wisc.edu                {
13010447Snilay@cs.wisc.edu                    m_value_string_ = ch;
13110447Snilay@cs.wisc.edu                    ist_.get(ch);
13210447Snilay@cs.wisc.edu                    while(ist_ && (isalnum(ch) || ('_' == ch)))
13310447Snilay@cs.wisc.edu                    {
13410447Snilay@cs.wisc.edu                        m_value_string_ += String(1, ch);
13510447Snilay@cs.wisc.edu                        ist_.get(ch);
13610447Snilay@cs.wisc.edu                    }
13710447Snilay@cs.wisc.edu                    ist_.putback(ch);
13810447Snilay@cs.wisc.edu                    m_curr_token_ = NAME;
13910447Snilay@cs.wisc.edu                    return m_curr_token_;
14010447Snilay@cs.wisc.edu                }
14110447Snilay@cs.wisc.edu                else
14210447Snilay@cs.wisc.edu                {
14310447Snilay@cs.wisc.edu                    String error_msg = "[Error] Bad token: '" + String(ch) + "'";
14410447Snilay@cs.wisc.edu                    throw Exception(error_msg);
14510447Snilay@cs.wisc.edu                }
14610447Snilay@cs.wisc.edu        }
14710447Snilay@cs.wisc.edu    }
14810447Snilay@cs.wisc.edu
14910447Snilay@cs.wisc.edu    double Calculator::prim(istringstream& ist_, bool is_get_)
15010447Snilay@cs.wisc.edu    {
15110447Snilay@cs.wisc.edu        if(is_get_)
15210447Snilay@cs.wisc.edu        {
15310447Snilay@cs.wisc.edu            getToken(ist_);
15410447Snilay@cs.wisc.edu        }
15510447Snilay@cs.wisc.edu
15610447Snilay@cs.wisc.edu        double v;
15710447Snilay@cs.wisc.edu        switch(m_curr_token_)
15810447Snilay@cs.wisc.edu        {
15910447Snilay@cs.wisc.edu            case NUMBER:
16010447Snilay@cs.wisc.edu                v = m_value_number_;
16110447Snilay@cs.wisc.edu                getToken(ist_);
16210447Snilay@cs.wisc.edu                return v;
16310447Snilay@cs.wisc.edu            case NAME:
16410447Snilay@cs.wisc.edu                if(getToken(ist_) == ASSIGN)
16510447Snilay@cs.wisc.edu                {
16610447Snilay@cs.wisc.edu                    String var_name = m_value_string_;
16710447Snilay@cs.wisc.edu                    v = expr(ist_, true);
16810447Snilay@cs.wisc.edu                    m_var_.set(var_name, v);
16910447Snilay@cs.wisc.edu                }
17010447Snilay@cs.wisc.edu                else
17110447Snilay@cs.wisc.edu                {
17210447Snilay@cs.wisc.edu                    v = m_var_.get(m_value_string_);
17310447Snilay@cs.wisc.edu                }
17410447Snilay@cs.wisc.edu                return v;
17510447Snilay@cs.wisc.edu            case NAME2:
17610447Snilay@cs.wisc.edu                v = getEnvVar(m_value_string_);
17710447Snilay@cs.wisc.edu                getToken(ist_);
17810447Snilay@cs.wisc.edu                return v;
17910447Snilay@cs.wisc.edu            case MINUS:
18010447Snilay@cs.wisc.edu                return -prim(ist_, true);
18110447Snilay@cs.wisc.edu            case LP:
18210447Snilay@cs.wisc.edu                v = expr(ist_, true);
18310447Snilay@cs.wisc.edu                ASSERT((m_curr_token_ == RP), "[Error] ')' expected");
18410447Snilay@cs.wisc.edu                getToken(ist_);
18510447Snilay@cs.wisc.edu                return v;
18610447Snilay@cs.wisc.edu            default:
18710447Snilay@cs.wisc.edu                ASSERT(0, "[Error] primary expected, get: '" + String(int(m_curr_token_)) + "'");
18810447Snilay@cs.wisc.edu        }
18910447Snilay@cs.wisc.edu    }
19010447Snilay@cs.wisc.edu
19110447Snilay@cs.wisc.edu    double Calculator::term(istringstream& ist_, bool is_get_)
19210447Snilay@cs.wisc.edu    {
19310447Snilay@cs.wisc.edu        double left = prim(ist_, is_get_);
19410447Snilay@cs.wisc.edu
19510447Snilay@cs.wisc.edu        while(1)
19610447Snilay@cs.wisc.edu        {
19710447Snilay@cs.wisc.edu            double d;
19810447Snilay@cs.wisc.edu            switch(m_curr_token_)
19910447Snilay@cs.wisc.edu            {
20010447Snilay@cs.wisc.edu                case MUL:
20110447Snilay@cs.wisc.edu                    left *= prim(ist_, true);
20210447Snilay@cs.wisc.edu                    break;
20310447Snilay@cs.wisc.edu                case DIV:
20410447Snilay@cs.wisc.edu                    d = prim(ist_, true);
20510447Snilay@cs.wisc.edu                    ASSERT(d, "[Error] divided by 0");
20610447Snilay@cs.wisc.edu                    left /= d;
20710447Snilay@cs.wisc.edu                    break;
20810447Snilay@cs.wisc.edu                default:
20910447Snilay@cs.wisc.edu                    return left;
21010447Snilay@cs.wisc.edu            }
21110447Snilay@cs.wisc.edu        }
21210447Snilay@cs.wisc.edu    }
21310447Snilay@cs.wisc.edu
21410447Snilay@cs.wisc.edu    double Calculator::expr(istringstream& ist_, bool is_get_)
21510447Snilay@cs.wisc.edu    {
21610447Snilay@cs.wisc.edu        double left = term(ist_, is_get_);
21710447Snilay@cs.wisc.edu
21810447Snilay@cs.wisc.edu        while(1)
21910447Snilay@cs.wisc.edu        {
22010447Snilay@cs.wisc.edu            switch(m_curr_token_)
22110447Snilay@cs.wisc.edu            {
22210447Snilay@cs.wisc.edu                case PLUS:
22310447Snilay@cs.wisc.edu                    left += term(ist_, true);
22410447Snilay@cs.wisc.edu                    break;
22510447Snilay@cs.wisc.edu                case MINUS:
22610447Snilay@cs.wisc.edu                    left -= term(ist_, true);
22710447Snilay@cs.wisc.edu                    break;
22810447Snilay@cs.wisc.edu                default:
22910447Snilay@cs.wisc.edu                    return left;
23010447Snilay@cs.wisc.edu            }
23110447Snilay@cs.wisc.edu        }
23210447Snilay@cs.wisc.edu    }
23310447Snilay@cs.wisc.edu
23410447Snilay@cs.wisc.edu    double Calculator::getEnvVar(const String& var_name_) const
23510447Snilay@cs.wisc.edu    {
23610447Snilay@cs.wisc.edu        return m_var_.get(var_name_);
23710447Snilay@cs.wisc.edu    }
23810447Snilay@cs.wisc.edu} // namespace LibUtil
23910447Snilay@cs.wisc.edu
240