Deleted Added
sdiff udiff text old ( 10447:a465576671d4 ) new ( 10448:bc1a3b7ab5ef )
full compact
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
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
47 void Calculator::evaluateString(const String& str_,
48 const map<String, String> &config,
49 DSENT::Model *ms_model,
50 map<string, double> &outputs)
51 {
52 istringstream ist(str_);
53
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;
71 cout << print_str << endl;
72 }
73 else
74 {
75 double v = expr(ist, false, config, ms_model);
76 outputs[print_str] = v;
77 cout << print_str << v << endl;
78 }
79 }
80 else
81 {
82 double v = expr(ist, false, config, ms_model);
83 outputs["Missing Expression"] = v;
84 cout << v << endl;
85 }
86 }
87 else
88 {
89 expr(ist, false, config, ms_model);
90 }
91 }
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
176 double Calculator::prim(istringstream& ist_, bool is_get_,
177 const map<String, String> &config,
178 DSENT::Model *ms_model)
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_;
196 v = expr(ist_, true, config, ms_model);
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:
205 v = getEnvVar(m_value_string_, config, ms_model);
206 getToken(ist_);
207 return v;
208 case MINUS:
209 return -prim(ist_, true, config, ms_model);
210 case LP:
211 v = expr(ist_, true, config, ms_model);
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
220 double Calculator::term(istringstream& ist_, bool is_get_,
221 const map<String, String> &config,
222 DSENT::Model *ms_model)
223 {
224 double left = prim(ist_, is_get_, config, ms_model);
225
226 while(1)
227 {
228 double d;
229 switch(m_curr_token_)
230 {
231 case MUL:
232 left *= prim(ist_, true, config, ms_model);
233 break;
234 case DIV:
235 d = prim(ist_, true, config, ms_model);
236 ASSERT(d, "[Error] divided by 0");
237 left /= d;
238 break;
239 default:
240 return left;
241 }
242 }
243 }
244
245 double Calculator::expr(istringstream& ist_, bool is_get_,
246 const map<String, String> &config,
247 DSENT::Model *ms_model)
248 {
249 double left = term(ist_, is_get_, config, ms_model);
250
251 while(1)
252 {
253 switch(m_curr_token_)
254 {
255 case PLUS:
256 left += term(ist_, true, config, ms_model);
257 break;
258 case MINUS:
259 left -= term(ist_, true, config, ms_model);
260 break;
261 default:
262 return left;
263 }
264 }
265 }
266
267 double Calculator::getEnvVar(const String& var_name_,
268 const map<String, String> &config,
269 DSENT::Model *ms_model) const
270 {
271 return m_var_.get(var_name_);
272 }
273} // namespace LibUtil