2 # This file is used to parse and evaluate expression in directive or PCD value.
4 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 from __future__
import print_function
16 from __future__
import absolute_import
17 from Common
.GlobalData
import *
18 from CommonDataClass
.Exceptions
import BadExpression
19 from CommonDataClass
.Exceptions
import WrnExpression
20 from .Misc
import GuidStringToGuidStructureString
, ParseFieldValue
21 import Common
.EdkLogger
as EdkLogger
23 from Common
.DataType
import *
25 from random
import sample
28 ERR_STRING_EXPR
= 'This operator cannot be used in string expression: [%s].'
29 ERR_SNYTAX
= 'Syntax error, the rest of expression cannot be evaluated: [%s].'
30 ERR_MATCH
= 'No matching right parenthesis.'
31 ERR_STRING_TOKEN
= 'Bad string token: [%s].'
32 ERR_MACRO_TOKEN
= 'Bad macro token: [%s].'
33 ERR_EMPTY_TOKEN
= 'Empty token is not allowed.'
34 ERR_PCD_RESOLVE
= 'The PCD should be FeatureFlag type or FixedAtBuild type: [%s].'
35 ERR_VALID_TOKEN
= 'No more valid token found from rest of string: [%s].'
36 ERR_EXPR_TYPE
= 'Different types found in expression.'
37 ERR_OPERATOR_UNSUPPORT
= 'Unsupported operator: [%s]'
38 ERR_REL_NOT_IN
= 'Expect "IN" after "not" operator.'
39 WRN_BOOL_EXPR
= 'Operand of boolean type cannot be used in arithmetic expression.'
40 WRN_EQCMP_STR_OTHERS
= '== Comparison between Operand of string type and Boolean/Number Type always return False.'
41 WRN_NECMP_STR_OTHERS
= '!= Comparison between Operand of string type and Boolean/Number Type always return True.'
42 ERR_RELCMP_STR_OTHERS
= 'Operator taking Operand of string type and Boolean/Number Type is not allowed: [%s].'
43 ERR_STRING_CMP
= 'Unicode string and general string cannot be compared: [%s %s %s]'
44 ERR_ARRAY_TOKEN
= 'Bad C array or C format GUID token: [%s].'
45 ERR_ARRAY_ELE
= 'This must be HEX value for NList or Array: [%s].'
46 ERR_EMPTY_EXPR
= 'Empty expression is not allowed.'
47 ERR_IN_OPERAND
= 'Macro after IN operator can only be: $(FAMILY), $(ARCH), $(TOOL_CHAIN_TAG) and $(TARGET).'
49 __ValidString
= re
.compile(r
'[_a-zA-Z][_0-9a-zA-Z]*$')
50 _ReLabel
= re
.compile('LABEL\((\w+)\)')
51 _ReOffset
= re
.compile('OFFSET_OF\((\w+)\)')
52 PcdPattern
= re
.compile(r
'[_a-zA-Z][0-9A-Za-z_]*\.[_a-zA-Z][0-9A-Za-z_]*$')
55 # Split string to list according double quote
56 # For example: abc"de\"f"ghi"jkl"mn will be: ['abc', '"de\"f"', 'ghi', '"jkl"', 'mn']
58 def SplitString(String
):
59 # There might be escaped quote: "abc\"def\\\"ghi", 'abc\'def\\\'ghi'
60 RanStr
= ''.join(sample(string
.ascii_letters
+ string
.digits
, 8))
61 String
= String
.replace('\\\\', RanStr
).strip()
66 for i
, ch
in enumerate(String
):
67 if ch
== '"' and not InSingleQuote
:
68 if String
[i
- 1] != '\\':
69 InDoubleQuote
= not InDoubleQuote
78 elif ch
== "'" and not InDoubleQuote
:
79 if String
[i
- 1] != '\\':
80 InSingleQuote
= not InSingleQuote
90 if InSingleQuote
or InDoubleQuote
:
91 raise BadExpression(ERR_STRING_TOKEN
% Item
)
94 for i
, ch
in enumerate(RetList
):
96 RetList
[i
] = ch
.replace(RanStr
,'\\\\')
99 def SplitPcdValueString(String
):
100 # There might be escaped comma in GUID() or DEVICE_PATH() or " "
101 # or ' ' or L' ' or L" "
102 RanStr
= ''.join(sample(string
.ascii_letters
+ string
.digits
, 8))
103 String
= String
.replace('\\\\', RanStr
).strip()
106 InSingleQuote
= False
107 InDoubleQuote
= False
109 for i
, ch
in enumerate(String
):
116 raise BadExpression(ERR_STRING_TOKEN
% Item
)
117 elif ch
== '"' and not InSingleQuote
:
118 if String
[i
-1] != '\\':
119 InDoubleQuote
= not InDoubleQuote
120 elif ch
== "'" and not InDoubleQuote
:
121 if String
[i
-1] != '\\':
122 InSingleQuote
= not InSingleQuote
124 if InParenthesis
or InSingleQuote
or InDoubleQuote
:
132 if InSingleQuote
or InDoubleQuote
or InParenthesis
:
133 raise BadExpression(ERR_STRING_TOKEN
% Item
)
136 for i
, ch
in enumerate(RetList
):
138 RetList
[i
] = ch
.replace(RanStr
,'\\\\')
141 def IsValidCName(Str
):
142 return True if __ValidString
.match(Str
) else False
144 def BuildOptionValue(PcdValue
, GuidDict
):
145 if PcdValue
.startswith('H'):
146 InputValue
= PcdValue
[1:]
147 elif PcdValue
.startswith("L'") or PcdValue
.startswith("'"):
148 InputValue
= PcdValue
149 elif PcdValue
.startswith('L'):
150 InputValue
= 'L"' + PcdValue
[1:] + '"'
152 InputValue
= PcdValue
154 PcdValue
= ValueExpressionEx(InputValue
, TAB_VOID
, GuidDict
)(True)
162 def ReplaceExprMacro(String
, Macros
, ExceptionList
= None):
163 StrList
= SplitString(String
)
164 for i
, String
in enumerate(StrList
):
166 if String
.startswith('"'):
168 MacroStartPos
= String
.find('$(')
169 if MacroStartPos
< 0:
170 for Pcd
in gPlatformPcds
:
172 if Pcd
not in gConditionalPcds
:
173 gConditionalPcds
.append(Pcd
)
176 while MacroStartPos
>= 0:
177 RetStr
= String
[0:MacroStartPos
]
178 MacroEndPos
= String
.find(')', MacroStartPos
)
180 raise BadExpression(ERR_MACRO_TOKEN
% String
[MacroStartPos
:])
181 Macro
= String
[MacroStartPos
+2:MacroEndPos
]
182 if Macro
not in Macros
:
183 # From C reference manual:
184 # If an undefined macro name appears in the constant-expression of
185 # !if or !elif, it is replaced by the integer constant 0.
188 Tklst
= RetStr
.split()
189 if Tklst
and Tklst
[-1] in {'IN', 'in'} and ExceptionList
and Macro
not in ExceptionList
:
190 raise BadExpression(ERR_IN_OPERAND
)
191 # Make sure the macro in exception list is encapsulated by double quote
192 # For example: DEFINE ARCH = IA32 X64
193 # $(ARCH) is replaced with "IA32 X64"
194 if ExceptionList
and Macro
in ExceptionList
:
195 RetStr
+= '"' + Macros
[Macro
] + '"'
196 elif Macros
[Macro
].strip():
197 RetStr
+= Macros
[Macro
]
201 RetStr
+= Macros
[Macro
]
202 RetStr
+= String
[MacroEndPos
+1:]
204 MacroStartPos
= String
.find('$(')
206 return ''.join(StrList
)
208 # transfer int to string for in/not in expression
212 StrList
.append(chr(Value
& 0xff))
214 Value
= '"' + ''.join(StrList
) + '"'
217 SupportedInMacroList
= ['TARGET', 'TOOL_CHAIN_TAG', 'ARCH', 'FAMILY']
219 class BaseExpression(object):
220 def __init__(self
, *args
, **kwargs
):
221 super(BaseExpression
, self
).__init
__()
223 # Check if current token matches the operators given from parameter
224 def _IsOperator(self
, OpSet
):
227 if self
._Token
in OpSet
:
228 if self
._Token
in self
.LogicalOperators
:
229 self
._Token
= self
.LogicalOperators
[self
._Token
]
234 class ValueExpression(BaseExpression
):
235 # Logical operator mapping
237 '&&' : 'and', '||' : 'or',
238 '!' : 'not', 'AND': 'and',
239 'OR' : 'or' , 'NOT': 'not',
240 'XOR': '^' , 'xor': '^',
241 'EQ' : '==' , 'NE' : '!=',
242 'GT' : '>' , 'LT' : '<',
243 'GE' : '>=' , 'LE' : '<=',
247 NonLetterOpLst
= ['+', '-', '*', '/', '%', '&', '|', '^', '~', '<<', '>>', '!', '=', '>', '<', '?', ':']
250 SymbolPattern
= re
.compile("("
251 "\$\([A-Z][A-Z0-9_]*\)|\$\(\w+\.\w+\)|\w+\.\w+|"
253 "(?<=\W)AND(?=\W)|(?<=\W)OR(?=\W)|(?<=\W)NOT(?=\W)|(?<=\W)XOR(?=\W)|"
254 "(?<=\W)EQ(?=\W)|(?<=\W)NE(?=\W)|(?<=\W)GT(?=\W)|(?<=\W)LT(?=\W)|(?<=\W)GE(?=\W)|(?<=\W)LE(?=\W)"
258 def Eval(Operator
, Oprand1
, Oprand2
= None):
261 if Operator
not in {"==", "!=", ">=", "<=", ">", "<", "in", "not in"} and \
262 (isinstance(Oprand1
, type('')) or isinstance(Oprand2
, type(''))):
263 raise BadExpression(ERR_STRING_EXPR
% Operator
)
264 if Operator
in {'in', 'not in'}:
265 if not isinstance(Oprand1
, type('')):
266 Oprand1
= IntToStr(Oprand1
)
267 if not isinstance(Oprand2
, type('')):
268 Oprand2
= IntToStr(Oprand2
)
271 # For python2 long type
272 type(sys
.maxsize
+ 1) : 0,
278 if Operator
in {"!", "NOT", "not"}:
279 if isinstance(Oprand1
, type('')):
280 raise BadExpression(ERR_STRING_EXPR
% Operator
)
281 EvalStr
= 'not Oprand1'
282 elif Operator
in {"~"}:
283 if isinstance(Oprand1
, type('')):
284 raise BadExpression(ERR_STRING_EXPR
% Operator
)
285 EvalStr
= '~ Oprand1'
287 if Operator
in {"+", "-"} and (type(True) in {type(Oprand1
), type(Oprand2
)}):
288 # Boolean in '+'/'-' will be evaluated but raise warning
289 WrnExp
= WrnExpression(WRN_BOOL_EXPR
)
290 elif type('') in {type(Oprand1
), type(Oprand2
)} and not isinstance(Oprand1
, type(Oprand2
)):
291 # == between string and number/boolean will always return False, != return True
293 WrnExp
= WrnExpression(WRN_EQCMP_STR_OTHERS
)
294 WrnExp
.result
= False
296 elif Operator
== "!=":
297 WrnExp
= WrnExpression(WRN_NECMP_STR_OTHERS
)
301 raise BadExpression(ERR_RELCMP_STR_OTHERS
% Operator
)
302 elif TypeDict
[type(Oprand1
)] != TypeDict
[type(Oprand2
)]:
303 if Operator
in {"==", "!=", ">=", "<=", ">", "<"} and set((TypeDict
[type(Oprand1
)], TypeDict
[type(Oprand2
)])) == set((TypeDict
[type(True)], TypeDict
[type(0)])):
304 # comparison between number and boolean is allowed
306 elif Operator
in {'&', '|', '^', "and", "or"} and set((TypeDict
[type(Oprand1
)], TypeDict
[type(Oprand2
)])) == set((TypeDict
[type(True)], TypeDict
[type(0)])):
307 # bitwise and logical operation between number and boolean is allowed
310 raise BadExpression(ERR_EXPR_TYPE
)
311 if isinstance(Oprand1
, type('')) and isinstance(Oprand2
, type('')):
312 if ((Oprand1
.startswith('L"') or Oprand1
.startswith("L'")) and (not Oprand2
.startswith('L"')) and (not Oprand2
.startswith("L'"))) or \
313 (((not Oprand1
.startswith('L"')) and (not Oprand1
.startswith("L'"))) and (Oprand2
.startswith('L"') or Oprand2
.startswith("L'"))):
314 raise BadExpression(ERR_STRING_CMP
% (Oprand1
, Operator
, Oprand2
))
315 if 'in' in Operator
and isinstance(Oprand2
, type('')):
316 Oprand2
= Oprand2
.split()
317 EvalStr
= 'Oprand1 ' + Operator
+ ' Oprand2'
319 # Local symbols used by built in eval function
325 Val
= eval(EvalStr
, {}, Dict
)
326 except Exception as Excpt
:
327 raise BadExpression(str(Excpt
))
329 if Operator
in {'and', 'or'}:
340 def __init__(self
, Expression
, SymbolTable
={}):
341 super(ValueExpression
, self
).__init
__(self
, Expression
, SymbolTable
)
342 self
._NoProcess
= False
343 if not isinstance(Expression
, type('')):
344 self
._Expr
= Expression
345 self
._NoProcess
= True
348 self
._Expr
= ReplaceExprMacro(Expression
.strip(),
350 SupportedInMacroList
)
352 if not self
._Expr
.strip():
353 raise BadExpression(ERR_EMPTY_EXPR
)
356 # The symbol table including PCD and macro mapping
358 self
._Symb
= copy
.deepcopy(SymbolTable
)
359 self
._Symb
.update(self
.LogicalOperators
)
361 self
._Len
= len(self
._Expr
)
363 self
._WarnExcept
= None
365 # Literal token without any conversion
366 self
._LiteralToken
= ''
368 # Public entry for this class
369 # @param RealValue: False: only evaluate if the expression is true or false, used for conditional expression
370 # True : return the evaluated str(value), used for PCD value
372 # @return: True or False if RealValue is False
373 # Evaluated value of string format if RealValue is True
375 def __call__(self
, RealValue
=False, Depth
=0):
381 self
._Expr
= self
._Expr
.strip()
382 if RealValue
and Depth
== 0:
383 self
._Token
= self
._Expr
384 if self
.__IsNumberToken
():
388 Token
= self
._GetToken
()
389 except BadExpression
:
391 if isinstance(Token
, type('')) and Token
.startswith('{') and Token
.endswith('}') and self
._Idx
>= self
._Len
:
397 Val
= self
._ConExpr
()
399 if isinstance(Val
, type('')):
405 elif not Val
.startswith('L"') and not Val
.startswith('{') and not Val
.startswith("L'") and not Val
.startswith("'"):
407 RealVal
= '"' + RealVal
+ '"'
409 # The expression has been parsed, but the end of expression is not reached
410 # It means the rest does not comply EBNF of <Expression>
411 if self
._Idx
!= self
._Len
:
412 raise BadExpression(ERR_SNYTAX
% self
._Expr
[self
._Idx
:])
415 RetVal
= str(RealVal
)
422 self
._WarnExcept
.result
= RetVal
423 raise self
._WarnExcept
427 # Template function to parse binary operators which have same precedence
428 # Expr [Operator Expr]*
429 def _ExprFuncTemplate(self
, EvalFunc
, OpSet
):
431 while self
._IsOperator
(OpSet
):
435 if self
._IsOperator
({':'}):
443 Val
= self
.Eval(Op
, Val
, EvalFunc())
444 except WrnExpression
as Warn
:
445 self
._WarnExcept
= Warn
450 return self
._ExprFuncTemplate
(self
._OrExpr
, {'?', ':'})
454 return self
._ExprFuncTemplate
(self
._AndExpr
, {"OR", "or", "||"})
458 return self
._ExprFuncTemplate
(self
._BitOr
, {"AND", "and", "&&"})
462 return self
._ExprFuncTemplate
(self
._BitXor
, {"|"})
466 return self
._ExprFuncTemplate
(self
._BitAnd
, {"XOR", "xor", "^"})
470 return self
._ExprFuncTemplate
(self
._EqExpr
, {"&"})
474 Val
= self
._RelExpr
()
475 while self
._IsOperator
({"==", "!=", "EQ", "NE", "IN", "in", "!", "NOT", "not"}):
477 if Op
in {"!", "NOT", "not"}:
478 if not self
._IsOperator
({"IN", "in"}):
479 raise BadExpression(ERR_REL_NOT_IN
)
480 Op
+= ' ' + self
._Token
482 Val
= self
.Eval(Op
, Val
, self
._RelExpr
())
483 except WrnExpression
as Warn
:
484 self
._WarnExcept
= Warn
490 return self
._ExprFuncTemplate
(self
._ShiftExpr
, {"<=", ">=", "<", ">", "LE", "GE", "LT", "GT"})
492 def _ShiftExpr(self
):
493 return self
._ExprFuncTemplate
(self
._AddExpr
, {"<<", ">>"})
497 return self
._ExprFuncTemplate
(self
._MulExpr
, {"+", "-"})
501 return self
._ExprFuncTemplate
(self
._UnaryExpr
, {"*", "/", "%"})
504 def _UnaryExpr(self
):
505 if self
._IsOperator
({"!", "NOT", "not"}):
506 Val
= self
._UnaryExpr
()
508 return self
.Eval('not', Val
)
509 except WrnExpression
as Warn
:
510 self
._WarnExcept
= Warn
512 if self
._IsOperator
({"~"}):
513 Val
= self
._UnaryExpr
()
515 return self
.Eval('~', Val
)
516 except WrnExpression
as Warn
:
517 self
._WarnExcept
= Warn
519 return self
._IdenExpr
()
521 # Parse identifier or encapsulated expression
523 Tk
= self
._GetToken
()
525 Val
= self
._ConExpr
()
527 # _GetToken may also raise BadExpression
528 if self
._GetToken
() != ')':
529 raise BadExpression(ERR_MATCH
)
530 except BadExpression
:
531 raise BadExpression(ERR_MATCH
)
535 # Skip whitespace or tab
537 for Char
in self
._Expr
[self
._Idx
:]:
538 if Char
not in ' \t':
542 # Try to convert string to number
543 def __IsNumberToken(self
):
545 if self
._Token
.lower()[0:2] == '0x' and len(self
._Token
) > 2:
547 if self
._Token
.startswith('"') or self
._Token
.startswith('L"'):
549 for Index
in range(len(self
._Token
)):
550 if self
._Token
[Index
] in {'"'}:
551 if self
._Token
[Index
- 1] == '\\':
554 if Flag
== 2 and self
._Token
.endswith('"'):
556 if self
._Token
.startswith("'") or self
._Token
.startswith("L'"):
558 for Index
in range(len(self
._Token
)):
559 if self
._Token
[Index
] in {"'"}:
560 if self
._Token
[Index
- 1] == '\\':
563 if Flag
== 2 and self
._Token
.endswith("'"):
566 self
._Token
= int(self
._Token
, Radix
)
574 def __GetArray(self
):
577 self
.__GetNList
(True)
578 Token
+= self
._LiteralToken
579 if self
._Idx
>= self
._Len
or self
._Expr
[self
._Idx
] != '}':
580 raise BadExpression(ERR_ARRAY_TOKEN
% Token
)
583 # All whitespace and tabs in array are already stripped.
584 IsArray
= IsGuid
= False
585 if len(Token
.split(',')) == 11 and len(Token
.split(',{')) == 2 \
586 and len(Token
.split('},')) == 1:
587 HexLen
= [11, 6, 6, 5, 4, 4, 4, 4, 4, 4, 6]
588 HexList
= Token
.split(',')
589 if HexList
[3].startswith('{') and \
590 not [Index
for Index
, Hex
in enumerate(HexList
) if len(Hex
) > HexLen
[Index
]]:
592 if Token
.lstrip('{').rstrip('}').find('{') == -1:
593 if not [Hex
for Hex
in Token
.lstrip('{').rstrip('}').split(',') if len(Hex
) > 4]:
595 if not IsArray
and not IsGuid
:
596 raise BadExpression(ERR_ARRAY_TOKEN
% Token
)
598 self
._Token
= self
._LiteralToken
= Token
601 # Parse string, the format must be: "..."
602 def __GetString(self
):
608 # Replace escape \\\", \"
609 if self
._Expr
[Idx
] == '"':
610 Expr
= self
._Expr
[self
._Idx
:].replace('\\\\', '//').replace('\\\"', '\\\'')
615 self
._Token
= self
._LiteralToken
= self
._Expr
[Idx
:self
._Idx
]
616 if not self
._Token
.endswith('"'):
617 raise BadExpression(ERR_STRING_TOKEN
% self
._Token
)
618 #Replace escape \\\', \'
619 elif self
._Expr
[Idx
] == "'":
620 Expr
= self
._Expr
[self
._Idx
:].replace('\\\\', '//').replace("\\\'", "\\\"")
625 self
._Token
= self
._LiteralToken
= self
._Expr
[Idx
:self
._Idx
]
626 if not self
._Token
.endswith("'"):
627 raise BadExpression(ERR_STRING_TOKEN
% self
._Token
)
628 self
._Token
= self
._Token
[1:-1]
631 # Get token that is comprised by alphanumeric, underscore or dot(used by PCD)
632 # @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...)
633 def __GetIdToken(self
, IsAlphaOp
= False):
635 for Ch
in self
._Expr
[self
._Idx
:]:
636 if not self
.__IsIdChar
(Ch
) or ('?' in self
._Expr
and Ch
== ':'):
641 self
._Token
= self
._LiteralToken
= IdToken
643 self
.__ResolveToken
()
646 # Try to resolve token
647 def __ResolveToken(self
):
649 raise BadExpression(ERR_EMPTY_TOKEN
)
652 if PcdPattern
.match(self
._Token
):
653 if self
._Token
not in self
._Symb
:
654 Ex
= BadExpression(ERR_PCD_RESOLVE
% self
._Token
)
657 self
._Token
= ValueExpression(self
._Symb
[self
._Token
], self
._Symb
)(True, self
._Depth
+1)
658 if not isinstance(self
._Token
, type('')):
659 self
._LiteralToken
= hex(self
._Token
)
662 if self
._Token
.startswith('"'):
663 self
._Token
= self
._Token
[1:-1]
664 elif self
._Token
in {"FALSE", "false", "False"}:
666 elif self
._Token
in {"TRUE", "true", "True"}:
669 self
.__IsNumberToken
()
671 def __GetNList(self
, InArray
=False):
672 self
._GetSingleToken
()
673 if not self
.__IsHexLiteral
():
675 raise BadExpression(ERR_ARRAY_ELE
% self
._Token
)
679 Expr
= self
._Expr
[self
._Idx
:]
680 if not Expr
.startswith(','):
683 NList
= self
._LiteralToken
684 while Expr
.startswith(','):
688 self
._GetSingleToken
()
689 if not self
.__IsHexLiteral
():
690 raise BadExpression(ERR_ARRAY_ELE
% self
._Token
)
691 NList
+= self
._LiteralToken
693 Expr
= self
._Expr
[self
._Idx
:]
694 self
._Token
= self
._LiteralToken
= NList
697 def __IsHexLiteral(self
):
698 if self
._LiteralToken
.startswith('{') and \
699 self
._LiteralToken
.endswith('}'):
702 if gHexPattern
.match(self
._LiteralToken
):
703 Token
= self
._LiteralToken
[2:]
705 self
._LiteralToken
= '0x0'
707 self
._LiteralToken
= '0x' + Token
712 return self
.__GetNList
()
716 return Ch
in '._:' or Ch
.isalnum()
719 def _GetSingleToken(self
):
721 Expr
= self
._Expr
[self
._Idx
:]
722 if Expr
.startswith('L"'):
725 UStr
= self
.__GetString
()
726 self
._Token
= 'L"' + UStr
+ '"'
728 elif Expr
.startswith("L'"):
731 UStr
= self
.__GetString
()
732 self
._Token
= "L'" + UStr
+ "'"
734 elif Expr
.startswith("'"):
735 UStr
= self
.__GetString
()
736 self
._Token
= "'" + UStr
+ "'"
738 elif Expr
.startswith('UINT'):
739 Re
= re
.compile('(?:UINT8|UINT16|UINT32|UINT64)\((.+)\)')
741 RetValue
= Re
.search(Expr
).group(1)
743 raise BadExpression('Invalid Expression %s' % Expr
)
748 Prefix
= self
._Expr
[Idx
:self
._Idx
- 1]
751 TmpValue
= self
._Expr
[Idx
:self
._Idx
- 1]
752 TmpValue
= ValueExpression(TmpValue
)(True)
753 TmpValue
= '0x%x' % int(TmpValue
) if not isinstance(TmpValue
, type('')) else TmpValue
755 self
._Token
, Size
= ParseFieldValue(Prefix
+ '(' + TmpValue
+ ')')
761 Match
= gGuidPattern
.match(Expr
)
762 if Match
and not Expr
[Match
.end():Match
.end()+1].isalnum() \
763 and Expr
[Match
.end():Match
.end()+1] != '_':
764 self
._Idx
+= Match
.end()
765 self
._Token
= ValueExpression(GuidStringToGuidStructureString(Expr
[0:Match
.end()]))(True, self
._Depth
+1)
767 elif self
.__IsIdChar
(Ch
):
768 return self
.__GetIdToken
()
770 return self
.__GetString
()
772 return self
.__GetArray
()
773 elif Ch
== '(' or Ch
== ')':
778 raise BadExpression(ERR_VALID_TOKEN
% Expr
)
781 def _GetOperator(self
):
783 LegalOpLst
= ['&&', '||', '!=', '==', '>=', '<='] + self
.NonLetterOpLst
+ ['?', ':']
786 Expr
= self
._Expr
[self
._Idx
:]
788 # Reach end of expression
792 # Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not
793 if Expr
[0].isalpha():
794 return self
.__GetIdToken
(True)
796 # Start to get regular operator: +, -, <, > ...
797 if Expr
[0] not in self
.NonLetterOpLst
:
802 if Ch
in self
.NonLetterOpLst
:
803 if Ch
in ['!', '~'] and OpToken
:
810 if OpToken
not in LegalOpLst
:
811 raise BadExpression(ERR_OPERATOR_UNSUPPORT
% OpToken
)
812 self
._Token
= OpToken
815 class ValueExpressionEx(ValueExpression
):
816 def __init__(self
, PcdValue
, PcdType
, SymbolTable
={}):
817 ValueExpression
.__init
__(self
, PcdValue
, SymbolTable
)
818 self
.PcdValue
= PcdValue
819 self
.PcdType
= PcdType
821 def __call__(self
, RealValue
=False, Depth
=0):
822 PcdValue
= self
.PcdValue
824 PcdValue
= ValueExpression
.__call
__(self
, RealValue
, Depth
)
825 if self
.PcdType
== TAB_VOID
and (PcdValue
.startswith("'") or PcdValue
.startswith("L'")):
826 PcdValue
, Size
= ParseFieldValue(PcdValue
)
828 for I
in range(Size
):
829 PcdValueList
.append('0x%02X'%(PcdValue
& 0xff))
830 PcdValue
= PcdValue
>> 8
831 PcdValue
= '{' + ','.join(PcdValueList
) + '}'
832 elif self
.PcdType
in TAB_PCD_NUMERIC_TYPES
and (PcdValue
.startswith("'") or \
833 PcdValue
.startswith('"') or PcdValue
.startswith("L'") or PcdValue
.startswith('L"') or PcdValue
.startswith('{')):
835 except WrnExpression
as Value
:
836 PcdValue
= Value
.result
837 except BadExpression
as Value
:
838 if self
.PcdType
in TAB_PCD_NUMERIC_TYPES
:
839 PcdValue
= PcdValue
.strip()
840 if PcdValue
.startswith('{') and PcdValue
.endswith('}'):
841 PcdValue
= SplitPcdValueString(PcdValue
[1:-1])
842 if ERR_STRING_CMP
.split(':')[0] in Value
.message
:
843 raise BadExpression("Type: %s, Value: %s, %s" % (self
.PcdType
, PcdValue
, Value
))
844 if isinstance(PcdValue
, type([])):
848 for Item
in PcdValue
:
850 if Item
.startswith(TAB_UINT8
):
852 ValueType
= TAB_UINT8
853 elif Item
.startswith(TAB_UINT16
):
855 ValueType
= TAB_UINT16
856 elif Item
.startswith(TAB_UINT32
):
858 ValueType
= TAB_UINT32
859 elif Item
.startswith(TAB_UINT64
):
861 ValueType
= TAB_UINT64
862 elif Item
[0] in {'"', "'", 'L'}:
867 ValueType
= TAB_UINT8
868 Item
= ValueExpressionEx(Item
, ValueType
, self
._Symb
)(True)
872 tmpValue
= int(Item
, 0)
874 raise BadExpression("Byte array number %s should less than 0xFF." % Item
)
875 except BadExpression
as Value
:
876 raise BadExpression(Value
)
879 ItemValue
, ItemSize
= ParseFieldValue(Item
)
881 ItemValue
= ParseFieldValue(Item
)[0]
883 if isinstance(ItemValue
, type('')):
884 ItemValue
= int(ItemValue
, 0)
886 TmpValue
= (ItemValue
<< (Size
* 8)) | TmpValue
887 Size
= Size
+ ItemSize
890 TmpValue
, Size
= ParseFieldValue(PcdValue
)
891 except BadExpression
as Value
:
892 raise BadExpression("Type: %s, Value: %s, %s" % (self
.PcdType
, PcdValue
, Value
))
893 if isinstance(TmpValue
, type('')):
895 TmpValue
= int(TmpValue
)
897 raise BadExpression(Value
)
899 PcdValue
= '0x%0{}X'.format(Size
) % (TmpValue
)
901 raise BadExpression('Type %s PCD Value is negative' % self
.PcdType
)
902 if self
.PcdType
== TAB_UINT8
and Size
> 1:
903 raise BadExpression('Type %s PCD Value Size is Larger than 1 byte' % self
.PcdType
)
904 if self
.PcdType
== TAB_UINT16
and Size
> 2:
905 raise BadExpression('Type %s PCD Value Size is Larger than 2 byte' % self
.PcdType
)
906 if self
.PcdType
== TAB_UINT32
and Size
> 4:
907 raise BadExpression('Type %s PCD Value Size is Larger than 4 byte' % self
.PcdType
)
908 if self
.PcdType
== TAB_UINT64
and Size
> 8:
909 raise BadExpression('Type %s PCD Value Size is Larger than 8 byte' % self
.PcdType
)
912 TmpValue
= int(PcdValue
)
914 if TmpValue
.bit_length() == 0:
917 for I
in range((TmpValue
.bit_length() + 7) / 8):
918 TmpList
.append('0x%02x' % ((TmpValue
>> I
* 8) & 0xff))
919 PcdValue
= '{' + ', '.join(TmpList
) + '}'
921 if PcdValue
.strip().startswith('{'):
922 PcdValueList
= SplitPcdValueString(PcdValue
.strip()[1:-1])
926 for Item
in PcdValueList
:
927 # compute byte offset of every LABEL
928 LabelList
= _ReLabel
.findall(Item
)
929 Item
= _ReLabel
.sub('', Item
)
932 for Label
in LabelList
:
933 if not IsValidCName(Label
):
934 raise BadExpression('%s is not a valid c variable name' % Label
)
935 if Label
not in LabelDict
:
936 LabelDict
[Label
] = str(LabelOffset
)
937 if Item
.startswith(TAB_UINT8
):
938 LabelOffset
= LabelOffset
+ 1
939 elif Item
.startswith(TAB_UINT16
):
940 LabelOffset
= LabelOffset
+ 2
941 elif Item
.startswith(TAB_UINT32
):
942 LabelOffset
= LabelOffset
+ 4
943 elif Item
.startswith(TAB_UINT64
):
944 LabelOffset
= LabelOffset
+ 8
947 ItemValue
, ItemSize
= ParseFieldValue(Item
)
948 LabelOffset
= LabelOffset
+ ItemSize
950 LabelOffset
= LabelOffset
+ 1
952 for Item
in PcdValueList
:
956 Item
= _ReLabel
.sub('', Item
)
960 OffsetList
= _ReOffset
.findall(Item
)
963 # replace each offset, except errors
964 for Offset
in OffsetList
:
966 Item
= Item
.replace('OFFSET_OF({})'.format(Offset
), LabelDict
[Offset
])
968 raise BadExpression('%s not defined' % Offset
)
970 NewPcdValueList
.append(Item
)
973 for Item
in NewPcdValueList
:
976 TokenSpaceGuidName
= ''
977 if Item
.startswith(TAB_GUID
) and Item
.endswith(')'):
979 TokenSpaceGuidName
= re
.search('GUID\((\w+)\)', Item
).group(1)
982 if TokenSpaceGuidName
and TokenSpaceGuidName
in self
._Symb
:
983 Item
= 'GUID(' + self
._Symb
[TokenSpaceGuidName
] + ')'
984 elif TokenSpaceGuidName
:
985 raise BadExpression('%s not found in DEC file' % TokenSpaceGuidName
)
986 Item
, Size
= ParseFieldValue(Item
)
987 for Index
in range(0, Size
):
988 ValueStr
= '0x%02X' % (int(Item
) & 255)
990 AllPcdValueList
.append(ValueStr
)
992 elif Item
.startswith('DEVICE_PATH') and Item
.endswith(')'):
993 Item
, Size
= ParseFieldValue(Item
)
994 AllPcdValueList
.append(Item
[1:-1])
998 if Item
.startswith(TAB_UINT8
):
1000 ValueType
= TAB_UINT8
1001 elif Item
.startswith(TAB_UINT16
):
1003 ValueType
= TAB_UINT16
1004 elif Item
.startswith(TAB_UINT32
):
1006 ValueType
= TAB_UINT32
1007 elif Item
.startswith(TAB_UINT64
):
1009 ValueType
= TAB_UINT64
1013 TmpValue
= ValueExpressionEx(Item
, ValueType
, self
._Symb
)(True)
1015 TmpValue
= ValueExpressionEx(Item
, self
.PcdType
, self
._Symb
)(True)
1016 Item
= '0x%x' % TmpValue
if not isinstance(TmpValue
, type('')) else TmpValue
1018 ItemValue
, ItemSize
= ParseFieldValue(Item
)
1019 if Item
[0] not in {'"', 'L', '{'} and ItemSize
> 1:
1020 raise BadExpression("Byte array number %s should less than 0xFF." % Item
)
1022 ItemValue
= ParseFieldValue(Item
)[0]
1023 for I
in range(0, ItemSize
):
1024 ValueStr
= '0x%02X' % (int(ItemValue
) & 255)
1026 AllPcdValueList
.append(ValueStr
)
1030 PcdValue
= '{' + ','.join(AllPcdValueList
) + '}'
1032 raise BadExpression("Type: %s, Value: %s, %s"%(self
.PcdType
, PcdValue
, Value
))
1034 if PcdValue
== 'True':
1036 if PcdValue
== 'False':
1042 if __name__
== '__main__':
1045 input = raw_input('Input expr: ')
1049 print(ValueExpression(input)(True))
1050 print(ValueExpression(input)(False))
1051 except WrnExpression
as Ex
:
1054 except Exception as Ex
: