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 <assert.h> 34 35 using std::string; 36 37 // Matches 38 const char* CRuleParser::_acDelimiters[CRuleParser::ENbStatuses] = { 39 "{", // EInit 40 "{} ", // EBeginCompoundRule 41 ",}", // EEndCompoundRule 42 ",}", // ECriterionRule 43 "{ ", // EContinue 44 "" // EDone 45 }; 46 47 CRuleParser::CRuleParser(const string& strApplicationRule, const CSelectionCriteriaDefinition* pSelectionCriteriaDefinition) : 48 _strApplicationRule(strApplicationRule), 49 _pSelectionCriteriaDefinition(pSelectionCriteriaDefinition), 50 _uiCurrentPos(0), 51 _uiCurrentDeepness(0), 52 _eStatus(CRuleParser::EInit), 53 _pRootRule(NULL) 54 { 55 } 56 57 CRuleParser::~CRuleParser() 58 { 59 delete _pRootRule; 60 } 61 62 // Parse 63 bool CRuleParser::parse(CCompoundRule* pParentRule, string& strError) 64 { 65 while (true) { 66 // Iterate till next relevant delimiter 67 if (!iterate(strError)) { 68 69 return false; 70 } 71 switch(_eStatus) { 72 case EBeginCompoundRule: { 73 74 // Create new compound rule 75 CCompoundRule* pCompoundRule = new CCompoundRule; 76 77 // Parse 78 if (!pCompoundRule->parse(*this, strError)) { 79 80 delete pCompoundRule; 81 82 return false; 83 } 84 // Parent rule creation context? 85 if (pParentRule) { 86 87 // Chain 88 pParentRule->addChild(pCompoundRule); 89 } else { 90 // Root rule 91 delete _pRootRule; 92 _pRootRule = pCompoundRule; 93 } 94 // Parse 95 if (!parse(pCompoundRule, strError)) { 96 97 return false; 98 } 99 // Go on 100 break; 101 } 102 case EEndCompoundRule: 103 return true; 104 case EContinue: 105 // Seek for new rule 106 break; 107 case ECriterionRule: { 108 // Create new criterion rule 109 CSelectionCriterionRule* pCriterionRule = new CSelectionCriterionRule; 110 111 // Parse 112 if (!pCriterionRule->parse(*this, strError)) { 113 114 delete pCriterionRule; 115 116 return false; 117 } 118 119 // Chain 120 pParentRule->addChild(pCriterionRule); 121 122 // Go on 123 break; 124 } 125 case EDone: { 126 // If the current state is EDone, check that at least one rule has been found. 127 if (_pRootRule) { 128 129 // At least one rule found 130 return true; 131 } else { 132 133 strError = "Syntax error, no rule found"; 134 135 return false; 136 } 137 138 } 139 default: 140 assert(0); 141 return false; 142 } 143 } 144 145 return true; 146 } 147 148 // Iterate 149 bool CRuleParser::iterate(string& strError) 150 { 151 string::size_type delimiter; 152 153 assert(_uiCurrentPos <= _strApplicationRule.length()); 154 155 // Consume spaces 156 if ((delimiter = _strApplicationRule.find_first_not_of(" ", _uiCurrentPos)) != string::npos) { 157 158 // New pos 159 _uiCurrentPos = delimiter; 160 } 161 162 // Parse 163 if ((_uiCurrentPos != _strApplicationRule.length()) && ((delimiter = _strApplicationRule.find_first_of(_acDelimiters[_eStatus], _uiCurrentPos)) != string::npos)) { 164 165 switch(_strApplicationRule[delimiter]) { 166 167 case '{': 168 _eStatus = EBeginCompoundRule; 169 // Extract type 170 _strRuleType = _strApplicationRule.substr(_uiCurrentPos, delimiter - _uiCurrentPos); 171 _uiCurrentDeepness++; 172 break; 173 case '}': 174 _eStatus = EEndCompoundRule; 175 176 if (!_uiCurrentDeepness--) { 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 (_uiCurrentDeepness) { 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 217 const string& CRuleParser::getType() const 218 { 219 return _strRuleType; 220 } 221 222 // Criteria defintion 223 const CSelectionCriteriaDefinition* CRuleParser::getSelectionCriteriaDefinition() const 224 { 225 return _pSelectionCriteriaDefinition; 226 } 227 228 // Root rule 229 CCompoundRule* CRuleParser::grabRootRule() 230 { 231 CCompoundRule* pRootRule = _pRootRule; 232 233 assert(pRootRule); 234 235 _pRootRule = NULL; 236 237 return pRootRule; 238 } 239 240 // Next word 241 bool 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