]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/UPT/Library/ExpressionValidate.py
Fix the typo for the structure definition of EFI_ADAPTER_INFO_NETWORK_BOOT in Adapter...
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Library / ExpressionValidate.py
CommitLineData
4234283c
LG
1## @file\r
2# This file is used to check PCD logical expression\r
3#\r
4# Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
5#\r
6# This program and the accompanying materials are licensed and made available \r
7# under the terms and conditions of the BSD License which accompanies this \r
8# distribution. The full text of the license may be found at \r
9# http://opensource.org/licenses/bsd-license.php\r
10#\r
11# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14'''\r
15ExpressionValidate\r
16'''\r
17\r
18##\r
19# Import Modules\r
20#\r
21import re\r
22from Logger import StringTable as ST\r
23\r
24## IsValidBareCString\r
25#\r
26# Check if String is comprised by whitespace(0x20), !(0x21), 0x23 - 0x7E\r
27# or '\n', '\t', '\f', '\r', '\b', '\0', '\\'\r
28#\r
29# @param String: string to be checked\r
30#\r
31def IsValidBareCString(String):\r
32 EscapeList = ['n', 't', 'f', 'r', 'b', '0', '\\', '"']\r
33 PreChar = ''\r
34 LastChar = ''\r
35 for Char in String:\r
36 LastChar = Char\r
37 if PreChar == '\\':\r
38 if Char not in EscapeList:\r
39 return False\r
40 if Char == '\\':\r
41 PreChar = ''\r
42 continue\r
43 else:\r
44 IntChar = ord(Char)\r
45 if IntChar != 0x20 and IntChar != 0x09 and IntChar != 0x21 \\r
46 and (IntChar < 0x23 or IntChar > 0x7e):\r
47 return False\r
48 PreChar = Char\r
49 \r
50 # Last char cannot be \ if PreChar is not \\r
51 if LastChar == '\\' and PreChar == LastChar:\r
52 return False\r
53 return True\r
54\r
55def _ValidateToken(Token):\r
56 Token = Token.strip()\r
57 Index = Token.find("\"")\r
58 if Index != -1:\r
59 return IsValidBareCString(Token[Index+1:-1])\r
60 return True\r
61\r
62## _ExprError\r
63#\r
64# @param Exception: Exception\r
65#\r
66class _ExprError(Exception):\r
67 def __init__(self, Error = ''):\r
68 Exception.__init__(self)\r
69 self.Error = Error\r
70\r
71## _ExprBase\r
72#\r
73class _ExprBase:\r
74 HEX_PATTERN = '[\t\s]*0[xX][a-fA-F0-9]+'\r
75 INT_PATTERN = '[\t\s]*[0-9]+'\r
76 MACRO_PATTERN = '[\t\s]*\$\(([A-Z][_A-Z0-9]*)\)'\r
77 PCD_PATTERN = \\r
78 '[\t\s]*[_a-zA-Z][a-zA-Z0-9_]*[\t\s]*\.[\t\s]*[_a-zA-Z][a-zA-Z0-9_]*'\r
79 QUOTED_PATTERN = '[\t\s]*L?"[^"]*"'\r
80 BOOL_PATTERN = '[\t\s]*(true|True|TRUE|false|False|FALSE)'\r
81 def __init__(self, Token):\r
82 self.Token = Token\r
83 self.Index = 0\r
84 self.Len = len(Token)\r
85 \r
86 ## SkipWhitespace\r
87 #\r
88 def SkipWhitespace(self):\r
89 for Char in self.Token[self.Index:]:\r
90 if Char not in ' \t':\r
91 break\r
92 self.Index += 1\r
93 \r
94 ## IsCurrentOp\r
95 #\r
96 # @param OpList: option list
97 # \r
98 def IsCurrentOp(self, OpList):\r
99 self.SkipWhitespace()\r
100 LetterOp = ["EQ", "NE", "GE", "LE", "GT", "LT", "NOT", "and", "AND", \r
101 "or", "OR", "XOR"]\r
102 OpMap = {\r
103 '|' : '|',\r
104 '&' : '&',\r
105 '!' : '=',\r
106 '>' : '=',\r
107 '<' : '='\r
108 }\r
109 for Operator in OpList:\r
110 if not self.Token[self.Index:].startswith(Operator):\r
111 continue\r
112 self.Index += len(Operator)\r
113 Char = self.Token[self.Index : self.Index + 1]\r
114 if (Operator in LetterOp and (Char == '_' or Char.isalnum())) \\r
115 or (Operator in OpMap and OpMap[Operator] == Char):\r
116 self.Index -= len(Operator)\r
117 break\r
118 return True\r
119 return False\r
120\r
121## _LogicalExpressionParser\r
122#\r
123# @param _ExprBase: _ExprBase object\r
124# \r
125class _LogicalExpressionParser(_ExprBase):\r
126 #\r
127 # STRINGITEM can only be logical field according to spec\r
128 #\r
129 STRINGITEM = -1\r
130 \r
131 #\r
132 # Evaluate to True or False\r
133 #\r
134 LOGICAL = 0\r
135 REALLOGICAL = 2\r
136 \r
137 #\r
138 # Just arithmetic expression\r
139 #\r
140 ARITH = 1\r
141 \r
142 def __init__(self, Token):\r
143 _ExprBase.__init__(self, Token)\r
144 self.Parens = 0\r
145 \r
146 def _CheckToken(self, MatchList):\r
147 for Match in MatchList:\r
148 if Match and Match.start() == 0:\r
149 if not _ValidateToken(\r
150 self.Token[self.Index:self.Index+Match.end()]\r
151 ):\r
152 return False\r
153 \r
154 self.Index += Match.end()\r
155 if self.Token[self.Index - 1] == '"':\r
156 return True\r
157 if self.Token[self.Index:self.Index+1] == '_' or \\r
158 self.Token[self.Index:self.Index+1].isalnum():\r
159 self.Index -= Match.end()\r
160 return False\r
161 \r
162 Token = self.Token[self.Index - Match.end():self.Index]\r
163 if Token.strip() in ["EQ", "NE", "GE", "LE", "GT", "LT",\r
164 "NOT", "and", "AND", "or", "OR", "XOR"]:\r
165 self.Index -= Match.end()\r
166 return False\r
167 \r
168 return True\r
169 return False\r
170 \r
171 def IsAtomicNumVal(self):\r
172 #\r
173 # Hex number\r
174 #\r
175 Match1 = re.compile(self.HEX_PATTERN).match(self.Token[self.Index:])\r
176 \r
177 #\r
178 # Number\r
179 #\r
180 Match2 = re.compile(self.INT_PATTERN).match(self.Token[self.Index:])\r
181 \r
182 #\r
183 # Macro\r
184 #\r
185 Match3 = re.compile(self.MACRO_PATTERN).match(self.Token[self.Index:])\r
186 \r
187 #\r
188 # PcdName\r
189 #\r
190 Match4 = re.compile(self.PCD_PATTERN).match(self.Token[self.Index:])\r
191 \r
192 return self._CheckToken([Match1, Match2, Match3, Match4])\r
193 \r
194\r
195 def IsAtomicItem(self):\r
196 #\r
197 # Macro\r
198 #\r
199 Match1 = re.compile(self.MACRO_PATTERN).match(self.Token[self.Index:])\r
200 \r
201 #\r
202 # PcdName\r
203 #\r
204 Match2 = re.compile(self.PCD_PATTERN).match(self.Token[self.Index:])\r
205 \r
206 #\r
207 # Quoted string\r
208 #\r
209 Match3 = re.compile(self.QUOTED_PATTERN).\\r
210 match(self.Token[self.Index:].replace('\\\\', '//').\\r
211 replace('\\\"', '\\\''))\r
212 \r
213 return self._CheckToken([Match1, Match2, Match3])\r
214 \r
215 ## A || B\r
216 #\r
217 def LogicalExpression(self):\r
218 Ret = self.SpecNot()\r
219 while self.IsCurrentOp(['||', 'OR', 'or', '&&', 'AND', 'and', 'XOR']):\r
220 if self.Token[self.Index-1] == '|' and self.Parens <= 0:\r
221 raise _ExprError(ST.ERR_EXPR_OR)\r
222 if Ret == self.ARITH:\r
223 raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)\r
224 Ret = self.SpecNot()\r
225 if Ret == self.ARITH:\r
226 raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)\r
227 Ret = self.REALLOGICAL\r
228 return Ret\r
229 \r
230 def SpecNot(self):\r
231 if self.IsCurrentOp(["NOT", "!"]):\r
232 return self.SpecNot()\r
233 return self.Rel()\r
234 \r
235 ## A < B, A > B, A <= B, A >= b\r
236 #\r
237 def Rel(self):\r
238 Ret = self.Expr()\r
239 if self.IsCurrentOp(["<=", ">=", ">", "<", "GT", "LT", "GE", "LE",\r
240 "==", "EQ", "!=", "NE"]):\r
241 if Ret == self.STRINGITEM or Ret == self.REALLOGICAL:\r
242 raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)\r
243 Ret = self.Expr()\r
244 if Ret == self.STRINGITEM or Ret == self.REALLOGICAL:\r
245 raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)\r
246 Ret = self.REALLOGICAL\r
247 return Ret\r
248 \r
249 ## A + B, A - B\r
250 #\r
251 def Expr(self):\r
252 Ret = self.Factor()\r
253 while self.IsCurrentOp(["+", "-", "&", "|", "^"]):\r
254 if self.Token[self.Index-1] == '|' and self.Parens <= 0:\r
255 raise _ExprError(ST.ERR_EXPR_OR)\r
256 if Ret == self.STRINGITEM or Ret == self.REALLOGICAL:\r
257 raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)\r
258 Ret = self.Factor()\r
259 if Ret == self.STRINGITEM or Ret == self.REALLOGICAL:\r
260 raise _ExprError(ST.ERR_EXPR_LOGICAL % self.Token)\r
261 Ret = self.ARITH\r
262 return Ret\r
263\r
264 ## Factor\r
265 # \r
266 def Factor(self):\r
267 if self.IsCurrentOp(["("]):\r
268 self.Parens += 1\r
269 Ret = self.LogicalExpression()\r
270 if not self.IsCurrentOp([")"]):\r
271 raise _ExprError(ST.ERR_EXPR_RIGHT_PAREN % \\r
272 (self.Token, self.Token[self.Index:]))\r
273 self.Parens -= 1\r
274 return Ret\r
275 \r
276 if self.IsAtomicItem():\r
277 if self.Token[self.Index - 1] == '"':\r
278 return self.STRINGITEM\r
279 return self.LOGICAL\r
280 elif self.IsAtomicNumVal():\r
281 return self.ARITH\r
282 else:\r
283 raise _ExprError(ST.ERR_EXPR_FACTOR % \\r
284 (self.Token, self.Token[self.Index:]))\r
285 \r
286 ## IsValidLogicalExpression\r
287 #\r
288 def IsValidLogicalExpression(self):\r
289 if self.Len == 0:\r
290 return False, ST.ERR_EXPR_EMPTY\r
291 try:\r
292 if self.LogicalExpression() == self.ARITH:\r
293 return False, ST.ERR_EXPR_LOGICAL % self.Token\r
294 except _ExprError, XExcept:\r
295 return False, XExcept.Error\r
296 self.SkipWhitespace()\r
297 if self.Index != self.Len:\r
298 return False, (ST.ERR_EXPR_BOOLEAN % \\r
299 (self.Token[self.Index:], self.Token))\r
300 return True, ''\r
301\r
302## _ValidRangeExpressionParser\r
303#\r
304class _ValidRangeExpressionParser(_ExprBase):\r
305 INT_RANGE_PATTERN = '[\t\s]*[0-9]+[\t\s]*-[\t\s]*[0-9]+'\r
306 HEX_RANGE_PATTERN = \\r
307 '[\t\s]*0[xX][a-fA-F0-9]+[\t\s]*-[\t\s]*0[xX][a-fA-F0-9]+'\r
308 def __init__(self, Token):\r
309 _ExprBase.__init__(self, Token)\r
310 \r
311 ## IsValidRangeExpression\r
312 #\r
313 def IsValidRangeExpression(self):\r
314 if self.Len == 0:\r
315 return False\r
316 try:\r
317 self.RangeExpression()\r
318 except _ExprError:\r
319 return False\r
320 self.SkipWhitespace()\r
321 if self.Index != self.Len:\r
322 return False\r
323 return True\r
324 \r
325 ## RangeExpression\r
326 #\r
327 def RangeExpression(self):\r
328 self.Unary()\r
329 while self.IsCurrentOp(['OR', 'AND', 'XOR']):\r
330 self.Unary()\r
331 \r
332 ## Unary\r
333 #\r
334 def Unary(self):\r
335 if self.IsCurrentOp(["NOT", "-"]):\r
336 return self.Unary()\r
337 return self.ValidRange()\r
338 \r
339 ## ValidRange\r
340 # \r
341 def ValidRange(self):\r
342 if self.IsCurrentOp(["("]):\r
343 self.RangeExpression()\r
344 if not self.IsCurrentOp([")"]):\r
345 raise _ExprError('')\r
346 return\r
347 \r
348 if self.IsCurrentOp(["LT", "GT", "LE", "GE", "EQ"]):\r
349 IntMatch = \\r
350 re.compile(self.INT_PATTERN).match(self.Token[self.Index:])\r
351 HexMatch = \\r
352 re.compile(self.HEX_PATTERN).match(self.Token[self.Index:])\r
353 if HexMatch and HexMatch.start() == 0:\r
354 self.Index += HexMatch.end()\r
355 elif IntMatch and IntMatch.start() == 0:\r
356 self.Index += IntMatch.end()\r
357 else:\r
358 raise _ExprError('')\r
359 else:\r
360 IntRangeMatch = re.compile(\r
361 self.INT_RANGE_PATTERN).match(self.Token[self.Index:]\r
362 )\r
363 HexRangeMatch = re.compile(\r
364 self.HEX_RANGE_PATTERN).match(self.Token[self.Index:]\r
365 )\r
366 if HexRangeMatch and HexRangeMatch.start() == 0:\r
367 self.Index += HexRangeMatch.end()\r
368 elif IntRangeMatch and IntRangeMatch.start() == 0:\r
369 self.Index += IntRangeMatch.end()\r
370 else:\r
371 raise _ExprError('')\r
372 \r
373 if self.Token[self.Index:self.Index+1] == '_' or \\r
374 self.Token[self.Index:self.Index+1].isalnum():\r
375 raise _ExprError('')\r
376\r
377## _StringTestParser\r
378#\r
379class _StringTestParser(_ExprBase):\r
380 def __init__(self, Token):\r
381 _ExprBase.__init__(self, Token)\r
382\r
383 ## IsValidStringTest\r
384 # \r
385 def IsValidStringTest(self):\r
386 if self.Len == 0:\r
387 return False, ST.ERR_EXPR_EMPTY\r
388 try:\r
389 self.StringTest()\r
390 except _ExprError, XExcept:\r
391 return False, XExcept.Error\r
392 return True, ''\r
393\r
394 ## StringItem\r
395 # \r
396 def StringItem(self):\r
397 Match1 = re.compile(self.QUOTED_PATTERN)\\r
398 .match(self.Token[self.Index:].replace('\\\\', '//')\\r
399 .replace('\\\"', '\\\''))\r
400 Match2 = re.compile(self.MACRO_PATTERN).match(self.Token[self.Index:])\r
401 Match3 = re.compile(self.PCD_PATTERN).match(self.Token[self.Index:])\r
402 MatchList = [Match1, Match2, Match3]\r
403 for Match in MatchList:\r
404 if Match and Match.start() == 0:\r
405 if not _ValidateToken(\r
406 self.Token[self.Index:self.Index+Match.end()]\r
407 ):\r
408 raise _ExprError(ST.ERR_EXPR_STRING_ITEM % \\r
409 (self.Token, self.Token[self.Index:]))\r
410 self.Index += Match.end()\r
411 Token = self.Token[self.Index - Match.end():self.Index]\r
412 if Token.strip() in ["EQ", "NE"]:\r
413 raise _ExprError(ST.ERR_EXPR_STRING_ITEM % \\r
414 (self.Token, self.Token[self.Index:]))\r
415 return\r
416 else:\r
417 raise _ExprError(ST.ERR_EXPR_STRING_ITEM % \\r
418 (self.Token, self.Token[self.Index:]))\r
419\r
420 ## StringTest\r
421 # \r
422 def StringTest(self):\r
423 self.StringItem()\r
424 if not self.IsCurrentOp(["==", "EQ", "!=", "NE"]):\r
425 raise _ExprError(ST.ERR_EXPR_EQUALITY % \\r
426 (self.Token, self.Token[self.Index:]))\r
427 self.StringItem()\r
428 if self.Index != self.Len:\r
429 raise _ExprError(ST.ERR_EXPR_BOOLEAN % \\r
430 (self.Token[self.Index:], self.Token))\r
431\r
432##\r
433# Check syntax of logical expression\r
434#\r
435# @param Token: expression token\r
436#\r
437def IsValidLogicalExpr(Token, Flag=False):\r
438 #\r
439 # Not do the check right now, keep the implementation for future enhancement.\r
440 #\r
441 if not Flag:\r
442 return True, ""\r
443 return _LogicalExpressionParser(Token).IsValidLogicalExpression()\r
444\r
445##\r
446# Check syntax of string test\r
447#\r
448# @param Token: string test token\r
449#\r
450def IsValidStringTest(Token, Flag=False):\r
451 #\r
452 # Not do the check right now, keep the implementation for future enhancement.\r
453 #\r
454 if not Flag:\r
455 return True, ""\r
456 return _StringTestParser(Token).IsValidStringTest()\r
457\r
458##\r
459# Check syntax of range expression\r
460#\r
461# @param Token: range expression token\r
462#\r
463def IsValidRangeExpr(Token):\r
464 return _ValidRangeExpressionParser(Token).IsValidRangeExpression()\r
465\r
466##\r
467# Check whether the feature flag expression is valid or not\r
468#\r
469# @param Token: feature flag expression\r
470#\r
471def IsValidFeatureFlagExp(Token, Flag=False):\r
472 #\r
473 # Not do the check right now, keep the implementation for future enhancement.\r
474 #\r
475 if not Flag:\r
476 return True, "", Token\r
477 else:\r
478 if Token in ['TRUE', 'FALSE', 'true', 'false', 'True', 'False',\r
479 '0x1', '0x01', '0x0', '0x00']:\r
480 return True, ""\r
481 Valid, Cause = IsValidStringTest(Token, Flag)\r
482 if not Valid:\r
483 Valid, Cause = IsValidLogicalExpr(Token, Flag)\r
484 if not Valid:\r
485 return False, Cause \r
486 return True, ""\r
487\r
488if __name__ == '__main__':\r
489 print _LogicalExpressionParser('a ^ b > a + b').IsValidLogicalExpression()\r