20 ";",
",",
"=",
"== != > < <= >=",
"&& || ^^",
"+ -",
"* /",
"^"};
29std::string makeErrorMessage(
const std::string &msg,
const std::string &expr,
size_t i) {
30 const size_t MAX_LEFT_SIZE = 10;
31 const size_t MAX_RIGHT_SIZE = 10;
32 std::ostringstream res;
33 res << msg <<
" at\n\n";
36 size_t n = expr.size();
37 std::string leftEllipsis =
"";
38 if (i > MAX_LEFT_SIZE) {
39 skip = i - MAX_LEFT_SIZE;
41 j = MAX_LEFT_SIZE + leftEllipsis.size();
44 std::string rightEllipsis =
"";
45 if (
n - j > MAX_RIGHT_SIZE) {
46 n = i + MAX_RIGHT_SIZE;
47 rightEllipsis =
"...";
50 res << leftEllipsis << expr.substr(skip,
n) << rightEllipsis <<
'\n';
51 res << std::string(j,
' ') <<
'^' <<
'\n';
66 :
std::runtime_error(makeErrorMessage(msg, expr, i)) {}
79 std::unordered_set<std::string> unary;
111 for (
size_t i = 0; i <
m_operators->binary.size(); i++) {
114 for (
const auto &
index : tkz) {
120 for (
auto str : ops) {
131 for (
const auto &op : ops) {
132 m_operators->symbols.insert(op.cbegin(), op.cend());
137 std::map<std::string, size_t>::const_iterator i =
m_operators->precedence.find(op);
150 size_t i =
str.find_first_not_of(
" \t\n\r");
151 size_t j =
str.find_last_not_of(
" \t\n\r");
152 if (i == std::string::npos || j == std::string::npos || j < i) {
155 str =
str.substr(i, j - i + 1);
164 if (
m_expr.find(
'(', 1) == std::string::npos) {
178 std::string op =
GetOp(0);
185 for (
size_t i = 0; i <=
m_tokens.size(); i++) {
199 size_t min_prec = 1000;
201 unsigned int lvl = 0;
202 const size_t last =
m_expr.size() - 1;
203 bool inString =
false;
205 bool canBeBinary =
false;
207 bool isNumber =
false;
208 bool canDotBeAdded =
false;
209 bool canEBeAdded =
false;
210 bool canPlusBeAdded =
false;
212 for (
size_t i = 0; i <
m_expr.size(); i++) {
215 if (!inString && skip == 0) {
219 canDotBeAdded =
false;
223 }
else if (c ==
'e' || c ==
'E') {
226 canDotBeAdded =
false;
227 canPlusBeAdded =
true;
231 }
else if (c ==
'+' || c ==
'-') {
232 if (canPlusBeAdded) {
233 canPlusBeAdded =
false;
235 canDotBeAdded =
false;
239 }
else if (!isdigit(c)) {
242 }
else if (isdigit(c)) {
244 canDotBeAdded =
true;
246 canPlusBeAdded =
false;
251 if (c ==
',' || c ==
';') {
264 std::string op =
m_expr.substr(i, is1 - i);
265 size_t prec = canBeBinary ?
m_operators->precedence[op] : 0;
270 if (op.size() == 2) {
278 std::string uop = op.substr(1, 1);
282 if (is1 + 2 > last) {
296 else if (op.size() == 1) {
306 if (prec <= min_prec) {
309 Token tok(is, i - 1, is1, prec);
310 tokens.emplace_back(tok);
319 else if (c !=
' ' && c !=
'\t' && c !=
'\r' && c !=
'\n') {
338 inString = !inString;
343 if (!tokens.empty()) {
346 for (
size_t i = 0; i < tokens.size(); i++) {
347 const Token &tok = tokens[i];
348 std::string op =
m_expr.substr(tok.
ie + 1, tok.
is1 - tok.
ie - 1);
351 last_tok.
ie = tok.
ie;
353 if (i != tokens.size() - 1)
354 m_tokens.emplace_back(tokens[i + 1]);
386 std::string myPads = pads +
" ";
388 logger.debug() << myPads <<
m_op <<
'[' <<
m_funct <<
']' <<
"(\n";
389 for (
const auto &term :
m_terms)
390 term.logPrint(myPads);
391 logger.debug() << myPads <<
")\n";
393 logger.debug() << myPads <<
m_op <<
m_funct <<
'\n';
400 op =
name.substr(0, 1);
408 tmp.parse(
name.substr(op.size()));
423 std::string::size_type i = std::string::npos;
425 bool inQuotes =
false;
426 for (std::string::const_iterator c =
name.begin(); c !=
name.end(); ++c) {
428 inQuotes = !inQuotes;
432 if (!inQuotes && *c ==
'(') {
433 i = c -
name.begin();
438 if (i != std::string::npos) {
439 std::string::size_type j =
name.find_last_of(
')');
440 if (j == std::string::npos || j < i) {
446 std::string args =
name.substr(i + 1, j - i - 1);
448 std::string f =
name.substr(0, i);
454 if (f.empty() &&
tmp.name() ==
",") {
457 std::string my_op =
m_op;
470 bool brackets =
false;
471 std::ostringstream res;
490 for (
const auto &term :
m_terms) {
491 res << term.operator_name();
492 size_t prec1 =
op_prec(term.m_funct);
493 bool isItUnary =
false;
494 if (term.size() == 1 &&
is_unary(term.m_funct)) {
498 bool bk = prec > 0 && prec1 > 0 && prec > prec1;
515 while (e->
name().empty() && e->
size() == 1) {
525 std::unordered_set<std::string> out;
527 std::string s =
name();
528 if (!s.empty() && !isdigit(s[0])) {
532 for (
const auto &e : *
this) {
534 std::unordered_set<std::string> tout = e.getVariables();
535 out.insert(tout.begin(), tout.end());
537 std::string s = e.name();
538 if (!s.empty() && !isdigit(s[0])) {
554 term.renameAll(oldName, newName);
std::map< DeltaEMode::Type, std::string > index
Specialised exception for parsing errors.
ParsingError(const std::string &msg, const std::string &expr, size_t i)
Constructor.
This class represents an expression made up of names, binary operators and brackets.
std::string name() const
Returns the name of the expression which is a function or variable name.
std::string m_expr
Saved expression string.
static void trim(std::string &str)
Remove leading and ending empty spaces from a string.
std::shared_ptr< Operators > m_operators
pointer ot the operators
void add_unary(const std::unordered_set< std::string > &ops)
Adds new unary operators to the expression.
std::unordered_set< std::string > getVariables() const
Return a list of all variable names in this expression.
void parse(const std::string &str)
Parse a string and create an expression.
std::string m_op
Operator connecting this expression to its sibling on the left.
std::string m_funct
Function name.
const Expression & bracketsRemoved() const
If the expression has 1 argument and empty function name it means it is wrapped in brackets This meth...
void logPrint(const std::string &pads="") const
Print the expression into std::cerr to show its structure.
void setFunct(const std::string &name)
Set the function name of this expression.
std::string GetOp(size_t i)
Get the operator connecting i-th token.
bool is_unary(const std::string &op) const
Check if a string is a unary operator.
Expression & operator=(const Expression &expr)
Assignment operator.
bool isFunct() const
Returns true if the expression is a function (i.e. has arguments)
void renameAll(const std::string &oldName, const std::string &newName)
Rename all variables with a given name.
std::vector< Token > Tokens
The container type.
std::string str() const
Returns this expression as a string.
std::string GetToken(size_t i)
Get i-th token.
Tokens m_tokens
The container for the token markers.
void toList(const std::string &sep=",")
Make sure the expression is a list of expression separated by sep, eg "term1,term2,...
bool is_op_symbol(const char c) const
Check if a character is a part of an operator.
Expression()
Default contructor.
size_t size() const
Returns the number of argumens.
std::vector< Expression > m_terms
Child expressions (function arguments)
static const std::vector< std::string > DEFAULT_OPS_STR
size_t op_prec(const std::string &op) const
Returns the precedence of operator op.
void add_operators(const std::vector< std::string > &ops)
Adds new binary operators to the expression.
void rename(const std::string &newName)
Rename this expression.
void tokenize()
Analyze the string in m_expr and find all top level tokens.
The Logger class is in charge of the publishing messages from the framework through various channels.
Iterator begin()
Iterator referring to first element in the container.
@ TOK_IGNORE_EMPTY
ignore empty tokens
@ TOK_TRIM
remove leading and trailing whitespace from tokens
const std::string EMPTY_EXPRESSION_NAME
Keeps operator that can be used in an expression.
This is a struct to mark a token in a string expression.
size_t is1
The index of the first symbol of the next token.
size_t is
The index of the first symbol of the token.
size_t ie
The index of the last symbol of the token.