235{
236
237
238
239
240
241 std::stack<std::vector<std::pair<MooseUnits::BaseUnit, int>>> stack;
242 std::stack<char> op_stack;
243 std::stack<MooseUnits>
out;
244
245 auto it = unit_string.begin();
246 const auto end = unit_string.end();
247
248 do
249 {
250
251 if (*it == ' ')
252 {
253 it++;
254 continue;
255 }
256
257 else if (*it == '(')
258 op_stack.push(*(it++));
259
260 else if (*it == '*' || *it == '/')
261 {
262
263 while (!op_stack.empty() && (op_stack.top() == '*' || op_stack.top() == '/'))
264 {
265 auto top = op_stack.top();
266 op_stack.pop();
267
270 unit_string, it, "Applying ", top, " but don't have enough items on the stack.");
271 auto rhs =
out.top();
273 if (top == '*')
274 out.top() =
out.top() * rhs;
275 else
276 out.top() =
out.top() / rhs;
277 }
278
279 op_stack.push(*(it++));
280 }
281
282 else if (*it == ')')
283 {
284 do
285 {
286 if (op_stack.empty())
287 parseError(unit_string, it,
"Mismatching right parenthesis.");
288
289 auto top = op_stack.top();
290 op_stack.pop();
291
292 if (top == '(')
293 break;
294
295 if (top == '*' || top == '/')
296 {
299 unit_string, it, "Applying ", top, " but don't have enough items on the stack.");
300 auto rhs =
out.top();
302 if (top == '*')
303 out.top() =
out.top() * rhs;
304 else
305 out.top() =
out.top() / rhs;
306 }
307 } while (true);
308 it++;
309 }
310
311 else if (*it == '^')
312 {
313
315 ++it;
316 if (it != end && *it == '-')
317 {
319 it++;
320 }
321
322 int num = 0;
324 while (*it >= '0' && *it <= '9')
325 {
326 num *= 10;
327 num += *(it++) - '0';
329 }
330
331
332 if (!valid)
333 {
334 if (it == end)
335 parseError(unit_string, it,
"Expected a number but found end of string.");
336 else
337 parseError(unit_string, it,
"Expected a number but got '", (*it),
"'.");
338 }
339
340
342 parseError(unit_string, it,
"Applying an exponent, but found no units in front of it.");
344 }
345 else
346 {
347 std::string unit;
348 while (it != end && ((*it >= 'a' && *it <= 'z') || (*it >= 'A' && *it <= 'Z') ||
349 (*it >= '0' && *it <= '9') || *it == '.' || *it == '-'))
350 unit += *(it++);
351
352
354 std::stringstream ss(unit);
355 if ((ss >> si_factor).fail() || !std::isfinite(si_factor))
356 si_factor = 1.0;
357 else
358 {
359 if (ss.eof())
360 {
362 continue;
363 }
364 ss >> unit;
365 }
366
367
368 auto len = unit.length();
369 if (len == 0)
370 {
371 if (it == end)
372 parseError(unit_string, it,
"Expected unit but found end of string.");
373 else
374 parseError(unit_string, it,
"Expected unit but found '", *it,
"'.");
375 }
376
377 unsigned int i = 0;
379 {
381 const auto slen = s.length();
382 if (slen <= len && unit.substr(len - slen) == s)
383 break;
384 }
385
386
388 parseError(unit_string, it,
"Unknown unit '", unit,
"'.");
389
390
392 const auto slen = s.length();
393 if (slen < len)
394 {
395 const auto prefix = unit.substr(0, len - slen);
398 si_factor = jt->second;
399 else
400 parseError(unit_string, it,
"Unknown SI prefix '", prefix,
"' on unit '", unit,
"'.");
401 }
402
403
406 }
407 } while (it != end);
408
409
410 while (!op_stack.empty())
411 {
412 auto top = op_stack.top();
413 op_stack.pop();
414
415 if (top == '(' || top == ')')
416 parseError(unit_string, it,
"Unit string contains unmatched parenthesis.");
417
418 if (top == '*' || top == '/')
419 {
422 it,
423 "Applying ",
424 top,
425 " but don't have enough items on the stack.",
427 auto rhs =
out.top();
429 if (top == '*')
430 out.top() =
out.top() * rhs;
431 else
432 out.top() =
out.top() / rhs;
433 }
434 }
435
436
438 mooseError(
"Internal parse error. Remaining output stack size should be 1, but is ",
440
443}
void parseError(const std::string &unit_string, std::string::const_iterator it, Args... args)
helper function to generate a pretty mooseError
static const std::vector< std::pair< std::string, MooseUnits > > _unit_table
static const std::map< std::string, Real > _si_prefix
data tables with SI prefixes and known units
KOKKOS_INLINE_FUNCTION T sign(T x)
Returns the sign of a value.
std::vector< ElemQuality > valid(const ElemType t)
OStreamProxy out(std::cout)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
MooseUnits pow(const MooseUnits &, int)