CMS 3D CMS Logo

GlobalLogicParser.cc
Go to the documentation of this file.
1 
15 // this class header
17 
18 // system include files
19 #include <stack>
20 
21 #include <iostream>
22 #include <sstream>
23 
24 #include <boost/algorithm/string.hpp>
25 
26 // user include files
27 
30 
31 // forward declarations
32 
33 // constructor(s)
34 
35 // default constructor
37  // empty, default C++ initialization for string and vector are enough
38 }
39 
40 // from the RPN vector and the operand token vector
41 // no checks for consistency, empty logical and numerical expressions
42 // requires special care when used
43 GlobalLogicParser::GlobalLogicParser(const RpnVector& rpnVec, const std::vector<OperandToken>& opTokenVector) {
44  m_rpnVector = rpnVec;
45  m_operandTokenVector = opTokenVector;
46 }
47 
48 // from a constant logical expression
49 // numerical expression will be empty
50 GlobalLogicParser::GlobalLogicParser(const std::string& logicalExpressionVal) {
51  // checks also for syntactic correctness of the logical expression
52 
53  if (!setLogicalExpression(logicalExpressionVal)) {
54  // error(s) in logical expression - printed in the relevant place
55  throw cms::Exception("FailModule") << "\nError in parsing the logical expression = " << logicalExpressionVal
56  << std::endl;
57  }
58 }
59 
60 // from a non-constant logical expression - add/remove spaces if needed
61 // numerical expression will be empty
63  // checks also for syntactic correctness of the logical expression
64 
65  // add spaces around brackets
66  std::string logicalExpressionBS;
67  addBracketSpaces(logicalExpressionVal, logicalExpressionBS);
68 
69  // trim leading or trailing spaces
70  boost::trim(logicalExpressionBS);
71 
72  if (!buildRpnVector(logicalExpressionBS)) {
73  // error(s) in logical expression
74  throw cms::Exception("FailModule") << "\nError in parsing the logical expression = " << logicalExpressionVal
75  << std::endl;
76  }
77 
78  //LogDebug("L1TGlobal")
79  // << "\nInitial logical expression = '" << logicalExpressionVal << "'"
80  // << "\nFinal logical expression = '" << logicalExpressionBS << "'\n"
81  // << std::endl;
82 
83  logicalExpressionVal = logicalExpressionBS;
84  m_logicalExpression = logicalExpressionVal;
85 
86  // build operand token vector
87  // dummy tokenNumber; tokenResult false
89 }
90 
91 // from a logical and a numerical expression
92 GlobalLogicParser::GlobalLogicParser(const std::string logicalExpressionVal, const std::string numericalExpressionVal) {
93  // checks also for correctness
94 
95  if (!setLogicalExpression(logicalExpressionVal)) {
96  // error(s) in logical expression - printed in the relevant place
97  throw cms::Exception("FailModule") << "\nError in parsing the logical expression = " << logicalExpressionVal
98  << std::endl;
99  }
100 
101  if (!setNumericalExpression(numericalExpressionVal)) {
102  // error(s) in numerical expression - printed in the relevant place
103  throw cms::Exception("FileModule") << "\nError in parsing the numerical expression = " << numericalExpressionVal
104  << std::endl;
105  }
106 }
107 
108 // from a logical and a numerical expression
109 // no checks for correctness - use it only after the correctness was tested
111  const std::string& numericalExpressionVal,
112  const bool dummy) {
113  clearRpnVector();
114  if (!buildRpnVector(logicalExpressionVal)) {
115  throw cms::Exception("FileModule") << "\nError in building RPN vector for the logical expression = "
116  << logicalExpressionVal << std::endl;
117  }
118 
119  m_logicalExpression = logicalExpressionVal;
120  m_numericalExpression = numericalExpressionVal;
121 }
122 
123 // destructor
125  // empty now
126 }
127 
128 // public methods
129 
130 // check a logical expression for correctness - add/remove spaces if needed
132  // add spaces around brackets
133  std::string logicalExpressionBS;
134  addBracketSpaces(logicalExpressionVal, logicalExpressionBS);
135 
136  // trim leading or trailing spaces
137  boost::trim(logicalExpressionBS);
138 
139  clearRpnVector();
140 
141  if (!buildRpnVector(logicalExpressionBS)) {
142  return false;
143  }
144 
145  LogDebug("L1TGlobal") << "\nGtLogicParser::checkLogicalExpression - "
146  << "\nInitial logical expression = '" << logicalExpressionVal << "'"
147  << "\nFinal logical expression = '" << logicalExpressionBS << "'\n"
148  << std::endl;
149 
150  logicalExpressionVal = logicalExpressionBS;
151 
152  return true;
153 }
154 
164 bool GlobalLogicParser::buildRpnVector(const std::string& logicalExpressionVal) {
165  //LogDebug("L1TGlobal")
166  //<< "\nGtLogicParser::buildRpnVector - "
167  //<< "\nLogical expression = '" << logicalExpressionVal << "'\n"
168  //<< std::endl;
169 
170  OperationType actualOperation = OP_NULL;
171  OperationType lastOperation = OP_NULL;
172 
173  // token as string and as TokenRPN, stack to form the postfix notation
174  std::string tokenString;
175  TokenRPN rpnToken;
176  std::stack<TokenRPN> operatorStack;
177 
178  static const std::string whitespaces = " \r\v\n\t";
179 
180  // clear possible old rpn vector
181  clearRpnVector();
182 
183  // stringstream to separate all tokens
184  std::istringstream exprStringStream(logicalExpressionVal);
185 
186  while (!exprStringStream.eof()) {
187  exprStringStream >> std::skipws >> std::ws >> tokenString;
188 
189  // skip the end
190  if (tokenString.find_first_not_of(whitespaces) == std::string::npos || tokenString.length() == 0) {
191  //LogTrace("L1TGlobal")
192  //<< " Break for token string = " << tokenString
193  //<< std::endl;
194 
195  break;
196  }
197 
198  actualOperation = getOperation(tokenString, lastOperation, rpnToken);
199 
200  //LogTrace("L1TGlobal")
201  //<< " Token string = '" << tokenString << "'"
202  //<< "\tActual Operation = " << actualOperation
203  //<< std::endl;
204 
205  // http://en.wikipedia.org/wiki/Postfix_notation#Converting_from_infix_notation
206 
207  switch (actualOperation) {
208  case OP_OPERAND: {
209  // operands get pushed to the postfix notation immediately
210  m_rpnVector.push_back(rpnToken);
211  }
212 
213  break;
214  case OP_INVALID: {
215  int errorPosition = exprStringStream.tellg();
216 
217  edm::LogError("L1TGlobal") << "\nLogical expression = '" << logicalExpressionVal << "'"
218  << "\n Syntax error during parsing: "
219  << "\n " << exprStringStream.str().substr(0, errorPosition) << "\n "
220  << exprStringStream.str().substr(errorPosition)
221  << "\n Returned empty RPN vector and result false." << std::endl;
222 
223  // clear the rpn vector before returning
224  clearRpnVector();
225 
226  return false;
227  }
228 
229  break;
230  case OP_NOT: {
231  operatorStack.push(rpnToken);
232  // there are no operators with higher precedence
233  }
234 
235  break;
236  case OP_XOR: {
237  // first pop operators with higher precedence (NOT)
238  while (!operatorStack.empty() && operatorStack.top().operation == OP_NOT) {
239  m_rpnVector.push_back(operatorStack.top());
240  operatorStack.pop();
241  }
242  operatorStack.push(rpnToken);
243  }
244 
245  break;
246  case OP_AND: {
247  // first pop operators with higher precedence (XOR, NOT)
248  while (!operatorStack.empty() &&
249  (operatorStack.top().operation == OP_NOT || operatorStack.top().operation == OP_AND)) {
250  m_rpnVector.push_back(operatorStack.top());
251  operatorStack.pop();
252  }
253  operatorStack.push(rpnToken);
254  }
255 
256  break;
257  case OP_OR: {
258  // pop operators with higher precedence (AND, XOR, NOT)
259  while (!operatorStack.empty() &&
260  (operatorStack.top().operation == OP_NOT || operatorStack.top().operation == OP_XOR ||
261  operatorStack.top().operation == OP_AND)) {
262  m_rpnVector.push_back(operatorStack.top());
263  operatorStack.pop();
264  }
265  // push operator on stack
266  operatorStack.push(rpnToken);
267  }
268 
269  break;
270  case OP_OPENBRACKET: {
271  // just push it on stack
272  operatorStack.push(rpnToken);
273  }
274 
275  break;
276  case OP_CLOSEBRACKET: {
277  // check if the operatorStack is empty
278  if (operatorStack.empty()) {
279  int errorPosition = exprStringStream.tellg();
280 
281  edm::LogError("L1TGlobal") << "\nLogical expression = '" << logicalExpressionVal << "'"
282  << "\n Syntax error during parsing - misplaced ')':"
283  << "\n " << exprStringStream.str().substr(0, errorPosition) << "\n "
284  << exprStringStream.str().substr(errorPosition)
285  << "\n Returned empty RPN vector and result false." << std::endl;
286 
287  // clear the rpn vector before returning
288  clearRpnVector();
289 
290  return false;
291  }
292 
293  // pop stack until a left parenthesis is found
294  do {
295  if (operatorStack.top().operation != OP_OPENBRACKET) {
296  m_rpnVector.push_back(operatorStack.top()); // pop
297  operatorStack.pop();
298  }
299  if (operatorStack.empty()) { // the operatorStack must not be empty
300 
301  int errorPosition = exprStringStream.tellg();
302 
303  edm::LogError("L1TGlobal") << "\nLogical expression = '" << logicalExpressionVal << "'"
304  << "\n Syntax error during parsing - misplaced ')':"
305  << "\n " << exprStringStream.str().substr(0, errorPosition) << "\n "
306  << exprStringStream.str().substr(errorPosition)
307  << "\n Returned empty RPN vector and result false." << std::endl;
308 
309  // clear the rpn vector before returning
310  clearRpnVector();
311  return false;
312  }
313  } while (operatorStack.top().operation != OP_OPENBRACKET);
314 
315  operatorStack.pop(); // pop the open bracket.
316  }
317 
318  break;
319  default: {
320  // empty
321  } break;
322  }
323 
324  lastOperation = actualOperation; // for the next turn
325  }
326 
327  // pop the rest of the operator stack
328  while (!operatorStack.empty()) {
329  if (operatorStack.top().operation == OP_OPENBRACKET) {
330  edm::LogError("L1TGlobal") << "\nLogical expression = '" << logicalExpressionVal << "'"
331  << "\n Syntax error during parsing - missing ')':"
332  << "\n Returned empty RPN vector and result false." << std::endl;
333 
334  // clear the rpn vector before returning
335  clearRpnVector();
336  return false;
337  }
338 
339  m_rpnVector.push_back(operatorStack.top());
340  operatorStack.pop();
341  }
342 
343  // count all operations and check if the result is 1
344  int counter = 0;
345  for (RpnVector::iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) {
346  if (it->operation == OP_OPERAND)
347  counter++;
348  if (it->operation == OP_OR || it->operation == OP_AND || it->operation == OP_XOR)
349  counter--;
350  if (counter < 1) {
351  edm::LogError("L1TGlobal") << "\nLogical expression = '" << logicalExpressionVal << "'"
352  << "\n Syntax error during parsing - too many operators"
353  << "\n Returned empty RPN vector and result false." << std::endl;
354 
355  // clear the rpn vector before returning
356  clearRpnVector();
357  return false;
358  }
359  }
360 
361  if (counter > 1) {
362  edm::LogError("L1TGlobal") << "\nLogical expression = '" << logicalExpressionVal << "'"
363  << "\n Syntax error during parsing - too many operands"
364  << "\n Returned empty RPN vector and result false." << std::endl;
365 
366  // clear the rpn vector before returning
367  clearRpnVector();
368  return false;
369  }
370  return true;
371 }
372 
373 // clear rpn vector
375 
376 // build from the RPN vector the operand token vector
377 // dummy tokenNumber and token result
379  //LogTrace("L1TGlobal")
380  //<< "\nGtLogicParser::buildOperandTokenVector - "
381  //<< std::endl;
382 
383  // reserve memory
384  size_t rpnVectorSize = m_rpnVector.size();
385  m_operandTokenVector.reserve(rpnVectorSize);
386 
387  int opNumber = 0;
388 
389  for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) {
390  //LogTrace("L1TGlobal")
391  //<< "\nit->operation = " << it->operation
392  //<< "\nit->operand = '" << it->operand << "'\n"
393  //<< std::endl;
394 
395  switch (it->operation) {
396  case OP_OPERAND: {
397  OperandToken opToken;
398  opToken.tokenName = it->operand;
399  opToken.tokenNumber = opNumber;
400  opToken.tokenResult = false;
401 
402  m_operandTokenVector.push_back(opToken);
403 
404  }
405 
406  break;
407  case OP_NOT: {
408  // do nothing
409  }
410 
411  break;
412  case OP_OR: {
413  // do nothing
414  }
415 
416  break;
417  case OP_AND: {
418  // do nothing
419  }
420  case OP_XOR: {
421  // do nothing
422  }
423 
424  break;
425  default: {
426  // should not arrive here
427  }
428 
429  break;
430  }
431 
432  opNumber++;
433  }
434 }
435 
436 // return the position index of the operand in the logical expression
437 int GlobalLogicParser::operandIndex(const std::string& operandNameVal) const {
438  int result = -1;
439 
440  OperationType actualOperation = OP_NULL;
441  OperationType lastOperation = OP_NULL;
442 
443  std::string tokenString;
444  TokenRPN rpnToken; // token to be used by getOperation
445 
446  // stringstream to separate all tokens
447  std::istringstream exprStringStream(m_logicalExpression);
448 
449  // temporary index for usage in the loop
450  int tmpIndex = -1;
451 
452  while (!exprStringStream.eof()) {
453  exprStringStream >> tokenString;
454 
455  //LogTrace("L1TGlobal")
456  //<< "Token string = " << tokenString
457  //<< std::endl;
458 
459  actualOperation = getOperation(tokenString, lastOperation, rpnToken);
460  if (actualOperation == OP_INVALID) {
461  // it should never be invalid
462  edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'"
463  << "\n Invalid operation/operand " << operandNameVal
464  << "\n Returned index is by default out of range (-1)." << std::endl;
465 
466  return result;
467  }
468 
469  if (actualOperation != OP_OPERAND) {
470  // do nothing
471 
472  } else {
473  tmpIndex++;
474  if (rpnToken.operand == operandNameVal) {
475  result = tmpIndex;
476 
477  //LogDebug("L1TGlobal")
478  //<< "\nGtLogicParser::operandIndex - "
479  //<< "\nLogical expression = '" << m_logicalExpression << "'"
480  //<< "\nIndex of operand " << operandNameVal << " = " << result
481  //<< std::endl;
482 
483  return result;
484  }
485  }
486  lastOperation = actualOperation;
487  }
488 
489  //
490  edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'"
491  << "\n Operand " << operandNameVal << " not found in the logical expression"
492  << "\n Returned index is by default out of range (-1)." << std::endl;
493 
494  return result;
495 }
496 
497 // return the name of the (iOperand)th operand in the logical expression
498 std::string GlobalLogicParser::operandName(const int iOperand) const {
500 
501  OperationType actualOperation = OP_NULL;
502  OperationType lastOperation = OP_NULL;
503 
504  std::string tokenString;
505  TokenRPN rpnToken; // token to be used by getOperation
506 
507  // stringstream to separate all tokens
508  std::istringstream exprStringStream(m_logicalExpression);
509 
510  // temporary index for usage in the loop
511  int tmpIndex = -1;
512 
513  while (!exprStringStream.eof()) {
514  exprStringStream >> tokenString;
515 
516  //LogTrace("L1TGlobal")
517  //<< "Token string = " << tokenString
518  //<< std::endl;
519 
520  actualOperation = getOperation(tokenString, lastOperation, rpnToken);
521  if (actualOperation == OP_INVALID) {
522  // it should never be invalid
523  edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'"
524  << "\n Invalid operation/operand at position " << iOperand
525  << "\n Returned empty name by default." << std::endl;
526 
527  return result;
528  }
529 
530  if (actualOperation != OP_OPERAND) {
531  // do nothing
532 
533  } else {
534  tmpIndex++;
535  if (tmpIndex == iOperand) {
536  result = rpnToken.operand;
537 
538  //LogDebug("L1TGlobal")
539  //<< "\nGtLogicParser::operandName - "
540  //<< "\nLogical expression = '" << m_logicalExpression << "'"
541  //<< "\nOperand with index " << iOperand << " = " << result
542  //<< std::endl;
543 
544  return result;
545  }
546  }
547  lastOperation = actualOperation;
548  }
549 
550  //
551  edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'"
552  << "\n No operand found at position " << iOperand << "\n Returned empty name by default."
553  << std::endl;
554 
555  return result;
556 }
557 
558 // return the result for an operand with name operandNameVal
559 // in the logical expression using the operand token vector
560 bool GlobalLogicParser::operandResult(const std::string& operandNameVal) const {
561  for (size_t i = 0; i < m_operandTokenVector.size(); ++i) {
562  if ((m_operandTokenVector[i]).tokenName == operandNameVal) {
563  return (m_operandTokenVector[i]).tokenResult;
564  }
565  }
566 
567  // return false - should not arrive here
568  edm::LogError("L1TGlobal") << "\n Operand " << operandNameVal << " not found in the operand token vector"
569  << "\n Returned false by default." << std::endl;
570 
571  return false;
572 }
573 
574 // return the result for an operand with tokenNumberVal
575 // using the operand token vector
576 bool GlobalLogicParser::operandResult(const int tokenNumberVal) const {
577  for (size_t i = 0; i < m_operandTokenVector.size(); ++i) {
578  if ((m_operandTokenVector[i]).tokenNumber == tokenNumberVal) {
579  return (m_operandTokenVector[i]).tokenResult;
580  }
581  }
582 
583  // return false - should not arrive here
584  edm::LogError("L1TGlobal") << "\n No operand with token number " << tokenNumberVal
585  << " found in the operand token vector"
586  << "\n Returned false by default." << std::endl;
587 
588  return false;
589 }
590 
591 // return the result for the logical expression
592 // require a proper operand token vector
594  //LogTrace("L1TGlobal")
595  //<< "\nGtLogicParser::expressionResult - "
596  //<< std::endl;
597 
598  // return false if there is no RPN vector built
599  if (m_rpnVector.empty()) {
600  edm::LogError("L1TGlobal") << "\n No built RPN vector exists."
601  << "\n Returned false by default." << std::endl;
602  return false;
603  }
604 
605  // stack containing temporary results
606  std::stack<bool> resultStack;
607  bool b1, b2;
608 
609  for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) {
610  //LogTrace("L1TGlobal")
611  //<< "\nit->operation = " << it->operation
612  //<< "\nit->operand = '" << it->operand << "'\n"
613  //<< std::endl;
614 
615  switch (it->operation) {
616  case OP_OPERAND: {
617  resultStack.push(operandResult(it->operand));
618  }
619 
620  break;
621  case OP_NOT: {
622  b1 = resultStack.top();
623  resultStack.pop(); // pop the top
624  resultStack.push(!b1); // and push the result
625  }
626 
627  break;
628  case OP_OR: {
629  b1 = resultStack.top();
630  resultStack.pop();
631  b2 = resultStack.top();
632  resultStack.pop();
633  resultStack.push(b1 || b2);
634  }
635 
636  break;
637  case OP_XOR: {
638  b1 = resultStack.top();
639  resultStack.pop();
640  b2 = resultStack.top();
641  resultStack.pop();
642  resultStack.push(b1 ^ b2);
643  }
644 
645  break;
646  case OP_AND: {
647  b1 = resultStack.top();
648  resultStack.pop();
649  b2 = resultStack.top();
650  resultStack.pop();
651  resultStack.push(b1 && b2);
652  }
653 
654  break;
655  default: {
656  // should not arrive here
657  }
658 
659  break;
660  }
661  }
662 
663  // get the result in the top of the stack
664 
665  //LogTrace("L1TGlobal")
666  //<< "\nGtLogicParser::expressionResult - "
667  //<< "\nResult = " << resultStack.top()
668  //<< std::endl;
669 
670  return resultStack.top();
671 }
672 
673 // return the result for an operand with name operandNameVal
674 // in the logical expression using a numerical expression
675 bool GlobalLogicParser::operandResultNumExp(const std::string& operandNameVal) const {
676  bool result = false;
677 
678  // get the position index of the operand in the logical string
679  const int iOperand = operandIndex(operandNameVal);
680 
681  result = operandResult(iOperand);
682 
683  return result;
684 }
685 
686 // return the result for an operand with index iOperand
687 // in the logical expression using a numerical expression
688 bool GlobalLogicParser::operandResultNumExp(const int iOperand) const {
689  bool result = false;
690 
691  // parse the numerical expression
692 
693  OperationType actualOperation = OP_NULL;
694  OperationType lastOperation = OP_NULL;
695 
696  std::string tokenString;
697  TokenRPN rpnToken; // token to be used by getOperation
698 
699  // stringstream to separate all tokens
700  std::istringstream exprStringStream(m_numericalExpression);
701 
702  // temporary index for usage in the loop
703  int tmpIndex = -1;
704 
705  while (!exprStringStream.eof()) {
706  exprStringStream >> tokenString;
707 
708  //LogTrace("L1TGlobal")
709  //<< "Token string = " << tokenString
710  //<< std::endl;
711 
712  actualOperation = getOperation(tokenString, lastOperation, rpnToken);
713  if (actualOperation == OP_INVALID) {
714  // it should never be invalid
715  edm::LogError("L1TGlobal") << "\nNumerical expression = '" << m_numericalExpression << "'"
716  << "\n Invalid operation/operand at position " << iOperand
717  << "\n Returned false by default." << std::endl;
718 
719  result = false;
720  return result;
721  }
722 
723  if (actualOperation != OP_OPERAND) {
724  // do nothing
725 
726  } else {
727  tmpIndex++;
728  if (tmpIndex == iOperand) {
729  if (rpnToken.operand == "1") {
730  result = true;
731  } else {
732  if (rpnToken.operand == "0") {
733  result = false;
734  } else {
735  // something went wrong - break
736  //
737  edm::LogError("L1TGlobal") << "\nNumerical expression = '" << m_numericalExpression << "'"
738  << "\n Invalid result for operand at position " << iOperand << ": "
739  << rpnToken.operand << "\n It must be 0 or 1"
740  << "\n Returned false by default." << std::endl;
741 
742  result = false;
743  return result;
744  }
745  }
746 
747  //LogDebug("L1TGlobal")
748  //<< "\nGtLogicParser::operandResult - "
749  //<< "\nNumerical expression = '" << m_numericalExpression << "'"
750  //<< "\nResult for operand with index " << iOperand
751  //<< " = " << result << "'\n"
752  //<< std::endl;
753 
754  return result;
755  }
756  }
757  lastOperation = actualOperation;
758  }
759 
760  //
761  edm::LogError("L1TGlobal") << "\nNumerical expression = '" << m_numericalExpression << "'"
762  << "\n No operand found at position " << iOperand << "\n Returned false by default."
763  << std::endl;
764 
765  return result;
766 }
767 
768 // build from the RPN vector the operand token vector
769 // using a numerical expression
771  //LogTrace("L1TGlobal")
772  //<< "\nGtLogicParser::buildOperandTokenVector - "
773  //<< std::endl;
774 
775  // reserve memory
776  size_t rpnVectorSize = m_rpnVector.size();
777  m_operandTokenVector.reserve(rpnVectorSize);
778 
779  int opNumber = 0;
780 
781  for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) {
782  //LogTrace("L1TGlobal")
783  //<< "\nit->operation = " << it->operation
784  //<< "\nit->operand = '" << it->operand << "'\n"
785  //<< std::endl;
786 
787  switch (it->operation) {
788  case OP_OPERAND: {
789  OperandToken opToken;
790  opToken.tokenName = it->operand;
791  opToken.tokenNumber = opNumber;
792  opToken.tokenResult = operandResultNumExp(it->operand);
793 
794  m_operandTokenVector.push_back(opToken);
795 
796  }
797 
798  break;
799  case OP_NOT: {
800  // do nothing
801  }
802 
803  break;
804  case OP_OR: {
805  // do nothing
806  }
807 
808  break;
809  case OP_XOR: {
810  // do nothing
811  }
812 
813  break;
814  case OP_AND: {
815  // do nothing
816  }
817 
818  break;
819  default: {
820  // should not arrive here
821  }
822 
823  break;
824  }
825 
826  opNumber++;
827  }
828 }
829 
830 // return the result for the logical expression
832  //LogTrace("L1TGlobal")
833  //<< "\nGtLogicParser::expressionResult - "
834  //<< std::endl;
835 
836  // return false if there is no expression
837  if (m_rpnVector.empty()) {
838  edm::LogError("L1TGlobal") << "\n No built RPN vector exists."
839  << "\n Returned false by default." << std::endl;
840  return false;
841  }
842 
843  // stack containing temporary results
844  std::stack<bool> resultStack;
845  bool b1, b2;
846 
847  for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) {
848  //LogTrace("L1TGlobal")
849  //<< "\nit->operation = " << it->operation
850  //<< "\nit->operand = '" << it->operand << "'\n"
851  //<< std::endl;
852 
853  switch (it->operation) {
854  case OP_OPERAND: {
855  resultStack.push(operandResultNumExp(it->operand));
856  }
857 
858  break;
859  case OP_NOT: {
860  b1 = resultStack.top();
861  resultStack.pop(); // pop the top
862  resultStack.push(!b1); // and push the result
863  }
864 
865  break;
866  case OP_OR: {
867  b1 = resultStack.top();
868  resultStack.pop();
869  b2 = resultStack.top();
870  resultStack.pop();
871  resultStack.push(b1 || b2);
872  }
873 
874  break;
875  case OP_XOR: {
876  b1 = resultStack.top();
877  resultStack.pop();
878  b2 = resultStack.top();
879  resultStack.pop();
880  resultStack.push(b1 ^ b2);
881  }
882 
883  break;
884  case OP_AND: {
885  b1 = resultStack.top();
886  resultStack.pop();
887  b2 = resultStack.top();
888  resultStack.pop();
889  resultStack.push(b1 && b2);
890  }
891 
892  break;
893  default: {
894  // should not arrive here
895  }
896 
897  break;
898  }
899  }
900 
901  // get the result in the top of the stack
902 
903  //LogTrace("L1TGlobal")
904  //<< "\nGtLogicParser::expressionResult - "
905  //<< "\nLogical expression = '" << m_logicalExpression << "'"
906  //<< "\nNumerical expression = '" << m_numericalExpression << "'"
907  //<< "\nResult = " << resultStack.top()
908  //<< std::endl;
909 
910  return resultStack.top();
911 }
912 
913 // convert the logical expression composed with names to
914 // a logical expression composed with int numbers using
915 // a (string, int) map
916 
917 void GlobalLogicParser::convertNameToIntLogicalExpression(const std::map<std::string, int>& nameToIntMap) {
918  if (m_logicalExpression.empty()) {
919  return;
920  }
921 
922  // non-empty logical expression
923 
924  OperationType actualOperation = OP_NULL;
925  OperationType lastOperation = OP_NULL;
926 
927  std::string tokenString;
928  TokenRPN rpnToken; // token to be used by getOperation
929 
930  int intValue = -1;
931 
932  // stringstream to separate all tokens
933  std::istringstream exprStringStream(m_logicalExpression);
934  std::string convertedLogicalExpression;
935 
936  while (!exprStringStream.eof()) {
937  exprStringStream >> tokenString;
938 
939  actualOperation = getOperation(tokenString, lastOperation, rpnToken);
940  if (actualOperation == OP_INVALID) {
941  // it should never be invalid
942  edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'"
943  << "\n Invalid operation/operand in logical expression."
944  << "\n Return empty logical expression." << std::endl;
945 
946  m_logicalExpression.clear();
947  return;
948  }
949 
950  if (actualOperation != OP_OPERAND) {
951  convertedLogicalExpression.append(getRuleFromType(actualOperation)->opString);
952 
953  } else {
954  typedef std::map<std::string, int>::const_iterator CIter;
955 
956  CIter it = nameToIntMap.find(rpnToken.operand);
957  if (it != nameToIntMap.end()) {
958  intValue = it->second;
959  std::stringstream intStr;
960  intStr << intValue;
961  convertedLogicalExpression.append(intStr.str());
962 
963  } else {
964  // it should never be happen
965  edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'"
966  << "\n Could not convert " << rpnToken.operand << " to integer!"
967  << "\n Return empty logical expression." << std::endl;
968 
969  m_logicalExpression.clear();
970  return;
971  }
972  }
973 
974  convertedLogicalExpression.append(" "); // one whitespace after each token
975  lastOperation = actualOperation;
976  }
977 
978  // remove the last space
979  //convertedLogicalExpression.erase(convertedLogicalExpression.size() - 1);
980  boost::trim(convertedLogicalExpression);
981 
982  LogDebug("L1TGlobal") << "\nGtLogicParser::convertNameToIntLogicalExpression - "
983  << "\nLogical expression (strings) = '" << m_logicalExpression << "'"
984  << "\nLogical expression (int) = '" << convertedLogicalExpression << "'\n"
985  << std::endl;
986 
987  // replace now the logical expression with strings with
988  // the converted logical expression
989 
990  m_logicalExpression = convertedLogicalExpression;
991 
992  return;
993 }
994 
995 // convert a logical expression composed with integer numbers to
996 // a logical expression composed with names using a map (int, string)
997 
998 void GlobalLogicParser::convertIntToNameLogicalExpression(const std::map<int, std::string>& intToNameMap) {
999  if (m_logicalExpression.empty()) {
1000  return;
1001  }
1002 
1003  // non-empty logical expression
1004 
1005  OperationType actualOperation = OP_NULL;
1006  OperationType lastOperation = OP_NULL;
1007 
1008  std::string tokenString;
1009  TokenRPN rpnToken; // token to be used by getOperation
1010 
1011  // stringstream to separate all tokens
1012  std::istringstream exprStringStream(m_logicalExpression);
1013  std::string convertedLogicalExpression;
1014 
1015  while (!exprStringStream.eof()) {
1016  exprStringStream >> tokenString;
1017 
1018  actualOperation = getOperation(tokenString, lastOperation, rpnToken);
1019  if (actualOperation == OP_INVALID) {
1020  // it should never be invalid
1021  edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'"
1022  << "\n Invalid operation/operand in logical expression."
1023  << "\n Return empty logical expression." << std::endl;
1024 
1025  m_logicalExpression.clear();
1026  return;
1027  }
1028 
1029  if (actualOperation != OP_OPERAND) {
1030  convertedLogicalExpression.append(getRuleFromType(actualOperation)->opString);
1031 
1032  } else {
1033  typedef std::map<int, std::string>::const_iterator CIter;
1034 
1035  // convert string to int
1036  int indexInt;
1037  std::istringstream iss(rpnToken.operand);
1038  iss >> std::dec >> indexInt;
1039 
1040  CIter it = intToNameMap.find(indexInt);
1041  if (it != intToNameMap.end()) {
1042  convertedLogicalExpression.append(it->second);
1043 
1044  } else {
1045  // it should never be happen
1046  edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'"
1047  << "\n Could not convert " << rpnToken.operand << " to string!"
1048  << "\n Return empty logical expression." << std::endl;
1049 
1050  m_logicalExpression.clear();
1051  return;
1052  }
1053  }
1054 
1055  convertedLogicalExpression.append(" "); // one whitespace after each token
1056  lastOperation = actualOperation;
1057  }
1058 
1059  // remove the last space
1060  //convertedLogicalExpression.erase(convertedLogicalExpression.size() - 1);
1061  boost::trim(convertedLogicalExpression);
1062 
1063  //LogDebug("L1TGlobal")
1064  // << "\nGtLogicParser::convertIntToNameLogicalExpression - "
1065  // << "\nLogical expression (int) = '" << m_logicalExpression << "'"
1066  // << "\nLogical expression (string) = '" << convertedLogicalExpression << "'\n"
1067  // << std::endl;
1068 
1069  // replace now the logical expression with int with
1070  // the converted logical expression
1071 
1072  m_logicalExpression = convertedLogicalExpression;
1073 
1074  return;
1075 }
1076 
1077 // return the list of operand tokens for the logical expression
1078 // which are to be used as seeds
1079 std::vector<GlobalLogicParser::OperandToken> GlobalLogicParser::expressionSeedsOperandList() {
1080  //LogDebug("L1TGlobal")
1081  //<< "\nGtLogicParser::expressionSeedsOperandList - "
1082  //<< "\nLogical expression = '" << m_logicalExpression << "'"
1083  //<< "\nm_rpnVector.size() = " << m_rpnVector.size()
1084  //<< "\nm_operandTokenVector.size() = " << m_operandTokenVector.size()
1085  //<< std::endl;
1086 
1087  // seed list
1088  std::vector<OperandToken> opVector;
1089  opVector.reserve(m_operandTokenVector.size());
1090 
1091  // temporary results
1092  std::stack<OperandToken> tmpStack;
1093  std::vector<OperandToken> tmpVector;
1094  tmpVector.reserve(m_operandTokenVector.size());
1095 
1096  OperandToken b1, b2;
1097 
1098  bool newOperandBlock = true;
1099  bool oneBlockOnly = true;
1100  bool operandOnly = true;
1101 
1102  int iOperand = -1;
1103 
1104  OperandToken dummyToken;
1105  dummyToken.tokenName = "dummy";
1106  dummyToken.tokenNumber = -1;
1107  dummyToken.tokenResult = false;
1108 
1109  for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) {
1110  //LogTrace("L1TGlobal")
1111  //<< "\nit->operation = " << it->operation
1112  //<< "\nit->operand = '" << it->operand << "'\n"
1113  //<< std::endl;
1114 
1115  switch (it->operation) {
1116  // RPN always start a block with an operand
1117  case OP_OPERAND: {
1118  // more blocks with operations
1119  // push operands from previous block, if any in the tmpVector
1120  // (reverse order to compensate the stack push/top/pop)
1121  if ((!newOperandBlock)) {
1122  for (std::vector<OperandToken>::reverse_iterator itOp = tmpVector.rbegin(); itOp != tmpVector.rend();
1123  itOp++) {
1124  opVector.push_back(*itOp);
1125 
1126  //LogTrace("L1TGlobal")
1127  //<< " Push operand " << (*itOp).tokenName
1128  //<<" on the seed operand list"
1129  //<< std::endl;
1130  }
1131 
1132  tmpVector.clear();
1133 
1134  newOperandBlock = true;
1135  oneBlockOnly = false;
1136  }
1137 
1138  iOperand++;
1139 
1140  //LogTrace("L1TGlobal")
1141  //<< " Push operand " << (m_operandTokenVector.at(iOperand)).tokenName
1142  //<< " on the operand stack"
1143  //<< std::endl;
1144 
1145  tmpStack.push(m_operandTokenVector.at(iOperand));
1146  }
1147 
1148  break;
1149  case OP_NOT: {
1150  newOperandBlock = false;
1151  operandOnly = false;
1152 
1153  b1 = tmpStack.top();
1154  tmpStack.pop(); // pop the top
1155 
1156  tmpStack.push(dummyToken); // and push dummy result
1157 
1158  //LogTrace("L1TGlobal")
1159  //<< " Clear tmp operand list"
1160  //<< std::endl;
1161 
1162  tmpVector.clear();
1163 
1164  }
1165 
1166  break;
1167  case OP_OR: {
1168  newOperandBlock = false;
1169  operandOnly = false;
1170 
1171  b1 = tmpStack.top();
1172  tmpStack.pop();
1173  b2 = tmpStack.top();
1174  tmpStack.pop();
1175 
1176  tmpStack.push(dummyToken); // and push dummy result
1177 
1178  if (b1.tokenNumber >= 0) {
1179  tmpVector.push_back(b1);
1180 
1181  //LogTrace("L1TGlobal")
1182  //<< " Push operand " << b1.tokenName
1183  //<<" on the tmp list"
1184  //<< std::endl;
1185  }
1186 
1187  if (b2.tokenNumber >= 0) {
1188  tmpVector.push_back(b2);
1189 
1190  //LogTrace("L1TGlobal")
1191  //<< " Push operand " << b2.tokenName
1192  //<<" on the tmp list"
1193  //<< std::endl;
1194  }
1195 
1196  }
1197 
1198  break;
1199  case OP_XOR: {
1200  newOperandBlock = false;
1201  operandOnly = false;
1202 
1203  b1 = tmpStack.top();
1204  tmpStack.pop();
1205  b2 = tmpStack.top();
1206  tmpStack.pop();
1207 
1208  tmpStack.push(dummyToken); // and push dummy result
1209 
1210  if (b1.tokenNumber >= 0) {
1211  tmpVector.push_back(b1);
1212 
1213  //LogTrace("L1TGlobal")
1214  //<< " Push operand " << b1.tokenName
1215  //<<" on the tmp list"
1216  //<< std::endl;
1217  }
1218 
1219  if (b2.tokenNumber >= 0) {
1220  tmpVector.push_back(b2);
1221 
1222  //LogTrace("L1TGlobal")
1223  //<< " Push operand " << b2.tokenName
1224  //<<" on the tmp list"
1225  //<< std::endl;
1226  }
1227 
1228  }
1229 
1230  break;
1231  case OP_AND: {
1232  newOperandBlock = false;
1233  operandOnly = false;
1234 
1235  b1 = tmpStack.top();
1236  tmpStack.pop();
1237  b2 = tmpStack.top();
1238  tmpStack.pop();
1239 
1240  tmpStack.push(dummyToken);
1241 
1242  if (b1.tokenNumber >= 0) {
1243  tmpVector.push_back(b1);
1244 
1245  //LogTrace("L1TGlobal")
1246  //<< " Push operand " << b1.tokenName
1247  //<<" on the tmp list"
1248  //<< std::endl;
1249  }
1250 
1251  if (b2.tokenNumber >= 0) {
1252  tmpVector.push_back(b2);
1253 
1254  //LogTrace("L1TGlobal")
1255  //<< " Push operand " << b2.tokenName
1256  //<<" on the tmp list"
1257  //<< std::endl;
1258  }
1259 
1260  }
1261 
1262  break;
1263  default: {
1264  // should not arrive here
1265  }
1266 
1267  break;
1268  }
1269  }
1270 
1271  // one block only or one operand only
1272  if (oneBlockOnly || operandOnly) {
1273  // one operand only -
1274  // there can be only one operand, otherwise one needs an operation
1275  if (operandOnly) {
1276  b1 = tmpStack.top();
1277  tmpVector.push_back(b1);
1278  }
1279 
1280  //
1281  for (std::vector<OperandToken>::reverse_iterator itOp = tmpVector.rbegin(); itOp != tmpVector.rend(); itOp++) {
1282  opVector.push_back(*itOp);
1283 
1284  //LogTrace("L1TGlobal")
1285  //<< " One block or one operand only: push operand " << (*itOp).tokenName
1286  //<<" on the seed operand list"
1287  //<< std::endl;
1288  }
1289 
1290  } else {
1291  //LogTrace("L1TGlobal")
1292  // << " More blocks: push the last block on the seed operand list" << std::endl;
1293 
1294  for (std::vector<OperandToken>::reverse_iterator itOp = tmpVector.rbegin(); itOp != tmpVector.rend(); itOp++) {
1295  opVector.push_back(*itOp);
1296 
1297  //LogTrace("L1TGlobal")
1298  //<< " Push operand: " << (*itOp).tokenName
1299  //<<" on the seed operand list"
1300  //<< std::endl;
1301  }
1302  }
1303 
1304  // remove duplicates from the seed vector
1305  // slow...
1306  std::vector<OperandToken> opVectorU;
1307  opVectorU.reserve(opVector.size());
1308 
1309  for (std::vector<OperandToken>::const_iterator constIt = opVector.begin(); constIt != opVector.end(); constIt++) {
1310  bool tokenIncluded = false;
1311 
1312  for (std::vector<OperandToken>::iterator itOpU = opVectorU.begin(); itOpU != opVectorU.end(); itOpU++) {
1313  if ((*itOpU).tokenName == (*constIt).tokenName) {
1314  tokenIncluded = true;
1315  break;
1316  }
1317  }
1318 
1319  if (!tokenIncluded) {
1320  opVectorU.push_back(*constIt);
1321  }
1322  }
1323 
1324  return opVectorU;
1325 }
1326 
1327 // private methods
1328 
1341  OperationType lastOperation,
1342  TokenRPN& rpnToken) const {
1343  OperationType actualOperation = OP_OPERAND; // default value
1344 
1345  int i = 0;
1346 
1347  while (m_operationRules[i].opType != OP_OPERAND) {
1348  if (tokenString == m_operationRules[i].opString) {
1349  actualOperation = (OperationType)m_operationRules[i].opType;
1350  break;
1351  }
1352  i++;
1353  }
1354 
1355  // check if the operation is allowed
1356  if (m_operationRules[i].forbiddenLastOperation & lastOperation) {
1357  return OP_INVALID;
1358  }
1359 
1360  //
1361  if (actualOperation == OP_OPERAND) {
1362  rpnToken.operand = tokenString;
1363 
1364  } else {
1365  rpnToken.operand = "";
1366  }
1367 
1368  rpnToken.operation = actualOperation;
1369 
1370  // else we got a valid operation
1371  return actualOperation;
1372 }
1373 
1385  int i = 0;
1386 
1387  while ((m_operationRules[i].opType != oType) && (m_operationRules[i].opType != OP_NULL)) {
1388  i++;
1389  }
1390 
1391  if (m_operationRules[i].opType == OP_NULL) {
1392  return nullptr;
1393  }
1394 
1395  return &(m_operationRules[i]);
1396 }
1397 
1398 // add spaces before and after parentheses - make separation easier
1399 void GlobalLogicParser::addBracketSpaces(const std::string& srcExpression, std::string& dstExpression) {
1400  static const std::string brackets = "()"; // the brackets to be found
1401 
1402  dstExpression = srcExpression; // copy the string
1403 
1404  size_t position = 0;
1405  while ((position = dstExpression.find_first_of(brackets, position)) != std::string::npos) {
1406  // add space after if none is there
1407  if (((position + 1) != std::string::npos) && (dstExpression[position + 1] != ' ')) {
1408  dstExpression.insert(position + 1, " ");
1409  }
1410 
1411  // add space before if none is there
1412  if ((position != 0) && (dstExpression[position - 1] != ' ')) {
1413  dstExpression.insert(position, " ");
1414  position++;
1415  }
1416  position++;
1417  }
1418 }
1419 
1420 // set the logical expression - check for correctness the input string
1421 bool GlobalLogicParser::setLogicalExpression(const std::string& logicalExpressionVal) {
1422  // add spaces around brackets
1423  std::string logicalExpressionBS;
1424  addBracketSpaces(logicalExpressionVal, logicalExpressionBS);
1425 
1426  // trim leading or trailing spaces
1427  boost::trim(logicalExpressionBS);
1428 
1429  clearRpnVector();
1430 
1431  if (!buildRpnVector(logicalExpressionBS)) {
1432  m_logicalExpression = "";
1433  return false;
1434  }
1435 
1436  m_logicalExpression = logicalExpressionBS;
1437 
1438  //LogDebug("L1TGlobal")
1439  //<< "\nGtLogicParser::setLogicalExpression - "
1440  //<< "\nLogical expression = '" << m_logicalExpression << "'\n"
1441  //<< std::endl;
1442 
1443  return true;
1444 }
1445 
1446 // set the numerical expression (the logical expression with each operand
1447 // replaced with the value) from a string
1448 // check also for correctness the input string
1449 bool GlobalLogicParser::setNumericalExpression(const std::string& numericalExpressionVal) {
1450  // add spaces around brackets
1451  std::string numericalExpressionBS;
1452  addBracketSpaces(numericalExpressionVal, numericalExpressionBS);
1453 
1454  // check for consistency with the logical expression
1455  // TODO FIXME
1456 
1457  // trim leading or trailing spaces
1458  boost::trim(numericalExpressionBS);
1459 
1460  m_numericalExpression = numericalExpressionBS;
1461 
1462  //LogDebug("L1TGlobal")
1463  //<< "\nGtLogicParser::setNumericalExpression - "
1464  //<< "\nNumerical Expression = '" << m_numericalExpression << "'\n"
1465  //<< std::endl;
1466 
1467  return true;
1468 }
1469 
1470 // static members
1471 
1472 // rules for operations
1473 // 1st column: operation string
1474 // 2nd column: operation type
1475 // 3rd column: forbiddenLastOperation (what operation the operator/operand must not follow)
1477  {"AND", OP_AND, OP_AND | OP_OR | OP_XOR | OP_NOT | OP_OPENBRACKET | OP_NULL},
1478  {"OR", OP_OR, OP_AND | OP_OR | OP_XOR | OP_NOT | OP_OPENBRACKET | OP_NULL},
1479  {"XOR", OP_XOR, OP_AND | OP_OR | OP_XOR | OP_NOT | OP_OPENBRACKET | OP_NULL},
1480  {"NOT", OP_NOT, OP_OPERAND | OP_CLOSEBRACKET},
1483  {nullptr, OP_OPERAND, OP_OPERAND | OP_CLOSEBRACKET},
1484  {nullptr, OP_NULL, OP_NULL}};
virtual const bool expressionResultNumExp() const
RpnVector m_rpnVector
RPN vector - equivalent to the logical expression.
const OperationRule * getRuleFromType(OperationType t)
get the rule entry to an operation type
std::vector< OperandToken > m_operandTokenVector
vector of operand tokens
signed integer value
Definition: value.h:25
void buildOperandTokenVectorNumExp()
static void trim(std::string &s)
std::string operandName(const int iOperand) const
return the name of the (iOperand)th operand in the logical expression
int operandIndex(const std::string &operandNameVal) const
return the position index of the operand in the logical expression
Log< level::Error, false > LogError
bool setLogicalExpression(const std::string &)
set the logical expression - check for correctness the input string
std::string m_numericalExpression
std::vector< GlobalLogicParser::OperandToken > expressionSeedsOperandList()
void clearRpnVector()
clear possible old rpn vector
auto &__restrict__ ws
bool buildRpnVector(const std::string &)
build the rpn vector
std::string m_logicalExpression
logical expression to be parsed
void convertIntToNameLogicalExpression(const std::map< int, std::string > &intToNameMap)
void addBracketSpaces(const std::string &, std::string &)
add spaces before and after parantheses
virtual OperationType getOperation(const std::string &tokenString, OperationType lastOperation, TokenRPN &rpnToken) const
std::vector< TokenRPN > RpnVector
bool checkLogicalExpression(std::string &)
check a logical expression for correctness - add/remove spaces if needed
void convertNameToIntLogicalExpression(const std::map< std::string, int > &nameToIntMap)
static int position[264][3]
Definition: ReadPGInfo.cc:289
GlobalLogicParser()
constructor(s)
virtual ~GlobalLogicParser()
destructor
static const struct OperationRule m_operationRules[]
static constexpr float b2
virtual const bool expressionResult() const
bool operandResultNumExp(const std::string &operandNameVal) const
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle brackets
Definition: Activities.doc:4
static constexpr float b1
bool setNumericalExpression(const std::string &)
#define LogDebug(id)
bool operandResult(const std::string &operandNameVal) const