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