]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/UPT/Library/ExpressionValidate.py
2 # This file is used to check PCD logical expression
4 # Copyright (c) 2011, 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",
109 for Operator
in OpList
:
110 if not self
.Token
[self
.Index
:].startswith(Operator
):
112 self
.Index
+= len(Operator
)
113 Char
= self
.Token
[self
.Index
: self
.Index
+ 1]
114 if (Operator
in LetterOp
and (Char
== '_' or Char
.isalnum())) \
115 or (Operator
in OpMap
and OpMap
[Operator
] == Char
):
116 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()
171 def IsAtomicNumVal(self
):
175 Match1
= re
.compile(self
.HEX_PATTERN
).match(self
.Token
[self
.Index
:])
180 Match2
= re
.compile(self
.INT_PATTERN
).match(self
.Token
[self
.Index
:])
185 Match3
= re
.compile(self
.MACRO_PATTERN
).match(self
.Token
[self
.Index
:])
190 Match4
= re
.compile(self
.PCD_PATTERN
).match(self
.Token
[self
.Index
:])
192 return self
._CheckToken
([Match1
, Match2
, Match3
, Match4
])
195 def IsAtomicItem(self
):
199 Match1
= re
.compile(self
.MACRO_PATTERN
).match(self
.Token
[self
.Index
:])
204 Match2
= re
.compile(self
.PCD_PATTERN
).match(self
.Token
[self
.Index
:])
209 Match3
= re
.compile(self
.QUOTED_PATTERN
).\
210 match(self
.Token
[self
.Index
:].replace('\\\\', '//').\
211 replace('\\\"', '\\\''))
213 return self
._CheckToken
([Match1
, Match2
, Match3
])
217 def LogicalExpression(self
):
219 while self
.IsCurrentOp(['||', 'OR', 'or', '&&', 'AND', 'and', 'XOR']):
220 if self
.Token
[self
.Index
-1] == '|' and self
.Parens
<= 0:
221 raise _ExprError(ST
.ERR_EXPR_OR
)
222 if Ret
== self
.ARITH
:
223 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
225 if Ret
== self
.ARITH
:
226 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
227 Ret
= self
.REALLOGICAL
231 if self
.IsCurrentOp(["NOT", "!"]):
232 return self
.SpecNot()
235 ## A < B, A > B, A <= B, A >= b
239 if self
.IsCurrentOp(["<=", ">=", ">", "<", "GT", "LT", "GE", "LE",
240 "==", "EQ", "!=", "NE"]):
241 if Ret
== self
.STRINGITEM
or Ret
== self
.REALLOGICAL
:
242 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
244 if Ret
== self
.STRINGITEM
or Ret
== self
.REALLOGICAL
:
245 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
246 Ret
= self
.REALLOGICAL
253 while self
.IsCurrentOp(["+", "-", "&", "|", "^"]):
254 if self
.Token
[self
.Index
-1] == '|' and self
.Parens
<= 0:
255 raise _ExprError(ST
.ERR_EXPR_OR
)
256 if Ret
== self
.STRINGITEM
or Ret
== self
.REALLOGICAL
:
257 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
259 if Ret
== self
.STRINGITEM
or Ret
== self
.REALLOGICAL
:
260 raise _ExprError(ST
.ERR_EXPR_LOGICAL
% self
.Token
)
267 if self
.IsCurrentOp(["("]):
269 Ret
= self
.LogicalExpression()
270 if not self
.IsCurrentOp([")"]):
271 raise _ExprError(ST
.ERR_EXPR_RIGHT_PAREN
% \
272 (self
.Token
, self
.Token
[self
.Index
:]))
276 if self
.IsAtomicItem():
277 if self
.Token
[self
.Index
- 1] == '"':
278 return self
.STRINGITEM
280 elif self
.IsAtomicNumVal():
283 raise _ExprError(ST
.ERR_EXPR_FACTOR
% \
284 (self
.Token
, self
.Token
[self
.Index
:]))
286 ## IsValidLogicalExpression
288 def IsValidLogicalExpression(self
):
290 return False, ST
.ERR_EXPR_EMPTY
292 if self
.LogicalExpression() == self
.ARITH
:
293 return False, ST
.ERR_EXPR_LOGICAL
% self
.Token
294 except _ExprError
, XExcept
:
295 return False, XExcept
.Error
296 self
.SkipWhitespace()
297 if self
.Index
!= self
.Len
:
298 return False, (ST
.ERR_EXPR_BOOLEAN
% \
299 (self
.Token
[self
.Index
:], self
.Token
))
302 ## _ValidRangeExpressionParser
304 class _ValidRangeExpressionParser(_ExprBase
):
305 INT_RANGE_PATTERN
= '[\t\s]*[0-9]+[\t\s]*-[\t\s]*[0-9]+'
306 HEX_RANGE_PATTERN
= \
307 '[\t\s]*0[xX][a-fA-F0-9]+[\t\s]*-[\t\s]*0[xX][a-fA-F0-9]+'
308 def __init__(self
, Token
):
309 _ExprBase
.__init
__(self
, Token
)
311 ## IsValidRangeExpression
313 def IsValidRangeExpression(self
):
317 self
.RangeExpression()
320 self
.SkipWhitespace()
321 if self
.Index
!= self
.Len
:
327 def RangeExpression(self
):
329 while self
.IsCurrentOp(['OR', 'AND', 'XOR']):
335 if self
.IsCurrentOp(["NOT", "-"]):
337 return self
.ValidRange()
341 def ValidRange(self
):
342 if self
.IsCurrentOp(["("]):
343 self
.RangeExpression()
344 if not self
.IsCurrentOp([")"]):
348 if self
.IsCurrentOp(["LT", "GT", "LE", "GE", "EQ"]):
350 re
.compile(self
.INT_PATTERN
).match(self
.Token
[self
.Index
:])
352 re
.compile(self
.HEX_PATTERN
).match(self
.Token
[self
.Index
:])
353 if HexMatch
and HexMatch
.start() == 0:
354 self
.Index
+= HexMatch
.end()
355 elif IntMatch
and IntMatch
.start() == 0:
356 self
.Index
+= IntMatch
.end()
360 IntRangeMatch
= re
.compile(
361 self
.INT_RANGE_PATTERN
).match(self
.Token
[self
.Index
:]
363 HexRangeMatch
= re
.compile(
364 self
.HEX_RANGE_PATTERN
).match(self
.Token
[self
.Index
:]
366 if HexRangeMatch
and HexRangeMatch
.start() == 0:
367 self
.Index
+= HexRangeMatch
.end()
368 elif IntRangeMatch
and IntRangeMatch
.start() == 0:
369 self
.Index
+= IntRangeMatch
.end()
373 if self
.Token
[self
.Index
:self
.Index
+1] == '_' or \
374 self
.Token
[self
.Index
:self
.Index
+1].isalnum():
379 class _StringTestParser(_ExprBase
):
380 def __init__(self
, Token
):
381 _ExprBase
.__init
__(self
, Token
)
385 def IsValidStringTest(self
):
387 return False, ST
.ERR_EXPR_EMPTY
390 except _ExprError
, XExcept
:
391 return False, XExcept
.Error
396 def StringItem(self
):
397 Match1
= re
.compile(self
.QUOTED_PATTERN
)\
398 .match(self
.Token
[self
.Index
:].replace('\\\\', '//')\
399 .replace('\\\"', '\\\''))
400 Match2
= re
.compile(self
.MACRO_PATTERN
).match(self
.Token
[self
.Index
:])
401 Match3
= re
.compile(self
.PCD_PATTERN
).match(self
.Token
[self
.Index
:])
402 MatchList
= [Match1
, Match2
, Match3
]
403 for Match
in MatchList
:
404 if Match
and Match
.start() == 0:
405 if not _ValidateToken(
406 self
.Token
[self
.Index
:self
.Index
+Match
.end()]
408 raise _ExprError(ST
.ERR_EXPR_STRING_ITEM
% \
409 (self
.Token
, self
.Token
[self
.Index
:]))
410 self
.Index
+= Match
.end()
411 Token
= self
.Token
[self
.Index
- Match
.end():self
.Index
]
412 if Token
.strip() in ["EQ", "NE"]:
413 raise _ExprError(ST
.ERR_EXPR_STRING_ITEM
% \
414 (self
.Token
, self
.Token
[self
.Index
:]))
417 raise _ExprError(ST
.ERR_EXPR_STRING_ITEM
% \
418 (self
.Token
, self
.Token
[self
.Index
:]))
422 def StringTest(self
):
424 if not self
.IsCurrentOp(["==", "EQ", "!=", "NE"]):
425 raise _ExprError(ST
.ERR_EXPR_EQUALITY
% \
426 (self
.Token
, self
.Token
[self
.Index
:]))
428 if self
.Index
!= self
.Len
:
429 raise _ExprError(ST
.ERR_EXPR_BOOLEAN
% \
430 (self
.Token
[self
.Index
:], self
.Token
))
433 # Check syntax of logical expression
435 # @param Token: expression token
437 def IsValidLogicalExpr(Token
, Flag
=False):
439 # Not do the check right now, keep the implementation for future enhancement.
443 return _LogicalExpressionParser(Token
).IsValidLogicalExpression()
446 # Check syntax of string test
448 # @param Token: string test token
450 def IsValidStringTest(Token
, Flag
=False):
452 # Not do the check right now, keep the implementation for future enhancement.
456 return _StringTestParser(Token
).IsValidStringTest()
459 # Check syntax of range expression
461 # @param Token: range expression token
463 def IsValidRangeExpr(Token
):
464 return _ValidRangeExpressionParser(Token
).IsValidRangeExpression()
467 # Check whether the feature flag expression is valid or not
469 # @param Token: feature flag expression
471 def IsValidFeatureFlagExp(Token
, Flag
=False):
473 # Not do the check right now, keep the implementation for future enhancement.
476 return True, "", Token
478 if Token
in ['TRUE', 'FALSE', 'true', 'false', 'True', 'False',
479 '0x1', '0x01', '0x0', '0x00']:
481 Valid
, Cause
= IsValidStringTest(Token
, Flag
)
483 Valid
, Cause
= IsValidLogicalExpr(Token
, Flag
)
488 if __name__
== '__main__':
489 print _LogicalExpressionParser('a ^ b > a + b').IsValidLogicalExpression()