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