Deleted Added
sdiff udiff text old ( 10447:a465576671d4 ) new ( 10448:bc1a3b7ab5ef )
full compact
1#include "Calculator.h"
2
3#include <cctype>
4#include <iostream>
5
6namespace LibUtil
7{
8 using std::cout;
9 using std::endl;
10 using std::scientific;
11
12 Calculator::Calculator()
13 {
14 m_reserved_chars_ = "+-*/;=()\\";
15 }
16
17 Calculator::~Calculator()
18 {}
19
20 void Calculator::reset()
21 {
22 m_var_.clear();
23 return;
24 }
25
26 void Calculator::evaluateString(const String& str_)
27 {
28 istringstream ist(str_);
29 while(ist)
30 {
31 getToken(ist);
32 if(m_curr_token_ == END) break;
33 if(m_curr_token_ == SEP) continue;
34 if((m_curr_token_ == NAME) && (m_value_string_ == "print"))
35 {
36 getToken(ist);
37
38 if(m_curr_token_ == STRING)
39 {
40 String print_str = m_value_string_;
41
42 getToken(ist);
43 if(m_curr_token_ == SEP)
44 {
45 cout << print_str << endl;
46 }
47 else
48 {
49 double v = expr(ist, false);
50 cout << scientific << print_str << v << endl;
51 }
52 }
53 else
54 {
55 double v = expr(ist, false);
56 cout << scientific << v << endl;
57 }
58 }
59 else
60 {
61 expr(ist, false);
62 }
63 }
64 return;
65 }
66
67 Calculator::Token Calculator::getToken(istringstream& ist_)
68 {
69 char ch;
70 do
71 {
72 ist_.get(ch);
73 if(!ist_)
74 {
75 m_curr_token_ = END;
76 return m_curr_token_;
77 }
78 }
79 while(ch != '\n' && isspace(ch));
80
81 switch(ch)
82 {
83 case '\n':
84 m_curr_token_ = END;
85 return m_curr_token_;
86 case ';':
87 m_curr_token_ = SEP;
88 return m_curr_token_;
89 case '*':
90 case '/':
91 case '+':
92 case '-':
93 case '(':
94 case ')':
95 case '=':
96 m_curr_token_ = Token(ch);
97 return m_curr_token_;
98 case '0': case '1': case '2': case '3': case '4':
99 case '5': case '6': case '7': case '8': case '9':
100 case '.':
101 ist_.putback(ch);
102 ist_ >> m_value_number_;
103 m_curr_token_ = NUMBER;
104 return m_curr_token_;
105 case '"':
106 ist_.get(ch);
107 m_value_string_ = "";
108 while(ist_ && ('"' != ch))
109 {
110 m_value_string_ += String(1, ch);
111 ist_.get(ch);
112 }
113 m_curr_token_ = STRING;
114 return m_curr_token_;
115 case '$':
116 ist_.get(ch);
117 ASSERT((ch == '('), "[Error] Bad token: '(' expected");
118 ist_.get(ch);
119 m_value_string_ = "";
120 while(ist_ && (!isspace(ch)) && (')' != ch))
121 {
122 m_value_string_ += String(1, ch);
123 ist_.get(ch);
124 }
125 m_curr_token_ = NAME2;
126 return m_curr_token_;
127 default:
128 if(isalpha(ch))
129 {
130 m_value_string_ = ch;
131 ist_.get(ch);
132 while(ist_ && (isalnum(ch) || ('_' == ch)))
133 {
134 m_value_string_ += String(1, ch);
135 ist_.get(ch);
136 }
137 ist_.putback(ch);
138 m_curr_token_ = NAME;
139 return m_curr_token_;
140 }
141 else
142 {
143 String error_msg = "[Error] Bad token: '" + String(ch) + "'";
144 throw Exception(error_msg);
145 }
146 }
147 }
148
149 double Calculator::prim(istringstream& ist_, bool is_get_)
150 {
151 if(is_get_)
152 {
153 getToken(ist_);
154 }
155
156 double v;
157 switch(m_curr_token_)
158 {
159 case NUMBER:
160 v = m_value_number_;
161 getToken(ist_);
162 return v;
163 case NAME:
164 if(getToken(ist_) == ASSIGN)
165 {
166 String var_name = m_value_string_;
167 v = expr(ist_, true);
168 m_var_.set(var_name, v);
169 }
170 else
171 {
172 v = m_var_.get(m_value_string_);
173 }
174 return v;
175 case NAME2:
176 v = getEnvVar(m_value_string_);
177 getToken(ist_);
178 return v;
179 case MINUS:
180 return -prim(ist_, true);
181 case LP:
182 v = expr(ist_, true);
183 ASSERT((m_curr_token_ == RP), "[Error] ')' expected");
184 getToken(ist_);
185 return v;
186 default:
187 ASSERT(0, "[Error] primary expected, get: '" + String(int(m_curr_token_)) + "'");
188 }
189 }
190
191 double Calculator::term(istringstream& ist_, bool is_get_)
192 {
193 double left = prim(ist_, is_get_);
194
195 while(1)
196 {
197 double d;
198 switch(m_curr_token_)
199 {
200 case MUL:
201 left *= prim(ist_, true);
202 break;
203 case DIV:
204 d = prim(ist_, true);
205 ASSERT(d, "[Error] divided by 0");
206 left /= d;
207 break;
208 default:
209 return left;
210 }
211 }
212 }
213
214 double Calculator::expr(istringstream& ist_, bool is_get_)
215 {
216 double left = term(ist_, is_get_);
217
218 while(1)
219 {
220 switch(m_curr_token_)
221 {
222 case PLUS:
223 left += term(ist_, true);
224 break;
225 case MINUS:
226 left -= term(ist_, true);
227 break;
228 default:
229 return left;
230 }
231 }
232 }
233
234 double Calculator::getEnvVar(const String& var_name_) const
235 {
236 return m_var_.get(var_name_);
237 }
238} // namespace LibUtil
239