ra4_draw  4bd0201e3d922d42bd545d4b045ed44db33454a4
function_parser.cpp
Go to the documentation of this file.
1 
21 #include "core/function_parser.hpp"
22 
23 #include <cstdlib>
24 #include <cctype>
25 
26 #include "core/utilities.hpp"
27 #include "core/named_func.hpp"
28 
29 using namespace std;
30 
35 
41 FunctionParser::FunctionParser(const string &function_string):
42  input_string_(function_string),
43  tokens_(),
44  tokenized_(false),
45  solved_(false){
46  ReplaceAll(input_string_, " ", "");
47 }
48 
53 const string & FunctionParser::FunctionString() const{
54  return input_string_;
55 }
56 
61 FunctionParser & FunctionParser::FunctionString(const string &function_string){
62  tokenized_ = false;
63  solved_ = false;
64  input_string_ = function_string;
65  ReplaceAll(input_string_, " ", "");
66  return *this;
67 }
68 
71 const vector<Token> & FunctionParser::Tokens() const{
72  return tokens_;
73 }
74 
78  Solve();
79  return tokens_.size() ? tokens_.at(0) : Token();
80 }
81 
85  Solve();
86  return tokens_.size() ? tokens_.at(0).function_
88  [](const Baby &){
89  return 0.;
90  });
91 }
92 
101 FunctionParser::FunctionParser(const vector<Token> &tokens):
102  input_string_(""),
103  tokens_(tokens),
104  tokenized_(true),
105  solved_(false){
107 }
108 
112  if(tokenized_) return;
113  size_t start = 0;
114  while(start < input_string_.size()){
115  char start_char = input_string_[start];
116  if(Token::GetType(input_string_.substr(start, 1)) != Token::Type::unknown){
117  tokens_.push_back(Token(input_string_.substr(start, 1)));
118  ++start;
119  }else if(Token::GetType(input_string_.substr(start, 2)) != Token::Type::unknown){
120  //This branch will catch digraphs "<=", ">=", and "!="
121  tokens_.push_back(Token(input_string_.substr(start, 2)));
122  start+=2;
123  }else if(start_char=='<'){
124  //"<=" digraph already caught
125  tokens_.push_back(Token(input_string_.substr(start, 1), Token::Type::less));
126  ++start;
127  }else if(start_char=='>'){
128  //">=" digraph already caught
129  tokens_.push_back(Token(input_string_.substr(start, 1), Token::Type::greater));
130  ++start;
131  }else if(start_char=='!'){
132  //"!=" digraph already caught
133  tokens_.push_back(Token(input_string_.substr(start, 1), Token::Type::logical_not));
134  ++start;
135  }else if(isalpha(start_char) || start_char == '_'){
136  size_t count = 1;
137  while(start+count < input_string_.size()
138  && (isalnum(input_string_[start+count]) || input_string_[start+count] == '_')){
139  ++count;
140  }
141  tokens_.push_back(Token(input_string_.substr(start, count), Token::Type::variable_name));
142  start+=count;
143  }else if(isdigit(start_char) || start_char == '.'){
144  string from_start = input_string_.substr(start);
145  char *cp = nullptr;
146  double val = strtod(&from_start[0], &cp);
147  string remaining = cp;
148  if(val != 0. || remaining != from_start){
149  size_t length = from_start.size() - remaining.size();
150  if(length < 1) length = 1;
151  tokens_.push_back(Token(from_start.substr(0, length), Token::Type::number));
152  start+=length;
153  }else{
154  tokens_.push_back(Token(input_string_.substr(start, 1), Token::Type::unknown));
155  ++start;
156  }
157  }else{
158  tokens_.push_back(Token(input_string_.substr(start, 1), Token::Type::unknown));
159  ++start;
160  }
161  }
162  tokenized_ = true;
163 }
164 
168  for(const auto &token: tokens_){
169  if(token.type_ == Token::Type::unknown){
170  ERROR("Function string \""+input_string_+"\" contains unknown token \""+token.string_rep_+"\".");
171  }
172  }
173 }
174 
179  for(auto &token: tokens_){
180  if(token.type_ == Token::Type::variable_name){
181  token.function_ = Baby::GetFunction(token.string_rep_);
182  token.type_ = token.function_.IsScalar() ? Token::Type::resolved_scalar : Token::Type::resolved_vector;
183  }else if(token.type_ == Token::Type::number){
184  char *cp = nullptr;
185  NamedFunc::ScalarType val = strtod(&token.string_rep_[0], &cp);
186  token.function_ = NamedFunc(token.string_rep_,
187  [val](const Baby &){
188  return val;
189  });
190  token.type_ = Token::Type::resolved_scalar;
191  }
192  }
193 }
194 
198  for(size_t i_open = 0; i_open < tokens_.size(); ++i_open){
199  size_t i_close = FindClose(i_open);
200  if(i_close <= i_open || i_close >= tokens_.size()) continue;
201 
202  FunctionParser fp(vector<Token>(tokens_.cbegin()+i_open+1, tokens_.cbegin()+i_close));
203  Token merged = fp.ResolveAsToken();
204 
205  CondenseTokens(i_open+1, i_close, merged);
206  }
207 }
208 
215  for(size_t i = 0; i+2 < tokens_.size(); ++i){
216  Token &open = tokens_.at(i+0);
217  Token &inner = tokens_.at(i+1);
218  Token &close = tokens_.at(i+2);
219 
220  if(open.type_ != Token::Type::open_paren
223  || close.type_ != Token::Type::close_paren){
224  continue;
225  }
226 
227  string name = ConcatenateTokenStrings(i, i+3);
228  NamedFunc merged_func = inner.function_;
229  merged_func.Name(name);
230  Token merged(merged_func);
231 
232  CondenseTokens(i, i+3, merged);
233  }
234 }
235 
243  for(size_t i = 0; i+3 < tokens_.size(); ++i){
244  Token &vec = tokens_.at(i);
245  Token &open = tokens_.at(i+1);
246  Token &sub = tokens_.at(i+2);
247  Token &close = tokens_.at(i+3);
248 
252  || close.type_ != Token::Type::close_square){
253  continue;
254  }
255 
256  function<VectorFunc> vec_func = vec.function_.VectorFunction();
257  function<ScalarFunc> sub_func = sub.function_.ScalarFunction();
258  function<ScalarFunc> function = [vec_func,sub_func](const Baby &b){
259  return vec_func(b).at(sub_func(b));
260  };
261  string name = ConcatenateTokenStrings(i, i+4);
262  Token merged(NamedFunc(name, function));
263 
264  CondenseTokens(i, i+4, merged);
265  }
266 }
267 
272  for(size_t i = 0; i < tokens_.size(); ++i){
273  Token prev;
274  if(i > 0){
275  prev = tokens_.at(i-1);
276  }else{
278  }
279  Token &cur = tokens_.at(i);
281 
284  Token::Type ambiguous_type = Token::Type::ambiguous_plus;
286  binary_type = Token::Type::binary_minus;
287  unary_type = Token::Type::unary_minus;
288  ambiguous_type = Token::Type::ambiguous_minus;
289  }
290 
291  switch(prev.type_){
294  case Token::Type::number:
298  cur.type_ = binary_type;
299  break;
307  case Token::Type::divide:
309  case Token::Type::equal:
312  case Token::Type::less:
320  cur.type_ = unary_type;
321  break;
323  default:
324  cur.type_ = ambiguous_type;
325  break;
326  }
327  }
328 }
329 
335  for(size_t i = 0; i+1 < tokens_.size(); ++i){
336  Token &op = tokens_.at(i);
337  Token &x = tokens_.at(i+1);
338 
340 
341  Token merged;
342  if(op.type_ == Token::Type::unary_plus){
343  merged = Token(NamedFunc(+x.function_));
344  }else if(op.type_ == Token::Type::unary_minus){
345  merged = Token(NamedFunc(-x.function_));
346  }else if(op.type_ == Token::Type::logical_not){
347  merged = Token(NamedFunc(!x.function_));
348  }else{
349  continue;
350  }
351 
352  CondenseTokens(i, i+2, merged);
353  if(i!=0) i-=2;//Need to check previous token in case of multiple unary operators
354  }
355 }
356 
362  for(size_t i = 0; i+2 < tokens_.size(); ++i){
363  Token &a = tokens_.at(i);
364  Token &op = tokens_.at(i+1);
365  Token &b = tokens_.at(i+2);
366 
369 
370  Token merged;
371  if(op.type_ == Token::Type::multiply){
372  merged = Token(NamedFunc(a.function_ * b.function_));
373  }else if(op.type_ == Token::Type::divide){
374  merged = Token(NamedFunc(a.function_ / b.function_));
375  }else if(op.type_ == Token::Type::modulus){
376  merged = Token(NamedFunc(a.function_ % b.function_));
377  }else{
378  continue;
379  }
380 
381  CondenseTokens(i, i+3, merged);
382  --i;//Need to recheck token in case of successive multiplications
383  }
384 }
385 
392  for(size_t i = 0; i+2 < tokens_.size(); ++i){
393  Token &a = tokens_.at(i);
394  Token &op = tokens_.at(i+1);
395  Token &b = tokens_.at(i+2);
396 
399 
400  Token merged;
402  merged = Token(NamedFunc(a.function_ + b.function_));
403  }else if(op.type_ == Token::Type::binary_minus){
404  merged = Token(NamedFunc(a.function_ - b.function_));
405  }else{
406  continue;
407  }
408 
409  CondenseTokens(i, i+3, merged);
410  --i;//Need to recheck token in case of successive additions
411  }
412 }
413 
420  for(size_t i = 0; i+2 < tokens_.size(); ++i){
421  Token &a = tokens_.at(i);
422  Token &op = tokens_.at(i+1);
423  Token &b = tokens_.at(i+2);
424 
427 
428  Token merged;
429  if(op.type_ == Token::Type::greater){
430  merged = Token(NamedFunc(a.function_ > b.function_));
431  }else if(op.type_ == Token::Type::less){
432  merged = Token(NamedFunc(a.function_ < b.function_));
433  }else if(op.type_ == Token::Type::greater_equal){
434  merged = Token(NamedFunc(a.function_ >= b.function_));
435  }else if(op.type_ == Token::Type::less_equal){
436  merged = Token(NamedFunc(a.function_ <= b.function_));
437  }else{
438  continue;
439  }
440 
441  CondenseTokens(i, i+3, merged);
442  --i;//Need to recheck token in case of successive comparisons
443  }
444 }
445 
451  for(size_t i = 0; i+2 < tokens_.size(); ++i){
452  Token &a = tokens_.at(i);
453  Token &op = tokens_.at(i+1);
454  Token &b = tokens_.at(i+2);
455 
458 
459  Token merged;
460  if(op.type_ == Token::Type::equal){
461  merged = Token(NamedFunc(a.function_ == b.function_));
462  }else if(op.type_ == Token::Type::not_equal){
463  merged = Token(NamedFunc(a.function_ != b.function_));
464  }else{
465  continue;
466  }
467 
468  CondenseTokens(i, i+3, merged);
469  --i;//Need to recheck token in case of successive comparisons
470  }
471 }
472 
477 void FunctionParser::And() const{
478  for(size_t i = 0; i+2 < tokens_.size(); ++i){
479  Token &a = tokens_.at(i);
480  Token &op = tokens_.at(i+1);
481  Token &b = tokens_.at(i+2);
482 
485 
486  Token merged;
488  merged = Token(NamedFunc(a.function_ && b.function_));
489  }else{
490  continue;
491  }
492 
493  CondenseTokens(i, i+3, merged);
494  --i;//Need to recheck token in case of successive ANDs
495  }
496 }
497 
502 void FunctionParser::Or() const{
503  for(size_t i = 0; i+2 < tokens_.size(); ++i){
504  Token &a = tokens_.at(i);
505  Token &op = tokens_.at(i+1);
506  Token &b = tokens_.at(i+2);
507 
510 
511  Token merged;
512  if(op.type_ == Token::Type::logical_or){
513  merged = Token(NamedFunc(a.function_ || b.function_));
514  }else{
515  continue;
516  }
517 
518  CondenseTokens(i, i+3, merged);
519  --i;//Need to recheck token in case of successive ORs
520  }
521 }
522 
526  if(tokens_.size() == 0){
527  DBG("No tokens found for " << (*this) << ".");
528  }else if(tokens_.size() > 1){
529  ostringstream oss;
530  oss << "Could not condense " << (*this) << "." << flush;
531  ERROR(oss.str());
532  }else if(tokens_.at(0).type_ != Token::Type::resolved_vector
533  && tokens_.at(0).type_ != Token::Type::resolved_scalar){
534  ostringstream oss;
535  oss << "Unknown token in " << (*this) << "." << flush;
536  ERROR(oss.str());
537  }
538 }
539 
546  if(tokens_.size() == 1){
547  tokens_.at(0).string_rep_ = input_string_;
548  tokens_.at(0).function_.Name(input_string_);
549  }
550 }
551 
555  if(solved_) return;
556  Tokenize();
561  ApplySubscripts();
563  ApplyUnary();
565  AddAndSubtract();
566  LessGreater();
567  EqualOrNot();
568  And();
569  Or();
570  CheckSolved();
571  CleanupName();
572  solved_ = true;
573 }
574 
583 size_t FunctionParser::FindClose(size_t i_open_token) const{
584  if(i_open_token > tokens_.size()) return tokens_.size();
585 
586  const auto &open_token = tokens_.at(i_open_token);
587  if(open_token.type_ != Token::Type::open_paren
588  && open_token.type_ != Token::Type::open_square){
589  return i_open_token;
590  }
591 
592  Token::Type open_type, close_type;
593  if(open_token.type_ == Token::Type::open_square){
594  open_type = Token::Type::open_square;
595  close_type = Token::Type::close_square;
596  }else{
597  open_type = Token::Type::open_paren;
598  close_type = Token::Type::close_paren;
599  }
600 
601  int open_count = 1;
602  size_t i_close_token;
603  for(i_close_token = i_open_token+1; i_close_token < tokens_.size() && open_count > 0; ++i_close_token){
604  const auto &token = tokens_.at(i_close_token);
605  if(token.type_ == open_type){
606  ++open_count;
607  }else if(token.type_ == close_type){
608  --open_count;
609  }
610  }
611  if(open_count <= 0){
612  return --i_close_token;
613  }else{
614  return tokens_.size();
615  }
616 }
617 
628 string FunctionParser::ConcatenateTokenStrings(size_t i_start, size_t i_end) const{
629  string result = "";
630  for(;i_start < i_end; ++i_start){
631  result += tokens_.at(i_start).string_rep_;
632  }
633  return result;
634 }
635 
645 void FunctionParser::CondenseTokens(size_t i_start, size_t i_end, const Token &replacement) const{
646  if(i_end < i_start) return;
647  size_t num_replaced = i_end-i_start;
648  vector<Token> new_tokens(tokens_.size()+1-num_replaced);
649  for(size_t i = 0; i < i_start; ++i){
650  new_tokens.at(i) = tokens_.at(i);
651  }
652  new_tokens.at(i_start) = replacement;
653  for(size_t i = i_start + 1; i < new_tokens.size(); ++i){
654  new_tokens.at(i) = tokens_.at(i+num_replaced-1);
655  }
656  tokens_ = new_tokens;
657 }
658 
667 ostream & operator << (ostream &stream, const FunctionParser &fp){
668  stream << "FunctionParser::" << fp.FunctionString() << "::{";
669  const auto &tokens = fp.Tokens();
670  for(auto token = tokens.cbegin();
671  token != tokens.cend();
672  ++token){
673  if(token != tokens.cbegin()) stream << ", ";
674  stream << (*token);
675  }
676  stream << '}';
677  return stream;
678 }
std::vector< Token > tokens_
List of tokens generated in parsing process.
#define DBG(x)
Definition: utilities.hpp:18
NamedFunc ResolveAsNamedFunc() const
Parses provided string into a single NamedFunc.
std::vector< ScalarType > VectorType
Definition: named_func.hpp:16
Token ResolveAsToken() const
Parses provided string into a single Token.
void ApplySubscripts() const
Merges subscript (bracket) Tokens with the contents.
void CleanupName() const
Restores string representation to initially provided string.
NamedFunc::VectorType VectorType
static NamedFunc GetFunction(const std::string &var_name)
Get a NamedFunc accessing specified variable.
Definition: baby.cpp:1712
const std::string & Name() const
Get the string representation of this function.
Definition: named_func.cpp:376
void Solve() const
Runs full parse from start to finish, caching result.
Abstract base class for access to ntuple variables.
Definition: baby.hpp:16
void AddAndSubtract() const
Merges binary "+" and "-" Tokens with their operands.
void ReplaceAll(std::string &str, const std::string &orig, const std::string &rep)
Definition: utilities.cpp:52
STL namespace.
ScalarType(const Baby &) ScalarFunc
Definition: named_func.hpp:17
void DisambiguatePlusMinus() const
Determines whether "+" and "-" Tokens correspond to unary or binary operators.
Combines a callable function taking a Baby and returning a scalar or vector with its string represent...
Definition: named_func.hpp:13
void ResolveVariables() const
Generates NamedFunc for each Token representing a constant or Baby variable.
void LessGreater() const
Merges "<", "<=", ">", and ">=" Tokens with their operands.
void ApplyUnary() const
Merges unary operator Tokens with their operands.
void EqualOrNot() const
Merges "==" and "!=" Tokens with their operands.
double ScalarType
Definition: named_func.hpp:15
void EvaluateGroupings() const
Recursively evaluates contents of parenthesis and brackets.
ostream & operator<<(ostream &stream, const FunctionParser &fp)
Print FunctionParser to output stream.
static Type GetType(char x)
VectorType(const Baby &) VectorFunc
Definition: named_func.hpp:18
const std::vector< Token > & Tokens() const
Get list of tokens as is at current stage of parsing.
std::string input_string_
String being parsed.
Type type_
Definition: token.hpp:34
void CheckSolved() const
Check that we have a single Token with a valid NamedFun.
NamedFunc::VectorFunc VectorFunc
#define ERROR(x)
Definition: utilities.hpp:17
void MultiplyAndDivide() const
Merges "*" and "/" Tokens with their operands.
Type
Definition: token.hpp:10
std::size_t FindClose(std::size_t i_open_token) const
Find position of closing parenthesis/bracket corresponding to given opening partner.
NamedFunc function_
Definition: token.hpp:32
void Or() const
Merges "||" Tokens with their operands.
void MergeParentheses() const
Merges parenthesis Tokens with the contents.
void And() const
Merges "&&" Tokens with their operands.
Definition: token.hpp:9
void CheckForUnknowns() const
Checks that all Tokens were understood.
bool solved_
String parsed into tokens, and all tokens succesfully merged.
bool tokenized_
String has been parsed into tokens.
const std::function< VectorFunc > & VectorFunction() const
Return the (possibly invalid) vector function.
Definition: named_func.cpp:434
void Tokenize() const
Parses the string into a list of Tokens.
NamedFunc::ScalarFunc ScalarFunc
std::string ConcatenateTokenStrings(std::size_t i_start, std::size_t i_end) const
Concatenates string representation of Tokens in range [i_start, i_end)
const std::string & FunctionString() const
Get string being parsed.
void CondenseTokens(std::size_t i_start, std::size_t i_end, const Token &replacement) const
Replace Tokens in range [i_start, i_end) with replacement.
FunctionParser()=default
Converts a string into a NamedFunc.
const std::function< ScalarFunc > & ScalarFunction() const
Return the (possibly invalid) scalar function.
Definition: named_func.cpp:426
NamedFunc::ScalarType ScalarType