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 
CRuleParser(const string & strApplicationRule,const CSelectionCriteriaDefinition * pSelectionCriteriaDefinition)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 
~CRuleParser()57 CRuleParser::~CRuleParser()
58 {
59     delete _pRootRule;
60 }
61 
62 // Parse
parse(CCompoundRule * pParentRule,string & strError)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
iterate(string & strError)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
getType() const217 const string& CRuleParser::getType() const
218 {
219     return _strRuleType;
220 }
221 
222 // Criteria defintion
getSelectionCriteriaDefinition() const223 const CSelectionCriteriaDefinition* CRuleParser::getSelectionCriteriaDefinition() const
224 {
225     return _pSelectionCriteriaDefinition;
226 }
227 
228 // Root rule
grabRootRule()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
next(string & strNext,string & strError)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