]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Common/Expression.py
486c537029571bd04c0d2cbac8e3633bcf65e44d
[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 - 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
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
255 self._Expr = ReplaceExprMacro(Expression.strip(),
256 SymbolTable,
257 SupportedInMacroList)
258
259 if not self._Expr.strip():
260 raise BadExpression(ERR_EMPTY_EXPR)
261
262 #
263 # The symbol table including PCD and macro mapping
264 #
265 self._Symb = copy.deepcopy(SymbolTable)
266 self._Symb.update(self.LogicalOperators)
267 self._Idx = 0
268 self._Len = len(self._Expr)
269 self._Token = ''
270 self._WarnExcept = None
271
272 # Literal token without any conversion
273 self._LiteralToken = ''
274
275 # Public entry for this class
276 # @param RealValue: False: only evaluate if the expression is true or false, used for conditional expression
277 # True : return the evaluated str(value), used for PCD value
278 #
279 # @return: True or False if RealValue is False
280 # Evaluated value of string format if RealValue is True
281 #
282 def __call__(self, RealValue=False, Depth=0):
283 if self._NoProcess:
284 return self._Expr
285
286 self._Depth = Depth
287
288 self._Expr = self._Expr.strip()
289 if RealValue and Depth == 0:
290 self._Token = self._Expr
291 if self.__IsNumberToken():
292 return self._Expr
293 Token = ''
294 try:
295 Token = self._GetToken()
296 except BadExpression:
297 pass
298 if type(Token) == type('') and Token.startswith('{') and Token.endswith('}') and self._Idx >= self._Len:
299 if len(Token) != len(self._Expr.replace(' ', '')):
300 raise BadExpression
301 return self._Expr
302
303 self._Idx = 0
304 self._Token = ''
305
306 Val = self._ConExpr()
307 RealVal = Val
308 if type(Val) == type(''):
309 if Val == 'L""':
310 Val = False
311 elif not Val:
312 Val = False
313 RealVal = '""'
314 elif not Val.startswith('L"') and not Val.startswith('{') and not Val.startswith("L'"):
315 Val = True
316 RealVal = '"' + RealVal + '"'
317
318 # The expression has been parsed, but the end of expression is not reached
319 # It means the rest does not comply EBNF of <Expression>
320 if self._Idx != self._Len:
321 raise BadExpression(ERR_SNYTAX % self._Expr[self._Idx:])
322
323 if RealValue:
324 RetVal = str(RealVal)
325 elif Val:
326 RetVal = True
327 else:
328 RetVal = False
329
330 if self._WarnExcept:
331 self._WarnExcept.result = RetVal
332 raise self._WarnExcept
333 else:
334 return RetVal
335
336 # Template function to parse binary operators which have same precedence
337 # Expr [Operator Expr]*
338 def _ExprFuncTemplate(self, EvalFunc, OpLst):
339 Val = EvalFunc()
340 while self._IsOperator(OpLst):
341 Op = self._Token
342 if Op == '?':
343 Val2 = EvalFunc()
344 if self._IsOperator(':'):
345 Val3 = EvalFunc()
346 if Val:
347 Val = Val2
348 else:
349 Val = Val3
350 continue
351 try:
352 Val = self.Eval(Op, Val, EvalFunc())
353 except WrnExpression, Warn:
354 self._WarnExcept = Warn
355 Val = Warn.result
356 return Val
357 # A [? B]*
358 def _ConExpr(self):
359 return self._ExprFuncTemplate(self._OrExpr, ['?', ':'])
360
361 # A [|| B]*
362 def _OrExpr(self):
363 return self._ExprFuncTemplate(self._AndExpr, ["OR", "or", "||"])
364
365 # A [&& B]*
366 def _AndExpr(self):
367 return self._ExprFuncTemplate(self._BitOr, ["AND", "and", "&&"])
368
369 # A [ | B]*
370 def _BitOr(self):
371 return self._ExprFuncTemplate(self._BitXor, ["|"])
372
373 # A [ ^ B]*
374 def _BitXor(self):
375 return self._ExprFuncTemplate(self._BitAnd, ["XOR", "xor", "^"])
376
377 # A [ & B]*
378 def _BitAnd(self):
379 return self._ExprFuncTemplate(self._EqExpr, ["&"])
380
381 # A [ == B]*
382 def _EqExpr(self):
383 Val = self._RelExpr()
384 while self._IsOperator(["==", "!=", "EQ", "NE", "IN", "in", "!", "NOT", "not"]):
385 Op = self._Token
386 if Op in ["!", "NOT", "not"]:
387 if not self._IsOperator(["IN", "in"]):
388 raise BadExpression(ERR_REL_NOT_IN)
389 Op += ' ' + self._Token
390 try:
391 Val = self.Eval(Op, Val, self._RelExpr())
392 except WrnExpression, Warn:
393 self._WarnExcept = Warn
394 Val = Warn.result
395 return Val
396
397 # A [ > B]*
398 def _RelExpr(self):
399 return self._ExprFuncTemplate(self._ShiftExpr, ["<=", ">=", "<", ">", "LE", "GE", "LT", "GT"])
400
401 def _ShiftExpr(self):
402 return self._ExprFuncTemplate(self._AddExpr, ["<<", ">>"])
403
404 # A [ + B]*
405 def _AddExpr(self):
406 return self._ExprFuncTemplate(self._MulExpr, ["+", "-"])
407
408 # A [ * B]*
409 def _MulExpr(self):
410 return self._ExprFuncTemplate(self._UnaryExpr, ["*", "/", "%"])
411
412 # [!]*A
413 def _UnaryExpr(self):
414 if self._IsOperator(["!", "NOT", "not"]):
415 Val = self._UnaryExpr()
416 try:
417 return self.Eval('not', Val)
418 except WrnExpression, Warn:
419 self._WarnExcept = Warn
420 return Warn.result
421 if self._IsOperator(["~"]):
422 Val = self._UnaryExpr()
423 try:
424 return self.Eval('~', Val)
425 except WrnExpression, Warn:
426 self._WarnExcept = Warn
427 return Warn.result
428 return self._IdenExpr()
429
430 # Parse identifier or encapsulated expression
431 def _IdenExpr(self):
432 Tk = self._GetToken()
433 if Tk == '(':
434 Val = self._ConExpr()
435 try:
436 # _GetToken may also raise BadExpression
437 if self._GetToken() != ')':
438 raise BadExpression(ERR_MATCH)
439 except BadExpression:
440 raise BadExpression(ERR_MATCH)
441 return Val
442 return Tk
443
444 # Skip whitespace or tab
445 def __SkipWS(self):
446 for Char in self._Expr[self._Idx:]:
447 if Char not in ' \t':
448 break
449 self._Idx += 1
450
451 # Try to convert string to number
452 def __IsNumberToken(self):
453 Radix = 10
454 if self._Token.lower()[0:2] == '0x' and len(self._Token) > 2:
455 Radix = 16
456 if self._Token.startswith('"') or self._Token.startswith('L"'):
457 Flag = 0
458 for Index in range(len(self._Token)):
459 if self._Token[Index] in ['"']:
460 Flag += 1
461 if Flag == 2 and self._Token.endswith('"'):
462 self._Token = ParseFieldValue(self._Token)[0]
463 return True
464 if self._Token.startswith("'") or self._Token.startswith("L'"):
465 Flag = 0
466 for Index in range(len(self._Token)):
467 if self._Token[Index] in ["'"]:
468 Flag += 1
469 if Flag == 2 and self._Token.endswith("'"):
470 self._Token = ParseFieldValue(self._Token)[0]
471 return True
472 try:
473 self._Token = int(self._Token, Radix)
474 return True
475 except ValueError:
476 return False
477 except TypeError:
478 return False
479
480 # Parse array: {...}
481 def __GetArray(self):
482 Token = '{'
483 self._Idx += 1
484 self.__GetNList(True)
485 Token += self._LiteralToken
486 if self._Idx >= self._Len or self._Expr[self._Idx] != '}':
487 raise BadExpression(ERR_ARRAY_TOKEN % Token)
488 Token += '}'
489
490 # All whitespace and tabs in array are already stripped.
491 IsArray = IsGuid = False
492 if len(Token.split(',')) == 11 and len(Token.split(',{')) == 2 \
493 and len(Token.split('},')) == 1:
494 HexLen = [11,6,6,5,4,4,4,4,4,4,6]
495 HexList= Token.split(',')
496 if HexList[3].startswith('{') and \
497 not [Index for Index, Hex in enumerate(HexList) if len(Hex) > HexLen[Index]]:
498 IsGuid = True
499 if Token.lstrip('{').rstrip('}').find('{') == -1:
500 if not [Hex for Hex in Token.lstrip('{').rstrip('}').split(',') if len(Hex) > 4]:
501 IsArray = True
502 if not IsArray and not IsGuid:
503 raise BadExpression(ERR_ARRAY_TOKEN % Token)
504 self._Idx += 1
505 self._Token = self._LiteralToken = Token
506 return self._Token
507
508 # Parse string, the format must be: "..."
509 def __GetString(self):
510 Idx = self._Idx
511
512 # Skip left quote
513 self._Idx += 1
514
515 # Replace escape \\\", \"
516 Expr = self._Expr[self._Idx:].replace('\\\\', '//').replace('\\\"', '\\\'')
517 for Ch in Expr:
518 self._Idx += 1
519 if Ch == '"' or Ch == "'":
520 break
521 self._Token = self._LiteralToken = self._Expr[Idx:self._Idx]
522 if self._Token.startswith('"') and not self._Token.endswith('"'):
523 raise BadExpression(ERR_STRING_TOKEN % self._Token)
524 if self._Token.startswith("'") and not self._Token.endswith("'"):
525 raise BadExpression(ERR_STRING_TOKEN % self._Token)
526 self._Token = self._Token[1:-1]
527 return self._Token
528
529 # Get token that is comprised by alphanumeric, underscore or dot(used by PCD)
530 # @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...)
531 def __GetIdToken(self, IsAlphaOp = False):
532 IdToken = ''
533 for Ch in self._Expr[self._Idx:]:
534 if not self.__IsIdChar(Ch) or ('?' in self._Expr and Ch == ':'):
535 break
536 self._Idx += 1
537 IdToken += Ch
538
539 self._Token = self._LiteralToken = IdToken
540 if not IsAlphaOp:
541 self.__ResolveToken()
542 return self._Token
543
544 # Try to resolve token
545 def __ResolveToken(self):
546 if not self._Token:
547 raise BadExpression(ERR_EMPTY_TOKEN)
548
549 # PCD token
550 if self.PcdPattern.match(self._Token):
551 if self._Token not in self._Symb:
552 Ex = BadExpression(ERR_PCD_RESOLVE % self._Token)
553 Ex.Pcd = self._Token
554 raise Ex
555 self._Token = ValueExpression(self._Symb[self._Token], self._Symb)(True, self._Depth+1)
556 if type(self._Token) != type(''):
557 self._LiteralToken = hex(self._Token)
558 return
559
560 if self._Token.startswith('"'):
561 self._Token = self._Token[1:-1]
562 elif self._Token in ["FALSE", "false", "False"]:
563 self._Token = False
564 elif self._Token in ["TRUE", "true", "True"]:
565 self._Token = True
566 else:
567 self.__IsNumberToken()
568
569 def __GetNList(self, InArray=False):
570 self._GetSingleToken()
571 if not self.__IsHexLiteral():
572 if InArray:
573 raise BadExpression(ERR_ARRAY_ELE % self._Token)
574 return self._Token
575
576 self.__SkipWS()
577 Expr = self._Expr[self._Idx:]
578 if not Expr.startswith(','):
579 return self._Token
580
581 NList = self._LiteralToken
582 while Expr.startswith(','):
583 NList += ','
584 self._Idx += 1
585 self.__SkipWS()
586 self._GetSingleToken()
587 if not self.__IsHexLiteral():
588 raise BadExpression(ERR_ARRAY_ELE % self._Token)
589 NList += self._LiteralToken
590 self.__SkipWS()
591 Expr = self._Expr[self._Idx:]
592 self._Token = self._LiteralToken = NList
593 return self._Token
594
595 def __IsHexLiteral(self):
596 if self._LiteralToken.startswith('{') and \
597 self._LiteralToken.endswith('}'):
598 return True
599
600 if self.HexPattern.match(self._LiteralToken):
601 Token = self._LiteralToken[2:]
602 if not Token:
603 self._LiteralToken = '0x0'
604 else:
605 self._LiteralToken = '0x' + Token
606 return True
607 return False
608
609 def _GetToken(self):
610 return self.__GetNList()
611
612 @staticmethod
613 def __IsIdChar(Ch):
614 return Ch in '._:' or Ch.isalnum()
615
616 # Parse operand
617 def _GetSingleToken(self):
618 self.__SkipWS()
619 Expr = self._Expr[self._Idx:]
620 if Expr.startswith('L"'):
621 # Skip L
622 self._Idx += 1
623 UStr = self.__GetString()
624 self._Token = 'L"' + UStr + '"'
625 self._Token, Size = ParseFieldValue(self._Token)
626 return self._Token
627 elif Expr.startswith("L'"):
628 # Skip L
629 self._Idx += 1
630 UStr = self.__GetString()
631 self._Token = "L'" + 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("'"):
640 UStr = self.__GetString()
641 self._Token = "'" + UStr + "'"
642 self._Token, Size = ParseFieldValue(self._Token)
643 return self._Token
644 elif Expr.startswith('UINT'):
645 Re = re.compile('(?:UINT8|UINT16|UINT32|UINT64)\((.+)\)')
646 try:
647 RetValue = Re.search(Expr).group(1)
648 except:
649 raise BadExpression('Invalid Expression %s' % Expr)
650 Idx = self._Idx
651 for Ch in Expr:
652 self._Idx += 1
653 if Ch == '(':
654 Prefix = self._Expr[Idx:self._Idx - 1]
655 Idx = self._Idx
656 if Ch == ')':
657 TmpValue = self._Expr[Idx :self._Idx - 1]
658 TmpValue = ValueExpression(TmpValue)(True)
659 TmpValue = '0x%x' % int(TmpValue) if type(TmpValue) != type('') else TmpValue
660 break
661 self._Token, Size = ParseFieldValue(Prefix + '(' + TmpValue + ')')
662 return self._Token
663
664 self._Token = ''
665 if Expr:
666 Ch = Expr[0]
667 Match = self.RegGuidPattern.match(Expr)
668 if Match and not Expr[Match.end():Match.end()+1].isalnum() \
669 and Expr[Match.end():Match.end()+1] != '_':
670 self._Idx += Match.end()
671 self._Token = ValueExpression(GuidStringToGuidStructureString(Expr[0:Match.end()]))(True, self._Depth+1)
672 return self._Token
673 elif self.__IsIdChar(Ch):
674 return self.__GetIdToken()
675 elif Ch == '"':
676 return self.__GetString()
677 elif Ch == '{':
678 return self.__GetArray()
679 elif Ch == '(' or Ch == ')':
680 self._Idx += 1
681 self._Token = Ch
682 return self._Token
683
684 raise BadExpression(ERR_VALID_TOKEN % Expr)
685
686 # Parse operator
687 def _GetOperator(self):
688 self.__SkipWS()
689 LegalOpLst = ['&&', '||', '!=', '==', '>=', '<='] + self.NonLetterOpLst + ['?',':']
690
691 self._Token = ''
692 Expr = self._Expr[self._Idx:]
693
694 # Reach end of expression
695 if not Expr:
696 return ''
697
698 # Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not
699 if Expr[0].isalpha():
700 return self.__GetIdToken(True)
701
702 # Start to get regular operator: +, -, <, > ...
703 if Expr[0] not in self.NonLetterOpLst:
704 return ''
705
706 OpToken = ''
707 for Ch in Expr:
708 if Ch in self.NonLetterOpLst:
709 if '!' == Ch and OpToken:
710 break
711 self._Idx += 1
712 OpToken += Ch
713 else:
714 break
715
716 if OpToken not in LegalOpLst:
717 raise BadExpression(ERR_OPERATOR_UNSUPPORT % OpToken)
718 self._Token = OpToken
719 return OpToken
720
721 # Check if current token matches the operators given from OpList
722 def _IsOperator(self, OpList):
723 Idx = self._Idx
724 self._GetOperator()
725 if self._Token in OpList:
726 if self._Token in self.LogicalOperators:
727 self._Token = self.LogicalOperators[self._Token]
728 return True
729 self._Idx = Idx
730 return False
731
732 class ValueExpressionEx(ValueExpression):
733 def __init__(self, PcdValue, PcdType, SymbolTable={}):
734 ValueExpression.__init__(self, PcdValue, SymbolTable)
735 self.PcdValue = PcdValue
736 self.PcdType = PcdType
737
738 def __call__(self, RealValue=False, Depth=0):
739 PcdValue = self.PcdValue
740 try:
741 PcdValue = ValueExpression.__call__(self, RealValue, Depth)
742 if self.PcdType == 'VOID*' and (PcdValue.startswith("'") or PcdValue.startswith("L'")):
743 raise BadExpression
744 elif self.PcdType in ['UINT8', 'UINT16', 'UINT32', 'UINT64', 'BOOLEAN'] and (PcdValue.startswith("'") or \
745 PcdValue.startswith('"') or PcdValue.startswith("L'") or PcdValue.startswith('L"') or PcdValue.startswith('{')):
746 raise BadExpression
747 except WrnExpression, Value:
748 PcdValue = Value.result
749 except BadExpression:
750 if self.PcdType in ['UINT8', 'UINT16', 'UINT32', 'UINT64', 'BOOLEAN']:
751 PcdValue = PcdValue.strip()
752 if type(PcdValue) == type('') and PcdValue.startswith('{') and PcdValue.endswith('}'):
753 PcdValue = PcdValue[1:-1].split(',')
754 if type(PcdValue) == type([]):
755 TmpValue = 0
756 Size = 0
757 for Item in PcdValue:
758 if Item.startswith('UINT16'):
759 ItemSize = 2
760 elif Item.startswith('UINT32'):
761 ItemSize = 4
762 elif Item.startswith('UINT64'):
763 ItemSize = 8
764 else:
765 ItemSize = 0
766 Item = ValueExpressionEx(Item, self.PcdType, self._Symb)(True)
767
768 if ItemSize == 0:
769 ItemValue, ItemSize = ParseFieldValue(Item)
770 else:
771 ItemValue = ParseFieldValue(Item)[0]
772
773 if type(ItemValue) == type(''):
774 ItemValue = int(ItemValue, 16) if ItemValue.startswith('0x') else int(ItemValue)
775
776 TmpValue = (ItemValue << (Size * 8)) | TmpValue
777 Size = Size + ItemSize
778 else:
779 TmpValue, Size = ParseFieldValue(PcdValue)
780 if type(TmpValue) == type(''):
781 TmpValue = int(TmpValue)
782 else:
783 PcdValue = '0x%0{}X'.format(Size) % (TmpValue)
784 if TmpValue < 0:
785 raise BadExpression('Type %s PCD Value is negative' % self.PcdType)
786 if self.PcdType == 'UINT8' and Size > 1:
787 raise BadExpression('Type %s PCD Value Size is Larger than 1 byte' % self.PcdType)
788 if self.PcdType == 'UINT16' and Size > 2:
789 raise BadExpression('Type %s PCD Value Size is Larger than 2 byte' % self.PcdType)
790 if self.PcdType == 'UINT32' and Size > 4:
791 raise BadExpression('Type %s PCD Value Size is Larger than 4 byte' % self.PcdType)
792 if self.PcdType == 'UINT64' and Size > 8:
793 raise BadExpression('Type %s PCD Value Size is Larger than 8 byte' % self.PcdType)
794 if self.PcdType in ['VOID*']:
795 try:
796 TmpValue = long(PcdValue)
797 TmpList = []
798 if TmpValue.bit_length() == 0:
799 PcdValue = '{0x00}'
800 else:
801 for I in range((TmpValue.bit_length() + 7) / 8):
802 TmpList.append('0x%02x' % ((TmpValue >> I * 8) & 0xff))
803 PcdValue = '{' + ', '.join(TmpList) + '}'
804 except:
805 if PcdValue.strip().startswith('{'):
806 PcdValue = PcdValue.strip()[1:-1].strip()
807 Size = 0
808 ValueStr = ''
809 TokenSpaceGuidName = ''
810 if PcdValue.startswith('GUID') and PcdValue.endswith(')'):
811 try:
812 TokenSpaceGuidName = re.search('GUID\((\w+)\)', PcdValue).group(1)
813 except:
814 pass
815 if TokenSpaceGuidName and TokenSpaceGuidName in self._Symb:
816 PcdValue = 'GUID(' + self._Symb[TokenSpaceGuidName] + ')'
817 elif TokenSpaceGuidName:
818 raise BadExpression('%s not found in DEC file' % TokenSpaceGuidName)
819
820 ListItem, Size = ParseFieldValue(PcdValue)
821 elif PcdValue.startswith('DEVICE_PATH') and PcdValue.endswith(')'):
822 ListItem, Size = ParseFieldValue(PcdValue)
823 else:
824 ListItem = PcdValue.split(',')
825
826 if type(ListItem) == type(0) or type(ListItem) == type(0L):
827 for Index in range(0, Size):
828 ValueStr += '0x%02X' % (int(ListItem) & 255)
829 ListItem >>= 8
830 ValueStr += ', '
831 PcdValue = '{' + ValueStr[:-2] + '}'
832 elif type(ListItem) == type(''):
833 if ListItem.startswith('{') and ListItem.endswith('}'):
834 PcdValue = ListItem
835 else:
836 LabelDict = {}
837 ReLabel = re.compile('LABEL\((\w+)\)')
838 ReOffset = re.compile('OFFSET_OF\((\w+)\)')
839 for Index, Item in enumerate(ListItem):
840 # for LABEL parse
841 Item = Item.strip()
842 try:
843 LabelList = ReLabel.findall(Item)
844 for Label in LabelList:
845 if Label not in LabelDict.keys():
846 LabelDict[Label] = str(Index)
847 Item = ReLabel.sub('', Item)
848 except:
849 pass
850 try:
851 OffsetList = ReOffset.findall(Item)
852 except:
853 pass
854 for Offset in OffsetList:
855 if Offset in LabelDict.keys():
856 Re = re.compile('OFFSET_OF\(%s\)'% Offset)
857 Item = Re.sub(LabelDict[Offset], Item)
858 else:
859 raise BadExpression('%s not defined before use' % Offset)
860 ValueType = ""
861 if Item.startswith('UINT16'):
862 ItemSize = 1
863 ValueType = "UINT8"
864 elif Item.startswith('UINT16'):
865 ItemSize = 2
866 ValueType = "UINT16"
867 elif Item.startswith('UINT32'):
868 ItemSize = 4
869 elif Item.startswith('UINT64'):
870 ItemSize = 8
871 else:
872 ItemSize = 0
873 if ValueType:
874 TmpValue = ValueExpressionEx(Item, ValueType, self._Symb)(True)
875 else:
876 TmpValue = ValueExpressionEx(Item, self.PcdType, self._Symb)(True)
877 Item = '0x%x' % TmpValue if type(TmpValue) != type('') else TmpValue
878 if ItemSize == 0:
879 ItemValue, ItemSize = ParseFieldValue(Item)
880 else:
881 ItemValue = ParseFieldValue(Item)[0]
882 for I in range(0, ItemSize):
883 ValueStr += '0x%02X' % (int(ItemValue) & 255)
884 ItemValue >>= 8
885 ValueStr += ', '
886 Size += ItemSize
887
888 if Size > 0:
889 PcdValue = '{' + ValueStr[:-2] + '}'
890 if PcdValue == 'True':
891 PcdValue = '1'
892 if PcdValue == 'False':
893 PcdValue = '0'
894
895 if RealValue:
896 return PcdValue
897
898 if __name__ == '__main__':
899 pass
900 while True:
901 input = raw_input('Input expr: ')
902 if input in 'qQ':
903 break
904 try:
905 print ValueExpression(input)(True)
906 print ValueExpression(input)(False)
907 except WrnExpression, Ex:
908 print Ex.result
909 print str(Ex)
910 except Exception, Ex:
911 print str(Ex)