| /* |
| * 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 |
| CCompoundRule *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 |
| CSelectionCriterionRule *pCriterionRule = new CSelectionCriterionRule; |
| |
| // Parse |
| if (!pCriterionRule->parse(*this, strError)) { |
| |
| delete pCriterionRule; |
| |
| return false; |
| } |
| |
| ALWAYS_ASSERT(pParentRule != NULL, "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 = NULL; |
| |
| 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; |
| } |