1/* 2 * Copyright (c) 2011-2014, Intel Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation and/or 13 * other materials provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors 16 * may be used to endorse or promote products derived from this software without 17 * specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30#include "RuleParser.h" 31#include "CompoundRule.h" 32#include "SelectionCriterionRule.h" 33#include "AlwaysAssert.hpp" 34#include <assert.h> 35 36using std::string; 37 38// Matches 39const char *CRuleParser::_acDelimiters[CRuleParser::ENbStatuses] = { 40 "{", // EInit 41 "{} ", // EBeginCompoundRule 42 ",}", // EEndCompoundRule 43 ",}", // ECriterionRule 44 "{ ", // EContinue 45 "" // EDone 46}; 47 48CRuleParser::CRuleParser(const string &strApplicationRule, 49 const CSelectionCriteriaDefinition *pSelectionCriteriaDefinition) 50 : _strApplicationRule(strApplicationRule), 51 _pSelectionCriteriaDefinition(pSelectionCriteriaDefinition) 52{ 53} 54 55CRuleParser::~CRuleParser() 56{ 57 delete _pRootRule; 58} 59 60// Parse 61bool CRuleParser::parse(CCompoundRule *pParentRule, string &strError) 62{ 63 while (true) { 64 // Iterate till next relevant delimiter 65 if (!iterate(strError)) { 66 67 return false; 68 } 69 switch (_eStatus) { 70 case EBeginCompoundRule: { 71 72 // Create new compound rule 73 CCompoundRule *pCompoundRule = new CCompoundRule; 74 75 // Parse 76 if (!pCompoundRule->parse(*this, strError)) { 77 78 delete pCompoundRule; 79 80 return false; 81 } 82 // Parent rule creation context? 83 if (pParentRule) { 84 85 // Chain 86 pParentRule->addChild(pCompoundRule); 87 } else { 88 // Root rule 89 delete _pRootRule; 90 _pRootRule = pCompoundRule; 91 } 92 // Parse 93 if (!parse(pCompoundRule, strError)) { 94 95 return false; 96 } 97 // Go on 98 break; 99 } 100 case EEndCompoundRule: 101 return true; 102 case EContinue: 103 // Seek for new rule 104 break; 105 case ECriterionRule: { 106 // Create new criterion rule 107 CSelectionCriterionRule *pCriterionRule = new CSelectionCriterionRule; 108 109 // Parse 110 if (!pCriterionRule->parse(*this, strError)) { 111 112 delete pCriterionRule; 113 114 return false; 115 } 116 117 ALWAYS_ASSERT(pParentRule != NULL, "Invalid parent rule given to rule parser"); 118 // Chain 119 pParentRule->addChild(pCriterionRule); 120 121 // Go on 122 break; 123 } 124 case EDone: { 125 // If the current state is EDone, check that at least one rule has been found. 126 if (_pRootRule) { 127 128 // At least one rule found 129 return true; 130 } else { 131 132 strError = "Syntax error, no rule found"; 133 134 return false; 135 } 136 } 137 default: 138 assert(0); 139 return false; 140 } 141 } 142 143 return true; 144} 145 146// Iterate 147bool CRuleParser::iterate(string &strError) 148{ 149 string::size_type delimiter; 150 151 ALWAYS_ASSERT(_uiCurrentPos <= _strApplicationRule.length(), "Current Position outside range"); 152 153 // Consume spaces 154 if ((delimiter = _strApplicationRule.find_first_not_of(" ", _uiCurrentPos)) != string::npos) { 155 156 // New pos 157 _uiCurrentPos = delimiter; 158 } 159 160 // Parse 161 if ((_uiCurrentPos != _strApplicationRule.length()) && 162 ((delimiter = _strApplicationRule.find_first_of(_acDelimiters[_eStatus], _uiCurrentPos)) != 163 string::npos)) { 164 165 switch (_strApplicationRule[delimiter]) { 166 167 case '{': 168 _eStatus = EBeginCompoundRule; 169 // Extract type 170 _strRuleType = _strApplicationRule.substr(_uiCurrentPos, delimiter - _uiCurrentPos); 171 _currentDeepness++; 172 break; 173 case '}': 174 _eStatus = EEndCompoundRule; 175 176 if (!_currentDeepness--) { 177 178 strError = "Missing opening brace"; 179 180 return false; 181 } 182 break; 183 case ' ': 184 _eStatus = ECriterionRule; 185 // Extract type 186 _strRuleType = _strApplicationRule.substr(_uiCurrentPos, delimiter - _uiCurrentPos); 187 break; 188 case ',': 189 _eStatus = EContinue; 190 break; 191 } 192 // New pos 193 _uiCurrentPos = delimiter + 1; 194 } else { 195 196 if (_currentDeepness) { 197 198 strError = "Missing closing brace"; 199 200 return false; 201 } 202 203 // Remaining characters 204 if (_uiCurrentPos != _strApplicationRule.length()) { 205 206 strError = "Syntax error"; 207 208 return false; 209 } 210 // Done 211 _eStatus = EDone; 212 } 213 return true; 214} 215 216// Rule type 217const string &CRuleParser::getType() const 218{ 219 return _strRuleType; 220} 221 222// Criteria defintion 223const CSelectionCriteriaDefinition *CRuleParser::getSelectionCriteriaDefinition() const 224{ 225 return _pSelectionCriteriaDefinition; 226} 227 228// Root rule 229CCompoundRule *CRuleParser::grabRootRule() 230{ 231 CCompoundRule *pRootRule = _pRootRule; 232 233 assert(pRootRule); 234 235 _pRootRule = NULL; 236 237 return pRootRule; 238} 239 240// Next word 241bool CRuleParser::next(string &strNext, string &strError) 242{ 243 string::size_type delimiter; 244 245 // Consume spaces 246 if ((delimiter = _strApplicationRule.find_first_not_of(" ", _uiCurrentPos)) != string::npos) { 247 248 // New pos 249 _uiCurrentPos = delimiter; 250 } 251 252 if ((delimiter = _strApplicationRule.find_first_of("{} ,", _uiCurrentPos)) == string::npos) { 253 254 strError = "Syntax error"; 255 256 return false; 257 } 258 259 strNext = _strApplicationRule.substr(_uiCurrentPos, delimiter - _uiCurrentPos); 260 261 // New pos 262 _uiCurrentPos = delimiter; 263 264 return true; 265} 266