/
githubmirror
/
cmssw
Обзор
Документация
Войти
/
githubmirror
/
cmssw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
DataFormats/L1TGlobal/src/GlobalLogicParser.cc
1 484 строки
44 KB
Shahzad Malik Muzaffar
[L1] Apply code checks/format
18 дек 2024, 10:28
18 дек 2024, 10:28
c7f535a
Код
Авторство
О чём код?
/** * \class GlobalLogicParser * * * Description: see header file. * * Implementation: * <TODO: enter implementation details> * * \author: Vasile Mihai Ghete - HEPHY Vienna * * */ // this class header #include "DataFormats/L1TGlobal/interface/GlobalLogicParser.h" // system include files #include <stack> #include <iostream> #include <sstream> #include <boost/algorithm/string.hpp> // user include files #include "FWCore/Utilities/interface/EDMException.h" #include "FWCore/MessageLogger/interface/MessageLogger.h" // forward declarations // constructor(s) // default constructor GlobalLogicParser::GlobalLogicParser() { // empty, default C++ initialization for string and vector are enough } // from the RPN vector and the operand token vector // no checks for consistency, empty logical and numerical expressions // requires special care when used GlobalLogicParser::GlobalLogicParser(const RpnVector& rpnVec, const std::vector<OperandToken>& opTokenVector) { m_rpnVector = rpnVec; m_operandTokenVector = opTokenVector; } // from a constant logical expression // numerical expression will be empty GlobalLogicParser::GlobalLogicParser(const std::string& logicalExpressionVal) { // checks also for syntactic correctness of the logical expression if (!setLogicalExpression(logicalExpressionVal)) { // error(s) in logical expression - printed in the relevant place throw cms::Exception("FailModule") << "\nError in parsing the logical expression = " << logicalExpressionVal << std::endl; } } // from a non-constant logical expression - add/remove spaces if needed // numerical expression will be empty GlobalLogicParser::GlobalLogicParser(std::string& logicalExpressionVal) { // checks also for syntactic correctness of the logical expression // add spaces around brackets std::string logicalExpressionBS; addBracketSpaces(logicalExpressionVal, logicalExpressionBS); // trim leading or trailing spaces boost::trim(logicalExpressionBS); if (!buildRpnVector(logicalExpressionBS)) { // error(s) in logical expression throw cms::Exception("FailModule") << "\nError in parsing the logical expression = " << logicalExpressionVal << std::endl; } //LogDebug("L1TGlobal") // << "\nInitial logical expression = '" << logicalExpressionVal << "'" // << "\nFinal logical expression = '" << logicalExpressionBS << "'\n" // << std::endl; logicalExpressionVal = logicalExpressionBS; m_logicalExpression = logicalExpressionVal; // build operand token vector // dummy tokenNumber; tokenResult false buildOperandTokenVector(); } // from a logical and a numerical expression GlobalLogicParser::GlobalLogicParser(const std::string logicalExpressionVal, const std::string numericalExpressionVal) { // checks also for correctness if (!setLogicalExpression(logicalExpressionVal)) { // error(s) in logical expression - printed in the relevant place throw cms::Exception("FailModule") << "\nError in parsing the logical expression = " << logicalExpressionVal << std::endl; } if (!setNumericalExpression(numericalExpressionVal)) { // error(s) in numerical expression - printed in the relevant place throw cms::Exception("FileModule") << "\nError in parsing the numerical expression = " << numericalExpressionVal << std::endl; } } // from a logical and a numerical expression // no checks for correctness - use it only after the correctness was tested GlobalLogicParser::GlobalLogicParser(const std::string& logicalExpressionVal, const std::string& numericalExpressionVal, const bool dummy) { clearRpnVector(); if (!buildRpnVector(logicalExpressionVal)) { throw cms::Exception("FileModule") << "\nError in building RPN vector for the logical expression = " << logicalExpressionVal << std::endl; } m_logicalExpression = logicalExpressionVal; m_numericalExpression = numericalExpressionVal; } // destructor GlobalLogicParser::~GlobalLogicParser() { // empty now } // public methods // check a logical expression for correctness - add/remove spaces if needed bool GlobalLogicParser::checkLogicalExpression(std::string& logicalExpressionVal) { // add spaces around brackets std::string logicalExpressionBS; addBracketSpaces(logicalExpressionVal, logicalExpressionBS); // trim leading or trailing spaces boost::trim(logicalExpressionBS); clearRpnVector(); if (!buildRpnVector(logicalExpressionBS)) { return false; } LogDebug("L1TGlobal") << "\nGtLogicParser::checkLogicalExpression - " << "\nInitial logical expression = '" << logicalExpressionVal << "'" << "\nFinal logical expression = '" << logicalExpressionBS << "'\n" << std::endl; logicalExpressionVal = logicalExpressionBS; return true; } /** * buildRpnVector Build the postfix notation. * * @param expression The expression to be parsed. * * @return "true" if everything was parsed. "false" if an error occured. * */ bool GlobalLogicParser::buildRpnVector(const std::string& logicalExpressionVal) { //LogDebug("L1TGlobal") //<< "\nGtLogicParser::buildRpnVector - " //<< "\nLogical expression = '" << logicalExpressionVal << "'\n" //<< std::endl; OperationType actualOperation = OP_NULL; OperationType lastOperation = OP_NULL; // token as string and as TokenRPN, stack to form the postfix notation std::string tokenString; TokenRPN rpnToken; std::stack<TokenRPN> operatorStack; static const std::string whitespaces = " \r\v\n\t"; // clear possible old rpn vector clearRpnVector(); // stringstream to separate all tokens std::istringstream exprStringStream(logicalExpressionVal); while (!exprStringStream.eof()) { exprStringStream >> std::skipws >> std::ws >> tokenString; // skip the end if (tokenString.find_first_not_of(whitespaces) == std::string::npos || tokenString.empty()) { //LogTrace("L1TGlobal") //<< " Break for token string = " << tokenString //<< std::endl; break; } actualOperation = getOperation(tokenString, lastOperation, rpnToken); //LogTrace("L1TGlobal") //<< " Token string = '" << tokenString << "'" //<< "\tActual Operation = " << actualOperation //<< std::endl; // http://en.wikipedia.org/wiki/Postfix_notation#Converting_from_infix_notation switch (actualOperation) { case OP_OPERAND: { // operands get pushed to the postfix notation immediately m_rpnVector.push_back(rpnToken); } break; case OP_INVALID: { int errorPosition = exprStringStream.tellg(); edm::LogError("L1TGlobal") << "\nLogical expression = '" << logicalExpressionVal << "'" << "\n Syntax error during parsing: " << "\n " << exprStringStream.str().substr(0, errorPosition) << "\n " << exprStringStream.str().substr(errorPosition) << "\n Returned empty RPN vector and result false." << std::endl; // clear the rpn vector before returning clearRpnVector(); return false; } break; case OP_NOT: { operatorStack.push(rpnToken); // there are no operators with higher precedence } break; case OP_XOR: { // first pop operators with higher precedence (NOT) while (!operatorStack.empty() && operatorStack.top().operation == OP_NOT) { m_rpnVector.push_back(operatorStack.top()); operatorStack.pop(); } operatorStack.push(rpnToken); } break; case OP_AND: { // first pop operators with higher precedence (XOR, NOT) while (!operatorStack.empty() && (operatorStack.top().operation == OP_NOT || operatorStack.top().operation == OP_AND)) { m_rpnVector.push_back(operatorStack.top()); operatorStack.pop(); } operatorStack.push(rpnToken); } break; case OP_OR: { // pop operators with higher precedence (AND, XOR, NOT) while (!operatorStack.empty() && (operatorStack.top().operation == OP_NOT || operatorStack.top().operation == OP_XOR || operatorStack.top().operation == OP_AND)) { m_rpnVector.push_back(operatorStack.top()); operatorStack.pop(); } // push operator on stack operatorStack.push(rpnToken); } break; case OP_OPENBRACKET: { // just push it on stack operatorStack.push(rpnToken); } break; case OP_CLOSEBRACKET: { // check if the operatorStack is empty if (operatorStack.empty()) { int errorPosition = exprStringStream.tellg(); edm::LogError("L1TGlobal") << "\nLogical expression = '" << logicalExpressionVal << "'" << "\n Syntax error during parsing - misplaced ')':" << "\n " << exprStringStream.str().substr(0, errorPosition) << "\n " << exprStringStream.str().substr(errorPosition) << "\n Returned empty RPN vector and result false." << std::endl; // clear the rpn vector before returning clearRpnVector(); return false; } // pop stack until a left parenthesis is found do { if (operatorStack.top().operation != OP_OPENBRACKET) { m_rpnVector.push_back(operatorStack.top()); // pop operatorStack.pop(); } if (operatorStack.empty()) { // the operatorStack must not be empty int errorPosition = exprStringStream.tellg(); edm::LogError("L1TGlobal") << "\nLogical expression = '" << logicalExpressionVal << "'" << "\n Syntax error during parsing - misplaced ')':" << "\n " << exprStringStream.str().substr(0, errorPosition) << "\n " << exprStringStream.str().substr(errorPosition) << "\n Returned empty RPN vector and result false." << std::endl; // clear the rpn vector before returning clearRpnVector(); return false; } } while (operatorStack.top().operation != OP_OPENBRACKET); operatorStack.pop(); // pop the open bracket. } break; default: { // empty } break; } lastOperation = actualOperation; // for the next turn } // pop the rest of the operator stack while (!operatorStack.empty()) { if (operatorStack.top().operation == OP_OPENBRACKET) { edm::LogError("L1TGlobal") << "\nLogical expression = '" << logicalExpressionVal << "'" << "\n Syntax error during parsing - missing ')':" << "\n Returned empty RPN vector and result false." << std::endl; // clear the rpn vector before returning clearRpnVector(); return false; } m_rpnVector.push_back(operatorStack.top()); operatorStack.pop(); } // count all operations and check if the result is 1 int counter = 0; for (RpnVector::iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) { if (it->operation == OP_OPERAND) counter++; if (it->operation == OP_OR || it->operation == OP_AND || it->operation == OP_XOR) counter--; if (counter < 1) { edm::LogError("L1TGlobal") << "\nLogical expression = '" << logicalExpressionVal << "'" << "\n Syntax error during parsing - too many operators" << "\n Returned empty RPN vector and result false." << std::endl; // clear the rpn vector before returning clearRpnVector(); return false; } } if (counter > 1) { edm::LogError("L1TGlobal") << "\nLogical expression = '" << logicalExpressionVal << "'" << "\n Syntax error during parsing - too many operands" << "\n Returned empty RPN vector and result false." << std::endl; // clear the rpn vector before returning clearRpnVector(); return false; } return true; } // clear rpn vector void GlobalLogicParser::clearRpnVector() { m_rpnVector.clear(); } // build from the RPN vector the operand token vector // dummy tokenNumber and token result void GlobalLogicParser::buildOperandTokenVector() { //LogTrace("L1TGlobal") //<< "\nGtLogicParser::buildOperandTokenVector - " //<< std::endl; // reserve memory size_t rpnVectorSize = m_rpnVector.size(); m_operandTokenVector.reserve(rpnVectorSize); int opNumber = 0; for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) { //LogTrace("L1TGlobal") //<< "\nit->operation = " << it->operation //<< "\nit->operand = '" << it->operand << "'\n" //<< std::endl; switch (it->operation) { case OP_OPERAND: { OperandToken opToken; opToken.tokenName = it->operand; opToken.tokenNumber = opNumber; opToken.tokenResult = false; m_operandTokenVector.push_back(opToken); } break; case OP_NOT: { // do nothing } break; case OP_OR: { // do nothing } break; case OP_AND: { // do nothing } case OP_XOR: { // do nothing } break; default: { // should not arrive here } break; } opNumber++; } } // return the position index of the operand in the logical expression int GlobalLogicParser::operandIndex(const std::string& operandNameVal) const { int result = -1; OperationType actualOperation = OP_NULL; OperationType lastOperation = OP_NULL; std::string tokenString; TokenRPN rpnToken; // token to be used by getOperation // stringstream to separate all tokens std::istringstream exprStringStream(m_logicalExpression); // temporary index for usage in the loop int tmpIndex = -1; while (!exprStringStream.eof()) { exprStringStream >> tokenString; //LogTrace("L1TGlobal") //<< "Token string = " << tokenString //<< std::endl; actualOperation = getOperation(tokenString, lastOperation, rpnToken); if (actualOperation == OP_INVALID) { // it should never be invalid edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'" << "\n Invalid operation/operand " << operandNameVal << "\n Returned index is by default out of range (-1)." << std::endl; return result; } if (actualOperation != OP_OPERAND) { // do nothing } else { tmpIndex++; if (rpnToken.operand == operandNameVal) { result = tmpIndex; //LogDebug("L1TGlobal") //<< "\nGtLogicParser::operandIndex - " //<< "\nLogical expression = '" << m_logicalExpression << "'" //<< "\nIndex of operand " << operandNameVal << " = " << result //<< std::endl; return result; } } lastOperation = actualOperation; } // edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'" << "\n Operand " << operandNameVal << " not found in the logical expression" << "\n Returned index is by default out of range (-1)." << std::endl; return result; } // return the name of the (iOperand)th operand in the logical expression std::string GlobalLogicParser::operandName(const int iOperand) const { std::string result; OperationType actualOperation = OP_NULL; OperationType lastOperation = OP_NULL; std::string tokenString; TokenRPN rpnToken; // token to be used by getOperation // stringstream to separate all tokens std::istringstream exprStringStream(m_logicalExpression); // temporary index for usage in the loop int tmpIndex = -1; while (!exprStringStream.eof()) { exprStringStream >> tokenString; //LogTrace("L1TGlobal") //<< "Token string = " << tokenString //<< std::endl; actualOperation = getOperation(tokenString, lastOperation, rpnToken); if (actualOperation == OP_INVALID) { // it should never be invalid edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'" << "\n Invalid operation/operand at position " << iOperand << "\n Returned empty name by default." << std::endl; return result; } if (actualOperation != OP_OPERAND) { // do nothing } else { tmpIndex++; if (tmpIndex == iOperand) { result = rpnToken.operand; //LogDebug("L1TGlobal") //<< "\nGtLogicParser::operandName - " //<< "\nLogical expression = '" << m_logicalExpression << "'" //<< "\nOperand with index " << iOperand << " = " << result //<< std::endl; return result; } } lastOperation = actualOperation; } // edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'" << "\n No operand found at position " << iOperand << "\n Returned empty name by default." << std::endl; return result; } // return the result for an operand with name operandNameVal // in the logical expression using the operand token vector bool GlobalLogicParser::operandResult(const std::string& operandNameVal) const { for (size_t i = 0; i < m_operandTokenVector.size(); ++i) { if ((m_operandTokenVector[i]).tokenName == operandNameVal) { return (m_operandTokenVector[i]).tokenResult; } } // return false - should not arrive here edm::LogError("L1TGlobal") << "\n Operand " << operandNameVal << " not found in the operand token vector" << "\n Returned false by default." << std::endl; return false; } // return the result for an operand with tokenNumberVal // using the operand token vector bool GlobalLogicParser::operandResult(const int tokenNumberVal) const { for (size_t i = 0; i < m_operandTokenVector.size(); ++i) { if ((m_operandTokenVector[i]).tokenNumber == tokenNumberVal) { return (m_operandTokenVector[i]).tokenResult; } } // return false - should not arrive here edm::LogError("L1TGlobal") << "\n No operand with token number " << tokenNumberVal << " found in the operand token vector" << "\n Returned false by default." << std::endl; return false; } // return the result for the logical expression // require a proper operand token vector const bool GlobalLogicParser::expressionResult() const { //LogTrace("L1TGlobal") //<< "\nGtLogicParser::expressionResult - " //<< std::endl; // return false if there is no RPN vector built if (m_rpnVector.empty()) { edm::LogError("L1TGlobal") << "\n No built RPN vector exists." << "\n Returned false by default." << std::endl; return false; } // stack containing temporary results std::stack<bool> resultStack; bool b1, b2; for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) { //LogTrace("L1TGlobal") //<< "\nit->operation = " << it->operation //<< "\nit->operand = '" << it->operand << "'\n" //<< std::endl; switch (it->operation) { case OP_OPERAND: { resultStack.push(operandResult(it->operand)); } break; case OP_NOT: { b1 = resultStack.top(); resultStack.pop(); // pop the top resultStack.push(!b1); // and push the result } break; case OP_OR: { b1 = resultStack.top(); resultStack.pop(); b2 = resultStack.top(); resultStack.pop(); resultStack.push(b1 || b2); } break; case OP_XOR: { b1 = resultStack.top(); resultStack.pop(); b2 = resultStack.top(); resultStack.pop(); resultStack.push(b1 ^ b2); } break; case OP_AND: { b1 = resultStack.top(); resultStack.pop(); b2 = resultStack.top(); resultStack.pop(); resultStack.push(b1 && b2); } break; default: { // should not arrive here } break; } } // get the result in the top of the stack //LogTrace("L1TGlobal") //<< "\nGtLogicParser::expressionResult - " //<< "\nResult = " << resultStack.top() //<< std::endl; return resultStack.top(); } // return the result for an operand with name operandNameVal // in the logical expression using a numerical expression bool GlobalLogicParser::operandResultNumExp(const std::string& operandNameVal) const { bool result = false; // get the position index of the operand in the logical string const int iOperand = operandIndex(operandNameVal); result = operandResult(iOperand); return result; } // return the result for an operand with index iOperand // in the logical expression using a numerical expression bool GlobalLogicParser::operandResultNumExp(const int iOperand) const { bool result = false; // parse the numerical expression OperationType actualOperation = OP_NULL; OperationType lastOperation = OP_NULL; std::string tokenString; TokenRPN rpnToken; // token to be used by getOperation // stringstream to separate all tokens std::istringstream exprStringStream(m_numericalExpression); // temporary index for usage in the loop int tmpIndex = -1; while (!exprStringStream.eof()) { exprStringStream >> tokenString; //LogTrace("L1TGlobal") //<< "Token string = " << tokenString //<< std::endl; actualOperation = getOperation(tokenString, lastOperation, rpnToken); if (actualOperation == OP_INVALID) { // it should never be invalid edm::LogError("L1TGlobal") << "\nNumerical expression = '" << m_numericalExpression << "'" << "\n Invalid operation/operand at position " << iOperand << "\n Returned false by default." << std::endl; result = false; return result; } if (actualOperation != OP_OPERAND) { // do nothing } else { tmpIndex++; if (tmpIndex == iOperand) { if (rpnToken.operand == "1") { result = true; } else { if (rpnToken.operand == "0") { result = false; } else { // something went wrong - break // edm::LogError("L1TGlobal") << "\nNumerical expression = '" << m_numericalExpression << "'" << "\n Invalid result for operand at position " << iOperand << ": " << rpnToken.operand << "\n It must be 0 or 1" << "\n Returned false by default." << std::endl; result = false; return result; } } //LogDebug("L1TGlobal") //<< "\nGtLogicParser::operandResult - " //<< "\nNumerical expression = '" << m_numericalExpression << "'" //<< "\nResult for operand with index " << iOperand //<< " = " << result << "'\n" //<< std::endl; return result; } } lastOperation = actualOperation; } // edm::LogError("L1TGlobal") << "\nNumerical expression = '" << m_numericalExpression << "'" << "\n No operand found at position " << iOperand << "\n Returned false by default." << std::endl; return result; } // build from the RPN vector the operand token vector // using a numerical expression void GlobalLogicParser::buildOperandTokenVectorNumExp() { //LogTrace("L1TGlobal") //<< "\nGtLogicParser::buildOperandTokenVector - " //<< std::endl; // reserve memory size_t rpnVectorSize = m_rpnVector.size(); m_operandTokenVector.reserve(rpnVectorSize); int opNumber = 0; for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) { //LogTrace("L1TGlobal") //<< "\nit->operation = " << it->operation //<< "\nit->operand = '" << it->operand << "'\n" //<< std::endl; switch (it->operation) { case OP_OPERAND: { OperandToken opToken; opToken.tokenName = it->operand; opToken.tokenNumber = opNumber; opToken.tokenResult = operandResultNumExp(it->operand); m_operandTokenVector.push_back(opToken); } break; case OP_NOT: { // do nothing } break; case OP_OR: { // do nothing } break; case OP_XOR: { // do nothing } break; case OP_AND: { // do nothing } break; default: { // should not arrive here } break; } opNumber++; } } // return the result for the logical expression const bool GlobalLogicParser::expressionResultNumExp() const { //LogTrace("L1TGlobal") //<< "\nGtLogicParser::expressionResult - " //<< std::endl; // return false if there is no expression if (m_rpnVector.empty()) { edm::LogError("L1TGlobal") << "\n No built RPN vector exists." << "\n Returned false by default." << std::endl; return false; } // stack containing temporary results std::stack<bool> resultStack; bool b1, b2; for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) { //LogTrace("L1TGlobal") //<< "\nit->operation = " << it->operation //<< "\nit->operand = '" << it->operand << "'\n" //<< std::endl; switch (it->operation) { case OP_OPERAND: { resultStack.push(operandResultNumExp(it->operand)); } break; case OP_NOT: { b1 = resultStack.top(); resultStack.pop(); // pop the top resultStack.push(!b1); // and push the result } break; case OP_OR: { b1 = resultStack.top(); resultStack.pop(); b2 = resultStack.top(); resultStack.pop(); resultStack.push(b1 || b2); } break; case OP_XOR: { b1 = resultStack.top(); resultStack.pop(); b2 = resultStack.top(); resultStack.pop(); resultStack.push(b1 ^ b2); } break; case OP_AND: { b1 = resultStack.top(); resultStack.pop(); b2 = resultStack.top(); resultStack.pop(); resultStack.push(b1 && b2); } break; default: { // should not arrive here } break; } } // get the result in the top of the stack //LogTrace("L1TGlobal") //<< "\nGtLogicParser::expressionResult - " //<< "\nLogical expression = '" << m_logicalExpression << "'" //<< "\nNumerical expression = '" << m_numericalExpression << "'" //<< "\nResult = " << resultStack.top() //<< std::endl; return resultStack.top(); } // convert the logical expression composed with names to // a logical expression composed with int numbers using // a (string, int) map void GlobalLogicParser::convertNameToIntLogicalExpression(const std::map<std::string, int>& nameToIntMap) { if (m_logicalExpression.empty()) { return; } // non-empty logical expression OperationType actualOperation = OP_NULL; OperationType lastOperation = OP_NULL; std::string tokenString; TokenRPN rpnToken; // token to be used by getOperation int intValue = -1; // stringstream to separate all tokens std::istringstream exprStringStream(m_logicalExpression); std::string convertedLogicalExpression; while (!exprStringStream.eof()) { exprStringStream >> tokenString; actualOperation = getOperation(tokenString, lastOperation, rpnToken); if (actualOperation == OP_INVALID) { // it should never be invalid edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'" << "\n Invalid operation/operand in logical expression." << "\n Return empty logical expression." << std::endl; m_logicalExpression.clear(); return; } if (actualOperation != OP_OPERAND) { convertedLogicalExpression.append(getRuleFromType(actualOperation)->opString); } else { typedef std::map<std::string, int>::const_iterator CIter; CIter it = nameToIntMap.find(rpnToken.operand); if (it != nameToIntMap.end()) { intValue = it->second; std::stringstream intStr; intStr << intValue; convertedLogicalExpression.append(intStr.str()); } else { // it should never be happen edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'" << "\n Could not convert " << rpnToken.operand << " to integer!" << "\n Return empty logical expression." << std::endl; m_logicalExpression.clear(); return; } } convertedLogicalExpression.append(" "); // one whitespace after each token lastOperation = actualOperation; } // remove the last space //convertedLogicalExpression.erase(convertedLogicalExpression.size() - 1); boost::trim(convertedLogicalExpression); LogDebug("L1TGlobal") << "\nGtLogicParser::convertNameToIntLogicalExpression - " << "\nLogical expression (strings) = '" << m_logicalExpression << "'" << "\nLogical expression (int) = '" << convertedLogicalExpression << "'\n" << std::endl; // replace now the logical expression with strings with // the converted logical expression m_logicalExpression = convertedLogicalExpression; return; } // convert a logical expression composed with integer numbers to // a logical expression composed with names using a map (int, string) void GlobalLogicParser::convertIntToNameLogicalExpression(const std::map<int, std::string>& intToNameMap) { if (m_logicalExpression.empty()) { return; } // non-empty logical expression OperationType actualOperation = OP_NULL; OperationType lastOperation = OP_NULL; std::string tokenString; TokenRPN rpnToken; // token to be used by getOperation // stringstream to separate all tokens std::istringstream exprStringStream(m_logicalExpression); std::string convertedLogicalExpression; while (!exprStringStream.eof()) { exprStringStream >> tokenString; actualOperation = getOperation(tokenString, lastOperation, rpnToken); if (actualOperation == OP_INVALID) { // it should never be invalid edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'" << "\n Invalid operation/operand in logical expression." << "\n Return empty logical expression." << std::endl; m_logicalExpression.clear(); return; } if (actualOperation != OP_OPERAND) { convertedLogicalExpression.append(getRuleFromType(actualOperation)->opString); } else { typedef std::map<int, std::string>::const_iterator CIter; // convert string to int int indexInt; std::istringstream iss(rpnToken.operand); iss >> std::dec >> indexInt; CIter it = intToNameMap.find(indexInt); if (it != intToNameMap.end()) { convertedLogicalExpression.append(it->second); } else { // it should never be happen edm::LogError("L1TGlobal") << "\nLogical expression = '" << m_logicalExpression << "'" << "\n Could not convert " << rpnToken.operand << " to string!" << "\n Return empty logical expression." << std::endl; m_logicalExpression.clear(); return; } } convertedLogicalExpression.append(" "); // one whitespace after each token lastOperation = actualOperation; } // remove the last space //convertedLogicalExpression.erase(convertedLogicalExpression.size() - 1); boost::trim(convertedLogicalExpression); //LogDebug("L1TGlobal") // << "\nGtLogicParser::convertIntToNameLogicalExpression - " // << "\nLogical expression (int) = '" << m_logicalExpression << "'" // << "\nLogical expression (string) = '" << convertedLogicalExpression << "'\n" // << std::endl; // replace now the logical expression with int with // the converted logical expression m_logicalExpression = convertedLogicalExpression; return; } // return the list of operand tokens for the logical expression // which are to be used as seeds std::vector<GlobalLogicParser::OperandToken> GlobalLogicParser::expressionSeedsOperandList() { //LogDebug("L1TGlobal") //<< "\nGtLogicParser::expressionSeedsOperandList - " //<< "\nLogical expression = '" << m_logicalExpression << "'" //<< "\nm_rpnVector.size() = " << m_rpnVector.size() //<< "\nm_operandTokenVector.size() = " << m_operandTokenVector.size() //<< std::endl; // seed list std::vector<OperandToken> opVector; opVector.reserve(m_operandTokenVector.size()); // temporary results std::stack<OperandToken> tmpStack; std::vector<OperandToken> tmpVector; tmpVector.reserve(m_operandTokenVector.size()); OperandToken b1, b2; bool newOperandBlock = true; bool oneBlockOnly = true; bool operandOnly = true; int iOperand = -1; OperandToken dummyToken; dummyToken.tokenName = "dummy"; dummyToken.tokenNumber = -1; dummyToken.tokenResult = false; for (RpnVector::const_iterator it = m_rpnVector.begin(); it != m_rpnVector.end(); it++) { //LogTrace("L1TGlobal") //<< "\nit->operation = " << it->operation //<< "\nit->operand = '" << it->operand << "'\n" //<< std::endl; switch (it->operation) { // RPN always start a block with an operand case OP_OPERAND: { // more blocks with operations // push operands from previous block, if any in the tmpVector // (reverse order to compensate the stack push/top/pop) if ((!newOperandBlock)) { for (std::vector<OperandToken>::reverse_iterator itOp = tmpVector.rbegin(); itOp != tmpVector.rend(); itOp++) { opVector.push_back(*itOp); //LogTrace("L1TGlobal") //<< " Push operand " << (*itOp).tokenName //<<" on the seed operand list" //<< std::endl; } tmpVector.clear(); newOperandBlock = true; oneBlockOnly = false; } iOperand++; //LogTrace("L1TGlobal") //<< " Push operand " << (m_operandTokenVector.at(iOperand)).tokenName //<< " on the operand stack" //<< std::endl; tmpStack.push(m_operandTokenVector.at(iOperand)); } break; case OP_NOT: { newOperandBlock = false; operandOnly = false; b1 = tmpStack.top(); tmpStack.pop(); // pop the top tmpStack.push(dummyToken); // and push dummy result //LogTrace("L1TGlobal") //<< " Clear tmp operand list" //<< std::endl; tmpVector.clear(); } break; case OP_OR: { newOperandBlock = false; operandOnly = false; b1 = tmpStack.top(); tmpStack.pop(); b2 = tmpStack.top(); tmpStack.pop(); tmpStack.push(dummyToken); // and push dummy result if (b1.tokenNumber >= 0) { tmpVector.push_back(b1); //LogTrace("L1TGlobal") //<< " Push operand " << b1.tokenName //<<" on the tmp list" //<< std::endl; } if (b2.tokenNumber >= 0) { tmpVector.push_back(b2); //LogTrace("L1TGlobal") //<< " Push operand " << b2.tokenName //<<" on the tmp list" //<< std::endl; } } break; case OP_XOR: { newOperandBlock = false; operandOnly = false; b1 = tmpStack.top(); tmpStack.pop(); b2 = tmpStack.top(); tmpStack.pop(); tmpStack.push(dummyToken); // and push dummy result if (b1.tokenNumber >= 0) { tmpVector.push_back(b1); //LogTrace("L1TGlobal") //<< " Push operand " << b1.tokenName //<<" on the tmp list" //<< std::endl; } if (b2.tokenNumber >= 0) { tmpVector.push_back(b2); //LogTrace("L1TGlobal") //<< " Push operand " << b2.tokenName //<<" on the tmp list" //<< std::endl; } } break; case OP_AND: { newOperandBlock = false; operandOnly = false; b1 = tmpStack.top(); tmpStack.pop(); b2 = tmpStack.top(); tmpStack.pop(); tmpStack.push(dummyToken); if (b1.tokenNumber >= 0) { tmpVector.push_back(b1); //LogTrace("L1TGlobal") //<< " Push operand " << b1.tokenName //<<" on the tmp list" //<< std::endl; } if (b2.tokenNumber >= 0) { tmpVector.push_back(b2); //LogTrace("L1TGlobal") //<< " Push operand " << b2.tokenName //<<" on the tmp list" //<< std::endl; } } break; default: { // should not arrive here } break; } } // one block only or one operand only if (oneBlockOnly || operandOnly) { // one operand only - // there can be only one operand, otherwise one needs an operation if (operandOnly) { b1 = tmpStack.top(); tmpVector.push_back(b1); } // for (std::vector<OperandToken>::reverse_iterator itOp = tmpVector.rbegin(); itOp != tmpVector.rend(); itOp++) { opVector.push_back(*itOp); //LogTrace("L1TGlobal") //<< " One block or one operand only: push operand " << (*itOp).tokenName //<<" on the seed operand list" //<< std::endl; } } else { //LogTrace("L1TGlobal") // << " More blocks: push the last block on the seed operand list" << std::endl; for (std::vector<OperandToken>::reverse_iterator itOp = tmpVector.rbegin(); itOp != tmpVector.rend(); itOp++) { opVector.push_back(*itOp); //LogTrace("L1TGlobal") //<< " Push operand: " << (*itOp).tokenName //<<" on the seed operand list" //<< std::endl; } } // remove duplicates from the seed vector // slow... std::vector<OperandToken> opVectorU; opVectorU.reserve(opVector.size()); for (std::vector<OperandToken>::const_iterator constIt = opVector.begin(); constIt != opVector.end(); constIt++) { bool tokenIncluded = false; for (std::vector<OperandToken>::iterator itOpU = opVectorU.begin(); itOpU != opVectorU.end(); itOpU++) { if ((*itOpU).tokenName == (*constIt).tokenName) { tokenIncluded = true; break; } } if (!tokenIncluded) { opVectorU.push_back(*constIt); } } return opVectorU; } // private methods /** * getOperation Get the operation from a string and check if it is allowed * * @param tokenString The string to examine. * @param lastOperation The last operation. * @param rpnToken The destination where the token for postfix notation is written to. * * @return The Operation type or OP_INVALID, if the operation is not allowed * */ GlobalLogicParser::OperationType GlobalLogicParser::getOperation(const std::string& tokenString, OperationType lastOperation, TokenRPN& rpnToken) const { OperationType actualOperation = OP_OPERAND; // default value int i = 0; while (m_operationRules[i].opType != OP_OPERAND) { if (tokenString == m_operationRules[i].opString) { actualOperation = (OperationType)m_operationRules[i].opType; break; } i++; } // check if the operation is allowed if (m_operationRules[i].forbiddenLastOperation & lastOperation) { return OP_INVALID; } // if (actualOperation == OP_OPERAND) { rpnToken.operand = tokenString; } else { rpnToken.operand = ""; } rpnToken.operation = actualOperation; // else we got a valid operation return actualOperation; } /** * getRuleFromType Looks for the entry in the operation rules * and returns a reference if it was found * * @param oType The type of the operation. * * @return The reference to the entry or 0 if the Rule was not found. * */ const GlobalLogicParser::OperationRule* GlobalLogicParser::getRuleFromType(OperationType oType) { int i = 0; while ((m_operationRules[i].opType != oType) && (m_operationRules[i].opType != OP_NULL)) { i++; } if (m_operationRules[i].opType == OP_NULL) { return nullptr; } return &(m_operationRules[i]); } // add spaces before and after parentheses - make separation easier void GlobalLogicParser::addBracketSpaces(const std::string& srcExpression, std::string& dstExpression) { static const std::string brackets = "()"; // the brackets to be found dstExpression = srcExpression; // copy the string size_t position = 0; while ((position = dstExpression.find_first_of(brackets, position)) != std::string::npos) { // add space after if none is there if (((position + 1) != std::string::npos) && (dstExpression[position + 1] != ' ')) { dstExpression.insert(position + 1, " "); } // add space before if none is there if ((position != 0) && (dstExpression[position - 1] != ' ')) { dstExpression.insert(position, " "); position++; } position++; } } // set the logical expression - check for correctness the input string bool GlobalLogicParser::setLogicalExpression(const std::string& logicalExpressionVal) { // add spaces around brackets std::string logicalExpressionBS; addBracketSpaces(logicalExpressionVal, logicalExpressionBS); // trim leading or trailing spaces boost::trim(logicalExpressionBS); clearRpnVector(); if (!buildRpnVector(logicalExpressionBS)) { m_logicalExpression = ""; return false; } m_logicalExpression = logicalExpressionBS; //LogDebug("L1TGlobal") //<< "\nGtLogicParser::setLogicalExpression - " //<< "\nLogical expression = '" << m_logicalExpression << "'\n" //<< std::endl; return true; } // set the numerical expression (the logical expression with each operand // replaced with the value) from a string // check also for correctness the input string bool GlobalLogicParser::setNumericalExpression(const std::string& numericalExpressionVal) { // add spaces around brackets std::string numericalExpressionBS; addBracketSpaces(numericalExpressionVal, numericalExpressionBS); // check for consistency with the logical expression // TODO FIXME // trim leading or trailing spaces boost::trim(numericalExpressionBS); m_numericalExpression = numericalExpressionBS; //LogDebug("L1TGlobal") //<< "\nGtLogicParser::setNumericalExpression - " //<< "\nNumerical Expression = '" << m_numericalExpression << "'\n" //<< std::endl; return true; } // static members // rules for operations // 1st column: operation string // 2nd column: operation type // 3rd column: forbiddenLastOperation (what operation the operator/operand must not follow) const struct GlobalLogicParser::OperationRule GlobalLogicParser::m_operationRules[] = { {"AND", OP_AND, OP_AND | OP_OR | OP_XOR | OP_NOT | OP_OPENBRACKET | OP_NULL}, {"OR", OP_OR, OP_AND | OP_OR | OP_XOR | OP_NOT | OP_OPENBRACKET | OP_NULL}, {"XOR", OP_XOR, OP_AND | OP_OR | OP_XOR | OP_NOT | OP_OPENBRACKET | OP_NULL}, {"NOT", OP_NOT, OP_OPERAND | OP_CLOSEBRACKET}, {"(", OP_OPENBRACKET, OP_OPERAND | OP_CLOSEBRACKET}, {")", OP_CLOSEBRACKET, OP_AND | OP_OR | OP_XOR | OP_NOT | OP_OPENBRACKET}, {nullptr, OP_OPERAND, OP_OPERAND | OP_CLOSEBRACKET}, {nullptr, OP_NULL, OP_NULL}};