Calculator.cc (10447:a465576671d4) Calculator.cc (10448:bc1a3b7ab5ef)
1/* Copyright (c) 2012 Massachusetts Institute of Technology
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 * THE SOFTWARE.
20 */
21
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
22#include "Calculator.h"
23
24#include <cctype>
25#include <iostream>
26
27namespace LibUtil
28{
29 using std::cout;
30 using std::endl;
31 using std::scientific;
32
33 Calculator::Calculator()
34 {
35 m_reserved_chars_ = "+-*/;=()\\";
36 }
37
38 Calculator::~Calculator()
39 {}
40
41 void Calculator::reset()
42 {
43 m_var_.clear();
44 return;
45 }
46
26 void Calculator::evaluateString(const String& str_)
47 void Calculator::evaluateString(const String& str_,
48 const map<String, String> &config,
49 DSENT::Model *ms_model,
50 map<string, double> &outputs)
27 {
28 istringstream ist(str_);
51 {
52 istringstream ist(str_);
53
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 {
54 while(ist)
55 {
56 getToken(ist);
57 if(m_curr_token_ == END) break;
58 if(m_curr_token_ == SEP) continue;
59 if((m_curr_token_ == NAME) && (m_value_string_ == "print"))
60 {
61 getToken(ist);
62
63 if(m_curr_token_ == STRING)
64 {
65 String print_str = m_value_string_;
66
67 getToken(ist);
68 if(m_curr_token_ == SEP)
69 {
70 outputs[print_str] = 0;
45 cout << print_str << endl;
46 }
47 else
48 {
71 cout << print_str << endl;
72 }
73 else
74 {
49 double v = expr(ist, false);
50 cout << scientific << print_str << v << endl;
75 double v = expr(ist, false, config, ms_model);
76 outputs[print_str] = v;
77 cout << print_str << v << endl;
51 }
52 }
53 else
54 {
78 }
79 }
80 else
81 {
55 double v = expr(ist, false);
56 cout << scientific << v << endl;
82 double v = expr(ist, false, config, ms_model);
83 outputs["Missing Expression"] = v;
84 cout << v << endl;
57 }
58 }
59 else
60 {
85 }
86 }
87 else
88 {
61 expr(ist, false);
89 expr(ist, false, config, ms_model);
62 }
63 }
90 }
91 }
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
92 }
93
94 Calculator::Token Calculator::getToken(istringstream& ist_)
95 {
96 char ch;
97 do
98 {
99 ist_.get(ch);
100 if(!ist_)
101 {
102 m_curr_token_ = END;
103 return m_curr_token_;
104 }
105 }
106 while(ch != '\n' && isspace(ch));
107
108 switch(ch)
109 {
110 case '\n':
111 m_curr_token_ = END;
112 return m_curr_token_;
113 case ';':
114 m_curr_token_ = SEP;
115 return m_curr_token_;
116 case '*':
117 case '/':
118 case '+':
119 case '-':
120 case '(':
121 case ')':
122 case '=':
123 m_curr_token_ = Token(ch);
124 return m_curr_token_;
125 case '0': case '1': case '2': case '3': case '4':
126 case '5': case '6': case '7': case '8': case '9':
127 case '.':
128 ist_.putback(ch);
129 ist_ >> m_value_number_;
130 m_curr_token_ = NUMBER;
131 return m_curr_token_;
132 case '"':
133 ist_.get(ch);
134 m_value_string_ = "";
135 while(ist_ && ('"' != ch))
136 {
137 m_value_string_ += String(1, ch);
138 ist_.get(ch);
139 }
140 m_curr_token_ = STRING;
141 return m_curr_token_;
142 case '$':
143 ist_.get(ch);
144 ASSERT((ch == '('), "[Error] Bad token: '(' expected");
145 ist_.get(ch);
146 m_value_string_ = "";
147 while(ist_ && (!isspace(ch)) && (')' != ch))
148 {
149 m_value_string_ += String(1, ch);
150 ist_.get(ch);
151 }
152 m_curr_token_ = NAME2;
153 return m_curr_token_;
154 default:
155 if(isalpha(ch))
156 {
157 m_value_string_ = ch;
158 ist_.get(ch);
159 while(ist_ && (isalnum(ch) || ('_' == ch)))
160 {
161 m_value_string_ += String(1, ch);
162 ist_.get(ch);
163 }
164 ist_.putback(ch);
165 m_curr_token_ = NAME;
166 return m_curr_token_;
167 }
168 else
169 {
170 String error_msg = "[Error] Bad token: '" + String(ch) + "'";
171 throw Exception(error_msg);
172 }
173 }
174 }
175
149 double Calculator::prim(istringstream& ist_, bool is_get_)
176 double Calculator::prim(istringstream& ist_, bool is_get_,
177 const map<String, String> &config,
178 DSENT::Model *ms_model)
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_;
179 {
180 if(is_get_)
181 {
182 getToken(ist_);
183 }
184
185 double v;
186 switch(m_curr_token_)
187 {
188 case NUMBER:
189 v = m_value_number_;
190 getToken(ist_);
191 return v;
192 case NAME:
193 if(getToken(ist_) == ASSIGN)
194 {
195 String var_name = m_value_string_;
167 v = expr(ist_, true);
196 v = expr(ist_, true, config, ms_model);
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:
197 m_var_.set(var_name, v);
198 }
199 else
200 {
201 v = m_var_.get(m_value_string_);
202 }
203 return v;
204 case NAME2:
176 v = getEnvVar(m_value_string_);
205 v = getEnvVar(m_value_string_, config, ms_model);
177 getToken(ist_);
178 return v;
179 case MINUS:
206 getToken(ist_);
207 return v;
208 case MINUS:
180 return -prim(ist_, true);
209 return -prim(ist_, true, config, ms_model);
181 case LP:
210 case LP:
182 v = expr(ist_, true);
211 v = expr(ist_, true, config, ms_model);
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
212 ASSERT((m_curr_token_ == RP), "[Error] ')' expected");
213 getToken(ist_);
214 return v;
215 default:
216 ASSERT(0, "[Error] primary expected, get: '" + String(int(m_curr_token_)) + "'");
217 }
218 }
219
191 double Calculator::term(istringstream& ist_, bool is_get_)
220 double Calculator::term(istringstream& ist_, bool is_get_,
221 const map<String, String> &config,
222 DSENT::Model *ms_model)
192 {
223 {
193 double left = prim(ist_, is_get_);
224 double left = prim(ist_, is_get_, config, ms_model);
194
195 while(1)
196 {
197 double d;
198 switch(m_curr_token_)
199 {
200 case MUL:
225
226 while(1)
227 {
228 double d;
229 switch(m_curr_token_)
230 {
231 case MUL:
201 left *= prim(ist_, true);
232 left *= prim(ist_, true, config, ms_model);
202 break;
203 case DIV:
233 break;
234 case DIV:
204 d = prim(ist_, true);
235 d = prim(ist_, true, config, ms_model);
205 ASSERT(d, "[Error] divided by 0");
206 left /= d;
207 break;
208 default:
209 return left;
210 }
211 }
212 }
213
236 ASSERT(d, "[Error] divided by 0");
237 left /= d;
238 break;
239 default:
240 return left;
241 }
242 }
243 }
244
214 double Calculator::expr(istringstream& ist_, bool is_get_)
245 double Calculator::expr(istringstream& ist_, bool is_get_,
246 const map<String, String> &config,
247 DSENT::Model *ms_model)
215 {
248 {
216 double left = term(ist_, is_get_);
249 double left = term(ist_, is_get_, config, ms_model);
217
218 while(1)
219 {
220 switch(m_curr_token_)
221 {
222 case PLUS:
250
251 while(1)
252 {
253 switch(m_curr_token_)
254 {
255 case PLUS:
223 left += term(ist_, true);
256 left += term(ist_, true, config, ms_model);
224 break;
225 case MINUS:
257 break;
258 case MINUS:
226 left -= term(ist_, true);
259 left -= term(ist_, true, config, ms_model);
227 break;
228 default:
229 return left;
230 }
231 }
232 }
233
260 break;
261 default:
262 return left;
263 }
264 }
265 }
266
234 double Calculator::getEnvVar(const String& var_name_) const
267 double Calculator::getEnvVar(const String& var_name_,
268 const map<String, String> &config,
269 DSENT::Model *ms_model) const
235 {
236 return m_var_.get(var_name_);
237 }
238} // namespace LibUtil
270 {
271 return m_var_.get(var_name_);
272 }
273} // namespace LibUtil
239