2 # This file is used to check PCD logical expression
4 # Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
6 # This program and the accompanying materials are licensed and made available
7 # under the terms and conditions of the BSD License which accompanies this
8 # distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
22 from Logger
import StringTable
as ST
26 # Check if String is comprised by whitespace(0x20), !(0x21), 0x23 - 0x7E
27 # or '\n', '\t', '\f', '\r', '\b', '\0', '\\'
29 # @param String: string to be checked
31 def IsValidBareCString(String
):
32 EscapeList
= ['n', 't', 'f', 'r', 'b', '0', '\\', '"']
38 if Char
not in EscapeList
:
45 if IntChar
!= 0x20 and IntChar
!= 0x09 and IntChar
!= 0x21 \
46 and (IntChar
< 0x23 or IntChar
> 0x7e):
50 # Last char cannot be \ if PreChar is not \
51 if LastChar
== '\\' and PreChar
== LastChar
:
55 def _ValidateToken(Token
):
57 Index
= Token
.find("\"")
59 return IsValidBareCString(Token
[Index
+1:-1])
64 # @param Exception: Exception
66 class _ExprError(Exception):
67 def __init__(self
, Error
= ''):
68 Exception.__init
__(self
)
74 HEX_PATTERN
= '[\t\s]*0[xX][a-fA-F0-9]+'
75 INT_PATTERN
= '[\t\s]*[0-9]+'
76 MACRO_PATTERN
= '[\t\s]*\$\(([A-Z][_A-Z0-9]*)\)'
78 '[\t\s]*[_a-zA-Z][a-zA-Z0-9_]*[\t\s]*\.[\t\s]*[_a-zA-Z][a-zA-Z0-9_]*'
79 QUOTED_PATTERN
= '[\t\s]*L?"[^"]*"'
80 BOOL_PATTERN
= '[\t\s]*(true|True|TRUE|false|False|FALSE)'
81 def __init__(self
, Token
):
88 def SkipWhitespace(self
):
89 for Char
in self
.Token
[self
.Index
:]:
96 # @param OpList: option list
98 def IsCurrentOp(self
, OpList
):
100 LetterOp
= ["EQ", "NE", "GE", "LE", "GT", "LT", "NOT", "and", "AND",
110 for Operator
in OpList
:
111 if not self
.Token
[self
.Index
:].startswith(Operator
):
114 self
.Index
+= len(Operator
)
115 Char
= self
.Token
[self
.Index
: self
.Index
+ 1]
117 if (Operator
in LetterOp
and (Char
== '_' or Char
.isalnum())) \
118 or (Operator
in OpMap
and OpMap
[Operator
] == Char
):
119 self
.Index
-= len(Operator
)
126 ## _LogicalExpressionParser
128 # @param _ExprBase: _ExprBase object
130 class _LogicalExpressionParser(_ExprBase
):
132 # STRINGITEM can only be logical field according to spec
137 # Evaluate to True or False
143 # Just arithmetic expression
147 def __init__(self
, Token
):
148 _ExprBase
.__init
__(self
, Token
)
151 def _CheckToken(self
, MatchList
):
152 for Match
in MatchList
:
153 if Match
and Match
.start() == 0:
154 if not _ValidateToken(
155 self
.Token
[self
.Index
:self
.Index
+Match
.end()]
159 self
.Index
+= Match
.end()
160 if self
.Token
[self
.Index
- 1] == '"':
162 if self
.Token
[self
.Index
:self
.Index
+1] == '_' or \
163 self
.Token
[self
.Index
:self
.Index
+1].isalnum():
164 self
.Index
-= Match
.end()
167 Token
= self
.Token
[self
.Index
- Match
.end():self
.Index
]
168 if Token
.strip() in ["EQ", "NE", "GE", "LE", "GT", "LT",
169 "NOT", "and", "AND", "or", "OR", "XOR"]:
170 self
.Index
-= Match
.end()
177 def IsAtomicNumVal(self
):
181 Match1
= re
.compile(self
.HEX_PATTERN
).match(self
.Token
[self
.Index
:])
186 Match2
= re
.compile(self
.INT_PATTERN
).match(self
.Token
[self
.Index
:])
191 Match3
= re
.compile(self
.MACRO_PATTERN
).match(self
.Token
[self
.Index
:])
196 Match4
= re
.compile(self
.PCD_PATTERN
).match(self
.Token
[self
.Index
:])
198 return self
._CheckToken
([Match1
, Match2
, Match3
, Match4
])
201 def IsAtomicItem(self
):
205 Match1
= re
.compile(self
.MACRO_PATTERN
).match(self
.Token
[self
.Index
:])
210 Match2
= re
.compile(self
.PCD_PATTERN
).match(self
.Token
[self
.Index
:])
215 Match3
= re
.compile(self
.QUOTED_PATTERN
).\
216 match(self
.Token
[self
.Index
:].replace('\\\\', '//').\
217 replace('\\\"', '\\\''))
219 return self
._CheckToken
([Match1
, Match2
, Match3
])
223 def LogicalExpression(self
):
225 while self
.IsCurrentOp(['||', 'OR', 'or', '&&', 'AND', 'and', 'XOR', 'xor', '^']):
226 if self
.Token
[self
.Index
-1] == '|' and self
.Parens
<= 0:
227 raise _ExprError(ST
.ERR_EXPR_OR
% self
.Token
)
228 if Ret
not in [self
.ARITH
, self
.LOGICAL
, self
.REALLOGICAL
, self
.STRINGITEM
]:
229 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
231 if Ret
not in [self
.ARITH
, self
.LOGICAL
, self
.REALLOGICAL
, self
.STRINGITEM
]:
232 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
233 Ret
= self
.REALLOGICAL
237 if self
.IsCurrentOp(["NOT", "!", "not"]):
238 return self
.SpecNot()
241 ## A < B, A > B, A <= B, A >= B
245 if self
.IsCurrentOp(["<=", ">=", ">", "<", "GT", "LT", "GE", "LE",
246 "==", "EQ", "!=", "NE"]):
247 if Ret
== self
.STRINGITEM
:
248 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
250 if Ret
== self
.REALLOGICAL
:
251 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
252 Ret
= self
.REALLOGICAL
259 while self
.IsCurrentOp(["+", "-", "&", "|", "^", "XOR", "xor"]):
260 if self
.Token
[self
.Index
-1] == '|' and self
.Parens
<= 0:
261 raise _ExprError(ST
.ERR_EXPR_OR
)
262 if Ret
== self
.STRINGITEM
or Ret
== self
.REALLOGICAL
:
263 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
265 if Ret
== self
.STRINGITEM
or Ret
== self
.REALLOGICAL
:
266 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
273 if self
.IsCurrentOp(["("]):
275 Ret
= self
.LogicalExpression()
276 if not self
.IsCurrentOp([")"]):
277 raise _ExprError(ST
.ERR_EXPR_RIGHT_PAREN
% \
278 (self
.Token
, self
.Token
[self
.Index
:]))
282 if self
.IsAtomicItem():
283 if self
.Token
[self
.Index
- 1] == '"':
284 return self
.STRINGITEM
286 elif self
.IsAtomicNumVal():
289 raise _ExprError(ST
.ERR_EXPR_FACTOR
% \
290 (self
.Token
[self
.Index
:], self
.Token
))
292 ## IsValidLogicalExpression
294 def IsValidLogicalExpression(self
):
296 return False, ST
.ERR_EXPRESS_EMPTY
298 if self
.LogicalExpression() not in [self
.ARITH
, self
.LOGICAL
, self
.REALLOGICAL
, self
.STRINGITEM
]:
299 return False, ST
.ERR_EXPR_LOGICAL
% self
.Token
300 except _ExprError
, XExcept
:
301 return False, XExcept
.Error
302 self
.SkipWhitespace()
303 if self
.Index
!= self
.Len
:
304 return False, (ST
.ERR_EXPR_BOOLEAN
% \
305 (self
.Token
[self
.Index
:], self
.Token
))
308 ## _ValidRangeExpressionParser
310 class _ValidRangeExpressionParser(_ExprBase
):
311 INT_RANGE_PATTERN
= '[\t\s]*[0-9]+[\t\s]*-[\t\s]*[0-9]+'
312 HEX_RANGE_PATTERN
= \
313 '[\t\s]*0[xX][a-fA-F0-9]+[\t\s]*-[\t\s]*0[xX][a-fA-F0-9]+'
314 def __init__(self
, Token
):
315 _ExprBase
.__init
__(self
, Token
)
319 self
.IsParenHappen
= False
320 self
.IsLogicalOpHappen
= False
322 ## IsValidRangeExpression
324 def IsValidRangeExpression(self
):
326 return False, ST
.ERR_EXPR_RANGE_EMPTY
328 if self
.RangeExpression() not in [self
.HEX
, self
.INT
]:
329 return False, ST
.ERR_EXPR_RANGE
% self
.Token
330 except _ExprError
, XExcept
:
331 return False, XExcept
.Error
333 self
.SkipWhitespace()
334 if self
.Index
!= self
.Len
:
335 return False, (ST
.ERR_EXPR_RANGE
% self
.Token
)
340 def RangeExpression(self
):
342 while self
.IsCurrentOp(['OR', 'AND', 'and', 'or']):
343 self
.IsLogicalOpHappen
= True
344 if not self
.IsParenHappen
:
345 raise _ExprError(ST
.ERR_PAREN_NOT_USED
% self
.Token
)
346 self
.IsParenHappen
= False
349 if self
.IsCurrentOp(['XOR']):
357 if self
.IsCurrentOp(["NOT"]):
360 return self
.ValidRange()
364 def ValidRange(self
):
366 if self
.IsCurrentOp(["("]):
367 self
.IsLogicalOpHappen
= False
368 self
.IsParenHappen
= True
371 raise _ExprError(ST
.ERR_EXPR_RANGE_DOUBLE_PAREN_NESTED
% self
.Token
)
372 Ret
= self
.RangeExpression()
373 if not self
.IsCurrentOp([")"]):
374 raise _ExprError(ST
.ERR_EXPR_RIGHT_PAREN
% self
.Token
)
378 if self
.IsLogicalOpHappen
:
379 raise _ExprError(ST
.ERR_PAREN_NOT_USED
% self
.Token
)
381 if self
.IsCurrentOp(["LT", "GT", "LE", "GE", "EQ", "XOR"]):
383 re
.compile(self
.INT_PATTERN
).match(self
.Token
[self
.Index
:])
385 re
.compile(self
.HEX_PATTERN
).match(self
.Token
[self
.Index
:])
386 if HexMatch
and HexMatch
.start() == 0:
387 self
.Index
+= HexMatch
.end()
389 elif IntMatch
and IntMatch
.start() == 0:
390 self
.Index
+= IntMatch
.end()
393 raise _ExprError(ST
.ERR_EXPR_RANGE_FACTOR
% (self
.Token
[self
.Index
:], self
.Token
))
395 IntRangeMatch
= re
.compile(
396 self
.INT_RANGE_PATTERN
).match(self
.Token
[self
.Index
:]
398 HexRangeMatch
= re
.compile(
399 self
.HEX_RANGE_PATTERN
).match(self
.Token
[self
.Index
:]
401 if HexRangeMatch
and HexRangeMatch
.start() == 0:
402 self
.Index
+= HexRangeMatch
.end()
404 elif IntRangeMatch
and IntRangeMatch
.start() == 0:
405 self
.Index
+= IntRangeMatch
.end()
408 raise _ExprError(ST
.ERR_EXPR_RANGE
% self
.Token
)
412 ## _ValidListExpressionParser
414 class _ValidListExpressionParser(_ExprBase
):
415 VALID_LIST_PATTERN
= '(0[xX][0-9a-fA-F]+|[0-9]+)([\t\s]*,[\t\s]*(0[xX][0-9a-fA-F]+|[0-9]+))*'
416 def __init__(self
, Token
):
417 _ExprBase
.__init
__(self
, Token
)
420 def IsValidListExpression(self
):
422 return False, ST
.ERR_EXPR_LIST_EMPTY
424 if self
.ListExpression() not in [self
.NUM
]:
425 return False, ST
.ERR_EXPR_LIST
% self
.Token
426 except _ExprError
, XExcept
:
427 return False, XExcept
.Error
429 self
.SkipWhitespace()
430 if self
.Index
!= self
.Len
:
431 return False, (ST
.ERR_EXPR_LIST
% self
.Token
)
435 def ListExpression(self
):
437 self
.SkipWhitespace()
438 ListMatch
= re
.compile(self
.VALID_LIST_PATTERN
).match(self
.Token
[self
.Index
:])
439 if ListMatch
and ListMatch
.start() == 0:
440 self
.Index
+= ListMatch
.end()
443 raise _ExprError(ST
.ERR_EXPR_LIST
% self
.Token
)
449 class _StringTestParser(_ExprBase
):
450 def __init__(self
, Token
):
451 _ExprBase
.__init
__(self
, Token
)
455 def IsValidStringTest(self
):
457 return False, ST
.ERR_EXPR_EMPTY
460 except _ExprError
, XExcept
:
461 return False, XExcept
.Error
466 def StringItem(self
):
467 Match1
= re
.compile(self
.QUOTED_PATTERN
)\
468 .match(self
.Token
[self
.Index
:].replace('\\\\', '//')\
469 .replace('\\\"', '\\\''))
470 Match2
= re
.compile(self
.MACRO_PATTERN
).match(self
.Token
[self
.Index
:])
471 Match3
= re
.compile(self
.PCD_PATTERN
).match(self
.Token
[self
.Index
:])
472 MatchList
= [Match1
, Match2
, Match3
]
473 for Match
in MatchList
:
474 if Match
and Match
.start() == 0:
475 if not _ValidateToken(
476 self
.Token
[self
.Index
:self
.Index
+Match
.end()]
478 raise _ExprError(ST
.ERR_EXPR_STRING_ITEM
% \
479 (self
.Token
, self
.Token
[self
.Index
:]))
480 self
.Index
+= Match
.end()
481 Token
= self
.Token
[self
.Index
- Match
.end():self
.Index
]
482 if Token
.strip() in ["EQ", "NE"]:
483 raise _ExprError(ST
.ERR_EXPR_STRING_ITEM
% \
484 (self
.Token
, self
.Token
[self
.Index
:]))
487 raise _ExprError(ST
.ERR_EXPR_STRING_ITEM
% \
488 (self
.Token
, self
.Token
[self
.Index
:]))
492 def StringTest(self
):
494 if not self
.IsCurrentOp(["==", "EQ", "!=", "NE"]):
495 raise _ExprError(ST
.ERR_EXPR_EQUALITY
% \
496 (self
.Token
[self
.Index
:], self
.Token
))
498 if self
.Index
!= self
.Len
:
499 raise _ExprError(ST
.ERR_EXPR_BOOLEAN
% \
500 (self
.Token
[self
.Index
:], self
.Token
))
503 # Check syntax of string test
505 # @param Token: string test token
507 def IsValidStringTest(Token
, Flag
=False):
509 # Not do the check right now, keep the implementation for future enhancement.
513 return _StringTestParser(Token
).IsValidStringTest()
517 # Check syntax of logical expression
519 # @param Token: expression token
521 def IsValidLogicalExpr(Token
, Flag
=False):
523 # Not do the check right now, keep the implementation for future enhancement.
527 return _LogicalExpressionParser(Token
).IsValidLogicalExpression()
530 # Check syntax of range expression
532 # @param Token: range expression token
534 def IsValidRangeExpr(Token
):
535 return _ValidRangeExpressionParser(Token
).IsValidRangeExpression()
538 # Check syntax of value list expression token
540 # @param Token: value list expression token
542 def IsValidListExpr(Token
):
543 return _ValidListExpressionParser(Token
).IsValidListExpression()
546 # Check whether the feature flag expression is valid or not
548 # @param Token: feature flag expression
550 def IsValidFeatureFlagExp(Token
, Flag
=False):
552 # Not do the check right now, keep the implementation for future enhancement.
555 return True, "", Token
557 if Token
in ['TRUE', 'FALSE', 'true', 'false', 'True', 'False',
558 '0x1', '0x01', '0x0', '0x00']:
560 Valid
, Cause
= IsValidStringTest(Token
, Flag
)
562 Valid
, Cause
= IsValidLogicalExpr(Token
, Flag
)
567 if __name__
== '__main__':
568 # print IsValidRangeExpr('LT 9')
569 print _LogicalExpressionParser('gCrownBayTokenSpaceGuid.PcdPciDevice1BridgeAddressLE0').IsValidLogicalExpression()