| /* | |
| * Copyright (c) 2011-2014, Intel Corporation | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without modification, | |
| * are permitted provided that the following conditions are met: | |
| * | |
| * 1. Redistributions of source code must retain the above copyright notice, this | |
| * list of conditions and the following disclaimer. | |
| * | |
| * 2. Redistributions in binary form must reproduce the above copyright notice, | |
| * this list of conditions and the following disclaimer in the documentation and/or | |
| * other materials provided with the distribution. | |
| * | |
| * 3. Neither the name of the copyright holder nor the names of its contributors | |
| * may be used to endorse or promote products derived from this software without | |
| * specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
| * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #include "RuleParser.h" | |
| #include "CompoundRule.h" | |
| #include "SelectionCriterionRule.h" | |
| #include "AlwaysAssert.hpp" | |
| #include <assert.h> | |
| using std::string; | |
| // Matches | |
| const char *CRuleParser::_acDelimiters[CRuleParser::ENbStatuses] = { | |
| "{", // EInit | |
| "{} ", // EBeginCompoundRule | |
| ",}", // EEndCompoundRule | |
| ",}", // ECriterionRule | |
| "{ ", // EContinue | |
| "" // EDone | |
| }; | |
| CRuleParser::CRuleParser(const string &strApplicationRule, | |
| const CSelectionCriteriaDefinition *pSelectionCriteriaDefinition) | |
| : _strApplicationRule(strApplicationRule), | |
| _pSelectionCriteriaDefinition(pSelectionCriteriaDefinition) | |
| { | |
| } | |
| CRuleParser::~CRuleParser() | |
| { | |
| delete _pRootRule; | |
| } | |
| // Parse | |
| bool CRuleParser::parse(CCompoundRule *pParentRule, string &strError) | |
| { | |
| while (true) { | |
| // Iterate till next relevant delimiter | |
| if (!iterate(strError)) { | |
| return false; | |
| } | |
| switch (_eStatus) { | |
| case EBeginCompoundRule: { | |
| // Create new compound rule | |
| auto pCompoundRule = new CCompoundRule; | |
| // Parse | |
| if (!pCompoundRule->parse(*this, strError)) { | |
| delete pCompoundRule; | |
| return false; | |
| } | |
| // Parent rule creation context? | |
| if (pParentRule) { | |
| // Chain | |
| pParentRule->addChild(pCompoundRule); | |
| } else { | |
| // Root rule | |
| delete _pRootRule; | |
| _pRootRule = pCompoundRule; | |
| } | |
| // Parse | |
| if (!parse(pCompoundRule, strError)) { | |
| return false; | |
| } | |
| // Go on | |
| break; | |
| } | |
| case EEndCompoundRule: | |
| return true; | |
| case EContinue: | |
| // Seek for new rule | |
| break; | |
| case ECriterionRule: { | |
| // Create new criterion rule | |
| auto pCriterionRule = new CSelectionCriterionRule; | |
| // Parse | |
| if (!pCriterionRule->parse(*this, strError)) { | |
| delete pCriterionRule; | |
| return false; | |
| } | |
| ALWAYS_ASSERT(pParentRule != nullptr, "Invalid parent rule given to rule parser"); | |
| // Chain | |
| pParentRule->addChild(pCriterionRule); | |
| // Go on | |
| break; | |
| } | |
| case EDone: { | |
| // If the current state is EDone, check that at least one rule has been found. | |
| if (_pRootRule) { | |
| // At least one rule found | |
| return true; | |
| } else { | |
| strError = "Syntax error, no rule found"; | |
| return false; | |
| } | |
| } | |
| default: | |
| assert(0); | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| // Iterate | |
| bool CRuleParser::iterate(string &strError) | |
| { | |
| string::size_type delimiter; | |
| ALWAYS_ASSERT(_uiCurrentPos <= _strApplicationRule.length(), "Current Position outside range"); | |
| // Consume spaces | |
| if ((delimiter = _strApplicationRule.find_first_not_of(" ", _uiCurrentPos)) != string::npos) { | |
| // New pos | |
| _uiCurrentPos = delimiter; | |
| } | |
| // Parse | |
| if ((_uiCurrentPos != _strApplicationRule.length()) && | |
| ((delimiter = _strApplicationRule.find_first_of(_acDelimiters[_eStatus], _uiCurrentPos)) != | |
| string::npos)) { | |
| switch (_strApplicationRule[delimiter]) { | |
| case '{': | |
| _eStatus = EBeginCompoundRule; | |
| // Extract type | |
| _strRuleType = _strApplicationRule.substr(_uiCurrentPos, delimiter - _uiCurrentPos); | |
| _currentDeepness++; | |
| break; | |
| case '}': | |
| _eStatus = EEndCompoundRule; | |
| if (!_currentDeepness--) { | |
| strError = "Missing opening brace"; | |
| return false; | |
| } | |
| break; | |
| case ' ': | |
| _eStatus = ECriterionRule; | |
| // Extract type | |
| _strRuleType = _strApplicationRule.substr(_uiCurrentPos, delimiter - _uiCurrentPos); | |
| break; | |
| case ',': | |
| _eStatus = EContinue; | |
| break; | |
| } | |
| // New pos | |
| _uiCurrentPos = delimiter + 1; | |
| } else { | |
| if (_currentDeepness) { | |
| strError = "Missing closing brace"; | |
| return false; | |
| } | |
| // Remaining characters | |
| if (_uiCurrentPos != _strApplicationRule.length()) { | |
| strError = "Syntax error"; | |
| return false; | |
| } | |
| // Done | |
| _eStatus = EDone; | |
| } | |
| return true; | |
| } | |
| // Rule type | |
| const string &CRuleParser::getType() const | |
| { | |
| return _strRuleType; | |
| } | |
| // Criteria defintion | |
| const CSelectionCriteriaDefinition *CRuleParser::getSelectionCriteriaDefinition() const | |
| { | |
| return _pSelectionCriteriaDefinition; | |
| } | |
| // Root rule | |
| CCompoundRule *CRuleParser::grabRootRule() | |
| { | |
| CCompoundRule *pRootRule = _pRootRule; | |
| assert(pRootRule); | |
| _pRootRule = nullptr; | |
| return pRootRule; | |
| } | |
| // Next word | |
| bool CRuleParser::next(string &strNext, string &strError) | |
| { | |
| string::size_type delimiter; | |
| // Consume spaces | |
| if ((delimiter = _strApplicationRule.find_first_not_of(" ", _uiCurrentPos)) != string::npos) { | |
| // New pos | |
| _uiCurrentPos = delimiter; | |
| } | |
| if ((delimiter = _strApplicationRule.find_first_of("{} ,", _uiCurrentPos)) == string::npos) { | |
| strError = "Syntax error"; | |
| return false; | |
| } | |
| strNext = _strApplicationRule.substr(_uiCurrentPos, delimiter - _uiCurrentPos); | |
| // New pos | |
| _uiCurrentPos = delimiter; | |
| return true; | |
| } |