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