Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:04:29

0001 /**
0002  * \class L1GtLogicParser
0003  *
0004  *
0005  * Description: see header file.
0006  *
0007  * Implementation:
0008  *    <TODO: enter implementation details>
0009  *
0010  * \author: Vasile Mihai Ghete - HEPHY Vienna
0011  *
0012  *
0013  */
0014 
0015 // this class header
0016 #include "DataFormats/L1GlobalTrigger/interface/L1GtLogicParser.h"
0017 
0018 // system include files
0019 #include <stack>
0020 
0021 #include <iostream>
0022 #include <sstream>
0023 
0024 #include <boost/algorithm/string.hpp>
0025 
0026 // user include files
0027 
0028 #include "FWCore/Utilities/interface/EDMException.h"
0029 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0030 
0031 // forward declarations
0032 
0033 // constructor(s)
0034 
0035 //   default constructor
0036 L1GtLogicParser::L1GtLogicParser() {
0037   // empty, default C++ initialization for string and vector are enough
0038 }
0039 
0040 //   from the RPN vector and the operand token vector
0041 //   no checks for consistency, empty logical and numerical expressions
0042 //   requires special care when used
0043 L1GtLogicParser::L1GtLogicParser(const RpnVector& rpnVec, const std::vector<OperandToken>& opTokenVector) {
0044   m_rpnVector = rpnVec;
0045   m_operandTokenVector = opTokenVector;
0046 }
0047 
0048 //   from a constant logical expression
0049 //   numerical expression will be empty
0050 L1GtLogicParser::L1GtLogicParser(const std::string& logicalExpressionVal) {
0051   // checks also for syntactic correctness of the logical expression
0052 
0053   if (!setLogicalExpression(logicalExpressionVal)) {
0054     // error(s) in logical expression - printed in the relevant place
0055     throw cms::Exception("FailModule") << "\nError in parsing the logical expression = " << logicalExpressionVal
0056                                        << std::endl;
0057   }
0058 }
0059 
0060 //   from a non-constant logical expression - add/remove spaces if needed
0061 //   numerical expression will be empty
0062 L1GtLogicParser::L1GtLogicParser(std::string& logicalExpressionVal) {
0063   // checks also for syntactic correctness of the logical expression
0064 
0065   // add spaces around brackets
0066   std::string logicalExpressionBS;
0067   addBracketSpaces(logicalExpressionVal, logicalExpressionBS);
0068 
0069   // trim leading or trailing spaces
0070   boost::trim(logicalExpressionBS);
0071 
0072   if (!buildRpnVector(logicalExpressionBS)) {
0073     // error(s) in logical expression
0074     throw cms::Exception("FailModule") << "\nError in parsing the logical expression = " << logicalExpressionVal
0075                                        << std::endl;
0076   }
0077 
0078   //LogDebug("L1GtLogicParser")
0079   //    << "\nInitial logical expression = '" << logicalExpressionVal << "'"
0080   //    << "\nFinal   logical expression = '" << logicalExpressionBS << "'\n"
0081   //    << std::endl;
0082 
0083   logicalExpressionVal = logicalExpressionBS;
0084   m_logicalExpression = logicalExpressionVal;
0085 
0086   // build operand token vector
0087   // dummy tokenNumber; tokenResult false
0088   buildOperandTokenVector();
0089 }
0090 
0091 //   from a logical and a numerical expression
0092 L1GtLogicParser::L1GtLogicParser(const std::string logicalExpressionVal, const std::string numericalExpressionVal) {
0093   // checks also for correctness
0094 
0095   if (!setLogicalExpression(logicalExpressionVal)) {
0096     // error(s) in logical expression - printed in the relevant place
0097     throw cms::Exception("FailModule") << "\nError in parsing the logical expression = " << logicalExpressionVal
0098                                        << std::endl;
0099   }
0100 
0101   if (!setNumericalExpression(numericalExpressionVal)) {
0102     // error(s) in numerical expression - printed in the relevant place
0103     throw cms::Exception("FileModule") << "\nError in parsing the numerical expression = " << numericalExpressionVal
0104                                        << std::endl;
0105   }
0106 }
0107 
0108 //   from a logical and a numerical expression
0109 //   no checks for correctness - use it only after the correctness was tested
0110 L1GtLogicParser::L1GtLogicParser(const std::string& logicalExpressionVal,
0111                                  const std::string& numericalExpressionVal,
0112                                  const bool dummy) {
0113   clearRpnVector();
0114   if (!buildRpnVector(logicalExpressionVal)) {
0115     throw cms::Exception("FileModule") << "\nError in building RPN vector for the logical expression = "
0116                                        << logicalExpressionVal << std::endl;
0117   }
0118 
0119   m_logicalExpression = logicalExpressionVal;
0120   m_numericalExpression = numericalExpressionVal;
0121 }
0122 
0123 // destructor
0124 L1GtLogicParser::~L1GtLogicParser() {
0125   // empty now
0126 }
0127 
0128 // public methods
0129 
0130 // check a logical expression for correctness - add/remove spaces if needed
0131 bool L1GtLogicParser::checkLogicalExpression(std::string& logicalExpressionVal) {
0132   // add spaces around brackets
0133   std::string logicalExpressionBS;
0134   addBracketSpaces(logicalExpressionVal, logicalExpressionBS);
0135 
0136   // trim leading or trailing spaces
0137   boost::trim(logicalExpressionBS);
0138 
0139   clearRpnVector();
0140 
0141   if (!buildRpnVector(logicalExpressionBS)) {
0142     return false;
0143   }
0144 
0145   LogDebug("L1GtLogicParser") << "\nL1GtLogicParser::checkLogicalExpression - "
0146                               << "\nInitial logical expression = '" << logicalExpressionVal << "'"
0147                               << "\nFinal   logical expression = '" << logicalExpressionBS << "'\n"
0148                               << std::endl;
0149 
0150   logicalExpressionVal = logicalExpressionBS;
0151 
0152   return true;
0153 }
0154 
0155 /**
0156  * buildRpnVector Build the postfix notation.
0157  *
0158  * @param expression The expression to be parsed.
0159  *
0160  * @return "true" if everything was parsed. "false" if an error occured.
0161  *
0162  */
0163 
0164 bool L1GtLogicParser::buildRpnVector(const std::string& logicalExpressionVal) {
0165   //LogDebug("L1GtLogicParser")
0166   //<< "\nL1GtLogicParser::buildRpnVector - "
0167   //<< "\nLogical expression = '" << logicalExpressionVal << "'\n"
0168   //<< std::endl;
0169 
0170   OperationType actualOperation = OP_NULL;
0171   OperationType lastOperation = OP_NULL;
0172 
0173   // token as string and as TokenRPN, stack to form the postfix notation
0174   std::string tokenString;
0175   TokenRPN rpnToken;
0176   std::stack<TokenRPN> operatorStack;
0177 
0178   static const std::string whitespaces = " \r\v\n\t";
0179 
0180   // clear possible old rpn vector
0181   clearRpnVector();
0182 
0183   // stringstream to separate all tokens
0184   std::istringstream exprStringStream(logicalExpressionVal);
0185 
0186   while (!exprStringStream.eof()) {
0187     exprStringStream >> std::skipws >> std::ws >> tokenString;
0188 
0189     // skip the end
0190     if (tokenString.find_first_not_of(whitespaces) == std::string::npos || tokenString.length() == 0) {
0191       //LogTrace("L1GtLogicParser")
0192       //<< "  Break for token string = " << tokenString
0193       //<< std::endl;
0194 
0195       break;
0196     }
0197 
0198     actualOperation = getOperation(tokenString, lastOperation, rpnToken);
0199 
0200     //LogTrace("L1GtLogicParser")
0201     //<< "  Token string = '" << tokenString << "'"
0202     //<< "\tActual Operation = " << actualOperation
0203     //<< std::endl;
0204 
0205     // http://en.wikipedia.org/wiki/Postfix_notation#Converting_from_infix_notation
0206 
0207     switch (actualOperation) {
0208       case OP_OPERAND: {
0209         // operands get pushed to the postfix notation immediately
0210         m_rpnVector.push_back(rpnToken);
0211       }
0212 
0213       break;
0214       case OP_INVALID: {
0215         int errorPosition = exprStringStream.tellg();
0216 
0217         edm::LogError("L1GtLogicParser") << "\nLogical expression = '" << logicalExpressionVal << "'"
0218                                          << "\n  Syntax error during parsing: "
0219                                          << "\n     " << exprStringStream.str().substr(0, errorPosition) << "\n     "
0220                                          << exprStringStream.str().substr(errorPosition)
0221                                          << "\n  Returned empty RPN vector and result false." << std::endl;
0222 
0223         // clear the rpn vector before returning
0224         clearRpnVector();
0225 
0226         return false;
0227       }
0228 
0229       break;
0230       case OP_NOT: {
0231         operatorStack.push(rpnToken);
0232         // there are no operators with higher precedence
0233       }
0234 
0235       break;
0236       case OP_AND: {
0237         // first pop operators with higher precedence (NOT)
0238         while (!operatorStack.empty() && operatorStack.top().operation == OP_NOT) {
0239           m_rpnVector.push_back(operatorStack.top());
0240           operatorStack.pop();
0241         }
0242         operatorStack.push(rpnToken);
0243       }
0244 
0245       break;
0246       case OP_OR: {
0247         // pop operators with higher precedence (AND, NOT)
0248         while (!operatorStack.empty() &&
0249                (operatorStack.top().operation == OP_NOT || operatorStack.top().operation == OP_AND)) {
0250           m_rpnVector.push_back(operatorStack.top());
0251           operatorStack.pop();
0252         }
0253         // push operator on stack
0254         operatorStack.push(rpnToken);
0255       }
0256 
0257       break;
0258       case OP_OPENBRACKET: {
0259         // just push it on stack
0260         operatorStack.push(rpnToken);
0261       }
0262 
0263       break;
0264       case OP_CLOSEBRACKET: {
0265         // check if the operatorStack is empty
0266         if (operatorStack.empty()) {
0267           int errorPosition = exprStringStream.tellg();
0268 
0269           edm::LogError("L1GtLogicParser") << "\nLogical expression = '" << logicalExpressionVal << "'"
0270                                            << "\n  Syntax error during parsing - misplaced ')':"
0271                                            << "\n     " << exprStringStream.str().substr(0, errorPosition) << "\n     "
0272                                            << exprStringStream.str().substr(errorPosition)
0273                                            << "\n  Returned empty RPN vector and result false." << std::endl;
0274 
0275           // clear the rpn vector before returning
0276           clearRpnVector();
0277 
0278           return false;
0279         }
0280 
0281         // pop stack until a left parenthesis is found
0282         do {
0283           if (operatorStack.top().operation != OP_OPENBRACKET) {
0284             m_rpnVector.push_back(operatorStack.top());  // pop
0285             operatorStack.pop();
0286           }
0287           if (operatorStack.empty()) {  // the operatorStack must not be empty
0288 
0289             int errorPosition = exprStringStream.tellg();
0290 
0291             edm::LogError("L1GtLogicParser") << "\nLogical expression = '" << logicalExpressionVal << "'"
0292                                              << "\n  Syntax error during parsing - misplaced ')':"
0293                                              << "\n     " << exprStringStream.str().substr(0, errorPosition)
0294                                              << "\n     " << exprStringStream.str().substr(errorPosition)
0295                                              << "\n  Returned empty RPN vector and result false." << std::endl;
0296 
0297             // clear the rpn vector before returning
0298             clearRpnVector();
0299             return false;
0300           }
0301         } while (operatorStack.top().operation != OP_OPENBRACKET);
0302 
0303         operatorStack.pop();  // pop the open bracket.
0304       }
0305 
0306       break;
0307       default: {
0308         // empty
0309       } break;
0310     }
0311 
0312     lastOperation = actualOperation;  // for the next turn
0313   }
0314 
0315   // pop the rest of the operator stack
0316   while (!operatorStack.empty()) {
0317     if (operatorStack.top().operation == OP_OPENBRACKET) {
0318       edm::LogError("L1GtLogicParser") << "\nLogical expression = '" << logicalExpressionVal << "'"
0319                                        << "\n  Syntax error during parsing - missing ')':"
0320                                        << "\n  Returned empty RPN vector and result false." << std::endl;
0321 
0322       // clear the rpn vector before returning
0323       clearRpnVector();
0324       return false;
0325     }
0326 
0327     m_rpnVector.push_back(operatorStack.top());
0328     operatorStack.pop();
0329   }
0330 
0331   // count all operations and check if the result is 1
0332   int counter = 0;
0333   for (RpnVector::iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) {
0334     if (it->operation == OP_OPERAND)
0335       counter++;
0336     if (it->operation == OP_OR || it->operation == OP_AND)
0337       counter--;
0338     if (counter < 1) {
0339       edm::LogError("L1GtLogicParser") << "\nLogical expression = '" << logicalExpressionVal << "'"
0340                                        << "\n  Syntax error during parsing - too many operators"
0341                                        << "\n  Returned empty RPN vector and result false." << std::endl;
0342 
0343       // clear the rpn vector before returning
0344       clearRpnVector();
0345       return false;
0346     }
0347   }
0348 
0349   if (counter > 1) {
0350     edm::LogError("L1GtLogicParser") << "\nLogical expression = '" << logicalExpressionVal << "'"
0351                                      << "\n  Syntax error during parsing - too many operands"
0352                                      << "\n  Returned empty RPN vector and result false." << std::endl;
0353 
0354     // clear the rpn vector before returning
0355     clearRpnVector();
0356     return false;
0357   }
0358 
0359   return true;
0360 }
0361 
0362 // clear rpn vector
0363 void L1GtLogicParser::clearRpnVector() { m_rpnVector.clear(); }
0364 
0365 // build from the RPN vector the operand token vector
0366 // dummy tokenNumber and token result
0367 void L1GtLogicParser::buildOperandTokenVector() {
0368   //LogTrace("L1GtLogicParser")
0369   //<< "\nL1GtLogicParser::buildOperandTokenVector - "
0370   //<< std::endl;
0371 
0372   // reserve memory
0373   size_t rpnVectorSize = m_rpnVector.size();
0374   m_operandTokenVector.reserve(rpnVectorSize);
0375 
0376   int opNumber = 0;
0377 
0378   for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) {
0379     //LogTrace("L1GtLogicParser")
0380     //<< "\nit->operation = " << it->operation
0381     //<< "\nit->operand =   '" << it->operand << "'\n"
0382     //<< std::endl;
0383 
0384     switch (it->operation) {
0385       case OP_OPERAND: {
0386         OperandToken opToken;
0387         opToken.tokenName = it->operand;
0388         opToken.tokenNumber = opNumber;
0389         opToken.tokenResult = false;
0390 
0391         m_operandTokenVector.push_back(opToken);
0392 
0393       }
0394 
0395       break;
0396       case OP_NOT: {
0397         // do nothing
0398       }
0399 
0400       break;
0401       case OP_OR: {
0402         // do nothing
0403       }
0404 
0405       break;
0406       case OP_AND: {
0407         // do nothing
0408       }
0409 
0410       break;
0411       default: {
0412         // should not arrive here
0413       }
0414 
0415       break;
0416     }
0417 
0418     opNumber++;
0419   }
0420 }
0421 
0422 // return the position index of the operand in the logical expression
0423 int L1GtLogicParser::operandIndex(const std::string& operandNameVal) const {
0424   int result = -1;
0425 
0426   OperationType actualOperation = OP_NULL;
0427   OperationType lastOperation = OP_NULL;
0428 
0429   std::string tokenString;
0430   TokenRPN rpnToken;  // token to be used by getOperation
0431 
0432   // stringstream to separate all tokens
0433   std::istringstream exprStringStream(m_logicalExpression);
0434 
0435   // temporary index for usage in the loop
0436   int tmpIndex = -1;
0437 
0438   while (!exprStringStream.eof()) {
0439     exprStringStream >> tokenString;
0440 
0441     //LogTrace("L1GtLogicParser")
0442     //<< "Token string = " << tokenString
0443     //<< std::endl;
0444 
0445     actualOperation = getOperation(tokenString, lastOperation, rpnToken);
0446     if (actualOperation == OP_INVALID) {
0447       // it should never be invalid
0448       edm::LogError("L1GtLogicParser") << "\nLogical expression = '" << m_logicalExpression << "'"
0449                                        << "\n  Invalid operation/operand " << operandNameVal
0450                                        << "\n  Returned index is by default out of range (-1)." << std::endl;
0451 
0452       return result;
0453     }
0454 
0455     if (actualOperation != OP_OPERAND) {
0456       // do nothing
0457 
0458     } else {
0459       tmpIndex++;
0460       if (rpnToken.operand == operandNameVal) {
0461         result = tmpIndex;
0462 
0463         //LogDebug("L1GtLogicParser")
0464         //<< "\nL1GtLogicParser::operandIndex - "
0465         //<< "\nLogical expression = '" << m_logicalExpression << "'"
0466         //<< "\nIndex of operand " << operandNameVal << " = " << result
0467         //<< std::endl;
0468 
0469         return result;
0470       }
0471     }
0472     lastOperation = actualOperation;
0473   }
0474 
0475   //
0476   edm::LogError("L1GtLogicParser") << "\nLogical expression = '" << m_logicalExpression << "'"
0477                                    << "\n  Operand " << operandNameVal << " not found in the logical expression"
0478                                    << "\n  Returned index is by default out of range (-1)." << std::endl;
0479 
0480   return result;
0481 }
0482 
0483 // return the name of the (iOperand)th operand in the logical expression
0484 std::string L1GtLogicParser::operandName(const int iOperand) const {
0485   std::string result;
0486 
0487   OperationType actualOperation = OP_NULL;
0488   OperationType lastOperation = OP_NULL;
0489 
0490   std::string tokenString;
0491   TokenRPN rpnToken;  // token to be used by getOperation
0492 
0493   // stringstream to separate all tokens
0494   std::istringstream exprStringStream(m_logicalExpression);
0495 
0496   // temporary index for usage in the loop
0497   int tmpIndex = -1;
0498 
0499   while (!exprStringStream.eof()) {
0500     exprStringStream >> tokenString;
0501 
0502     //LogTrace("L1GtLogicParser")
0503     //<< "Token string = " << tokenString
0504     //<< std::endl;
0505 
0506     actualOperation = getOperation(tokenString, lastOperation, rpnToken);
0507     if (actualOperation == OP_INVALID) {
0508       // it should never be invalid
0509       edm::LogError("L1GtLogicParser") << "\nLogical expression = '" << m_logicalExpression << "'"
0510                                        << "\n  Invalid operation/operand at position " << iOperand
0511                                        << "\n  Returned empty name by default." << std::endl;
0512 
0513       return result;
0514     }
0515 
0516     if (actualOperation != OP_OPERAND) {
0517       // do nothing
0518 
0519     } else {
0520       tmpIndex++;
0521       if (tmpIndex == iOperand) {
0522         result = rpnToken.operand;
0523 
0524         //LogDebug("L1GtLogicParser")
0525         //<< "\nL1GtLogicParser::operandName - "
0526         //<< "\nLogical expression = '" << m_logicalExpression << "'"
0527         //<< "\nOperand with index " << iOperand << " = " << result
0528         //<< std::endl;
0529 
0530         return result;
0531       }
0532     }
0533     lastOperation = actualOperation;
0534   }
0535 
0536   //
0537   edm::LogError("L1GtLogicParser") << "\nLogical expression = '" << m_logicalExpression << "'"
0538                                    << "\n  No operand found at position " << iOperand
0539                                    << "\n  Returned empty name by default." << std::endl;
0540 
0541   return result;
0542 }
0543 
0544 // return the result for an operand with name operandNameVal
0545 // in the logical expression using the operand token vector
0546 bool L1GtLogicParser::operandResult(const std::string& operandNameVal) const {
0547   for (size_t i = 0; i < m_operandTokenVector.size(); ++i) {
0548     if ((m_operandTokenVector[i]).tokenName == operandNameVal) {
0549       return (m_operandTokenVector[i]).tokenResult;
0550     }
0551   }
0552 
0553   // return false - should not arrive here
0554   edm::LogError("L1GtLogicParser") << "\n  Operand " << operandNameVal << " not found in the operand token vector"
0555                                    << "\n  Returned false by default." << std::endl;
0556 
0557   return false;
0558 }
0559 
0560 // return the result for an operand with tokenNumberVal
0561 // using the operand token vector
0562 bool L1GtLogicParser::operandResult(const int tokenNumberVal) const {
0563   for (size_t i = 0; i < m_operandTokenVector.size(); ++i) {
0564     if ((m_operandTokenVector[i]).tokenNumber == tokenNumberVal) {
0565       return (m_operandTokenVector[i]).tokenResult;
0566     }
0567   }
0568 
0569   // return false - should not arrive here
0570   edm::LogError("L1GtLogicParser") << "\n  No operand with token number " << tokenNumberVal
0571                                    << " found in the operand token vector"
0572                                    << "\n  Returned false by default." << std::endl;
0573 
0574   return false;
0575 }
0576 
0577 // return the result for the logical expression
0578 // require a proper operand token vector
0579 const bool L1GtLogicParser::expressionResult() const {
0580   //LogTrace("L1GtLogicParser")
0581   //<< "\nL1GtLogicParser::expressionResult - "
0582   //<< std::endl;
0583 
0584   // return false if there is no RPN vector built
0585   if (m_rpnVector.empty()) {
0586     edm::LogError("L1GtLogicParser") << "\n  No built RPN vector exists."
0587                                      << "\n  Returned false by default." << std::endl;
0588     return false;
0589   }
0590 
0591   // stack containing temporary results
0592   std::stack<bool> resultStack;
0593   bool b1, b2;
0594 
0595   for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) {
0596     //LogTrace("L1GtLogicParser")
0597     //<< "\nit->operation = " << it->operation
0598     //<< "\nit->operand =   '" << it->operand << "'\n"
0599     //<< std::endl;
0600 
0601     switch (it->operation) {
0602       case OP_OPERAND: {
0603         resultStack.push(operandResult(it->operand));
0604       }
0605 
0606       break;
0607       case OP_NOT: {
0608         b1 = resultStack.top();
0609         resultStack.pop();      // pop the top
0610         resultStack.push(!b1);  // and push the result
0611       }
0612 
0613       break;
0614       case OP_OR: {
0615         b1 = resultStack.top();
0616         resultStack.pop();
0617         b2 = resultStack.top();
0618         resultStack.pop();
0619         resultStack.push(b1 || b2);
0620       }
0621 
0622       break;
0623       case OP_AND: {
0624         b1 = resultStack.top();
0625         resultStack.pop();
0626         b2 = resultStack.top();
0627         resultStack.pop();
0628         resultStack.push(b1 && b2);
0629       }
0630 
0631       break;
0632       default: {
0633         // should not arrive here
0634       }
0635 
0636       break;
0637     }
0638   }
0639 
0640   // get the result in the top of the stack
0641 
0642   //LogTrace("L1GtLogicParser")
0643   //<< "\nL1GtLogicParser::expressionResult - "
0644   //<< "\nResult = " << resultStack.top()
0645   //<< std::endl;
0646 
0647   return resultStack.top();
0648 }
0649 
0650 // return the result for an operand with name operandNameVal
0651 // in the logical expression using a numerical expression
0652 bool L1GtLogicParser::operandResultNumExp(const std::string& operandNameVal) const {
0653   bool result = false;
0654 
0655   // get the position index of the operand in the logical string
0656   const int iOperand = operandIndex(operandNameVal);
0657 
0658   result = operandResult(iOperand);
0659 
0660   return result;
0661 }
0662 
0663 // return the result for an operand with index iOperand
0664 // in the logical expression using a numerical expression
0665 bool L1GtLogicParser::operandResultNumExp(const int iOperand) const {
0666   bool result = false;
0667 
0668   // parse the numerical expression
0669 
0670   OperationType actualOperation = OP_NULL;
0671   OperationType lastOperation = OP_NULL;
0672 
0673   std::string tokenString;
0674   TokenRPN rpnToken;  // token to be used by getOperation
0675 
0676   // stringstream to separate all tokens
0677   std::istringstream exprStringStream(m_numericalExpression);
0678 
0679   // temporary index for usage in the loop
0680   int tmpIndex = -1;
0681 
0682   while (!exprStringStream.eof()) {
0683     exprStringStream >> tokenString;
0684 
0685     //LogTrace("L1GtLogicParser")
0686     //<< "Token string = " << tokenString
0687     //<< std::endl;
0688 
0689     actualOperation = getOperation(tokenString, lastOperation, rpnToken);
0690     if (actualOperation == OP_INVALID) {
0691       // it should never be invalid
0692       edm::LogError("L1GtLogicParser") << "\nNumerical expression = '" << m_numericalExpression << "'"
0693                                        << "\n  Invalid operation/operand at position " << iOperand
0694                                        << "\n  Returned false by default." << std::endl;
0695 
0696       result = false;
0697       return result;
0698     }
0699 
0700     if (actualOperation != OP_OPERAND) {
0701       // do nothing
0702 
0703     } else {
0704       tmpIndex++;
0705       if (tmpIndex == iOperand) {
0706         if (rpnToken.operand == "1") {
0707           result = true;
0708         } else {
0709           if (rpnToken.operand == "0") {
0710             result = false;
0711           } else {
0712             // something went wrong - break
0713             //
0714             edm::LogError("L1GtLogicParser") << "\nNumerical expression = '" << m_numericalExpression << "'"
0715                                              << "\n  Invalid result for operand at position " << iOperand << ": "
0716                                              << rpnToken.operand << "\n  It must be 0 or 1"
0717                                              << "\n  Returned false by default." << std::endl;
0718 
0719             result = false;
0720             return result;
0721           }
0722         }
0723 
0724         //LogDebug("L1GtLogicParser")
0725         //<< "\nL1GtLogicParser::operandResult - "
0726         //<< "\nNumerical expression = '" << m_numericalExpression << "'"
0727         //<< "\nResult for operand with index " << iOperand
0728         //<< " = " << result << "'\n"
0729         //<< std::endl;
0730 
0731         return result;
0732       }
0733     }
0734     lastOperation = actualOperation;
0735   }
0736 
0737   //
0738   edm::LogError("L1GtLogicParser") << "\nNumerical expression = '" << m_numericalExpression << "'"
0739                                    << "\n  No operand found at position " << iOperand
0740                                    << "\n  Returned false by default." << std::endl;
0741 
0742   return result;
0743 }
0744 
0745 // build from the RPN vector the operand token vector
0746 // using a numerical expression
0747 void L1GtLogicParser::buildOperandTokenVectorNumExp() {
0748   //LogTrace("L1GtLogicParser")
0749   //<< "\nL1GtLogicParser::buildOperandTokenVector - "
0750   //<< std::endl;
0751 
0752   // reserve memory
0753   size_t rpnVectorSize = m_rpnVector.size();
0754   m_operandTokenVector.reserve(rpnVectorSize);
0755 
0756   int opNumber = 0;
0757 
0758   for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) {
0759     //LogTrace("L1GtLogicParser")
0760     //<< "\nit->operation = " << it->operation
0761     //<< "\nit->operand =   '" << it->operand << "'\n"
0762     //<< std::endl;
0763 
0764     switch (it->operation) {
0765       case OP_OPERAND: {
0766         OperandToken opToken;
0767         opToken.tokenName = it->operand;
0768         opToken.tokenNumber = opNumber;
0769         opToken.tokenResult = operandResultNumExp(it->operand);
0770 
0771         m_operandTokenVector.push_back(opToken);
0772 
0773       }
0774 
0775       break;
0776       case OP_NOT: {
0777         // do nothing
0778       }
0779 
0780       break;
0781       case OP_OR: {
0782         // do nothing
0783       }
0784 
0785       break;
0786       case OP_AND: {
0787         // do nothing
0788       }
0789 
0790       break;
0791       default: {
0792         // should not arrive here
0793       }
0794 
0795       break;
0796     }
0797 
0798     opNumber++;
0799   }
0800 }
0801 
0802 // return the result for the logical expression
0803 const bool L1GtLogicParser::expressionResultNumExp() const {
0804   //LogTrace("L1GtLogicParser")
0805   //<< "\nL1GtLogicParser::expressionResult - "
0806   //<< std::endl;
0807 
0808   // return false if there is no expression
0809   if (m_rpnVector.empty()) {
0810     edm::LogError("L1GtLogicParser") << "\n  No built RPN vector exists."
0811                                      << "\n  Returned false by default." << std::endl;
0812     return false;
0813   }
0814 
0815   // stack containing temporary results
0816   std::stack<bool> resultStack;
0817   bool b1, b2;
0818 
0819   for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) {
0820     //LogTrace("L1GtLogicParser")
0821     //<< "\nit->operation = " << it->operation
0822     //<< "\nit->operand =   '" << it->operand << "'\n"
0823     //<< std::endl;
0824 
0825     switch (it->operation) {
0826       case OP_OPERAND: {
0827         resultStack.push(operandResultNumExp(it->operand));
0828       }
0829 
0830       break;
0831       case OP_NOT: {
0832         b1 = resultStack.top();
0833         resultStack.pop();      // pop the top
0834         resultStack.push(!b1);  // and push the result
0835       }
0836 
0837       break;
0838       case OP_OR: {
0839         b1 = resultStack.top();
0840         resultStack.pop();
0841         b2 = resultStack.top();
0842         resultStack.pop();
0843         resultStack.push(b1 || b2);
0844       }
0845 
0846       break;
0847       case OP_AND: {
0848         b1 = resultStack.top();
0849         resultStack.pop();
0850         b2 = resultStack.top();
0851         resultStack.pop();
0852         resultStack.push(b1 && b2);
0853       }
0854 
0855       break;
0856       default: {
0857         // should not arrive here
0858       }
0859 
0860       break;
0861     }
0862   }
0863 
0864   // get the result in the top of the stack
0865 
0866   //LogTrace("L1GtLogicParser")
0867   //<< "\nL1GtLogicParser::expressionResult - "
0868   //<< "\nLogical expression   = '" << m_logicalExpression << "'"
0869   //<< "\nNumerical expression = '" << m_numericalExpression << "'"
0870   //<< "\nResult = " << resultStack.top()
0871   //<< std::endl;
0872 
0873   return resultStack.top();
0874 }
0875 
0876 // convert the logical expression composed with names to
0877 // a logical expression composed with int numbers using
0878 // a (string, int)  map
0879 
0880 void L1GtLogicParser::convertNameToIntLogicalExpression(const std::map<std::string, int>& nameToIntMap) {
0881   if (m_logicalExpression.empty()) {
0882     return;
0883   }
0884 
0885   // non-empty logical expression
0886 
0887   OperationType actualOperation = OP_NULL;
0888   OperationType lastOperation = OP_NULL;
0889 
0890   std::string tokenString;
0891   TokenRPN rpnToken;  // token to be used by getOperation
0892 
0893   int intValue = -1;
0894 
0895   // stringstream to separate all tokens
0896   std::istringstream exprStringStream(m_logicalExpression);
0897   std::string convertedLogicalExpression;
0898 
0899   while (!exprStringStream.eof()) {
0900     exprStringStream >> tokenString;
0901 
0902     actualOperation = getOperation(tokenString, lastOperation, rpnToken);
0903     if (actualOperation == OP_INVALID) {
0904       // it should never be invalid
0905       edm::LogError("L1GtLogicParser") << "\nLogical expression = '" << m_logicalExpression << "'"
0906                                        << "\n  Invalid operation/operand in logical expression."
0907                                        << "\n  Return empty logical expression." << std::endl;
0908 
0909       m_logicalExpression.clear();
0910       return;
0911     }
0912 
0913     if (actualOperation != OP_OPERAND) {
0914       convertedLogicalExpression.append(getRuleFromType(actualOperation)->opString);
0915 
0916     } else {
0917       typedef std::map<std::string, int>::const_iterator CIter;
0918 
0919       CIter it = nameToIntMap.find(rpnToken.operand);
0920       if (it != nameToIntMap.end()) {
0921         intValue = it->second;
0922         std::stringstream intStr;
0923         intStr << intValue;
0924         convertedLogicalExpression.append(intStr.str());
0925 
0926       } else {
0927         // it should never be happen
0928         edm::LogError("L1GtLogicParser") << "\nLogical expression = '" << m_logicalExpression << "'"
0929                                          << "\n  Could not convert " << rpnToken.operand << " to integer!"
0930                                          << "\n  Return empty logical expression." << std::endl;
0931 
0932         m_logicalExpression.clear();
0933         return;
0934       }
0935     }
0936 
0937     convertedLogicalExpression.append(" ");  // one whitespace after each token
0938     lastOperation = actualOperation;
0939   }
0940 
0941   // remove the last space
0942   //convertedLogicalExpression.erase(convertedLogicalExpression.size() - 1);
0943   boost::trim(convertedLogicalExpression);
0944 
0945   LogDebug("L1GtLogicParser") << "\nL1GtLogicParser::convertNameToIntLogicalExpression - "
0946                               << "\nLogical expression (strings) = '" << m_logicalExpression << "'"
0947                               << "\nLogical expression (int)     = '" << convertedLogicalExpression << "'\n"
0948                               << std::endl;
0949 
0950   // replace now the logical expression with strings with
0951   // the converted logical expression
0952 
0953   m_logicalExpression = convertedLogicalExpression;
0954 
0955   return;
0956 }
0957 
0958 // convert a logical expression composed with integer numbers to
0959 // a logical expression composed with names using a map (int, string)
0960 
0961 void L1GtLogicParser::convertIntToNameLogicalExpression(const std::map<int, std::string>& intToNameMap) {
0962   if (m_logicalExpression.empty()) {
0963     return;
0964   }
0965 
0966   // non-empty logical expression
0967 
0968   OperationType actualOperation = OP_NULL;
0969   OperationType lastOperation = OP_NULL;
0970 
0971   std::string tokenString;
0972   TokenRPN rpnToken;  // token to be used by getOperation
0973 
0974   // stringstream to separate all tokens
0975   std::istringstream exprStringStream(m_logicalExpression);
0976   std::string convertedLogicalExpression;
0977 
0978   while (!exprStringStream.eof()) {
0979     exprStringStream >> tokenString;
0980 
0981     actualOperation = getOperation(tokenString, lastOperation, rpnToken);
0982     if (actualOperation == OP_INVALID) {
0983       // it should never be invalid
0984       edm::LogError("L1GtLogicParser") << "\nLogical expression = '" << m_logicalExpression << "'"
0985                                        << "\n  Invalid operation/operand in logical expression."
0986                                        << "\n  Return empty logical expression." << std::endl;
0987 
0988       m_logicalExpression.clear();
0989       return;
0990     }
0991 
0992     if (actualOperation != OP_OPERAND) {
0993       convertedLogicalExpression.append(getRuleFromType(actualOperation)->opString);
0994 
0995     } else {
0996       typedef std::map<int, std::string>::const_iterator CIter;
0997 
0998       // convert string to int
0999       int indexInt;
1000       std::istringstream iss(rpnToken.operand);
1001       iss >> std::dec >> indexInt;
1002 
1003       CIter it = intToNameMap.find(indexInt);
1004       if (it != intToNameMap.end()) {
1005         convertedLogicalExpression.append(it->second);
1006 
1007       } else {
1008         // it should never be happen
1009         edm::LogError("L1GtLogicParser") << "\nLogical expression = '" << m_logicalExpression << "'"
1010                                          << "\n  Could not convert " << rpnToken.operand << " to string!"
1011                                          << "\n  Return empty logical expression." << std::endl;
1012 
1013         m_logicalExpression.clear();
1014         return;
1015       }
1016     }
1017 
1018     convertedLogicalExpression.append(" ");  // one whitespace after each token
1019     lastOperation = actualOperation;
1020   }
1021 
1022   // remove the last space
1023   //convertedLogicalExpression.erase(convertedLogicalExpression.size() - 1);
1024   boost::trim(convertedLogicalExpression);
1025 
1026   //LogDebug("L1GtLogicParser")
1027   //        << "\nL1GtLogicParser::convertIntToNameLogicalExpression - "
1028   //        << "\nLogical expression (int) =    '" << m_logicalExpression << "'"
1029   //        << "\nLogical expression (string) = '" << convertedLogicalExpression << "'\n"
1030   //        << std::endl;
1031 
1032   // replace now the logical expression with int with
1033   // the converted logical expression
1034 
1035   m_logicalExpression = convertedLogicalExpression;
1036 
1037   return;
1038 }
1039 
1040 // return the list of operand tokens for the logical expression
1041 // which are to be used as seeds
1042 std::vector<L1GtLogicParser::OperandToken> L1GtLogicParser::expressionSeedsOperandList() {
1043   //LogDebug("L1GtLogicParser")
1044   //<< "\nL1GtLogicParser::expressionSeedsOperandList - "
1045   //<< "\nLogical expression = '" << m_logicalExpression << "'"
1046   //<< "\nm_rpnVector.size() = " << m_rpnVector.size()
1047   //<< "\nm_operandTokenVector.size() = " << m_operandTokenVector.size()
1048   //<< std::endl;
1049 
1050   // seed list
1051   std::vector<OperandToken> opVector;
1052   opVector.reserve(m_operandTokenVector.size());
1053 
1054   // temporary results
1055   std::stack<OperandToken> tmpStack;
1056   std::vector<OperandToken> tmpVector;
1057   tmpVector.reserve(m_operandTokenVector.size());
1058 
1059   OperandToken b1, b2;
1060 
1061   bool newOperandBlock = true;
1062   bool oneBlockOnly = true;
1063   bool operandOnly = true;
1064 
1065   int iOperand = -1;
1066 
1067   OperandToken dummyToken;
1068   dummyToken.tokenName = "dummy";
1069   dummyToken.tokenNumber = -1;
1070   dummyToken.tokenResult = false;
1071 
1072   for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) {
1073     //LogTrace("L1GtLogicParser")
1074     //<< "\nit->operation = " << it->operation
1075     //<< "\nit->operand =   '" << it->operand << "'\n"
1076     //<< std::endl;
1077 
1078     switch (it->operation) {
1079       // RPN always start a block with an operand
1080       case OP_OPERAND: {
1081         // more blocks with operations
1082         // push operands from previous block, if any in the tmpVector
1083         // (reverse order to compensate the stack push/top/pop)
1084         if ((!newOperandBlock)) {
1085           for (std::vector<OperandToken>::reverse_iterator itOp = tmpVector.rbegin(); itOp != tmpVector.rend();
1086                itOp++) {
1087             opVector.push_back(*itOp);
1088 
1089             //LogTrace("L1GtLogicParser")
1090             //<< "  Push operand " << (*itOp).tokenName
1091             //<<" on the seed operand list"
1092             //<< std::endl;
1093           }
1094 
1095           tmpVector.clear();
1096 
1097           newOperandBlock = true;
1098           oneBlockOnly = false;
1099         }
1100 
1101         iOperand++;
1102 
1103         //LogTrace("L1GtLogicParser")
1104         //<< "  Push operand " << (m_operandTokenVector.at(iOperand)).tokenName
1105         //<< " on the operand stack"
1106         //<< std::endl;
1107 
1108         tmpStack.push(m_operandTokenVector.at(iOperand));
1109       }
1110 
1111       break;
1112       case OP_NOT: {
1113         newOperandBlock = false;
1114         operandOnly = false;
1115 
1116         b1 = tmpStack.top();
1117         tmpStack.pop();  // pop the top
1118 
1119         tmpStack.push(dummyToken);  // and push dummy result
1120 
1121         //LogTrace("L1GtLogicParser")
1122         //<< "  Clear tmp operand list"
1123         //<< std::endl;
1124 
1125         tmpVector.clear();
1126 
1127       }
1128 
1129       break;
1130       case OP_OR: {
1131         newOperandBlock = false;
1132         operandOnly = false;
1133 
1134         b1 = tmpStack.top();
1135         tmpStack.pop();
1136         b2 = tmpStack.top();
1137         tmpStack.pop();
1138 
1139         tmpStack.push(dummyToken);  // and push dummy result
1140 
1141         if (b1.tokenNumber >= 0) {
1142           tmpVector.push_back(b1);
1143 
1144           //LogTrace("L1GtLogicParser")
1145           //<< "  Push operand " << b1.tokenName
1146           //<<" on the tmp list"
1147           //<< std::endl;
1148         }
1149 
1150         if (b2.tokenNumber >= 0) {
1151           tmpVector.push_back(b2);
1152 
1153           //LogTrace("L1GtLogicParser")
1154           //<< "  Push operand " << b2.tokenName
1155           //<<" on the tmp list"
1156           //<< std::endl;
1157         }
1158 
1159       }
1160 
1161       break;
1162       case OP_AND: {
1163         newOperandBlock = false;
1164         operandOnly = false;
1165 
1166         b1 = tmpStack.top();
1167         tmpStack.pop();
1168         b2 = tmpStack.top();
1169         tmpStack.pop();
1170 
1171         tmpStack.push(dummyToken);
1172 
1173         if (b1.tokenNumber >= 0) {
1174           tmpVector.push_back(b1);
1175 
1176           //LogTrace("L1GtLogicParser")
1177           //<< "  Push operand " << b1.tokenName
1178           //<<" on the tmp list"
1179           //<< std::endl;
1180         }
1181 
1182         if (b2.tokenNumber >= 0) {
1183           tmpVector.push_back(b2);
1184 
1185           //LogTrace("L1GtLogicParser")
1186           //<< "  Push operand " << b2.tokenName
1187           //<<" on the tmp list"
1188           //<< std::endl;
1189         }
1190 
1191       }
1192 
1193       break;
1194       default: {
1195         // should not arrive here
1196       }
1197 
1198       break;
1199     }
1200   }
1201 
1202   // one block only or one operand only
1203   if (oneBlockOnly || operandOnly) {
1204     // one operand only -
1205     // there can be only one operand, otherwise one needs an operation
1206     if (operandOnly) {
1207       b1 = tmpStack.top();
1208       tmpVector.push_back(b1);
1209     }
1210 
1211     //
1212     for (std::vector<OperandToken>::reverse_iterator itOp = tmpVector.rbegin(); itOp != tmpVector.rend(); itOp++) {
1213       opVector.push_back(*itOp);
1214 
1215       //LogTrace("L1GtLogicParser")
1216       //<< "  One block or one operand only: push operand " << (*itOp).tokenName
1217       //<<" on the seed operand list"
1218       //<< std::endl;
1219     }
1220 
1221   } else {
1222     //LogTrace("L1GtLogicParser")
1223     //        << "  More blocks:  push the last block on the seed operand list" << std::endl;
1224 
1225     for (std::vector<OperandToken>::reverse_iterator itOp = tmpVector.rbegin(); itOp != tmpVector.rend(); itOp++) {
1226       opVector.push_back(*itOp);
1227 
1228       //LogTrace("L1GtLogicParser")
1229       //<< "  Push operand:  " << (*itOp).tokenName
1230       //<<" on the seed operand list"
1231       //<< std::endl;
1232     }
1233   }
1234 
1235   // remove duplicates from the seed vector
1236   // slow...
1237   std::vector<OperandToken> opVectorU;
1238   opVectorU.reserve(opVector.size());
1239 
1240   for (std::vector<OperandToken>::const_iterator constIt = opVector.begin(); constIt != opVector.end(); constIt++) {
1241     bool tokenIncluded = false;
1242 
1243     for (std::vector<OperandToken>::iterator itOpU = opVectorU.begin(); itOpU != opVectorU.end(); itOpU++) {
1244       if ((*itOpU).tokenName == (*constIt).tokenName) {
1245         tokenIncluded = true;
1246         break;
1247       }
1248     }
1249 
1250     if (!tokenIncluded) {
1251       opVectorU.push_back(*constIt);
1252     }
1253   }
1254 
1255   return opVectorU;
1256 }
1257 
1258 // private methods
1259 
1260 /**
1261  * getOperation Get the operation from a string and check if it is allowed
1262  *
1263  * @param tokenString   The string to examine.
1264  * @param lastOperation The last operation.
1265  * @param rpnToken      The destination where the token for postfix notation is written to.
1266  *
1267  * @return              The Operation type or OP_INVALID, if the operation is not allowed
1268  *
1269  */
1270 
1271 L1GtLogicParser::OperationType L1GtLogicParser::getOperation(const std::string& tokenString,
1272                                                              OperationType lastOperation,
1273                                                              TokenRPN& rpnToken) const {
1274   OperationType actualOperation = OP_OPERAND;  // default value
1275 
1276   int i = 0;
1277 
1278   while (m_operationRules[i].opType != OP_OPERAND) {
1279     if (tokenString == m_operationRules[i].opString) {
1280       actualOperation = (OperationType)m_operationRules[i].opType;
1281       break;
1282     }
1283     i++;
1284   }
1285 
1286   // check if the operation is allowed
1287   if (m_operationRules[i].forbiddenLastOperation & lastOperation) {
1288     return OP_INVALID;
1289   }
1290 
1291   //
1292   if (actualOperation == OP_OPERAND) {
1293     rpnToken.operand = tokenString;
1294 
1295   } else {
1296     rpnToken.operand = "";
1297   }
1298 
1299   rpnToken.operation = actualOperation;
1300 
1301   // else we got a valid operation
1302   return actualOperation;
1303 }
1304 
1305 /**
1306  * getRuleFromType Looks for the entry in the operation rules
1307  *     and returns a reference if it was found
1308  *
1309  * @param oType The type of the operation.
1310  *
1311  * @return The reference to the entry or 0 if the Rule was not found.
1312  *
1313  */
1314 
1315 const L1GtLogicParser::OperationRule* L1GtLogicParser::getRuleFromType(OperationType oType) {
1316   int i = 0;
1317 
1318   while ((m_operationRules[i].opType != oType) && (m_operationRules[i].opType != OP_NULL)) {
1319     i++;
1320   }
1321 
1322   if (m_operationRules[i].opType == OP_NULL) {
1323     return nullptr;
1324   }
1325 
1326   return &(m_operationRules[i]);
1327 }
1328 
1329 // add spaces before and after parentheses - make separation easier
1330 void L1GtLogicParser::addBracketSpaces(const std::string& srcExpression, std::string& dstExpression) {
1331   static const std::string brackets = "()";  // the brackets to be found
1332 
1333   dstExpression = srcExpression;  // copy the string
1334 
1335   size_t position = 0;
1336   while ((position = dstExpression.find_first_of(brackets, position)) != std::string::npos) {
1337     // add space after if none is there
1338     if (((position + 1) != std::string::npos) && (dstExpression[position + 1] != ' ')) {
1339       dstExpression.insert(position + 1, " ");
1340     }
1341 
1342     // add space before if none is there
1343     if ((position != 0) && (dstExpression[position - 1] != ' ')) {
1344       dstExpression.insert(position, " ");
1345       position++;
1346     }
1347     position++;
1348   }
1349 }
1350 
1351 // set the logical expression - check for correctness the input string
1352 bool L1GtLogicParser::setLogicalExpression(const std::string& logicalExpressionVal) {
1353   // add spaces around brackets
1354   std::string logicalExpressionBS;
1355   addBracketSpaces(logicalExpressionVal, logicalExpressionBS);
1356 
1357   // trim leading or trailing spaces
1358   boost::trim(logicalExpressionBS);
1359 
1360   clearRpnVector();
1361 
1362   if (!buildRpnVector(logicalExpressionBS)) {
1363     m_logicalExpression = "";
1364     return false;
1365   }
1366 
1367   m_logicalExpression = logicalExpressionBS;
1368 
1369   //LogDebug("L1GtLogicParser")
1370   //<< "\nL1GtLogicParser::setLogicalExpression - "
1371   //<< "\nLogical expression = '" << m_logicalExpression << "'\n"
1372   //<< std::endl;
1373 
1374   return true;
1375 }
1376 
1377 // set the numerical expression (the logical expression with each operand
1378 // replaced with the value) from a string
1379 // check also for correctness the input string
1380 bool L1GtLogicParser::setNumericalExpression(const std::string& numericalExpressionVal) {
1381   // add spaces around brackets
1382   std::string numericalExpressionBS;
1383   addBracketSpaces(numericalExpressionVal, numericalExpressionBS);
1384 
1385   // check for consistency with the logical expression
1386   // TODO FIXME
1387 
1388   // trim leading or trailing spaces
1389   boost::trim(numericalExpressionBS);
1390 
1391   m_numericalExpression = numericalExpressionBS;
1392 
1393   //LogDebug("L1GtLogicParser")
1394   //<< "\nL1GtLogicParser::setNumericalExpression - "
1395   //<< "\nNumerical Expression = '" << m_numericalExpression << "'\n"
1396   //<< std::endl;
1397 
1398   return true;
1399 }
1400 
1401 // static members
1402 
1403 // rules for operations
1404 // 1st column: operation string
1405 // 2nd column: operation type
1406 // 3rd column: forbiddenLastOperation (what operation the operator/operand must not follow)
1407 const struct L1GtLogicParser::OperationRule L1GtLogicParser::m_operationRules[] = {
1408     {"AND", OP_AND, OP_AND | OP_OR | OP_NOT | OP_OPENBRACKET | OP_NULL},
1409     {"OR", OP_OR, OP_AND | OP_OR | OP_NOT | OP_OPENBRACKET | OP_NULL},
1410     {"NOT", OP_NOT, OP_OPERAND | OP_CLOSEBRACKET},
1411     {"(", OP_OPENBRACKET, OP_OPERAND | OP_CLOSEBRACKET},
1412     {")", OP_CLOSEBRACKET, OP_AND | OP_OR | OP_NOT | OP_OPENBRACKET},
1413     {nullptr, OP_OPERAND, OP_OPERAND | OP_CLOSEBRACKET},
1414     {nullptr, OP_NULL, OP_NULL}};