]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Common/Expression.py
BaseTools: Fix the bug for QuarkPlatformPkg build failure
[mirror_edk2.git] / BaseTools / Source / Python / Common / Expression.py
1 ## @file
2 # This file is used to parse and evaluate expression in directive or PCD value.
3 #
4 # Copyright (c) 2011 - 2017, 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
9 #
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.
12
13 ## Import Modules
14 #
15 from Common.GlobalData import *
16 from CommonDataClass.Exceptions import BadExpression
17 from CommonDataClass.Exceptions import WrnExpression
18 from Misc import GuidStringToGuidStructureString, ParseFieldValue
19 import Common.EdkLogger as EdkLogger
20 import copy
21
22 ERR_STRING_EXPR = 'This operator cannot be used in string expression: [%s].'
23 ERR_SNYTAX = 'Syntax error, the rest of expression cannot be evaluated: [%s].'
24 ERR_MATCH = 'No matching right parenthesis.'
25 ERR_STRING_TOKEN = 'Bad string token: [%s].'
26 ERR_MACRO_TOKEN = 'Bad macro token: [%s].'
27 ERR_EMPTY_TOKEN = 'Empty token is not allowed.'
28 ERR_PCD_RESOLVE = 'PCD token cannot be resolved: [%s].'
29 ERR_VALID_TOKEN = 'No more valid token found from rest of string: [%s].'
30 ERR_EXPR_TYPE = 'Different types found in expression.'
31 ERR_OPERATOR_UNSUPPORT = 'Unsupported operator: [%s]'
32 ERR_REL_NOT_IN = 'Expect "IN" after "not" operator.'
33 WRN_BOOL_EXPR = 'Operand of boolean type cannot be used in arithmetic expression.'
34 WRN_EQCMP_STR_OTHERS = '== Comparison between Operand of string type and Boolean/Number Type always return False.'
35 WRN_NECMP_STR_OTHERS = '!= Comparison between Operand of string type and Boolean/Number Type always return True.'
36 ERR_RELCMP_STR_OTHERS = 'Operator taking Operand of string type and Boolean/Number Type is not allowed: [%s].'
37 ERR_STRING_CMP = 'Unicode string and general string cannot be compared: [%s %s %s]'
38 ERR_ARRAY_TOKEN = 'Bad C array or C format GUID token: [%s].'
39 ERR_ARRAY_ELE = 'This must be HEX value for NList or Array: [%s].'
40 ERR_EMPTY_EXPR = 'Empty expression is not allowed.'
41 ERR_IN_OPERAND = 'Macro after IN operator can only be: $(FAMILY), $(ARCH), $(TOOL_CHAIN_TAG) and $(TARGET).'
42
43 ## SplitString
44 # Split string to list according double quote
45 # For example: abc"de\"f"ghi"jkl"mn will be: ['abc', '"de\"f"', 'ghi', '"jkl"', 'mn']
46 #
47 def SplitString(String):
48 # There might be escaped quote: "abc\"def\\\"ghi"
49 Str = String.replace('\\\\', '//').replace('\\\"', '\\\'')
50 RetList = []
51 InQuote = False
52 Item = ''
53 for i, ch in enumerate(Str):
54 if ch == '"':
55 InQuote = not InQuote
56 if not InQuote:
57 Item += String[i]
58 RetList.append(Item)
59 Item = ''
60 continue
61 if Item:
62 RetList.append(Item)
63 Item = ''
64 Item += String[i]
65 if InQuote:
66 raise BadExpression(ERR_STRING_TOKEN % Item)
67 if Item:
68 RetList.append(Item)
69 return RetList
70
71 ## ReplaceExprMacro
72 #
73 def ReplaceExprMacro(String, Macros, ExceptionList = None):
74 StrList = SplitString(String)
75 for i, String in enumerate(StrList):
76 InQuote = False
77 if String.startswith('"'):
78 InQuote = True
79 MacroStartPos = String.find('$(')
80 if MacroStartPos < 0:
81 for Pcd in gPlatformPcds.keys():
82 if Pcd in String:
83 if Pcd not in gConditionalPcds:
84 gConditionalPcds.append(Pcd)
85 continue
86 RetStr = ''
87 while MacroStartPos >= 0:
88 RetStr = String[0:MacroStartPos]
89 MacroEndPos = String.find(')', MacroStartPos)
90 if MacroEndPos < 0:
91 raise BadExpression(ERR_MACRO_TOKEN % String[MacroStartPos:])
92 Macro = String[MacroStartPos+2:MacroEndPos]
93 if Macro not in Macros:
94 # From C reference manual:
95 # If an undefined macro name appears in the constant-expression of
96 # !if or !elif, it is replaced by the integer constant 0.
97 RetStr += '0'
98 elif not InQuote:
99 Tklst = RetStr.split()
100 if Tklst and Tklst[-1] in ['IN', 'in'] and ExceptionList and Macro not in ExceptionList:
101 raise BadExpression(ERR_IN_OPERAND)
102 # Make sure the macro in exception list is encapsulated by double quote
103 # For example: DEFINE ARCH = IA32 X64
104 # $(ARCH) is replaced with "IA32 X64"
105 if ExceptionList and Macro in ExceptionList:
106 RetStr += '"' + Macros[Macro] + '"'
107 elif Macros[Macro].strip():
108 RetStr += Macros[Macro]
109 else:
110 RetStr += '""'
111 else:
112 RetStr += Macros[Macro]
113 RetStr += String[MacroEndPos+1:]
114 String = RetStr
115 MacroStartPos = String.find('$(')
116 StrList[i] = RetStr
117 return ''.join(StrList)
118
119 # transfer int to string for in/not in expression
120 def IntToStr(Value):
121 StrList = []
122 while Value > 0:
123 StrList.append(chr(Value & 0xff))
124 Value = Value >> 8
125 Value = '"' + ''.join(StrList) + '"'
126 return Value
127
128 SupportedInMacroList = ['TARGET', 'TOOL_CHAIN_TAG', 'ARCH', 'FAMILY']
129
130 class ValueExpression(object):
131 # Logical operator mapping
132 LogicalOperators = {
133 '&&' : 'and', '||' : 'or',
134 '!' : 'not', 'AND': 'and',
135 'OR' : 'or' , 'NOT': 'not',
136 'XOR': '^' , 'xor': '^',
137 'EQ' : '==' , 'NE' : '!=',
138 'GT' : '>' , 'LT' : '<',
139 'GE' : '>=' , 'LE' : '<=',
140 'IN' : 'in'
141 }
142
143 NonLetterOpLst = ['+', '-', '*', '/', '%', '&', '|', '^', '~', '<<', '>>', '!', '=', '>', '<', '?', ':']
144
145 PcdPattern = re.compile(r'[_a-zA-Z][0-9A-Za-z_]*\.[_a-zA-Z][0-9A-Za-z_]*$')
146 HexPattern = re.compile(r'0[xX][0-9a-fA-F]+$')
147 RegGuidPattern = re.compile(r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}')
148
149 SymbolPattern = re.compile("("
150 "\$\([A-Z][A-Z0-9_]*\)|\$\(\w+\.\w+\)|\w+\.\w+|"
151 "&&|\|\||!(?!=)|"
152 "(?<=\W)AND(?=\W)|(?<=\W)OR(?=\W)|(?<=\W)NOT(?=\W)|(?<=\W)XOR(?=\W)|"
153 "(?<=\W)EQ(?=\W)|(?<=\W)NE(?=\W)|(?<=\W)GT(?=\W)|(?<=\W)LT(?=\W)|(?<=\W)GE(?=\W)|(?<=\W)LE(?=\W)"
154 ")")
155
156 @staticmethod
157 def Eval(Operator, Oprand1, Oprand2 = None):
158 WrnExp = None
159
160 if Operator not in ["in", "not in"] and (type(Oprand1) == type('') or type(Oprand2) == type('')):
161 if type(Oprand1) == type(''):
162 if Oprand1[0] in ['"', "'"] or Oprand1.startswith('L"') or Oprand1.startswith("L'")or Oprand1.startswith('UINT'):
163 Oprand1, Size = ParseFieldValue(Oprand1)
164 else:
165 Oprand1,Size = ParseFieldValue('"' + Oprand1 + '"')
166 if type(Oprand2) == type(''):
167 if Oprand2[0] in ['"', "'"] or Oprand2.startswith('L"') or Oprand2.startswith("L'") or Oprand2.startswith('UINT'):
168 Oprand2, Size = ParseFieldValue(Oprand2)
169 else:
170 Oprand2, Size = ParseFieldValue('"' + Oprand2 + '"')
171 if type(Oprand1) == type('') or type(Oprand2) == type(''):
172 raise BadExpression(ERR_STRING_EXPR % Operator)
173 if Operator in ['in', 'not in']:
174 if type(Oprand1) != type(''):
175 Oprand1 = IntToStr(Oprand1)
176 if type(Oprand2) != type(''):
177 Oprand2 = IntToStr(Oprand2)
178 TypeDict = {
179 type(0) : 0,
180 type(0L) : 0,
181 type('') : 1,
182 type(True) : 2
183 }
184
185 EvalStr = ''
186 if Operator in ["!", "NOT", "not"]:
187 if type(Oprand1) == type(''):
188 raise BadExpression(ERR_STRING_EXPR % Operator)
189 EvalStr = 'not Oprand1'
190 elif Operator in ["~"]:
191 if type(Oprand1) == type(''):
192 raise BadExpression(ERR_STRING_EXPR % Operator)
193 EvalStr = '~ Oprand1'
194 else:
195 if Operator in ["+", "-"] and (type(True) in [type(Oprand1), type(Oprand2)]):
196 # Boolean in '+'/'-' will be evaluated but raise warning
197 WrnExp = WrnExpression(WRN_BOOL_EXPR)
198 elif type('') in [type(Oprand1), type(Oprand2)] and type(Oprand1)!= type(Oprand2):
199 # == between string and number/boolean will always return False, != return True
200 if Operator == "==":
201 WrnExp = WrnExpression(WRN_EQCMP_STR_OTHERS)
202 WrnExp.result = False
203 raise WrnExp
204 elif Operator == "!=":
205 WrnExp = WrnExpression(WRN_NECMP_STR_OTHERS)
206 WrnExp.result = True
207 raise WrnExp
208 else:
209 raise BadExpression(ERR_RELCMP_STR_OTHERS % Operator)
210 elif TypeDict[type(Oprand1)] != TypeDict[type(Oprand2)]:
211 if Operator in ["==", "!=", ">=", "<=", ">", "<"] and set((TypeDict[type(Oprand1)], TypeDict[type(Oprand2)])) == set((TypeDict[type(True)], TypeDict[type(0)])):
212 # comparison between number and boolean is allowed
213 pass
214 elif Operator in ['&', '|', '^', "and", "or"] and set((TypeDict[type(Oprand1)], TypeDict[type(Oprand2)])) == set((TypeDict[type(True)], TypeDict[type(0)])):
215 # bitwise and logical operation between number and boolean is allowed
216 pass
217 else:
218 raise BadExpression(ERR_EXPR_TYPE)
219 if type(Oprand1) == type('') and type(Oprand2) == type(''):
220 if (Oprand1.startswith('L"') and not Oprand2.startswith('L"')) or \
221 (not Oprand1.startswith('L"') and Oprand2.startswith('L"')):
222 raise BadExpression(ERR_STRING_CMP % (Oprand1, Operator, Oprand2))
223 if 'in' in Operator and type(Oprand2) == type(''):
224 Oprand2 = Oprand2.split()
225 EvalStr = 'Oprand1 ' + Operator + ' Oprand2'
226
227 # Local symbols used by built in eval function
228 Dict = {
229 'Oprand1' : Oprand1,
230 'Oprand2' : Oprand2
231 }
232 try:
233 Val = eval(EvalStr, {}, Dict)
234 except Exception, Excpt:
235 raise BadExpression(str(Excpt))
236
237 if Operator in ['and', 'or']:
238 if Val:
239 Val = True
240 else:
241 Val = False
242
243 if WrnExp:
244 WrnExp.result = Val
245 raise WrnExp
246 return Val
247
248 def __init__(self, Expression, SymbolTable={}):
249 self._NoProcess = False
250 if type(Expression) != type(''):
251 self._Expr = Expression
252 self._NoProcess = True
253 return
254 if Expression.strip().startswith('{') and Expression.strip().endswith('}'):
255 self._Expr = Expression
256 self._NoProcess = True
257
258 self._Expr = ReplaceExprMacro(Expression.strip(),
259 SymbolTable,
260 SupportedInMacroList)
261
262 if not self._Expr.strip():
263 raise BadExpression(ERR_EMPTY_EXPR)
264
265 #
266 # The symbol table including PCD and macro mapping
267 #
268 self._Symb = copy.deepcopy(SymbolTable)
269 self._Symb.update(self.LogicalOperators)
270 self._Idx = 0
271 self._Len = len(self._Expr)
272 self._Token = ''
273 self._WarnExcept = None
274
275 # Literal token without any conversion
276 self._LiteralToken = ''
277
278 # Public entry for this class
279 # @param RealValue: False: only evaluate if the expression is true or false, used for conditional expression
280 # True : return the evaluated str(value), used for PCD value
281 #
282 # @return: True or False if RealValue is False
283 # Evaluated value of string format if RealValue is True
284 #
285 def __call__(self, RealValue=False, Depth=0):
286 if self._NoProcess:
287 return self._Expr
288
289 self._Depth = Depth
290
291 self._Expr = self._Expr.strip()
292 if RealValue and Depth == 0:
293 self._Token = self._Expr
294 if self.__IsNumberToken():
295 return self._Expr
296
297 try:
298 Token = self._GetToken()
299 if type(Token) == type('') and Token.startswith('{') and Token.endswith('}') and self._Idx >= self._Len:
300 return self._Expr
301 except BadExpression:
302 pass
303
304 self._Idx = 0
305 self._Token = ''
306
307 Val = self._ConExpr()
308 RealVal = Val
309 if type(Val) == type(''):
310 if Val == 'L""':
311 Val = False
312 elif not Val:
313 Val = False
314 RealVal = '""'
315 elif not Val.startswith('L"') and not Val.startswith('{') and not Val.startswith("L'"):
316 Val = True
317 RealVal = '"' + RealVal + '"'
318
319 # The expression has been parsed, but the end of expression is not reached
320 # It means the rest does not comply EBNF of <Expression>
321 if self._Idx != self._Len:
322 raise BadExpression(ERR_SNYTAX % self._Expr[self._Idx:])
323
324 if RealValue:
325 RetVal = str(RealVal)
326 elif Val:
327 RetVal = True
328 else:
329 RetVal = False
330
331 if self._WarnExcept:
332 self._WarnExcept.result = RetVal
333 raise self._WarnExcept
334 else:
335 return RetVal
336
337 # Template function to parse binary operators which have same precedence
338 # Expr [Operator Expr]*
339 def _ExprFuncTemplate(self, EvalFunc, OpLst):
340 Val = EvalFunc()
341 while self._IsOperator(OpLst):
342 Op = self._Token
343 if Op == '?':
344 Val2 = EvalFunc()
345 if self._IsOperator(':'):
346 Val3 = EvalFunc()
347 if Val:
348 Val = Val2
349 else:
350 Val = Val3
351 continue
352 try:
353 Val = self.Eval(Op, Val, EvalFunc())
354 except WrnExpression, Warn:
355 self._WarnExcept = Warn
356 Val = Warn.result
357 return Val
358 # A [? B]*
359 def _ConExpr(self):
360 return self._ExprFuncTemplate(self._OrExpr, ['?', ':'])
361
362 # A [|| B]*
363 def _OrExpr(self):
364 return self._ExprFuncTemplate(self._AndExpr, ["OR", "or", "||"])
365
366 # A [&& B]*
367 def _AndExpr(self):
368 return self._ExprFuncTemplate(self._BitOr, ["AND", "and", "&&"])
369
370 # A [ | B]*
371 def _BitOr(self):
372 return self._ExprFuncTemplate(self._BitXor, ["|"])
373
374 # A [ ^ B]*
375 def _BitXor(self):
376 return self._ExprFuncTemplate(self._BitAnd, ["XOR", "xor", "^"])
377
378 # A [ & B]*
379 def _BitAnd(self):
380 return self._ExprFuncTemplate(self._EqExpr, ["&"])
381
382 # A [ == B]*
383 def _EqExpr(self):
384 Val = self._RelExpr()
385 while self._IsOperator(["==", "!=", "EQ", "NE", "IN", "in", "!", "NOT", "not"]):
386 Op = self._Token
387 if Op in ["!", "NOT", "not"]:
388 if not self._IsOperator(["IN", "in"]):
389 raise BadExpression(ERR_REL_NOT_IN)
390 Op += ' ' + self._Token
391 try:
392 Val = self.Eval(Op, Val, self._RelExpr())
393 except WrnExpression, Warn:
394 self._WarnExcept = Warn
395 Val = Warn.result
396 return Val
397
398 # A [ > B]*
399 def _RelExpr(self):
400 return self._ExprFuncTemplate(self._ShiftExpr, ["<=", ">=", "<", ">", "LE", "GE", "LT", "GT"])
401
402 def _ShiftExpr(self):
403 return self._ExprFuncTemplate(self._AddExpr, ["<<", ">>"])
404
405 # A [ + B]*
406 def _AddExpr(self):
407 return self._ExprFuncTemplate(self._MulExpr, ["+", "-"])
408
409 # A [ * B]*
410 def _MulExpr(self):
411 return self._ExprFuncTemplate(self._UnaryExpr, ["*", "/", "%"])
412
413 # [!]*A
414 def _UnaryExpr(self):
415 if self._IsOperator(["!", "NOT", "not"]):
416 Val = self._UnaryExpr()
417 try:
418 return self.Eval('not', Val)
419 except WrnExpression, Warn:
420 self._WarnExcept = Warn
421 return Warn.result
422 if self._IsOperator(["~"]):
423 Val = self._UnaryExpr()
424 try:
425 return self.Eval('~', Val)
426 except WrnExpression, Warn:
427 self._WarnExcept = Warn
428 return Warn.result
429 return self._IdenExpr()
430
431 # Parse identifier or encapsulated expression
432 def _IdenExpr(self):
433 Tk = self._GetToken()
434 if Tk == '(':
435 Val = self._ConExpr()
436 try:
437 # _GetToken may also raise BadExpression
438 if self._GetToken() != ')':
439 raise BadExpression(ERR_MATCH)
440 except BadExpression:
441 raise BadExpression(ERR_MATCH)
442 return Val
443 return Tk
444
445 # Skip whitespace or tab
446 def __SkipWS(self):
447 for Char in self._Expr[self._Idx:]:
448 if Char not in ' \t':
449 break
450 self._Idx += 1
451
452 # Try to convert string to number
453 def __IsNumberToken(self):
454 Radix = 10
455 if self._Token.lower()[0:2] == '0x' and len(self._Token) > 2:
456 Radix = 16
457 if self._Token.startswith('"') or self._Token.startswith("'")\
458 or self._Token.startswith("L'") or self._Token.startswith('L"'):
459 Flag = 0
460 for Index in range(len(self._Token)):
461 if self._Token[Index] in ['"', "'"]:
462 Flag += 1
463 if Flag == 2:
464 self._Token = ParseFieldValue(self._Token)[0]
465 return True
466 try:
467 self._Token = int(self._Token, Radix)
468 return True
469 except ValueError:
470 return False
471 except TypeError:
472 return False
473
474 # Parse array: {...}
475 def __GetArray(self):
476 Token = '{'
477 self._Idx += 1
478 self.__GetNList(True)
479 Token += self._LiteralToken
480 if self._Idx >= self._Len or self._Expr[self._Idx] != '}':
481 raise BadExpression(ERR_ARRAY_TOKEN % Token)
482 Token += '}'
483
484 # All whitespace and tabs in array are already stripped.
485 IsArray = IsGuid = False
486 if len(Token.split(',')) == 11 and len(Token.split(',{')) == 2 \
487 and len(Token.split('},')) == 1:
488 HexLen = [11,6,6,5,4,4,4,4,4,4,6]
489 HexList= Token.split(',')
490 if HexList[3].startswith('{') and \
491 not [Index for Index, Hex in enumerate(HexList) if len(Hex) > HexLen[Index]]:
492 IsGuid = True
493 if Token.lstrip('{').rstrip('}').find('{') == -1:
494 if not [Hex for Hex in Token.lstrip('{').rstrip('}').split(',') if len(Hex) > 4]:
495 IsArray = True
496 if not IsArray and not IsGuid:
497 raise BadExpression(ERR_ARRAY_TOKEN % Token)
498 self._Idx += 1
499 self._Token = self._LiteralToken = Token
500 return self._Token
501
502 # Parse string, the format must be: "..."
503 def __GetString(self):
504 Idx = self._Idx
505
506 # Skip left quote
507 self._Idx += 1
508
509 # Replace escape \\\", \"
510 Expr = self._Expr[self._Idx:].replace('\\\\', '//').replace('\\\"', '\\\'')
511 for Ch in Expr:
512 self._Idx += 1
513 if Ch == '"' or Ch == "'":
514 break
515 self._Token = self._LiteralToken = self._Expr[Idx:self._Idx]
516 if self._Token.startswith('"') and not self._Token.endswith('"'):
517 raise BadExpression(ERR_STRING_TOKEN % self._Token)
518 if self._Token.startswith("'") and not self._Token.endswith("'"):
519 raise BadExpression(ERR_STRING_TOKEN % self._Token)
520 self._Token = self._Token[1:-1]
521 return self._Token
522
523 # Get token that is comprised by alphanumeric, underscore or dot(used by PCD)
524 # @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...)
525 def __GetIdToken(self, IsAlphaOp = False):
526 IdToken = ''
527 for Ch in self._Expr[self._Idx:]:
528 if not self.__IsIdChar(Ch) or ('?' in self._Expr and Ch == ':'):
529 break
530 self._Idx += 1
531 IdToken += Ch
532
533 self._Token = self._LiteralToken = IdToken
534 if not IsAlphaOp:
535 self.__ResolveToken()
536 return self._Token
537
538 # Try to resolve token
539 def __ResolveToken(self):
540 if not self._Token:
541 raise BadExpression(ERR_EMPTY_TOKEN)
542
543 # PCD token
544 if self.PcdPattern.match(self._Token):
545 if self._Token not in self._Symb:
546 Ex = BadExpression(ERR_PCD_RESOLVE % self._Token)
547 Ex.Pcd = self._Token
548 raise Ex
549 self._Token = ValueExpression(self._Symb[self._Token], self._Symb)(True, self._Depth+1)
550 if type(self._Token) != type(''):
551 self._LiteralToken = hex(self._Token)
552 return
553
554 if self._Token.startswith('"'):
555 self._Token = self._Token[1:-1]
556 elif self._Token in ["FALSE", "false", "False"]:
557 self._Token = False
558 elif self._Token in ["TRUE", "true", "True"]:
559 self._Token = True
560 else:
561 self.__IsNumberToken()
562
563 def __GetNList(self, InArray=False):
564 self._GetSingleToken()
565 if not self.__IsHexLiteral():
566 if InArray:
567 raise BadExpression(ERR_ARRAY_ELE % self._Token)
568 return self._Token
569
570 self.__SkipWS()
571 Expr = self._Expr[self._Idx:]
572 if not Expr.startswith(','):
573 return self._Token
574
575 NList = self._LiteralToken
576 while Expr.startswith(','):
577 NList += ','
578 self._Idx += 1
579 self.__SkipWS()
580 self._GetSingleToken()
581 if not self.__IsHexLiteral():
582 raise BadExpression(ERR_ARRAY_ELE % self._Token)
583 NList += self._LiteralToken
584 self.__SkipWS()
585 Expr = self._Expr[self._Idx:]
586 self._Token = self._LiteralToken = NList
587 return self._Token
588
589 def __IsHexLiteral(self):
590 if self._LiteralToken.startswith('{') and \
591 self._LiteralToken.endswith('}'):
592 return True
593
594 if self.HexPattern.match(self._LiteralToken):
595 Token = self._LiteralToken[2:]
596 Token = Token.lstrip('0')
597 if not Token:
598 self._LiteralToken = '0x0'
599 else:
600 self._LiteralToken = '0x' + Token.lower()
601 return True
602 return False
603
604 def _GetToken(self):
605 return self.__GetNList()
606
607 @staticmethod
608 def __IsIdChar(Ch):
609 return Ch in '._:' or Ch.isalnum()
610
611 # Parse operand
612 def _GetSingleToken(self):
613 self.__SkipWS()
614 Expr = self._Expr[self._Idx:]
615 if Expr.startswith('L"'):
616 # Skip L
617 self._Idx += 1
618 UStr = self.__GetString()
619 self._Token = 'L"' + UStr + '"'
620 self._Token, Size = ParseFieldValue(self._Token)
621 return self._Token
622 elif Expr.startswith("L'"):
623 # Skip L
624 self._Idx += 1
625 UStr = self.__GetString()
626 self._Token = "L'" + UStr + "'"
627 self._Token, Size = ParseFieldValue(self._Token)
628 return self._Token
629 elif Expr.startswith('"'):
630 UStr = self.__GetString()
631 self._Token = '"' + UStr + '"'
632 self._Token, Size = ParseFieldValue(self._Token)
633 return self._Token
634 elif Expr.startswith("'"):
635 UStr = self.__GetString()
636 self._Token = "'" + UStr + "'"
637 self._Token, Size = ParseFieldValue(self._Token)
638 return self._Token
639 elif Expr.startswith('UINT'):
640 Re = re.compile('(?:UINT8|UINT16|UINT32|UINT64)\((.+)\)')
641 try:
642 RetValue = Re.search(Expr).group(1)
643 except:
644 raise BadExpression('Invalid Expression %s' % Expr)
645 Idx = self._Idx
646 for Ch in Expr:
647 self._Idx += 1
648 if Ch == '(':
649 Prefix = self._Expr[Idx:self._Idx - 1]
650 Idx = self._Idx
651 if Ch == ')':
652 TmpValue = self._Expr[Idx :self._Idx - 1]
653 TmpValue = ValueExpression(TmpValue)(True)
654 TmpValue = '0x%x' % int(TmpValue) if type(TmpValue) != type('') else TmpValue
655 break
656 self._Token, Size = ParseFieldValue(Prefix + '(' + TmpValue + ')')
657 return self._Token
658
659 self._Token = ''
660 if Expr:
661 Ch = Expr[0]
662 Match = self.RegGuidPattern.match(Expr)
663 if Match and not Expr[Match.end():Match.end()+1].isalnum() \
664 and Expr[Match.end():Match.end()+1] != '_':
665 self._Idx += Match.end()
666 self._Token = ValueExpression(GuidStringToGuidStructureString(Expr[0:Match.end()]))(True, self._Depth+1)
667 return self._Token
668 elif self.__IsIdChar(Ch):
669 return self.__GetIdToken()
670 elif Ch == '"':
671 return self.__GetString()
672 elif Ch == '{':
673 return self.__GetArray()
674 elif Ch == '(' or Ch == ')':
675 self._Idx += 1
676 self._Token = Ch
677 return self._Token
678
679 raise BadExpression(ERR_VALID_TOKEN % Expr)
680
681 # Parse operator
682 def _GetOperator(self):
683 self.__SkipWS()
684 LegalOpLst = ['&&', '||', '!=', '==', '>=', '<='] + self.NonLetterOpLst + ['?',':']
685
686 self._Token = ''
687 Expr = self._Expr[self._Idx:]
688
689 # Reach end of expression
690 if not Expr:
691 return ''
692
693 # Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not
694 if Expr[0].isalpha():
695 return self.__GetIdToken(True)
696
697 # Start to get regular operator: +, -, <, > ...
698 if Expr[0] not in self.NonLetterOpLst:
699 return ''
700
701 OpToken = ''
702 for Ch in Expr:
703 if Ch in self.NonLetterOpLst:
704 if '!' == Ch and OpToken:
705 break
706 self._Idx += 1
707 OpToken += Ch
708 else:
709 break
710
711 if OpToken not in LegalOpLst:
712 raise BadExpression(ERR_OPERATOR_UNSUPPORT % OpToken)
713 self._Token = OpToken
714 return OpToken
715
716 # Check if current token matches the operators given from OpList
717 def _IsOperator(self, OpList):
718 Idx = self._Idx
719 self._GetOperator()
720 if self._Token in OpList:
721 if self._Token in self.LogicalOperators:
722 self._Token = self.LogicalOperators[self._Token]
723 return True
724 self._Idx = Idx
725 return False
726
727 class ValueExpressionEx(ValueExpression):
728 def __init__(self, PcdValue, PcdType, SymbolTable={}):
729 ValueExpression.__init__(self, PcdValue, SymbolTable)
730 self.PcdValue = PcdValue
731 self.PcdType = PcdType
732
733 def __call__(self, RealValue=False, Depth=0):
734 PcdValue = self.PcdValue
735 try:
736 PcdValue = ValueExpression.__call__(self, RealValue, Depth)
737 except WrnExpression, Value:
738 PcdValue = Value.result
739
740 if PcdValue == 'True':
741 PcdValue = '1'
742 if PcdValue == 'False':
743 PcdValue = '0'
744 if self.PcdType in ['UINT8', 'UINT16', 'UINT32', 'UINT64', 'BOOLEAN']:
745 PcdValue = PcdValue.strip()
746 if type(PcdValue) == type('') and PcdValue.startswith('{') and PcdValue.endswith('}'):
747 PcdValue = PcdValue[1:-1].split(',')
748 if type(PcdValue) == type([]):
749 TmpValue = 0
750 Size = 0
751 for Item in PcdValue:
752 if Item.startswith('UINT16'):
753 ItemSize = 2
754 elif Item.startswith('UINT32'):
755 ItemSize = 4
756 elif Item.startswith('UINT64'):
757 ItemSize = 8
758 else:
759 ItemSize = 0
760 Item = ValueExpressionEx(Item, self.PcdType, self._Symb)(True)
761
762 if ItemSize == 0:
763 ItemValue, ItemSize = ParseFieldValue(Item)
764 else:
765 ItemValue = ParseFieldValue(Item)[0]
766
767 if type(ItemValue) == type(''):
768 ItemValue = int(ItemValue, 16) if ItemValue.startswith('0x') else int(ItemValue)
769
770 TmpValue = (ItemValue << (Size * 8)) | TmpValue
771 Size = Size + ItemSize
772 else:
773 TmpValue, Size = ParseFieldValue(PcdValue)
774 if type(TmpValue) == type(''):
775 TmpValue = int(TmpValue)
776 else:
777 PcdValue = '0x%0{}X'.format(Size) % (TmpValue)
778 if TmpValue < 0:
779 raise BadExpression('Type %s PCD Value is negative' % self.PcdType)
780 if self.PcdType == 'UINT8' and Size > 1:
781 raise BadExpression('Type %s PCD Value Size is Larger than 1 byte' % self.PcdType)
782 if self.PcdType == 'UINT16' and Size > 2:
783 raise BadExpression('Type %s PCD Value Size is Larger than 2 byte' % self.PcdType)
784 if self.PcdType == 'UINT32' and Size > 4:
785 raise BadExpression('Type %s PCD Value Size is Larger than 4 byte' % self.PcdType)
786 if self.PcdType == 'UINT64' and Size > 8:
787 raise BadExpression('Type %s PCD Value Size is Larger than 8 byte' % self.PcdType)
788 if self.PcdType in ['VOID*']:
789 try:
790 TmpValue = long(PcdValue)
791 TmpList = []
792 if TmpValue.bit_length() == 0:
793 PcdValue = '{0x00}'
794 else:
795 for I in range((TmpValue.bit_length() + 7) / 8):
796 TmpList.append('0x%02x' % ((TmpValue >> I * 8) & 0xff))
797 PcdValue = '{' + ', '.join(TmpList) + '}'
798 except:
799 if PcdValue.strip().startswith('{'):
800 PcdValue = PcdValue.strip()[1:-1].strip()
801 Size = 0
802 ValueStr = ''
803 TokenSpaceGuidName = ''
804 if PcdValue.startswith('GUID') and PcdValue.endswith(')'):
805 try:
806 TokenSpaceGuidName = re.search('GUID\((\w+)\)', PcdValue).group(1)
807 except:
808 pass
809 if TokenSpaceGuidName and TokenSpaceGuidName in self._Symb:
810 PcdValue = 'GUID(' + self._Symb[TokenSpaceGuidName] + ')'
811 elif TokenSpaceGuidName:
812 raise BadExpression('%s not found in DEC file' % TokenSpaceGuidName)
813
814 ListItem, Size = ParseFieldValue(PcdValue)
815 elif PcdValue.startswith('DEVICE_PATH') and PcdValue.endswith(')'):
816 ListItem, Size = ParseFieldValue(PcdValue)
817 else:
818 ListItem = PcdValue.split(',')
819
820 if type(ListItem) == type(0) or type(ListItem) == type(0L):
821 for Index in range(0, Size):
822 ValueStr += '0x%02X' % (int(ListItem) & 255)
823 ListItem >>= 8
824 ValueStr += ', '
825 PcdValue = '{' + ValueStr[:-2] + '}'
826 elif type(ListItem) == type(''):
827 if ListItem.startswith('{') and ListItem.endswith('}'):
828 PcdValue = ListItem
829 else:
830 LabelDict = {}
831 ReLabel = re.compile('LABEL\((\w+)\)')
832 ReOffset = re.compile('OFFSET_OF\((\w+)\)')
833 for Index, Item in enumerate(ListItem):
834 # for LABEL parse
835 Item = Item.strip()
836 try:
837 LabelList = ReLabel.findall(Item)
838 for Label in LabelList:
839 if Label not in LabelDict.keys():
840 LabelDict[Label] = str(Index)
841 Item = ReLabel.sub('', Item)
842 except:
843 pass
844 try:
845 OffsetList = ReOffset.findall(Item)
846 except:
847 pass
848 for Offset in OffsetList:
849 if Offset in LabelDict.keys():
850 Re = re.compile('OFFSET_OF\(%s\)'% Offset)
851 Item = Re.sub(LabelDict[Offset], Item)
852 else:
853 raise BadExpression('%s not defined before use' % Offset)
854 if Item.startswith('UINT16'):
855 ItemSize = 2
856 elif Item.startswith('UINT32'):
857 ItemSize = 4
858 elif Item.startswith('UINT64'):
859 ItemSize = 8
860 else:
861 ItemSize = 0
862 TmpValue = ValueExpressionEx(Item, self.PcdType, self._Symb)(True)
863 Item = '0x%x' % TmpValue if type(TmpValue) != type('') else TmpValue
864 if ItemSize == 0:
865 ItemValue, ItemSize = ParseFieldValue(Item)
866 else:
867 ItemValue = ParseFieldValue(Item)[0]
868 for I in range(0, ItemSize):
869 ValueStr += '0x%02X' % (int(ItemValue) & 255)
870 ItemValue >>= 8
871 ValueStr += ', '
872 Size += ItemSize
873
874 if Size > 0:
875 PcdValue = '{' + ValueStr[:-2] + '}'
876 if RealValue:
877 return PcdValue
878
879 if __name__ == '__main__':
880 pass
881 while True:
882 input = raw_input('Input expr: ')
883 if input in 'qQ':
884 break
885 try:
886 print ValueExpression(input)(True)
887 print ValueExpression(input)(False)
888 except WrnExpression, Ex:
889 print Ex.result
890 print str(Ex)
891 except Exception, Ex:
892 print str(Ex)