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 Common
.GlobalData
import *
16 from CommonDataClass
.Exceptions
import BadExpression
17 from CommonDataClass
.Exceptions
import WrnExpression
18 from Misc
import GuidStringToGuidStructureString
, ParseFieldValue
, IsFieldValueAnArray
19 import Common
.EdkLogger
as EdkLogger
21 from Common
.DataType
import *
23 ERR_STRING_EXPR
= 'This operator cannot be used in string expression: [%s].'
24 ERR_SNYTAX
= 'Syntax error, the rest of expression cannot be evaluated: [%s].'
25 ERR_MATCH
= 'No matching right parenthesis.'
26 ERR_STRING_TOKEN
= 'Bad string token: [%s].'
27 ERR_MACRO_TOKEN
= 'Bad macro token: [%s].'
28 ERR_EMPTY_TOKEN
= 'Empty token is not allowed.'
29 ERR_PCD_RESOLVE
= 'PCD token cannot be resolved: [%s].'
30 ERR_VALID_TOKEN
= 'No more valid token found from rest of string: [%s].'
31 ERR_EXPR_TYPE
= 'Different types found in expression.'
32 ERR_OPERATOR_UNSUPPORT
= 'Unsupported operator: [%s]'
33 ERR_REL_NOT_IN
= 'Expect "IN" after "not" operator.'
34 WRN_BOOL_EXPR
= 'Operand of boolean type cannot be used in arithmetic expression.'
35 WRN_EQCMP_STR_OTHERS
= '== Comparison between Operand of string type and Boolean/Number Type always return False.'
36 WRN_NECMP_STR_OTHERS
= '!= Comparison between Operand of string type and Boolean/Number Type always return True.'
37 ERR_RELCMP_STR_OTHERS
= 'Operator taking Operand of string type and Boolean/Number Type is not allowed: [%s].'
38 ERR_STRING_CMP
= 'Unicode string and general string cannot be compared: [%s %s %s]'
39 ERR_ARRAY_TOKEN
= 'Bad C array or C format GUID token: [%s].'
40 ERR_ARRAY_ELE
= 'This must be HEX value for NList or Array: [%s].'
41 ERR_EMPTY_EXPR
= 'Empty expression is not allowed.'
42 ERR_IN_OPERAND
= 'Macro after IN operator can only be: $(FAMILY), $(ARCH), $(TOOL_CHAIN_TAG) and $(TARGET).'
44 __ValidString
= re
.compile(r
'[_a-zA-Z][_0-9a-zA-Z]*$')
45 _ReLabel
= re
.compile('LABEL\((\w+)\)')
46 _ReOffset
= re
.compile('OFFSET_OF\((\w+)\)')
47 PcdPattern
= re
.compile(r
'[_a-zA-Z][0-9A-Za-z_]*\.[_a-zA-Z][0-9A-Za-z_]*$')
50 # Split string to list according double quote
51 # For example: abc"de\"f"ghi"jkl"mn will be: ['abc', '"de\"f"', 'ghi', '"jkl"', 'mn']
53 def SplitString(String
):
54 # There might be escaped quote: "abc\"def\\\"ghi", 'abc\'def\\\'ghi'
59 for i
, ch
in enumerate(String
):
60 if ch
== '"' and not InSingleQuote
:
61 if String
[i
- 1] != '\\':
62 InDoubleQuote
= not InDoubleQuote
71 elif ch
== "'" and not InDoubleQuote
:
72 if String
[i
- 1] != '\\':
73 InSingleQuote
= not InSingleQuote
83 if InSingleQuote
or InDoubleQuote
:
84 raise BadExpression(ERR_STRING_TOKEN
% Item
)
89 def SplitPcdValueString(String
):
90 # There might be escaped comma in GUID() or DEVICE_PATH() or " "
91 # or ' ' or L' ' or L" "
97 for i
, ch
in enumerate(String
):
104 raise BadExpression(ERR_STRING_TOKEN
% Item
)
105 elif ch
== '"' and not InSingleQuote
:
106 if String
[i
-1] != '\\':
107 InDoubleQuote
= not InDoubleQuote
108 elif ch
== "'" and not InDoubleQuote
:
109 if String
[i
-1] != '\\':
110 InSingleQuote
= not InSingleQuote
112 if InParenthesis
or InSingleQuote
or InDoubleQuote
:
120 if InSingleQuote
or InDoubleQuote
or InParenthesis
:
121 raise BadExpression(ERR_STRING_TOKEN
% Item
)
126 def IsValidCName(Str
):
127 return True if __ValidString
.match(Str
) else False
129 def BuildOptionValue(PcdValue
, GuidDict
):
130 if PcdValue
.startswith('H'):
131 InputValue
= PcdValue
[1:]
132 elif PcdValue
.startswith("L'") or PcdValue
.startswith("'"):
133 InputValue
= PcdValue
134 elif PcdValue
.startswith('L'):
135 InputValue
= 'L"' + PcdValue
[1:] + '"'
137 InputValue
= PcdValue
138 if IsFieldValueAnArray(InputValue
):
140 PcdValue
= ValueExpressionEx(InputValue
, TAB_VOID
, GuidDict
)(True)
147 def ReplaceExprMacro(String
, Macros
, ExceptionList
= None):
148 StrList
= SplitString(String
)
149 for i
, String
in enumerate(StrList
):
151 if String
.startswith('"'):
153 MacroStartPos
= String
.find('$(')
154 if MacroStartPos
< 0:
155 for Pcd
in gPlatformPcds
:
157 if Pcd
not in gConditionalPcds
:
158 gConditionalPcds
.append(Pcd
)
161 while MacroStartPos
>= 0:
162 RetStr
= String
[0:MacroStartPos
]
163 MacroEndPos
= String
.find(')', MacroStartPos
)
165 raise BadExpression(ERR_MACRO_TOKEN
% String
[MacroStartPos
:])
166 Macro
= String
[MacroStartPos
+2:MacroEndPos
]
167 if Macro
not in Macros
:
168 # From C reference manual:
169 # If an undefined macro name appears in the constant-expression of
170 # !if or !elif, it is replaced by the integer constant 0.
173 Tklst
= RetStr
.split()
174 if Tklst
and Tklst
[-1] in {'IN', 'in'} and ExceptionList
and Macro
not in ExceptionList
:
175 raise BadExpression(ERR_IN_OPERAND
)
176 # Make sure the macro in exception list is encapsulated by double quote
177 # For example: DEFINE ARCH = IA32 X64
178 # $(ARCH) is replaced with "IA32 X64"
179 if ExceptionList
and Macro
in ExceptionList
:
180 RetStr
+= '"' + Macros
[Macro
] + '"'
181 elif Macros
[Macro
].strip():
182 RetStr
+= Macros
[Macro
]
186 RetStr
+= Macros
[Macro
]
187 RetStr
+= String
[MacroEndPos
+1:]
189 MacroStartPos
= String
.find('$(')
191 return ''.join(StrList
)
193 # transfer int to string for in/not in expression
197 StrList
.append(chr(Value
& 0xff))
199 Value
= '"' + ''.join(StrList
) + '"'
202 SupportedInMacroList
= ['TARGET', 'TOOL_CHAIN_TAG', 'ARCH', 'FAMILY']
204 class BaseExpression(object):
205 def __init__(self
, *args
, **kwargs
):
206 super(BaseExpression
, self
).__init
__()
208 # Check if current token matches the operators given from parameter
209 def _IsOperator(self
, OpSet
):
212 if self
._Token
in OpSet
:
213 if self
._Token
in self
.LogicalOperators
:
214 self
._Token
= self
.LogicalOperators
[self
._Token
]
219 class ValueExpression(BaseExpression
):
220 # Logical operator mapping
222 '&&' : 'and', '||' : 'or',
223 '!' : 'not', 'AND': 'and',
224 'OR' : 'or' , 'NOT': 'not',
225 'XOR': '^' , 'xor': '^',
226 'EQ' : '==' , 'NE' : '!=',
227 'GT' : '>' , 'LT' : '<',
228 'GE' : '>=' , 'LE' : '<=',
232 NonLetterOpLst
= ['+', '-', '*', '/', '%', '&', '|', '^', '~', '<<', '>>', '!', '=', '>', '<', '?', ':']
235 SymbolPattern
= re
.compile("("
236 "\$\([A-Z][A-Z0-9_]*\)|\$\(\w+\.\w+\)|\w+\.\w+|"
238 "(?<=\W)AND(?=\W)|(?<=\W)OR(?=\W)|(?<=\W)NOT(?=\W)|(?<=\W)XOR(?=\W)|"
239 "(?<=\W)EQ(?=\W)|(?<=\W)NE(?=\W)|(?<=\W)GT(?=\W)|(?<=\W)LT(?=\W)|(?<=\W)GE(?=\W)|(?<=\W)LE(?=\W)"
243 def Eval(Operator
, Oprand1
, Oprand2
= None):
246 if Operator
not in {"==", "!=", ">=", "<=", ">", "<", "in", "not in"} and \
247 (type(Oprand1
) == type('') or type(Oprand2
) == type('')):
248 raise BadExpression(ERR_STRING_EXPR
% Operator
)
249 if Operator
in {'in', 'not in'}:
250 if type(Oprand1
) != type(''):
251 Oprand1
= IntToStr(Oprand1
)
252 if type(Oprand2
) != type(''):
253 Oprand2
= IntToStr(Oprand2
)
262 if Operator
in {"!", "NOT", "not"}:
263 if type(Oprand1
) == type(''):
264 raise BadExpression(ERR_STRING_EXPR
% Operator
)
265 EvalStr
= 'not Oprand1'
266 elif Operator
in {"~"}:
267 if type(Oprand1
) == type(''):
268 raise BadExpression(ERR_STRING_EXPR
% Operator
)
269 EvalStr
= '~ Oprand1'
271 if Operator
in {"+", "-"} and (type(True) in {type(Oprand1
), type(Oprand2
)}):
272 # Boolean in '+'/'-' will be evaluated but raise warning
273 WrnExp
= WrnExpression(WRN_BOOL_EXPR
)
274 elif type('') in {type(Oprand1
), type(Oprand2
)} and type(Oprand1
)!= type(Oprand2
):
275 # == between string and number/boolean will always return False, != return True
277 WrnExp
= WrnExpression(WRN_EQCMP_STR_OTHERS
)
278 WrnExp
.result
= False
280 elif Operator
== "!=":
281 WrnExp
= WrnExpression(WRN_NECMP_STR_OTHERS
)
285 raise BadExpression(ERR_RELCMP_STR_OTHERS
% Operator
)
286 elif TypeDict
[type(Oprand1
)] != TypeDict
[type(Oprand2
)]:
287 if Operator
in {"==", "!=", ">=", "<=", ">", "<"} and set((TypeDict
[type(Oprand1
)], TypeDict
[type(Oprand2
)])) == set((TypeDict
[type(True)], TypeDict
[type(0)])):
288 # comparison between number and boolean is allowed
290 elif Operator
in {'&', '|', '^', "and", "or"} and set((TypeDict
[type(Oprand1
)], TypeDict
[type(Oprand2
)])) == set((TypeDict
[type(True)], TypeDict
[type(0)])):
291 # bitwise and logical operation between number and boolean is allowed
294 raise BadExpression(ERR_EXPR_TYPE
)
295 if type(Oprand1
) == type('') and type(Oprand2
) == type(''):
296 if (Oprand1
.startswith('L"') and not Oprand2
.startswith('L"')) or \
297 (not Oprand1
.startswith('L"') and Oprand2
.startswith('L"')):
298 raise BadExpression(ERR_STRING_CMP
% (Oprand1
, Operator
, Oprand2
))
299 if 'in' in Operator
and type(Oprand2
) == type(''):
300 Oprand2
= Oprand2
.split()
301 EvalStr
= 'Oprand1 ' + Operator
+ ' Oprand2'
303 # Local symbols used by built in eval function
309 Val
= eval(EvalStr
, {}, Dict
)
310 except Exception, Excpt
:
311 raise BadExpression(str(Excpt
))
313 if Operator
in {'and', 'or'}:
324 def __init__(self
, Expression
, SymbolTable
={}):
325 super(ValueExpression
, self
).__init
__(self
, Expression
, SymbolTable
)
326 self
._NoProcess
= False
327 if type(Expression
) != type(''):
328 self
._Expr
= Expression
329 self
._NoProcess
= True
332 self
._Expr
= ReplaceExprMacro(Expression
.strip(),
334 SupportedInMacroList
)
336 if not self
._Expr
.strip():
337 raise BadExpression(ERR_EMPTY_EXPR
)
340 # The symbol table including PCD and macro mapping
342 self
._Symb
= copy
.deepcopy(SymbolTable
)
343 self
._Symb
.update(self
.LogicalOperators
)
345 self
._Len
= len(self
._Expr
)
347 self
._WarnExcept
= None
349 # Literal token without any conversion
350 self
._LiteralToken
= ''
352 # Public entry for this class
353 # @param RealValue: False: only evaluate if the expression is true or false, used for conditional expression
354 # True : return the evaluated str(value), used for PCD value
356 # @return: True or False if RealValue is False
357 # Evaluated value of string format if RealValue is True
359 def __call__(self
, RealValue
=False, Depth
=0):
365 self
._Expr
= self
._Expr
.strip()
366 if RealValue
and Depth
== 0:
367 self
._Token
= self
._Expr
368 if self
.__IsNumberToken
():
372 Token
= self
._GetToken
()
373 except BadExpression
:
375 if type(Token
) == type('') and Token
.startswith('{') and Token
.endswith('}') and self
._Idx
>= self
._Len
:
381 Val
= self
._ConExpr
()
383 if type(Val
) == type(''):
389 elif not Val
.startswith('L"') and not Val
.startswith('{') and not Val
.startswith("L'"):
391 RealVal
= '"' + RealVal
+ '"'
393 # The expression has been parsed, but the end of expression is not reached
394 # It means the rest does not comply EBNF of <Expression>
395 if self
._Idx
!= self
._Len
:
396 raise BadExpression(ERR_SNYTAX
% self
._Expr
[self
._Idx
:])
399 RetVal
= str(RealVal
)
406 self
._WarnExcept
.result
= RetVal
407 raise self
._WarnExcept
411 # Template function to parse binary operators which have same precedence
412 # Expr [Operator Expr]*
413 def _ExprFuncTemplate(self
, EvalFunc
, OpSet
):
415 while self
._IsOperator
(OpSet
):
419 if self
._IsOperator
({':'}):
427 Val
= self
.Eval(Op
, Val
, EvalFunc())
428 except WrnExpression
, Warn
:
429 self
._WarnExcept
= Warn
434 return self
._ExprFuncTemplate
(self
._OrExpr
, {'?', ':'})
438 return self
._ExprFuncTemplate
(self
._AndExpr
, {"OR", "or", "||"})
442 return self
._ExprFuncTemplate
(self
._BitOr
, {"AND", "and", "&&"})
446 return self
._ExprFuncTemplate
(self
._BitXor
, {"|"})
450 return self
._ExprFuncTemplate
(self
._BitAnd
, {"XOR", "xor", "^"})
454 return self
._ExprFuncTemplate
(self
._EqExpr
, {"&"})
458 Val
= self
._RelExpr
()
459 while self
._IsOperator
({"==", "!=", "EQ", "NE", "IN", "in", "!", "NOT", "not"}):
461 if Op
in {"!", "NOT", "not"}:
462 if not self
._IsOperator
({"IN", "in"}):
463 raise BadExpression(ERR_REL_NOT_IN
)
464 Op
+= ' ' + self
._Token
466 Val
= self
.Eval(Op
, Val
, self
._RelExpr
())
467 except WrnExpression
, Warn
:
468 self
._WarnExcept
= Warn
474 return self
._ExprFuncTemplate
(self
._ShiftExpr
, {"<=", ">=", "<", ">", "LE", "GE", "LT", "GT"})
476 def _ShiftExpr(self
):
477 return self
._ExprFuncTemplate
(self
._AddExpr
, {"<<", ">>"})
481 return self
._ExprFuncTemplate
(self
._MulExpr
, {"+", "-"})
485 return self
._ExprFuncTemplate
(self
._UnaryExpr
, {"*", "/", "%"})
488 def _UnaryExpr(self
):
489 if self
._IsOperator
({"!", "NOT", "not"}):
490 Val
= self
._UnaryExpr
()
492 return self
.Eval('not', Val
)
493 except WrnExpression
, Warn
:
494 self
._WarnExcept
= Warn
496 if self
._IsOperator
({"~"}):
497 Val
= self
._UnaryExpr
()
499 return self
.Eval('~', Val
)
500 except WrnExpression
, Warn
:
501 self
._WarnExcept
= Warn
503 return self
._IdenExpr
()
505 # Parse identifier or encapsulated expression
507 Tk
= self
._GetToken
()
509 Val
= self
._ConExpr
()
511 # _GetToken may also raise BadExpression
512 if self
._GetToken
() != ')':
513 raise BadExpression(ERR_MATCH
)
514 except BadExpression
:
515 raise BadExpression(ERR_MATCH
)
519 # Skip whitespace or tab
521 for Char
in self
._Expr
[self
._Idx
:]:
522 if Char
not in ' \t':
526 # Try to convert string to number
527 def __IsNumberToken(self
):
529 if self
._Token
.lower()[0:2] == '0x' and len(self
._Token
) > 2:
531 if self
._Token
.startswith('"') or self
._Token
.startswith('L"'):
533 for Index
in range(len(self
._Token
)):
534 if self
._Token
[Index
] in {'"'}:
535 if self
._Token
[Index
- 1] == '\\':
538 if Flag
== 2 and self
._Token
.endswith('"'):
540 if self
._Token
.startswith("'") or self
._Token
.startswith("L'"):
542 for Index
in range(len(self
._Token
)):
543 if self
._Token
[Index
] in {"'"}:
544 if self
._Token
[Index
- 1] == '\\':
547 if Flag
== 2 and self
._Token
.endswith("'"):
550 self
._Token
= int(self
._Token
, Radix
)
558 def __GetArray(self
):
561 self
.__GetNList
(True)
562 Token
+= self
._LiteralToken
563 if self
._Idx
>= self
._Len
or self
._Expr
[self
._Idx
] != '}':
564 raise BadExpression(ERR_ARRAY_TOKEN
% Token
)
567 # All whitespace and tabs in array are already stripped.
568 IsArray
= IsGuid
= False
569 if len(Token
.split(',')) == 11 and len(Token
.split(',{')) == 2 \
570 and len(Token
.split('},')) == 1:
571 HexLen
= [11,6,6,5,4,4,4,4,4,4,6]
572 HexList
= Token
.split(',')
573 if HexList
[3].startswith('{') and \
574 not [Index
for Index
, Hex
in enumerate(HexList
) if len(Hex
) > HexLen
[Index
]]:
576 if Token
.lstrip('{').rstrip('}').find('{') == -1:
577 if not [Hex
for Hex
in Token
.lstrip('{').rstrip('}').split(',') if len(Hex
) > 4]:
579 if not IsArray
and not IsGuid
:
580 raise BadExpression(ERR_ARRAY_TOKEN
% Token
)
582 self
._Token
= self
._LiteralToken
= Token
585 # Parse string, the format must be: "..."
586 def __GetString(self
):
592 # Replace escape \\\", \"
593 if self
._Expr
[Idx
] == '"':
594 Expr
= self
._Expr
[self
._Idx
:].replace('\\\\', '//').replace('\\\"', '\\\'')
599 self
._Token
= self
._LiteralToken
= self
._Expr
[Idx
:self
._Idx
]
600 if not self
._Token
.endswith('"'):
601 raise BadExpression(ERR_STRING_TOKEN
% self
._Token
)
602 #Replace escape \\\', \'
603 elif self
._Expr
[Idx
] == "'":
604 Expr
= self
._Expr
[self
._Idx
:].replace('\\\\', '//').replace("\\\'", "\\\"")
609 self
._Token
= self
._LiteralToken
= self
._Expr
[Idx
:self
._Idx
]
610 if not self
._Token
.endswith("'"):
611 raise BadExpression(ERR_STRING_TOKEN
% self
._Token
)
612 self
._Token
= self
._Token
[1:-1]
615 # Get token that is comprised by alphanumeric, underscore or dot(used by PCD)
616 # @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...)
617 def __GetIdToken(self
, IsAlphaOp
= False):
619 for Ch
in self
._Expr
[self
._Idx
:]:
620 if not self
.__IsIdChar
(Ch
) or ('?' in self
._Expr
and Ch
== ':'):
625 self
._Token
= self
._LiteralToken
= IdToken
627 self
.__ResolveToken
()
630 # Try to resolve token
631 def __ResolveToken(self
):
633 raise BadExpression(ERR_EMPTY_TOKEN
)
636 if PcdPattern
.match(self
._Token
):
637 if self
._Token
not in self
._Symb
:
638 Ex
= BadExpression(ERR_PCD_RESOLVE
% self
._Token
)
641 self
._Token
= ValueExpression(self
._Symb
[self
._Token
], self
._Symb
)(True, self
._Depth
+1)
642 if type(self
._Token
) != type(''):
643 self
._LiteralToken
= hex(self
._Token
)
646 if self
._Token
.startswith('"'):
647 self
._Token
= self
._Token
[1:-1]
648 elif self
._Token
in {"FALSE", "false", "False"}:
650 elif self
._Token
in {"TRUE", "true", "True"}:
653 self
.__IsNumberToken
()
655 def __GetNList(self
, InArray
=False):
656 self
._GetSingleToken
()
657 if not self
.__IsHexLiteral
():
659 raise BadExpression(ERR_ARRAY_ELE
% self
._Token
)
663 Expr
= self
._Expr
[self
._Idx
:]
664 if not Expr
.startswith(','):
667 NList
= self
._LiteralToken
668 while Expr
.startswith(','):
672 self
._GetSingleToken
()
673 if not self
.__IsHexLiteral
():
674 raise BadExpression(ERR_ARRAY_ELE
% self
._Token
)
675 NList
+= self
._LiteralToken
677 Expr
= self
._Expr
[self
._Idx
:]
678 self
._Token
= self
._LiteralToken
= NList
681 def __IsHexLiteral(self
):
682 if self
._LiteralToken
.startswith('{') and \
683 self
._LiteralToken
.endswith('}'):
686 if gHexPattern
.match(self
._LiteralToken
):
687 Token
= self
._LiteralToken
[2:]
689 self
._LiteralToken
= '0x0'
691 self
._LiteralToken
= '0x' + Token
696 return self
.__GetNList
()
700 return Ch
in '._:' or Ch
.isalnum()
703 def _GetSingleToken(self
):
705 Expr
= self
._Expr
[self
._Idx
:]
706 if Expr
.startswith('L"'):
709 UStr
= self
.__GetString
()
710 self
._Token
= 'L"' + UStr
+ '"'
712 elif Expr
.startswith("L'"):
715 UStr
= self
.__GetString
()
716 self
._Token
= "L'" + UStr
+ "'"
718 elif Expr
.startswith("'"):
719 UStr
= self
.__GetString
()
720 self
._Token
= "'" + UStr
+ "'"
722 elif Expr
.startswith('UINT'):
723 Re
= re
.compile('(?:UINT8|UINT16|UINT32|UINT64)\((.+)\)')
725 RetValue
= Re
.search(Expr
).group(1)
727 raise BadExpression('Invalid Expression %s' % Expr
)
732 Prefix
= self
._Expr
[Idx
:self
._Idx
- 1]
735 TmpValue
= self
._Expr
[Idx
:self
._Idx
- 1]
736 TmpValue
= ValueExpression(TmpValue
)(True)
737 TmpValue
= '0x%x' % int(TmpValue
) if type(TmpValue
) != type('') else TmpValue
739 self
._Token
, Size
= ParseFieldValue(Prefix
+ '(' + TmpValue
+ ')')
745 Match
= gGuidPattern
.match(Expr
)
746 if Match
and not Expr
[Match
.end():Match
.end()+1].isalnum() \
747 and Expr
[Match
.end():Match
.end()+1] != '_':
748 self
._Idx
+= Match
.end()
749 self
._Token
= ValueExpression(GuidStringToGuidStructureString(Expr
[0:Match
.end()]))(True, self
._Depth
+1)
751 elif self
.__IsIdChar
(Ch
):
752 return self
.__GetIdToken
()
754 return self
.__GetString
()
756 return self
.__GetArray
()
757 elif Ch
== '(' or Ch
== ')':
762 raise BadExpression(ERR_VALID_TOKEN
% Expr
)
765 def _GetOperator(self
):
767 LegalOpLst
= ['&&', '||', '!=', '==', '>=', '<='] + self
.NonLetterOpLst
+ ['?',':']
770 Expr
= self
._Expr
[self
._Idx
:]
772 # Reach end of expression
776 # Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not
777 if Expr
[0].isalpha():
778 return self
.__GetIdToken
(True)
780 # Start to get regular operator: +, -, <, > ...
781 if Expr
[0] not in self
.NonLetterOpLst
:
786 if Ch
in self
.NonLetterOpLst
:
787 if '!' == Ch
and OpToken
:
794 if OpToken
not in LegalOpLst
:
795 raise BadExpression(ERR_OPERATOR_UNSUPPORT
% OpToken
)
796 self
._Token
= OpToken
799 class ValueExpressionEx(ValueExpression
):
800 def __init__(self
, PcdValue
, PcdType
, SymbolTable
={}):
801 ValueExpression
.__init
__(self
, PcdValue
, SymbolTable
)
802 self
.PcdValue
= PcdValue
803 self
.PcdType
= PcdType
805 def __call__(self
, RealValue
=False, Depth
=0):
806 PcdValue
= self
.PcdValue
808 PcdValue
= ValueExpression
.__call
__(self
, RealValue
, Depth
)
809 if self
.PcdType
== TAB_VOID
and (PcdValue
.startswith("'") or PcdValue
.startswith("L'")):
810 PcdValue
, Size
= ParseFieldValue(PcdValue
)
812 for I
in range(Size
):
813 PcdValueList
.append('0x%02X'%(PcdValue
& 0xff))
814 PcdValue
= PcdValue
>> 8
815 PcdValue
= '{' + ','.join(PcdValueList
) + '}'
816 elif self
.PcdType
in TAB_PCD_NUMERIC_TYPES
and (PcdValue
.startswith("'") or \
817 PcdValue
.startswith('"') or PcdValue
.startswith("L'") or PcdValue
.startswith('L"') or PcdValue
.startswith('{')):
819 except WrnExpression
, Value
:
820 PcdValue
= Value
.result
821 except BadExpression
, Value
:
822 if self
.PcdType
in TAB_PCD_NUMERIC_TYPES
:
823 PcdValue
= PcdValue
.strip()
824 if PcdValue
.startswith('{') and PcdValue
.endswith('}'):
825 PcdValue
= SplitPcdValueString(PcdValue
[1:-1])
826 if type(PcdValue
) == type([]):
830 for Item
in PcdValue
:
832 if Item
.startswith(TAB_UINT8
):
834 ValueType
= TAB_UINT8
835 elif Item
.startswith(TAB_UINT16
):
837 ValueType
= TAB_UINT16
838 elif Item
.startswith(TAB_UINT32
):
840 ValueType
= TAB_UINT32
841 elif Item
.startswith(TAB_UINT64
):
843 ValueType
= TAB_UINT64
844 elif Item
[0] in {'"',"'",'L'}:
849 ValueType
= TAB_UINT8
850 Item
= ValueExpressionEx(Item
, ValueType
, self
._Symb
)(True)
854 tmpValue
= int(Item
, 0)
856 raise BadExpression("Byte array number %s should less than 0xFF." % Item
)
857 except BadExpression
, Value
:
858 raise BadExpression(Value
)
861 ItemValue
, ItemSize
= ParseFieldValue(Item
)
863 ItemValue
= ParseFieldValue(Item
)[0]
865 if type(ItemValue
) == type(''):
866 ItemValue
= int(ItemValue
, 0)
868 TmpValue
= (ItemValue
<< (Size
* 8)) | TmpValue
869 Size
= Size
+ ItemSize
872 TmpValue
, Size
= ParseFieldValue(PcdValue
)
873 except BadExpression
, Value
:
874 raise BadExpression("Type: %s, Value: %s, %s" % (self
.PcdType
, PcdValue
, Value
))
875 if type(TmpValue
) == type(''):
877 TmpValue
= int(TmpValue
)
879 raise BadExpression(Value
)
881 PcdValue
= '0x%0{}X'.format(Size
) % (TmpValue
)
883 raise BadExpression('Type %s PCD Value is negative' % self
.PcdType
)
884 if self
.PcdType
== TAB_UINT8
and Size
> 1:
885 raise BadExpression('Type %s PCD Value Size is Larger than 1 byte' % self
.PcdType
)
886 if self
.PcdType
== TAB_UINT16
and Size
> 2:
887 raise BadExpression('Type %s PCD Value Size is Larger than 2 byte' % self
.PcdType
)
888 if self
.PcdType
== TAB_UINT32
and Size
> 4:
889 raise BadExpression('Type %s PCD Value Size is Larger than 4 byte' % self
.PcdType
)
890 if self
.PcdType
== TAB_UINT64
and Size
> 8:
891 raise BadExpression('Type %s PCD Value Size is Larger than 8 byte' % self
.PcdType
)
894 TmpValue
= long(PcdValue
)
896 if TmpValue
.bit_length() == 0:
899 for I
in range((TmpValue
.bit_length() + 7) / 8):
900 TmpList
.append('0x%02x' % ((TmpValue
>> I
* 8) & 0xff))
901 PcdValue
= '{' + ', '.join(TmpList
) + '}'
903 if PcdValue
.strip().startswith('{'):
904 PcdValueList
= SplitPcdValueString(PcdValue
.strip()[1:-1])
908 for Item
in PcdValueList
:
909 # compute byte offset of every LABEL
910 LabelList
= _ReLabel
.findall(Item
)
911 Item
= _ReLabel
.sub('', Item
)
914 for Label
in LabelList
:
915 if not IsValidCName(Label
):
916 raise BadExpression('%s is not a valid c variable name' % Label
)
917 if Label
not in LabelDict
:
918 LabelDict
[Label
] = str(LabelOffset
)
919 if Item
.startswith(TAB_UINT8
):
920 LabelOffset
= LabelOffset
+ 1
921 elif Item
.startswith(TAB_UINT16
):
922 LabelOffset
= LabelOffset
+ 2
923 elif Item
.startswith(TAB_UINT32
):
924 LabelOffset
= LabelOffset
+ 4
925 elif Item
.startswith(TAB_UINT64
):
926 LabelOffset
= LabelOffset
+ 8
929 ItemValue
, ItemSize
= ParseFieldValue(Item
)
930 LabelOffset
= LabelOffset
+ ItemSize
932 LabelOffset
= LabelOffset
+ 1
934 for Item
in PcdValueList
:
938 Item
= _ReLabel
.sub('', Item
)
942 OffsetList
= _ReOffset
.findall(Item
)
945 # replace each offset, except errors
946 for Offset
in OffsetList
:
948 Item
= Item
.replace('OFFSET_OF({})'.format(Offset
),LabelDict
[Offset
])
950 raise BadExpression('%s not defined' % Offset
)
952 NewPcdValueList
.append(Item
)
955 for Item
in NewPcdValueList
:
958 TokenSpaceGuidName
= ''
959 if Item
.startswith(TAB_GUID
) and Item
.endswith(')'):
961 TokenSpaceGuidName
= re
.search('GUID\((\w+)\)', Item
).group(1)
964 if TokenSpaceGuidName
and TokenSpaceGuidName
in self
._Symb
:
965 Item
= 'GUID(' + self
._Symb
[TokenSpaceGuidName
] + ')'
966 elif TokenSpaceGuidName
:
967 raise BadExpression('%s not found in DEC file' % TokenSpaceGuidName
)
968 Item
, Size
= ParseFieldValue(Item
)
969 for Index
in range(0, Size
):
970 ValueStr
= '0x%02X' % (int(Item
) & 255)
972 AllPcdValueList
.append(ValueStr
)
974 elif Item
.startswith('DEVICE_PATH') and Item
.endswith(')'):
975 Item
, Size
= ParseFieldValue(Item
)
976 AllPcdValueList
.append(Item
[1:-1])
980 if Item
.startswith(TAB_UINT8
):
982 ValueType
= TAB_UINT8
983 elif Item
.startswith(TAB_UINT16
):
985 ValueType
= TAB_UINT16
986 elif Item
.startswith(TAB_UINT32
):
988 ValueType
= TAB_UINT32
989 elif Item
.startswith(TAB_UINT64
):
991 ValueType
= TAB_UINT64
995 TmpValue
= ValueExpressionEx(Item
, ValueType
, self
._Symb
)(True)
997 TmpValue
= ValueExpressionEx(Item
, self
.PcdType
, self
._Symb
)(True)
998 Item
= '0x%x' % TmpValue
if type(TmpValue
) != type('') else TmpValue
1000 ItemValue
, ItemSize
= ParseFieldValue(Item
)
1001 if Item
[0] not in {'"','L','{'} and ItemSize
> 1:
1002 raise BadExpression("Byte array number %s should less than 0xFF." % Item
)
1004 ItemValue
= ParseFieldValue(Item
)[0]
1005 for I
in range(0, ItemSize
):
1006 ValueStr
= '0x%02X' % (int(ItemValue
) & 255)
1008 AllPcdValueList
.append(ValueStr
)
1012 PcdValue
= '{' + ','.join(AllPcdValueList
) + '}'
1014 raise BadExpression("Type: %s, Value: %s, %s"%(self
.PcdType
, PcdValue
, Value
))
1016 if PcdValue
== 'True':
1018 if PcdValue
== 'False':
1024 if __name__
== '__main__':
1027 input = raw_input('Input expr: ')
1031 print ValueExpression(input)(True)
1032 print ValueExpression(input)(False)
1033 except WrnExpression
, Ex
:
1036 except Exception, Ex
: