parse_utils.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2024 Jose Luis Blanco Claraco |
5  | Copyright (C) 2017 Borys Tymchenko (Odessa Polytechnic University) |
6  | Distributed under 3-clause BSD License |
7  | See COPYING |
8  +-------------------------------------------------------------------------+ */
9 
10 #include "parse_utils.h"
11 
12 #include <mrpt/core/exceptions.h>
13 #include <mrpt/core/get_env.h>
14 #include <mrpt/expr/CRuntimeCompiledExpression.h>
15 #include <mrpt/random/RandomGenerators.h>
16 #include <mrpt/system/filesystem.h>
17 #include <mrpt/system/os.h>
18 #include <mrpt/system/string_utils.h>
19 #include <mrpt/version.h>
20 
21 #include <algorithm>
22 #include <cstdlib>
23 #include <iostream>
24 #include <sstream>
25 
26 thread_local const bool MVSIM_VERBOSE_PARSE = mrpt::get_env<bool>("MVSIM_VERBOSE_PARSE", false);
27 
28 using namespace mvsim;
29 
30 namespace
31 {
32 std::string parseEnvVars(const std::string& text)
33 {
34  MRPT_TRY_START
35 
36  const auto start = text.find("$env{");
37  if (start == std::string::npos) return text;
38 
39  const std::string pre = text.substr(0, start);
40  const std::string post = text.substr(start + 5);
41 
42  const auto post_end = post.find('}');
43  if (post_end == std::string::npos)
44  {
45  THROW_EXCEPTION_FMT(
46  "Column=%u: Cannot find matching `}` for `$env{` in: `%s`",
47  static_cast<unsigned int>(start), text.c_str());
48  }
49 
50  const auto varname = post.substr(0, post_end);
51  std::string varvalue;
52  const char* v = ::getenv(varname.c_str());
53  if (v != nullptr)
54  varvalue = std::string(v);
55  else
56  {
57  THROW_EXCEPTION_FMT(
58  "parseEnvVars(): Undefined environment variable found: $env{%s}", varname.c_str());
59  }
60 
61  return parseEnvVars(pre + varvalue + post.substr(post_end + 1));
62  MRPT_TRY_END
63 }
64 
65 std::string parseVars(
66  const std::string& text, const std::map<std::string, std::string>& variableNamesValues)
67 {
68  MRPT_TRY_START
69 
70  const auto start = text.find("${");
71  if (start == std::string::npos) return text;
72 
73  const std::string pre = text.substr(0, start);
74  const std::string post = text.substr(start + 2);
75 
76  const auto post_end = post.find('}');
77  if (post_end == std::string::npos)
78  {
79  THROW_EXCEPTION_FMT(
80  "Column=%u: Cannot find matching `}` for `${` in: `%s`",
81  static_cast<unsigned int>(start), text.c_str());
82  }
83 
84  const auto varname = post.substr(0, post_end);
85  std::string varvalue;
86  if (const auto it = variableNamesValues.find(varname); it != variableNamesValues.end())
87  {
88  varvalue = it->second;
89  }
90  else
91  {
92  std::string allKnown;
93  for (const auto& kv : variableNamesValues)
94  {
95  allKnown += kv.first;
96  allKnown += ",";
97  }
98 
99  THROW_EXCEPTION_FMT(
100  "parseVars(): Undefined variable found: ${%s}. Known ones are: %s", varname.c_str(),
101  allKnown.c_str());
102  }
103 
104  return parseVars(pre + varvalue + post.substr(post_end + 1), variableNamesValues);
105  MRPT_TRY_END
106 }
107 
108 std::string parseCmdRuns(const std::string& text)
109 {
110  MRPT_TRY_START
111 
112  const auto start = text.find("$(");
113  if (start == std::string::npos) return text;
114 
115  const std::string pre = text.substr(0, start);
116  const std::string post = text.substr(start + 2);
117 
118  const auto post_end = post.find(')');
119  if (post_end == std::string::npos)
120  {
121  THROW_EXCEPTION_FMT(
122  "Column=%u: Cannot find matching `)` for `$(` in: `%s`",
123  static_cast<unsigned int>(start), text.c_str());
124  }
125 
126  const auto cmd = post.substr(0, post_end);
127 
128  // Launch command and get console output:
129  std::string cmdOut;
130 
131  int ret = mrpt::system::executeCommand(cmd, &cmdOut);
132  if (ret != 0)
133  {
134  THROW_EXCEPTION_FMT("Error (retval=%i) executing external command: `%s`", ret, cmd.c_str());
135  }
136  // Clear whitespaces:
137  cmdOut = mrpt::system::trim(cmdOut);
138  cmdOut.erase(std::remove(cmdOut.begin(), cmdOut.end(), '\r'), cmdOut.end());
139  cmdOut.erase(std::remove(cmdOut.begin(), cmdOut.end(), '\n'), cmdOut.end());
140 
141  return parseCmdRuns(pre + cmdOut + post.substr(post_end + 1));
142  MRPT_TRY_END
143 }
144 
145 double my_rand()
146 {
147  auto& rng = mrpt::random::getRandomGenerator();
148  return rng.drawUniform(0.0, 1.0);
149 }
150 double my_unifrnd(double xMin, double xMax)
151 {
152  auto& rng = mrpt::random::getRandomGenerator();
153  return rng.drawUniform(xMin, xMax);
154 }
155 double randn()
156 {
157  auto& rng = mrpt::random::getRandomGenerator();
158  return rng.drawGaussian1D_normalized();
159 }
160 double randomize(double seed)
161 {
162  auto& rng = mrpt::random::getRandomGenerator();
163  rng.randomize(seed);
164  return 0;
165 }
166 
167 // Examples: "$f{180/5}", "$f{ ${MAX_SPEED} * sin(deg2rad(45)) }"
168 std::string parseMathExpr(
169  const std::string& text, const std::map<std::string, std::string>& variableNamesValues)
170 {
171  MRPT_TRY_START
172 
173  const auto start = text.find("$f{");
174  if (start == std::string::npos) return text;
175 
176  const std::string pre = text.substr(0, start);
177  const std::string post = text.substr(start + 3);
178 
179  const auto post_end = post.find('}');
180  if (post_end == std::string::npos)
181  {
182  THROW_EXCEPTION_FMT(
183  "Column=%u: Cannot find matching `}` for `${` in: `%s`",
184  static_cast<unsigned int>(start), text.c_str());
185  }
186 
187  const auto sExpr = post.substr(0, post_end);
188 
189  mrpt::expr::CRuntimeCompiledExpression expr;
190 
191  expr.register_function("rand", &my_rand);
192  expr.register_function("unifrnd", &my_unifrnd);
193  expr.register_function("randn", &randn);
194  expr.register_function("randomize", &randomize);
195 
196  std::map<std::string, double> numericVars;
197  for (const auto& kv : variableNamesValues)
198  {
199  std::stringstream ss(kv.second);
200 
201  double val = 0;
202  if (!(ss >> val)) continue;
203 
204  numericVars[kv.first] = val;
205  }
206 
207  // Compile expression (will throw on syntax error):
208  expr.compile(sExpr, numericVars);
209  const double val = expr.eval();
210 
211  return parseCmdRuns(pre + mrpt::format("%g", val) + post.substr(post_end + 1));
212 
213  MRPT_TRY_END
214 }
215 } // namespace
216 
217 std::string mvsim::parse(
218  const std::string& input, const std::map<std::string, std::string>& variableNamesValues)
219 {
221  {
222  std::cout << "[mvsim::parse] Input : '" << input << "' "
223  << "with these variables: ";
224  for (const auto& kv : variableNamesValues) std::cout << kv.first << ", ";
225  std::cout << "\n";
226  }
227 
228  std::string s = input;
229 
230  std::string prevValue = s;
231  for (int iter = 0; iter < 10; iter++)
232  {
233  s = parseVars(s, variableNamesValues);
234  s = parseEnvVars(s);
235  s = parseCmdRuns(s);
236  s = parseMathExpr(s, variableNamesValues);
237  // We may need to iterate since, in general, each expression generator
238  // might generate another kind of expression:
239  if (s == prevValue) break;
240  prevValue = s;
241  }
242 
244  {
245  std::cout << "[mvsim::parse] Output: '" << s << "'\n";
246  }
247 
248  return s;
249 }
250 
251 std::string mvsim::trim(const std::string& s)
252 {
253  auto out = mrpt::system::trim(s);
254  while (!out.empty() && (out[0] == '\r' || out[0] == '\n')) out.erase(0, 1);
255  return out;
256 }
mvsim
Definition: Client.h:21
parse_utils.h
MVSIM_VERBOSE_PARSE
const thread_local bool MVSIM_VERBOSE_PARSE
Definition: parse_utils.cpp:26
s
XmlRpcServer s
parseVars
static std::string parseVars(const std::string &text, const std::map< std::string, std::string > &variables, const std::set< std::string > &varsRetain, const size_t searchStartPos=0)
Definition: xml_utils.cpp:373
mvsim::parse
std::string parse(const std::string &input, const std::map< std::string, std::string > &variableNamesValues={})
Definition: parse_utils.cpp:217
mvsim::trim
std::string trim(const std::string &s)
Definition: parse_utils.cpp:251
start
ROSCPP_DECL void start()
cmd
string cmd


mvsim
Author(s):
autogenerated on Wed May 28 2025 02:13:08