2 # This file is used to check PCD logical expression
4 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
11 from __future__
import print_function
17 from Logger
import StringTable
as ST
21 # Check if String is comprised by whitespace(0x20), !(0x21), 0x23 - 0x7E
22 # or '\n', '\t', '\f', '\r', '\b', '\0', '\\'
24 # @param String: string to be checked
26 def IsValidBareCString(String
):
27 EscapeList
= ['n', 't', 'f', 'r', 'b', '0', '\\', '"']
33 if Char
not in EscapeList
:
40 if IntChar
!= 0x20 and IntChar
!= 0x09 and IntChar
!= 0x21 \
41 and (IntChar
< 0x23 or IntChar
> 0x7e):
45 # Last char cannot be \ if PreChar is not \
46 if LastChar
== '\\' and PreChar
== LastChar
:
50 def _ValidateToken(Token
):
52 Index
= Token
.find("\"")
54 return IsValidBareCString(Token
[Index
+1:-1])
59 # @param Exception: Exception
61 class _ExprError(Exception):
62 def __init__(self
, Error
= ''):
63 Exception.__init
__(self
)
69 HEX_PATTERN
= '[\t\s]*0[xX][a-fA-F0-9]+'
70 INT_PATTERN
= '[\t\s]*[0-9]+'
71 MACRO_PATTERN
= '[\t\s]*\$\(([A-Z][_A-Z0-9]*)\)'
73 '[\t\s]*[_a-zA-Z][a-zA-Z0-9_]*[\t\s]*\.[\t\s]*[_a-zA-Z][a-zA-Z0-9_]*'
74 QUOTED_PATTERN
= '[\t\s]*L?"[^"]*"'
75 BOOL_PATTERN
= '[\t\s]*(true|True|TRUE|false|False|FALSE)'
76 def __init__(self
, Token
):
83 def SkipWhitespace(self
):
84 for Char
in self
.Token
[self
.Index
:]:
91 # @param OpList: option list
93 def IsCurrentOp(self
, OpList
):
95 LetterOp
= ["EQ", "NE", "GE", "LE", "GT", "LT", "NOT", "and", "AND",
105 for Operator
in OpList
:
106 if not self
.Token
[self
.Index
:].startswith(Operator
):
109 self
.Index
+= len(Operator
)
110 Char
= self
.Token
[self
.Index
: self
.Index
+ 1]
112 if (Operator
in LetterOp
and (Char
== '_' or Char
.isalnum())) \
113 or (Operator
in OpMap
and OpMap
[Operator
] == Char
):
114 self
.Index
-= len(Operator
)
121 ## _LogicalExpressionParser
123 # @param _ExprBase: _ExprBase object
125 class _LogicalExpressionParser(_ExprBase
):
127 # STRINGITEM can only be logical field according to spec
132 # Evaluate to True or False
138 # Just arithmetic expression
142 def __init__(self
, Token
):
143 _ExprBase
.__init
__(self
, Token
)
146 def _CheckToken(self
, MatchList
):
147 for Match
in MatchList
:
148 if Match
and Match
.start() == 0:
149 if not _ValidateToken(
150 self
.Token
[self
.Index
:self
.Index
+Match
.end()]
154 self
.Index
+= Match
.end()
155 if self
.Token
[self
.Index
- 1] == '"':
157 if self
.Token
[self
.Index
:self
.Index
+1] == '_' or \
158 self
.Token
[self
.Index
:self
.Index
+1].isalnum():
159 self
.Index
-= Match
.end()
162 Token
= self
.Token
[self
.Index
- Match
.end():self
.Index
]
163 if Token
.strip() in ["EQ", "NE", "GE", "LE", "GT", "LT",
164 "NOT", "and", "AND", "or", "OR", "XOR"]:
165 self
.Index
-= Match
.end()
172 def IsAtomicNumVal(self
):
176 Match1
= re
.compile(self
.HEX_PATTERN
).match(self
.Token
[self
.Index
:])
181 Match2
= re
.compile(self
.INT_PATTERN
).match(self
.Token
[self
.Index
:])
186 Match3
= re
.compile(self
.MACRO_PATTERN
).match(self
.Token
[self
.Index
:])
191 Match4
= re
.compile(self
.PCD_PATTERN
).match(self
.Token
[self
.Index
:])
193 return self
._CheckToken
([Match1
, Match2
, Match3
, Match4
])
196 def IsAtomicItem(self
):
200 Match1
= re
.compile(self
.MACRO_PATTERN
).match(self
.Token
[self
.Index
:])
205 Match2
= re
.compile(self
.PCD_PATTERN
).match(self
.Token
[self
.Index
:])
210 Match3
= re
.compile(self
.QUOTED_PATTERN
).\
211 match(self
.Token
[self
.Index
:].replace('\\\\', '//').\
212 replace('\\\"', '\\\''))
214 return self
._CheckToken
([Match1
, Match2
, Match3
])
218 def LogicalExpression(self
):
220 while self
.IsCurrentOp(['||', 'OR', 'or', '&&', 'AND', 'and', 'XOR', 'xor', '^']):
221 if self
.Token
[self
.Index
-1] == '|' and self
.Parens
<= 0:
222 raise _ExprError(ST
.ERR_EXPR_OR
% self
.Token
)
223 if Ret
not in [self
.ARITH
, self
.LOGICAL
, self
.REALLOGICAL
, self
.STRINGITEM
]:
224 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
226 if Ret
not in [self
.ARITH
, self
.LOGICAL
, self
.REALLOGICAL
, self
.STRINGITEM
]:
227 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
228 Ret
= self
.REALLOGICAL
232 if self
.IsCurrentOp(["NOT", "!", "not"]):
233 return self
.SpecNot()
236 ## A < B, A > B, A <= B, A >= B
240 if self
.IsCurrentOp(["<=", ">=", ">", "<", "GT", "LT", "GE", "LE",
241 "==", "EQ", "!=", "NE"]):
242 if Ret
== self
.STRINGITEM
:
243 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
245 if Ret
== self
.REALLOGICAL
:
246 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
247 Ret
= self
.REALLOGICAL
254 while self
.IsCurrentOp(["+", "-", "&", "|", "^", "XOR", "xor"]):
255 if self
.Token
[self
.Index
-1] == '|' and self
.Parens
<= 0:
256 raise _ExprError(ST
.ERR_EXPR_OR
)
257 if Ret
== self
.STRINGITEM
or Ret
== self
.REALLOGICAL
:
258 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
260 if Ret
== self
.STRINGITEM
or Ret
== self
.REALLOGICAL
:
261 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
268 if self
.IsCurrentOp(["("]):
270 Ret
= self
.LogicalExpression()
271 if not self
.IsCurrentOp([")"]):
272 raise _ExprError(ST
.ERR_EXPR_RIGHT_PAREN
% \
273 (self
.Token
, self
.Token
[self
.Index
:]))
277 if self
.IsAtomicItem():
278 if self
.Token
[self
.Index
- 1] == '"':
279 return self
.STRINGITEM
281 elif self
.IsAtomicNumVal():
284 raise _ExprError(ST
.ERR_EXPR_FACTOR
% \
285 (self
.Token
[self
.Index
:], self
.Token
))
287 ## IsValidLogicalExpression
289 def IsValidLogicalExpression(self
):
291 return False, ST
.ERR_EXPRESS_EMPTY
293 if self
.LogicalExpression() not in [self
.ARITH
, self
.LOGICAL
, self
.REALLOGICAL
, self
.STRINGITEM
]:
294 return False, ST
.ERR_EXPR_LOGICAL
% self
.Token
295 except _ExprError
as XExcept
:
296 return False, XExcept
.Error
297 self
.SkipWhitespace()
298 if self
.Index
!= self
.Len
:
299 return False, (ST
.ERR_EXPR_BOOLEAN
% \
300 (self
.Token
[self
.Index
:], self
.Token
))
303 ## _ValidRangeExpressionParser
305 class _ValidRangeExpressionParser(_ExprBase
):
306 INT_RANGE_PATTERN
= '[\t\s]*[0-9]+[\t\s]*-[\t\s]*[0-9]+'
307 HEX_RANGE_PATTERN
= \
308 '[\t\s]*0[xX][a-fA-F0-9]+[\t\s]*-[\t\s]*0[xX][a-fA-F0-9]+'
309 def __init__(self
, Token
):
310 _ExprBase
.__init
__(self
, Token
)
314 self
.IsParenHappen
= False
315 self
.IsLogicalOpHappen
= False
317 ## IsValidRangeExpression
319 def IsValidRangeExpression(self
):
321 return False, ST
.ERR_EXPR_RANGE_EMPTY
323 if self
.RangeExpression() not in [self
.HEX
, self
.INT
]:
324 return False, ST
.ERR_EXPR_RANGE
% self
.Token
325 except _ExprError
as XExcept
:
326 return False, XExcept
.Error
328 self
.SkipWhitespace()
329 if self
.Index
!= self
.Len
:
330 return False, (ST
.ERR_EXPR_RANGE
% self
.Token
)
335 def RangeExpression(self
):
337 while self
.IsCurrentOp(['OR', 'AND', 'and', 'or']):
338 self
.IsLogicalOpHappen
= True
339 if not self
.IsParenHappen
:
340 raise _ExprError(ST
.ERR_PAREN_NOT_USED
% self
.Token
)
341 self
.IsParenHappen
= False
344 if self
.IsCurrentOp(['XOR']):
352 if self
.IsCurrentOp(["NOT"]):
355 return self
.ValidRange()
359 def ValidRange(self
):
361 if self
.IsCurrentOp(["("]):
362 self
.IsLogicalOpHappen
= False
363 self
.IsParenHappen
= True
366 raise _ExprError(ST
.ERR_EXPR_RANGE_DOUBLE_PAREN_NESTED
% self
.Token
)
367 Ret
= self
.RangeExpression()
368 if not self
.IsCurrentOp([")"]):
369 raise _ExprError(ST
.ERR_EXPR_RIGHT_PAREN
% self
.Token
)
373 if self
.IsLogicalOpHappen
:
374 raise _ExprError(ST
.ERR_PAREN_NOT_USED
% self
.Token
)
376 if self
.IsCurrentOp(["LT", "GT", "LE", "GE", "EQ", "XOR"]):
378 re
.compile(self
.INT_PATTERN
).match(self
.Token
[self
.Index
:])
380 re
.compile(self
.HEX_PATTERN
).match(self
.Token
[self
.Index
:])
381 if HexMatch
and HexMatch
.start() == 0:
382 self
.Index
+= HexMatch
.end()
384 elif IntMatch
and IntMatch
.start() == 0:
385 self
.Index
+= IntMatch
.end()
388 raise _ExprError(ST
.ERR_EXPR_RANGE_FACTOR
% (self
.Token
[self
.Index
:], self
.Token
))
390 IntRangeMatch
= re
.compile(
391 self
.INT_RANGE_PATTERN
).match(self
.Token
[self
.Index
:]
393 HexRangeMatch
= re
.compile(
394 self
.HEX_RANGE_PATTERN
).match(self
.Token
[self
.Index
:]
396 if HexRangeMatch
and HexRangeMatch
.start() == 0:
397 self
.Index
+= HexRangeMatch
.end()
399 elif IntRangeMatch
and IntRangeMatch
.start() == 0:
400 self
.Index
+= IntRangeMatch
.end()
403 raise _ExprError(ST
.ERR_EXPR_RANGE
% self
.Token
)
407 ## _ValidListExpressionParser
409 class _ValidListExpressionParser(_ExprBase
):
410 VALID_LIST_PATTERN
= '(0[xX][0-9a-fA-F]+|[0-9]+)([\t\s]*,[\t\s]*(0[xX][0-9a-fA-F]+|[0-9]+))*'
411 def __init__(self
, Token
):
412 _ExprBase
.__init
__(self
, Token
)
415 def IsValidListExpression(self
):
417 return False, ST
.ERR_EXPR_LIST_EMPTY
419 if self
.ListExpression() not in [self
.NUM
]:
420 return False, ST
.ERR_EXPR_LIST
% self
.Token
421 except _ExprError
as XExcept
:
422 return False, XExcept
.Error
424 self
.SkipWhitespace()
425 if self
.Index
!= self
.Len
:
426 return False, (ST
.ERR_EXPR_LIST
% self
.Token
)
430 def ListExpression(self
):
432 self
.SkipWhitespace()
433 ListMatch
= re
.compile(self
.VALID_LIST_PATTERN
).match(self
.Token
[self
.Index
:])
434 if ListMatch
and ListMatch
.start() == 0:
435 self
.Index
+= ListMatch
.end()
438 raise _ExprError(ST
.ERR_EXPR_LIST
% self
.Token
)
444 class _StringTestParser(_ExprBase
):
445 def __init__(self
, Token
):
446 _ExprBase
.__init
__(self
, Token
)
450 def IsValidStringTest(self
):
452 return False, ST
.ERR_EXPR_EMPTY
455 except _ExprError
as XExcept
:
456 return False, XExcept
.Error
461 def StringItem(self
):
462 Match1
= re
.compile(self
.QUOTED_PATTERN
)\
463 .match(self
.Token
[self
.Index
:].replace('\\\\', '//')\
464 .replace('\\\"', '\\\''))
465 Match2
= re
.compile(self
.MACRO_PATTERN
).match(self
.Token
[self
.Index
:])
466 Match3
= re
.compile(self
.PCD_PATTERN
).match(self
.Token
[self
.Index
:])
467 MatchList
= [Match1
, Match2
, Match3
]
468 for Match
in MatchList
:
469 if Match
and Match
.start() == 0:
470 if not _ValidateToken(
471 self
.Token
[self
.Index
:self
.Index
+Match
.end()]
473 raise _ExprError(ST
.ERR_EXPR_STRING_ITEM
% \
474 (self
.Token
, self
.Token
[self
.Index
:]))
475 self
.Index
+= Match
.end()
476 Token
= self
.Token
[self
.Index
- Match
.end():self
.Index
]
477 if Token
.strip() in ["EQ", "NE"]:
478 raise _ExprError(ST
.ERR_EXPR_STRING_ITEM
% \
479 (self
.Token
, self
.Token
[self
.Index
:]))
482 raise _ExprError(ST
.ERR_EXPR_STRING_ITEM
% \
483 (self
.Token
, self
.Token
[self
.Index
:]))
487 def StringTest(self
):
489 if not self
.IsCurrentOp(["==", "EQ", "!=", "NE"]):
490 raise _ExprError(ST
.ERR_EXPR_EQUALITY
% \
491 (self
.Token
[self
.Index
:], self
.Token
))
493 if self
.Index
!= self
.Len
:
494 raise _ExprError(ST
.ERR_EXPR_BOOLEAN
% \
495 (self
.Token
[self
.Index
:], self
.Token
))
498 # Check syntax of string test
500 # @param Token: string test token
502 def IsValidStringTest(Token
, Flag
=False):
504 # Not do the check right now, keep the implementation for future enhancement.
508 return _StringTestParser(Token
).IsValidStringTest()
512 # Check syntax of logical expression
514 # @param Token: expression token
516 def IsValidLogicalExpr(Token
, Flag
=False):
518 # Not do the check right now, keep the implementation for future enhancement.
522 return _LogicalExpressionParser(Token
).IsValidLogicalExpression()
525 # Check syntax of range expression
527 # @param Token: range expression token
529 def IsValidRangeExpr(Token
):
530 return _ValidRangeExpressionParser(Token
).IsValidRangeExpression()
533 # Check syntax of value list expression token
535 # @param Token: value list expression token
537 def IsValidListExpr(Token
):
538 return _ValidListExpressionParser(Token
).IsValidListExpression()
541 # Check whether the feature flag expression is valid or not
543 # @param Token: feature flag expression
545 def IsValidFeatureFlagExp(Token
, Flag
=False):
547 # Not do the check right now, keep the implementation for future enhancement.
550 return True, "", Token
552 if Token
in ['TRUE', 'FALSE', 'true', 'false', 'True', 'False',
553 '0x1', '0x01', '0x0', '0x00']:
555 Valid
, Cause
= IsValidStringTest(Token
, Flag
)
557 Valid
, Cause
= IsValidLogicalExpr(Token
, Flag
)
562 if __name__
== '__main__':
563 # print IsValidRangeExpr('LT 9')
564 print(_LogicalExpressionParser('gCrownBayTokenSpaceGuid.PcdPciDevice1BridgeAddressLE0').IsValidLogicalExpression())