ATLAS Offline Software
LogicParser.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 
7 #include <boost/tokenizer.hpp>
8 #include <iostream>
9 #include <string>
10 #include <iterator>
11 
12 TrigConf::LogicParser::LogicParser()
13 {}
14 
15 namespace {
16  void printSubExpr(const std::string & id, const std::vector<std::string> & tokExpr, size_t & front, const size_t back) {
17  std::cout << id << ": ";
18  for(size_t i = front; i<=back; i++) {
19  std::cout << tokExpr[i] << " ";
20  }
21  std::cout << std::endl;
22  }
23 
24  size_t findMatchingClosingParenthesis(const std::vector<std::string> & tokExpr, size_t front, size_t back) {
25  if(tokExpr[front]!="(") {
26  throw TrigConf::LogicParsingException(std::string("Looking for closing parenthesis, but not starting with '(', but '") + tokExpr[front] + "'");
27  }
28  size_t pos(front);
29  size_t parCount = 1;
30  size_t matchingClosingPar = 0;
31  while(++pos <= back) {
32  if(tokExpr[pos]=="(") {
33  parCount++;
34  }
35  if(tokExpr[pos]==")") {
36  parCount--;
37  }
38  if(parCount==0) {
39  matchingClosingPar = pos;
40  break;
41  }
42  }
43  if( matchingClosingPar == 0 ) {
44  printSubExpr("Search for matching parenthesis", tokExpr, front, back);
45  throw TrigConf::LogicParsingException("Found no closing parenthesis, matching '('");
46  }
47  return matchingClosingPar;
48  }
49 
50 }
51 
52 std::shared_ptr<TrigConf::Logic>
53 TrigConf::LogicParser::parse(const std::string & expr) {
54  std::unique_ptr<TrigConf::Logic> node( nullptr );
55  try {
56  auto exprTok = tokenize(expr);
57  node = buildTree(exprTok);
58  node->setExpression(expr);
59  } catch (LogicParsingException & ex) {
60  std::cerr << "Error in expression " << expr << ":" << ex.msg() << std::endl;
61  throw;
62  return nullptr;
63  }
64  return std::shared_ptr<TrigConf::Logic>(std::move(node));
65 }
66 
67 std::vector<std::string>
68 TrigConf::LogicParser::tokenize(const std::string & expr) const {
69  std::vector<std::string> tokens;
70  // build tokens with separators ()&|! and <space>. Keeps all separators except <space> in the list of tokens
71  for ( auto & tok : boost::tokenizer<boost::char_separator<char> > (expr, boost::char_separator<char>(" ", "()&|!")) ) {
72  tokens.emplace_back(tok);
73  }
74  return tokens;
75 }
76 
77 
78 
79 std::unique_ptr<TrigConf::Logic>
80 TrigConf::LogicParser::buildTree(const std::vector<std::string> & tokExpr) const {
81 
82  size_t front = 0;
83  size_t back = tokExpr.size()-1;
84  return buildNode(tokExpr,front,back);
85 }
86 
87 
88 std::unique_ptr<TrigConf::Logic>
89 TrigConf::LogicParser::buildNode(const std::vector<std::string> & tokExpr, size_t front, size_t back) const {
90 
91  auto logicLeft = findSubExpr(tokExpr,front, back);
92 
93  if(front >= back) {
94  return logicLeft;
95  }
96 
97  std::string token = tokExpr[front];
98  if( token!="&" && token != "|" ) {
99  throw LogicParsingException(std::string("Did expect a & or | here, but got a ") + token + ".");
100  }
101  front++;
102 
103  // cppcheck-suppress accessMoved; false positive
104  LogicOPS * logic = token=="&" ? static_cast<LogicOPS*>(new LogicAND(std::move(logicLeft))) : static_cast<LogicOPS*>(new LogicOR(std::move(logicLeft)));
105 
106  auto logicRight = buildNode(tokExpr, front, back);
107 
108  if(logicRight->nodeType() == logic->nodeType()) {
109  auto subLogics = static_cast<LogicOPS*>(logicRight.get())->takeSubLogics();
110  for(auto && sublogic : std::move(subLogics)) {
111  logic->addSubLogic(std::move(sublogic));
112  }
113  } else {
114  logic->addSubLogic(std::move(logicRight));
115  }
116 
117  return std::unique_ptr<TrigConf::Logic>( logic );
118 }
119 
120 
121 
127 std::unique_ptr<TrigConf::Logic>
128 TrigConf::LogicParser::findSubExpr(const std::vector<std::string> & tokExpr, size_t & front, const size_t back) const {
129 
130  std::string token = tokExpr[front];
131 
132  auto logic = std::unique_ptr<TrigConf::Logic>( nullptr );
133 
134  if(token=="!") {
135  front++; // to eat the '!'
136  token = tokExpr[front];
137  if(token == "(") {
138  logic = findSubExpr(tokExpr,front, back);
139  } else {
140  front++; // eat this token
141  logic = std::unique_ptr<TrigConf::Logic>(new LogicLeaf(token));
142  }
143  logic->setNegate();
144  } else if(token=="(") {
145  size_t parEnd = findMatchingClosingParenthesis(tokExpr, front, back);
146  logic = buildNode(tokExpr,front+1,parEnd-1);
147  front = parEnd + 1;
148  } else {
149  logic = std::unique_ptr<TrigConf::Logic>(new LogicLeaf(token));
150  ++front;
151  }
152  return logic;
153 }
154 
CxxUtils::tokenize
std::vector< std::string > tokenize(const std::string &the_str, std::string_view delimiters)
Splits the string into smaller substrings.
Definition: Control/CxxUtils/Root/StringUtils.cxx:15
parse
std::map< std::string, std::string > parse(const std::string &list)
Definition: egammaLayerRecalibTool.cxx:1054
beamspotman.tokens
tokens
Definition: beamspotman.py:1284
lumiFormat.i
int i
Definition: lumiFormat.py:85
PyPoolBrowser.node
node
Definition: PyPoolBrowser.py:131
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:18
LogicParser.h
TrigConf::LogicParsingException
Definition: Logic.h:16
node
Definition: memory_hooks-stdcmalloc.h:74