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.
17 from __future__
import print_function
23 from Logger
import StringTable
as ST
27 # Check if String is comprised by whitespace(0x20), !(0x21), 0x23 - 0x7E
28 # or '\n', '\t', '\f', '\r', '\b', '\0', '\\'
30 # @param String: string to be checked
32 def IsValidBareCString(String
):
33 EscapeList
= ['n', 't', 'f', 'r', 'b', '0', '\\', '"']
39 if Char
not in EscapeList
:
46 if IntChar
!= 0x20 and IntChar
!= 0x09 and IntChar
!= 0x21 \
47 and (IntChar
< 0x23 or IntChar
> 0x7e):
51 # Last char cannot be \ if PreChar is not \
52 if LastChar
== '\\' and PreChar
== LastChar
:
56 def _ValidateToken(Token
):
58 Index
= Token
.find("\"")
60 return IsValidBareCString(Token
[Index
+1:-1])
65 # @param Exception: Exception
67 class _ExprError(Exception):
68 def __init__(self
, Error
= ''):
69 Exception.__init
__(self
)
75 HEX_PATTERN
= '[\t\s]*0[xX][a-fA-F0-9]+'
76 INT_PATTERN
= '[\t\s]*[0-9]+'
77 MACRO_PATTERN
= '[\t\s]*\$\(([A-Z][_A-Z0-9]*)\)'
79 '[\t\s]*[_a-zA-Z][a-zA-Z0-9_]*[\t\s]*\.[\t\s]*[_a-zA-Z][a-zA-Z0-9_]*'
80 QUOTED_PATTERN
= '[\t\s]*L?"[^"]*"'
81 BOOL_PATTERN
= '[\t\s]*(true|True|TRUE|false|False|FALSE)'
82 def __init__(self
, Token
):
89 def SkipWhitespace(self
):
90 for Char
in self
.Token
[self
.Index
:]:
97 # @param OpList: option list
99 def IsCurrentOp(self
, OpList
):
100 self
.SkipWhitespace()
101 LetterOp
= ["EQ", "NE", "GE", "LE", "GT", "LT", "NOT", "and", "AND",
111 for Operator
in OpList
:
112 if not self
.Token
[self
.Index
:].startswith(Operator
):
115 self
.Index
+= len(Operator
)
116 Char
= self
.Token
[self
.Index
: self
.Index
+ 1]
118 if (Operator
in LetterOp
and (Char
== '_' or Char
.isalnum())) \
119 or (Operator
in OpMap
and OpMap
[Operator
] == Char
):
120 self
.Index
-= len(Operator
)
127 ## _LogicalExpressionParser
129 # @param _ExprBase: _ExprBase object
131 class _LogicalExpressionParser(_ExprBase
):
133 # STRINGITEM can only be logical field according to spec
138 # Evaluate to True or False
144 # Just arithmetic expression
148 def __init__(self
, Token
):
149 _ExprBase
.__init
__(self
, Token
)
152 def _CheckToken(self
, MatchList
):
153 for Match
in MatchList
:
154 if Match
and Match
.start() == 0:
155 if not _ValidateToken(
156 self
.Token
[self
.Index
:self
.Index
+Match
.end()]
160 self
.Index
+= Match
.end()
161 if self
.Token
[self
.Index
- 1] == '"':
163 if self
.Token
[self
.Index
:self
.Index
+1] == '_' or \
164 self
.Token
[self
.Index
:self
.Index
+1].isalnum():
165 self
.Index
-= Match
.end()
168 Token
= self
.Token
[self
.Index
- Match
.end():self
.Index
]
169 if Token
.strip() in ["EQ", "NE", "GE", "LE", "GT", "LT",
170 "NOT", "and", "AND", "or", "OR", "XOR"]:
171 self
.Index
-= Match
.end()
178 def IsAtomicNumVal(self
):
182 Match1
= re
.compile(self
.HEX_PATTERN
).match(self
.Token
[self
.Index
:])
187 Match2
= re
.compile(self
.INT_PATTERN
).match(self
.Token
[self
.Index
:])
192 Match3
= re
.compile(self
.MACRO_PATTERN
).match(self
.Token
[self
.Index
:])
197 Match4
= re
.compile(self
.PCD_PATTERN
).match(self
.Token
[self
.Index
:])
199 return self
._CheckToken
([Match1
, Match2
, Match3
, Match4
])
202 def IsAtomicItem(self
):
206 Match1
= re
.compile(self
.MACRO_PATTERN
).match(self
.Token
[self
.Index
:])
211 Match2
= re
.compile(self
.PCD_PATTERN
).match(self
.Token
[self
.Index
:])
216 Match3
= re
.compile(self
.QUOTED_PATTERN
).\
217 match(self
.Token
[self
.Index
:].replace('\\\\', '//').\
218 replace('\\\"', '\\\''))
220 return self
._CheckToken
([Match1
, Match2
, Match3
])
224 def LogicalExpression(self
):
226 while self
.IsCurrentOp(['||', 'OR', 'or', '&&', 'AND', 'and', 'XOR', 'xor', '^']):
227 if self
.Token
[self
.Index
-1] == '|' and self
.Parens
<= 0:
228 raise _ExprError(ST
.ERR_EXPR_OR
% self
.Token
)
229 if Ret
not in [self
.ARITH
, self
.LOGICAL
, self
.REALLOGICAL
, self
.STRINGITEM
]:
230 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
232 if Ret
not in [self
.ARITH
, self
.LOGICAL
, self
.REALLOGICAL
, self
.STRINGITEM
]:
233 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
234 Ret
= self
.REALLOGICAL
238 if self
.IsCurrentOp(["NOT", "!", "not"]):
239 return self
.SpecNot()
242 ## A < B, A > B, A <= B, A >= B
246 if self
.IsCurrentOp(["<=", ">=", ">", "<", "GT", "LT", "GE", "LE",
247 "==", "EQ", "!=", "NE"]):
248 if Ret
== self
.STRINGITEM
:
249 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
251 if Ret
== self
.REALLOGICAL
:
252 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
253 Ret
= self
.REALLOGICAL
260 while self
.IsCurrentOp(["+", "-", "&", "|", "^", "XOR", "xor"]):
261 if self
.Token
[self
.Index
-1] == '|' and self
.Parens
<= 0:
262 raise _ExprError(ST
.ERR_EXPR_OR
)
263 if Ret
== self
.STRINGITEM
or Ret
== self
.REALLOGICAL
:
264 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
266 if Ret
== self
.STRINGITEM
or Ret
== self
.REALLOGICAL
:
267 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
274 if self
.IsCurrentOp(["("]):
276 Ret
= self
.LogicalExpression()
277 if not self
.IsCurrentOp([")"]):
278 raise _ExprError(ST
.ERR_EXPR_RIGHT_PAREN
% \
279 (self
.Token
, self
.Token
[self
.Index
:]))
283 if self
.IsAtomicItem():
284 if self
.Token
[self
.Index
- 1] == '"':
285 return self
.STRINGITEM
287 elif self
.IsAtomicNumVal():
290 raise _ExprError(ST
.ERR_EXPR_FACTOR
% \
291 (self
.Token
[self
.Index
:], self
.Token
))
293 ## IsValidLogicalExpression
295 def IsValidLogicalExpression(self
):
297 return False, ST
.ERR_EXPRESS_EMPTY
299 if self
.LogicalExpression() not in [self
.ARITH
, self
.LOGICAL
, self
.REALLOGICAL
, self
.STRINGITEM
]:
300 return False, ST
.ERR_EXPR_LOGICAL
% self
.Token
301 except _ExprError
as XExcept
:
302 return False, XExcept
.Error
303 self
.SkipWhitespace()
304 if self
.Index
!= self
.Len
:
305 return False, (ST
.ERR_EXPR_BOOLEAN
% \
306 (self
.Token
[self
.Index
:], self
.Token
))
309 ## _ValidRangeExpressionParser
311 class _ValidRangeExpressionParser(_ExprBase
):
312 INT_RANGE_PATTERN
= '[\t\s]*[0-9]+[\t\s]*-[\t\s]*[0-9]+'
313 HEX_RANGE_PATTERN
= \
314 '[\t\s]*0[xX][a-fA-F0-9]+[\t\s]*-[\t\s]*0[xX][a-fA-F0-9]+'
315 def __init__(self
, Token
):
316 _ExprBase
.__init
__(self
, Token
)
320 self
.IsParenHappen
= False
321 self
.IsLogicalOpHappen
= False
323 ## IsValidRangeExpression
325 def IsValidRangeExpression(self
):
327 return False, ST
.ERR_EXPR_RANGE_EMPTY
329 if self
.RangeExpression() not in [self
.HEX
, self
.INT
]:
330 return False, ST
.ERR_EXPR_RANGE
% self
.Token
331 except _ExprError
as XExcept
:
332 return False, XExcept
.Error
334 self
.SkipWhitespace()
335 if self
.Index
!= self
.Len
:
336 return False, (ST
.ERR_EXPR_RANGE
% self
.Token
)
341 def RangeExpression(self
):
343 while self
.IsCurrentOp(['OR', 'AND', 'and', 'or']):
344 self
.IsLogicalOpHappen
= True
345 if not self
.IsParenHappen
:
346 raise _ExprError(ST
.ERR_PAREN_NOT_USED
% self
.Token
)
347 self
.IsParenHappen
= False
350 if self
.IsCurrentOp(['XOR']):
358 if self
.IsCurrentOp(["NOT"]):
361 return self
.ValidRange()
365 def ValidRange(self
):
367 if self
.IsCurrentOp(["("]):
368 self
.IsLogicalOpHappen
= False
369 self
.IsParenHappen
= True
372 raise _ExprError(ST
.ERR_EXPR_RANGE_DOUBLE_PAREN_NESTED
% self
.Token
)
373 Ret
= self
.RangeExpression()
374 if not self
.IsCurrentOp([")"]):
375 raise _ExprError(ST
.ERR_EXPR_RIGHT_PAREN
% self
.Token
)
379 if self
.IsLogicalOpHappen
:
380 raise _ExprError(ST
.ERR_PAREN_NOT_USED
% self
.Token
)
382 if self
.IsCurrentOp(["LT", "GT", "LE", "GE", "EQ", "XOR"]):
384 re
.compile(self
.INT_PATTERN
).match(self
.Token
[self
.Index
:])
386 re
.compile(self
.HEX_PATTERN
).match(self
.Token
[self
.Index
:])
387 if HexMatch
and HexMatch
.start() == 0:
388 self
.Index
+= HexMatch
.end()
390 elif IntMatch
and IntMatch
.start() == 0:
391 self
.Index
+= IntMatch
.end()
394 raise _ExprError(ST
.ERR_EXPR_RANGE_FACTOR
% (self
.Token
[self
.Index
:], self
.Token
))
396 IntRangeMatch
= re
.compile(
397 self
.INT_RANGE_PATTERN
).match(self
.Token
[self
.Index
:]
399 HexRangeMatch
= re
.compile(
400 self
.HEX_RANGE_PATTERN
).match(self
.Token
[self
.Index
:]
402 if HexRangeMatch
and HexRangeMatch
.start() == 0:
403 self
.Index
+= HexRangeMatch
.end()
405 elif IntRangeMatch
and IntRangeMatch
.start() == 0:
406 self
.Index
+= IntRangeMatch
.end()
409 raise _ExprError(ST
.ERR_EXPR_RANGE
% self
.Token
)
413 ## _ValidListExpressionParser
415 class _ValidListExpressionParser(_ExprBase
):
416 VALID_LIST_PATTERN
= '(0[xX][0-9a-fA-F]+|[0-9]+)([\t\s]*,[\t\s]*(0[xX][0-9a-fA-F]+|[0-9]+))*'
417 def __init__(self
, Token
):
418 _ExprBase
.__init
__(self
, Token
)
421 def IsValidListExpression(self
):
423 return False, ST
.ERR_EXPR_LIST_EMPTY
425 if self
.ListExpression() not in [self
.NUM
]:
426 return False, ST
.ERR_EXPR_LIST
% self
.Token
427 except _ExprError
as XExcept
:
428 return False, XExcept
.Error
430 self
.SkipWhitespace()
431 if self
.Index
!= self
.Len
:
432 return False, (ST
.ERR_EXPR_LIST
% self
.Token
)
436 def ListExpression(self
):
438 self
.SkipWhitespace()
439 ListMatch
= re
.compile(self
.VALID_LIST_PATTERN
).match(self
.Token
[self
.Index
:])
440 if ListMatch
and ListMatch
.start() == 0:
441 self
.Index
+= ListMatch
.end()
444 raise _ExprError(ST
.ERR_EXPR_LIST
% self
.Token
)
450 class _StringTestParser(_ExprBase
):
451 def __init__(self
, Token
):
452 _ExprBase
.__init
__(self
, Token
)
456 def IsValidStringTest(self
):
458 return False, ST
.ERR_EXPR_EMPTY
461 except _ExprError
as XExcept
:
462 return False, XExcept
.Error
467 def StringItem(self
):
468 Match1
= re
.compile(self
.QUOTED_PATTERN
)\
469 .match(self
.Token
[self
.Index
:].replace('\\\\', '//')\
470 .replace('\\\"', '\\\''))
471 Match2
= re
.compile(self
.MACRO_PATTERN
).match(self
.Token
[self
.Index
:])
472 Match3
= re
.compile(self
.PCD_PATTERN
).match(self
.Token
[self
.Index
:])
473 MatchList
= [Match1
, Match2
, Match3
]
474 for Match
in MatchList
:
475 if Match
and Match
.start() == 0:
476 if not _ValidateToken(
477 self
.Token
[self
.Index
:self
.Index
+Match
.end()]
479 raise _ExprError(ST
.ERR_EXPR_STRING_ITEM
% \
480 (self
.Token
, self
.Token
[self
.Index
:]))
481 self
.Index
+= Match
.end()
482 Token
= self
.Token
[self
.Index
- Match
.end():self
.Index
]
483 if Token
.strip() in ["EQ", "NE"]:
484 raise _ExprError(ST
.ERR_EXPR_STRING_ITEM
% \
485 (self
.Token
, self
.Token
[self
.Index
:]))
488 raise _ExprError(ST
.ERR_EXPR_STRING_ITEM
% \
489 (self
.Token
, self
.Token
[self
.Index
:]))
493 def StringTest(self
):
495 if not self
.IsCurrentOp(["==", "EQ", "!=", "NE"]):
496 raise _ExprError(ST
.ERR_EXPR_EQUALITY
% \
497 (self
.Token
[self
.Index
:], self
.Token
))
499 if self
.Index
!= self
.Len
:
500 raise _ExprError(ST
.ERR_EXPR_BOOLEAN
% \
501 (self
.Token
[self
.Index
:], self
.Token
))
504 # Check syntax of string test
506 # @param Token: string test token
508 def IsValidStringTest(Token
, Flag
=False):
510 # Not do the check right now, keep the implementation for future enhancement.
514 return _StringTestParser(Token
).IsValidStringTest()
518 # Check syntax of logical expression
520 # @param Token: expression token
522 def IsValidLogicalExpr(Token
, Flag
=False):
524 # Not do the check right now, keep the implementation for future enhancement.
528 return _LogicalExpressionParser(Token
).IsValidLogicalExpression()
531 # Check syntax of range expression
533 # @param Token: range expression token
535 def IsValidRangeExpr(Token
):
536 return _ValidRangeExpressionParser(Token
).IsValidRangeExpression()
539 # Check syntax of value list expression token
541 # @param Token: value list expression token
543 def IsValidListExpr(Token
):
544 return _ValidListExpressionParser(Token
).IsValidListExpression()
547 # Check whether the feature flag expression is valid or not
549 # @param Token: feature flag expression
551 def IsValidFeatureFlagExp(Token
, Flag
=False):
553 # Not do the check right now, keep the implementation for future enhancement.
556 return True, "", Token
558 if Token
in ['TRUE', 'FALSE', 'true', 'false', 'True', 'False',
559 '0x1', '0x01', '0x0', '0x00']:
561 Valid
, Cause
= IsValidStringTest(Token
, Flag
)
563 Valid
, Cause
= IsValidLogicalExpr(Token
, Flag
)
568 if __name__
== '__main__':
569 # print IsValidRangeExpr('LT 9')
570 print(_LogicalExpressionParser('gCrownBayTokenSpaceGuid.PcdPciDevice1BridgeAddressLE0').IsValidLogicalExpression())