]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Common/RangeExpression.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Source / Python / Common / RangeExpression.py
CommitLineData
82a6a960
BF
1# # @file\r
2# This file is used to parse and evaluate range expression in Pcd declaration.\r
3#\r
c1e73234 4# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
2e351cbe 5# SPDX-License-Identifier: BSD-2-Clause-Patent\r
82a6a960
BF
6\r
7# # Import Modules\r
8#\r
1ccc4d89 9from __future__ import print_function\r
82a6a960
BF
10from Common.GlobalData import *\r
11from CommonDataClass.Exceptions import BadExpression\r
12from CommonDataClass.Exceptions import WrnExpression\r
13import uuid\r
ccaa7754 14from Common.Expression import PcdPattern, BaseExpression\r
25598f8b 15from Common.DataType import *\r
938cf4c3 16from re import compile\r
82a6a960
BF
17\r
18ERR_STRING_EXPR = 'This operator cannot be used in string expression: [%s].'\r
19ERR_SNYTAX = 'Syntax error, the rest of expression cannot be evaluated: [%s].'\r
20ERR_MATCH = 'No matching right parenthesis.'\r
21ERR_STRING_TOKEN = 'Bad string token: [%s].'\r
22ERR_MACRO_TOKEN = 'Bad macro token: [%s].'\r
23ERR_EMPTY_TOKEN = 'Empty token is not allowed.'\r
fa6e2804 24ERR_PCD_RESOLVE = 'The PCD should be FeatureFlag type or FixedAtBuild type: [%s].'\r
82a6a960
BF
25ERR_VALID_TOKEN = 'No more valid token found from rest of string: [%s].'\r
26ERR_EXPR_TYPE = 'Different types found in expression.'\r
27ERR_OPERATOR_UNSUPPORT = 'Unsupported operator: [%s]'\r
28ERR_REL_NOT_IN = 'Expect "IN" after "not" operator.'\r
29WRN_BOOL_EXPR = 'Operand of boolean type cannot be used in arithmetic expression.'\r
30WRN_EQCMP_STR_OTHERS = '== Comparison between Operand of string type and Boolean/Number Type always return False.'\r
31WRN_NECMP_STR_OTHERS = '!= Comparison between Operand of string type and Boolean/Number Type always return True.'\r
32ERR_RELCMP_STR_OTHERS = 'Operator taking Operand of string type and Boolean/Number Type is not allowed: [%s].'\r
33ERR_STRING_CMP = 'Unicode string and general string cannot be compared: [%s %s %s]'\r
34ERR_ARRAY_TOKEN = 'Bad C array or C format GUID token: [%s].'\r
35ERR_ARRAY_ELE = 'This must be HEX value for NList or Array: [%s].'\r
36ERR_EMPTY_EXPR = 'Empty expression is not allowed.'\r
37ERR_IN_OPERAND = 'Macro after IN operator can only be: $(FAMILY), $(ARCH), $(TOOL_CHAIN_TAG) and $(TARGET).'\r
38\r
82a6a960
BF
39class RangeObject(object):\r
40 def __init__(self, start, end, empty = False):\r
f7496d71 41\r
82a6a960
BF
42 if int(start) < int(end):\r
43 self.start = int(start)\r
44 self.end = int(end)\r
45 else:\r
46 self.start = int(end)\r
47 self.end = int(start)\r
48 self.empty = empty\r
49\r
50class RangeContainer(object):\r
51 def __init__(self):\r
52 self.rangelist = []\r
f7496d71 53\r
82a6a960
BF
54 def push(self, RangeObject):\r
55 self.rangelist.append(RangeObject)\r
56 self.rangelist = sorted(self.rangelist, key = lambda rangeobj : rangeobj.start)\r
57 self.merge()\r
f7496d71 58\r
82a6a960
BF
59 def pop(self):\r
60 for item in self.rangelist:\r
61 yield item\r
f7496d71
LG
62\r
63 def __clean__(self):\r
82a6a960
BF
64 newrangelist = []\r
65 for rangeobj in self.rangelist:\r
66 if rangeobj.empty == True:\r
67 continue\r
68 else:\r
69 newrangelist.append(rangeobj)\r
f7496d71 70 self.rangelist = newrangelist\r
82a6a960
BF
71 def merge(self):\r
72 self.__clean__()\r
73 for i in range(0, len(self.rangelist) - 1):\r
74 if self.rangelist[i + 1].start > self.rangelist[i].end:\r
75 continue\r
76 else:\r
77 self.rangelist[i + 1].start = self.rangelist[i].start\r
f7496d71 78 self.rangelist[i + 1].end = self.rangelist[i + 1].end > self.rangelist[i].end and self.rangelist[i + 1].end or self.rangelist[i].end\r
82a6a960
BF
79 self.rangelist[i].empty = True\r
80\r
81 self.__clean__()\r
f7496d71 82\r
82a6a960 83 def dump(self):\r
72443dd2 84 print("----------------------")\r
82a6a960
BF
85 rangelist = ""\r
86 for object in self.rangelist:\r
87 rangelist = rangelist + "[%d , %d]" % (object.start, object.end)\r
72443dd2 88 print(rangelist)\r
f7496d71
LG
89\r
90\r
91class XOROperatorObject(object):\r
92 def __init__(self):\r
82a6a960 93 pass\r
f7496d71 94 def Calculate(self, Operand, DataType, SymbolTable):\r
0d1f5b2b 95 if isinstance(Operand, type('')) and not Operand.isalnum():\r
82a6a960
BF
96 Expr = "XOR ..."\r
97 raise BadExpression(ERR_SNYTAX % Expr)\r
98 rangeId = str(uuid.uuid1())\r
99 rangeContainer = RangeContainer()\r
100 rangeContainer.push(RangeObject(0, int(Operand) - 1))\r
25598f8b 101 rangeContainer.push(RangeObject(int(Operand) + 1, MAX_VAL_TYPE[DataType]))\r
82a6a960
BF
102 SymbolTable[rangeId] = rangeContainer\r
103 return rangeId\r
104\r
105class LEOperatorObject(object):\r
f7496d71 106 def __init__(self):\r
82a6a960 107 pass\r
f7496d71 108 def Calculate(self, Operand, DataType, SymbolTable):\r
0d1f5b2b 109 if isinstance(Operand, type('')) and not Operand.isalnum():\r
82a6a960
BF
110 Expr = "LE ..."\r
111 raise BadExpression(ERR_SNYTAX % Expr)\r
112 rangeId1 = str(uuid.uuid1())\r
113 rangeContainer = RangeContainer()\r
114 rangeContainer.push(RangeObject(0, int(Operand)))\r
115 SymbolTable[rangeId1] = rangeContainer\r
116 return rangeId1\r
117class LTOperatorObject(object):\r
f7496d71 118 def __init__(self):\r
82a6a960
BF
119 pass\r
120 def Calculate(self, Operand, DataType, SymbolTable):\r
0d1f5b2b 121 if isinstance(Operand, type('')) and not Operand.isalnum():\r
f7496d71
LG
122 Expr = "LT ..."\r
123 raise BadExpression(ERR_SNYTAX % Expr)\r
82a6a960
BF
124 rangeId1 = str(uuid.uuid1())\r
125 rangeContainer = RangeContainer()\r
126 rangeContainer.push(RangeObject(0, int(Operand) - 1))\r
127 SymbolTable[rangeId1] = rangeContainer\r
f7496d71 128 return rangeId1\r
82a6a960
BF
129\r
130class GEOperatorObject(object):\r
f7496d71 131 def __init__(self):\r
82a6a960 132 pass\r
f7496d71 133 def Calculate(self, Operand, DataType, SymbolTable):\r
0d1f5b2b 134 if isinstance(Operand, type('')) and not Operand.isalnum():\r
82a6a960
BF
135 Expr = "GE ..."\r
136 raise BadExpression(ERR_SNYTAX % Expr)\r
137 rangeId1 = str(uuid.uuid1())\r
138 rangeContainer = RangeContainer()\r
25598f8b 139 rangeContainer.push(RangeObject(int(Operand), MAX_VAL_TYPE[DataType]))\r
82a6a960 140 SymbolTable[rangeId1] = rangeContainer\r
f7496d71
LG
141 return rangeId1\r
142\r
82a6a960 143class GTOperatorObject(object):\r
f7496d71 144 def __init__(self):\r
82a6a960 145 pass\r
f7496d71 146 def Calculate(self, Operand, DataType, SymbolTable):\r
0d1f5b2b 147 if isinstance(Operand, type('')) and not Operand.isalnum():\r
82a6a960
BF
148 Expr = "GT ..."\r
149 raise BadExpression(ERR_SNYTAX % Expr)\r
150 rangeId1 = str(uuid.uuid1())\r
151 rangeContainer = RangeContainer()\r
25598f8b 152 rangeContainer.push(RangeObject(int(Operand) + 1, MAX_VAL_TYPE[DataType]))\r
82a6a960 153 SymbolTable[rangeId1] = rangeContainer\r
f7496d71
LG
154 return rangeId1\r
155\r
82a6a960 156class EQOperatorObject(object):\r
f7496d71 157 def __init__(self):\r
82a6a960 158 pass\r
f7496d71 159 def Calculate(self, Operand, DataType, SymbolTable):\r
0d1f5b2b 160 if isinstance(Operand, type('')) and not Operand.isalnum():\r
82a6a960
BF
161 Expr = "EQ ..."\r
162 raise BadExpression(ERR_SNYTAX % Expr)\r
163 rangeId1 = str(uuid.uuid1())\r
164 rangeContainer = RangeContainer()\r
ccaa7754 165 rangeContainer.push(RangeObject(int(Operand), int(Operand)))\r
82a6a960 166 SymbolTable[rangeId1] = rangeContainer\r
f7496d71
LG
167 return rangeId1\r
168\r
82a6a960
BF
169def GetOperatorObject(Operator):\r
170 if Operator == '>':\r
171 return GTOperatorObject()\r
172 elif Operator == '>=':\r
173 return GEOperatorObject()\r
174 elif Operator == '<':\r
175 return LTOperatorObject()\r
176 elif Operator == '<=':\r
177 return LEOperatorObject()\r
178 elif Operator == '==':\r
179 return EQOperatorObject()\r
180 elif Operator == '^':\r
181 return XOROperatorObject()\r
182 else:\r
183 raise BadExpression("Bad Operator")\r
184\r
b2aeaf57 185class RangeExpression(BaseExpression):\r
82a6a960
BF
186 # Logical operator mapping\r
187 LogicalOperators = {\r
188 '&&' : 'and', '||' : 'or',\r
189 '!' : 'not', 'AND': 'and',\r
190 'OR' : 'or' , 'NOT': 'not',\r
191 'XOR': '^' , 'xor': '^',\r
192 'EQ' : '==' , 'NE' : '!=',\r
193 'GT' : '>' , 'LT' : '<',\r
194 'GE' : '>=' , 'LE' : '<=',\r
195 'IN' : 'in'\r
196 }\r
197\r
198 NonLetterOpLst = ['+', '-', '&', '|', '^', '!', '=', '>', '<']\r
199\r
938cf4c3 200 RangePattern = compile(r'[0-9]+ - [0-9]+')\r
82a6a960
BF
201\r
202 def preProcessRangeExpr(self, expr):\r
203 # convert hex to int\r
204 # convert interval to object index. ex. 1 - 10 to a GUID\r
205 expr = expr.strip()\r
206 NumberDict = {}\r
56326323 207 for HexNumber in gHexPattern.findall(expr):\r
82a6a960
BF
208 Number = str(int(HexNumber, 16))\r
209 NumberDict[HexNumber] = Number\r
210 for HexNum in NumberDict:\r
211 expr = expr.replace(HexNum, NumberDict[HexNum])\r
f7496d71
LG
212\r
213 rangedict = {}\r
82a6a960
BF
214 for validrange in self.RangePattern.findall(expr):\r
215 start, end = validrange.split(" - ")\r
216 start = start.strip()\r
217 end = end.strip()\r
218 rangeid = str(uuid.uuid1())\r
219 rangeContainer = RangeContainer()\r
220 rangeContainer.push(RangeObject(start, end))\r
221 self.operanddict[str(rangeid)] = rangeContainer\r
222 rangedict[validrange] = str(rangeid)\r
f7496d71 223\r
82a6a960
BF
224 for validrange in rangedict:\r
225 expr = expr.replace(validrange, rangedict[validrange])\r
f7496d71
LG
226\r
227 self._Expr = expr\r
82a6a960 228 return expr\r
f7496d71
LG
229\r
230\r
82a6a960
BF
231 def EvalRange(self, Operator, Oprand):\r
232\r
233 operatorobj = GetOperatorObject(Operator)\r
234 return operatorobj.Calculate(Oprand, self.PcdDataType, self.operanddict)\r
f7496d71 235\r
82a6a960
BF
236 def Rangeintersection(self, Oprand1, Oprand2):\r
237 rangeContainer1 = self.operanddict[Oprand1]\r
238 rangeContainer2 = self.operanddict[Oprand2]\r
239 rangeContainer = RangeContainer()\r
240 for range1 in rangeContainer1.pop():\r
241 for range2 in rangeContainer2.pop():\r
0b5203bd
BF
242 start1 = range1.start\r
243 end1 = range1.end\r
244 start2 = range2.start\r
245 end2 = range2.end\r
246 if start1 >= start2:\r
247 start1, start2 = start2, start1\r
248 end1, end2 = end2, end1\r
82a6a960
BF
249 if range1.empty:\r
250 rangeid = str(uuid.uuid1())\r
251 rangeContainer.push(RangeObject(0, 0, True))\r
0b5203bd 252 if end1 < start2:\r
82a6a960
BF
253 rangeid = str(uuid.uuid1())\r
254 rangeContainer.push(RangeObject(0, 0, True))\r
0b5203bd 255 elif end1 == start2:\r
82a6a960 256 rangeid = str(uuid.uuid1())\r
0b5203bd
BF
257 rangeContainer.push(RangeObject(end1, end1))\r
258 elif end1 <= end2 and end1 > start2:\r
82a6a960 259 rangeid = str(uuid.uuid1())\r
0b5203bd
BF
260 rangeContainer.push(RangeObject(start2, end1))\r
261 elif end1 >= end2:\r
82a6a960 262 rangeid = str(uuid.uuid1())\r
0b5203bd 263 rangeContainer.push(RangeObject(start2, end2))\r
f7496d71 264\r
82a6a960
BF
265 self.operanddict[rangeid] = rangeContainer\r
266# rangeContainer.dump()\r
267 return rangeid\r
f7496d71 268\r
82a6a960
BF
269 def Rangecollections(self, Oprand1, Oprand2):\r
270\r
271 rangeContainer1 = self.operanddict[Oprand1]\r
272 rangeContainer2 = self.operanddict[Oprand2]\r
273 rangeContainer = RangeContainer()\r
f7496d71 274\r
82a6a960
BF
275 for rangeobj in rangeContainer2.pop():\r
276 rangeContainer.push(rangeobj)\r
277 for rangeobj in rangeContainer1.pop():\r
278 rangeContainer.push(rangeobj)\r
f7496d71 279\r
82a6a960
BF
280 rangeid = str(uuid.uuid1())\r
281 self.operanddict[rangeid] = rangeContainer\r
f7496d71 282\r
82a6a960
BF
283# rangeContainer.dump()\r
284 return rangeid\r
f7496d71
LG
285\r
286\r
fb0b35e0 287 def NegativeRange(self, Oprand1):\r
82a6a960 288 rangeContainer1 = self.operanddict[Oprand1]\r
f7496d71
LG
289\r
290\r
82a6a960 291 rangeids = []\r
f7496d71 292\r
82a6a960
BF
293 for rangeobj in rangeContainer1.pop():\r
294 rangeContainer = RangeContainer()\r
295 rangeid = str(uuid.uuid1())\r
296 if rangeobj.empty:\r
25598f8b 297 rangeContainer.push(RangeObject(0, MAX_VAL_TYPE[self.PcdDataType]))\r
82a6a960
BF
298 else:\r
299 if rangeobj.start > 0:\r
300 rangeContainer.push(RangeObject(0, rangeobj.start - 1))\r
25598f8b
CJ
301 if rangeobj.end < MAX_VAL_TYPE[self.PcdDataType]:\r
302 rangeContainer.push(RangeObject(rangeobj.end + 1, MAX_VAL_TYPE[self.PcdDataType]))\r
82a6a960
BF
303 self.operanddict[rangeid] = rangeContainer\r
304 rangeids.append(rangeid)\r
305\r
306 if len(rangeids) == 0:\r
307 rangeContainer = RangeContainer()\r
25598f8b 308 rangeContainer.push(RangeObject(0, MAX_VAL_TYPE[self.PcdDataType]))\r
82a6a960
BF
309 rangeid = str(uuid.uuid1())\r
310 self.operanddict[rangeid] = rangeContainer\r
311 return rangeid\r
312\r
313 if len(rangeids) == 1:\r
314 return rangeids[0]\r
315\r
316 re = self.Rangeintersection(rangeids[0], rangeids[1])\r
317 for i in range(2, len(rangeids)):\r
318 re = self.Rangeintersection(re, rangeids[i])\r
f7496d71 319\r
82a6a960
BF
320 rangeid2 = str(uuid.uuid1())\r
321 self.operanddict[rangeid2] = self.operanddict[re]\r
322 return rangeid2\r
f7496d71 323\r
82a6a960 324 def Eval(self, Operator, Oprand1, Oprand2 = None):\r
f7496d71 325\r
82a6a960 326 if Operator in ["!", "NOT", "not"]:\r
b1a9e404 327 if not gGuidPattern.match(Oprand1.strip()):\r
82a6a960 328 raise BadExpression(ERR_STRING_EXPR % Operator)\r
fb0b35e0 329 return self.NegativeRange(Oprand1)\r
82a6a960
BF
330 else:\r
331 if Operator in ["==", ">=", "<=", ">", "<", '^']:\r
332 return self.EvalRange(Operator, Oprand1)\r
333 elif Operator == 'and' :\r
b1a9e404 334 if not gGuidPatternEnd.match(Oprand1.strip()) or not gGuidPatternEnd.match(Oprand2.strip()):\r
82a6a960 335 raise BadExpression(ERR_STRING_EXPR % Operator)\r
f7496d71 336 return self.Rangeintersection(Oprand1, Oprand2)\r
82a6a960 337 elif Operator == 'or':\r
b1a9e404 338 if not gGuidPatternEnd.match(Oprand1.strip()) or not gGuidPatternEnd.match(Oprand2.strip()):\r
82a6a960
BF
339 raise BadExpression(ERR_STRING_EXPR % Operator)\r
340 return self.Rangecollections(Oprand1, Oprand2)\r
341 else:\r
342 raise BadExpression(ERR_STRING_EXPR % Operator)\r
343\r
344\r
e32f7bc9
FZ
345 def __init__(self, Expression, PcdDataType, SymbolTable = None):\r
346 if SymbolTable is None:\r
347 SymbolTable = {}\r
1ccc4d89 348 super(RangeExpression, self).__init__(self, Expression, PcdDataType, SymbolTable)\r
82a6a960 349 self._NoProcess = False\r
0d1f5b2b 350 if not isinstance(Expression, type('')):\r
82a6a960
BF
351 self._Expr = Expression\r
352 self._NoProcess = True\r
353 return\r
354\r
355 self._Expr = Expression.strip()\r
356\r
357 if not self._Expr.strip():\r
358 raise BadExpression(ERR_EMPTY_EXPR)\r
359\r
360 #\r
361 # The symbol table including PCD and macro mapping\r
362 #\r
363 self._Symb = SymbolTable\r
364 self._Symb.update(self.LogicalOperators)\r
365 self._Idx = 0\r
366 self._Len = len(self._Expr)\r
367 self._Token = ''\r
368 self._WarnExcept = None\r
f7496d71 369\r
82a6a960
BF
370\r
371 # Literal token without any conversion\r
372 self._LiteralToken = ''\r
f7496d71 373\r
82a6a960
BF
374 # store the operand object\r
375 self.operanddict = {}\r
376 # The Pcd max value depends on PcdDataType\r
377 self.PcdDataType = PcdDataType\r
378\r
379 # Public entry for this class\r
380 # @param RealValue: False: only evaluate if the expression is true or false, used for conditional expression\r
381 # True : return the evaluated str(value), used for PCD value\r
382 #\r
383 # @return: True or False if RealValue is False\r
384 # Evaluated value of string format if RealValue is True\r
385 #\r
386 def __call__(self, RealValue = False, Depth = 0):\r
387 if self._NoProcess:\r
388 return self._Expr\r
389\r
390 self._Depth = Depth\r
391\r
392 self._Expr = self._Expr.strip()\r
f7496d71 393\r
82a6a960 394 self.preProcessRangeExpr(self._Expr)\r
f7496d71 395\r
82a6a960
BF
396 # check if the expression does not need to evaluate\r
397 if RealValue and Depth == 0:\r
398 self._Token = self._Expr\r
b1a9e404 399 if gGuidPatternEnd.match(self._Expr):\r
82a6a960
BF
400 return [self.operanddict[self._Expr] ]\r
401\r
402 self._Idx = 0\r
403 self._Token = ''\r
404\r
405 Val = self._OrExpr()\r
406 RealVal = Val\r
f7496d71 407\r
82a6a960
BF
408 RangeIdList = RealVal.split("or")\r
409 RangeList = []\r
410 for rangeid in RangeIdList:\r
411 RangeList.append(self.operanddict[rangeid.strip()])\r
f7496d71 412\r
82a6a960
BF
413 return RangeList\r
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
82a6a960 418 Val = EvalFunc()\r
4d601fc6 419 while self._IsOperator(OpSet):\r
82a6a960
BF
420 Op = self._Token\r
421 try:\r
422 Val = self.Eval(Op, Val, EvalFunc())\r
5b0671c1 423 except WrnExpression as Warn:\r
82a6a960
BF
424 self._WarnExcept = Warn\r
425 Val = Warn.result\r
426 return Val\r
427\r
428 # A [|| B]*\r
429 def _OrExpr(self):\r
4d601fc6 430 return self._ExprFuncTemplate(self._AndExpr, {"OR", "or"})\r
82a6a960
BF
431\r
432 # A [&& B]*\r
433 def _AndExpr(self):\r
4d601fc6 434 return self._ExprFuncTemplate(self._NeExpr, {"AND", "and"})\r
82a6a960
BF
435\r
436 def _NeExpr(self):\r
437 Val = self._RelExpr()\r
4d601fc6 438 while self._IsOperator({"!=", "NOT", "not"}):\r
82a6a960
BF
439 Op = self._Token\r
440 if Op in ["!", "NOT", "not"]:\r
4d601fc6 441 if not self._IsOperator({"IN", "in"}):\r
82a6a960
BF
442 raise BadExpression(ERR_REL_NOT_IN)\r
443 Op += ' ' + self._Token\r
444 try:\r
445 Val = self.Eval(Op, Val, self._RelExpr())\r
5b0671c1 446 except WrnExpression as Warn:\r
82a6a960
BF
447 self._WarnExcept = Warn\r
448 Val = Warn.result\r
449 return Val\r
450\r
451 # [!]*A\r
452 def _RelExpr(self):\r
ccaa7754 453 if self._IsOperator({"NOT", "LE", "GE", "LT", "GT", "EQ", "XOR"}):\r
82a6a960
BF
454 Token = self._Token\r
455 Val = self._NeExpr()\r
456 try:\r
457 return self.Eval(Token, Val)\r
5b0671c1 458 except WrnExpression as Warn:\r
82a6a960
BF
459 self._WarnExcept = Warn\r
460 return Warn.result\r
461 return self._IdenExpr()\r
462\r
463 # Parse identifier or encapsulated expression\r
464 def _IdenExpr(self):\r
465 Tk = self._GetToken()\r
466 if Tk == '(':\r
467 Val = self._OrExpr()\r
468 try:\r
469 # _GetToken may also raise BadExpression\r
470 if self._GetToken() != ')':\r
471 raise BadExpression(ERR_MATCH)\r
472 except BadExpression:\r
473 raise BadExpression(ERR_MATCH)\r
474 return Val\r
475 return Tk\r
476\r
477 # Skip whitespace or tab\r
478 def __SkipWS(self):\r
479 for Char in self._Expr[self._Idx:]:\r
480 if Char not in ' \t':\r
481 break\r
482 self._Idx += 1\r
483\r
484 # Try to convert string to number\r
485 def __IsNumberToken(self):\r
486 Radix = 10\r
487 if self._Token.lower()[0:2] == '0x' and len(self._Token) > 2:\r
488 Radix = 16\r
489 try:\r
490 self._Token = int(self._Token, Radix)\r
491 return True\r
492 except ValueError:\r
493 return False\r
494 except TypeError:\r
495 return False\r
496\r
497 # Parse array: {...}\r
498 def __GetArray(self):\r
499 Token = '{'\r
500 self._Idx += 1\r
501 self.__GetNList(True)\r
502 Token += self._LiteralToken\r
503 if self._Idx >= self._Len or self._Expr[self._Idx] != '}':\r
504 raise BadExpression(ERR_ARRAY_TOKEN % Token)\r
505 Token += '}'\r
506\r
507 # All whitespace and tabs in array are already stripped.\r
508 IsArray = IsGuid = False\r
509 if len(Token.split(',')) == 11 and len(Token.split(',{')) == 2 \\r
510 and len(Token.split('},')) == 1:\r
511 HexLen = [11, 6, 6, 5, 4, 4, 4, 4, 4, 4, 6]\r
512 HexList = Token.split(',')\r
513 if HexList[3].startswith('{') and \\r
514 not [Index for Index, Hex in enumerate(HexList) if len(Hex) > HexLen[Index]]:\r
515 IsGuid = True\r
516 if Token.lstrip('{').rstrip('}').find('{') == -1:\r
517 if not [Hex for Hex in Token.lstrip('{').rstrip('}').split(',') if len(Hex) > 4]:\r
518 IsArray = True\r
519 if not IsArray and not IsGuid:\r
520 raise BadExpression(ERR_ARRAY_TOKEN % Token)\r
521 self._Idx += 1\r
522 self._Token = self._LiteralToken = Token\r
523 return self._Token\r
524\r
525 # Parse string, the format must be: "..."\r
526 def __GetString(self):\r
527 Idx = self._Idx\r
528\r
529 # Skip left quote\r
530 self._Idx += 1\r
531\r
532 # Replace escape \\\", \"\r
533 Expr = self._Expr[self._Idx:].replace('\\\\', '//').replace('\\\"', '\\\'')\r
534 for Ch in Expr:\r
535 self._Idx += 1\r
536 if Ch == '"':\r
537 break\r
538 self._Token = self._LiteralToken = self._Expr[Idx:self._Idx]\r
539 if not self._Token.endswith('"'):\r
540 raise BadExpression(ERR_STRING_TOKEN % self._Token)\r
541 self._Token = self._Token[1:-1]\r
542 return self._Token\r
543\r
544 # Get token that is comprised by alphanumeric, underscore or dot(used by PCD)\r
545 # @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...)\r
546 def __GetIdToken(self, IsAlphaOp = False):\r
547 IdToken = ''\r
548 for Ch in self._Expr[self._Idx:]:\r
549 if not self.__IsIdChar(Ch):\r
550 break\r
551 self._Idx += 1\r
552 IdToken += Ch\r
553\r
554 self._Token = self._LiteralToken = IdToken\r
555 if not IsAlphaOp:\r
556 self.__ResolveToken()\r
557 return self._Token\r
558\r
559 # Try to resolve token\r
560 def __ResolveToken(self):\r
561 if not self._Token:\r
562 raise BadExpression(ERR_EMPTY_TOKEN)\r
563\r
564 # PCD token\r
e6c2468a 565 if PcdPattern.match(self._Token):\r
82a6a960
BF
566 if self._Token not in self._Symb:\r
567 Ex = BadExpression(ERR_PCD_RESOLVE % self._Token)\r
568 Ex.Pcd = self._Token\r
569 raise Ex\r
570 self._Token = RangeExpression(self._Symb[self._Token], self._Symb)(True, self._Depth + 1)\r
0d1f5b2b 571 if not isinstance(self._Token, type('')):\r
82a6a960
BF
572 self._LiteralToken = hex(self._Token)\r
573 return\r
574\r
575 if self._Token.startswith('"'):\r
576 self._Token = self._Token[1:-1]\r
577 elif self._Token in ["FALSE", "false", "False"]:\r
578 self._Token = False\r
579 elif self._Token in ["TRUE", "true", "True"]:\r
580 self._Token = True\r
581 else:\r
582 self.__IsNumberToken()\r
583\r
584 def __GetNList(self, InArray = False):\r
585 self._GetSingleToken()\r
586 if not self.__IsHexLiteral():\r
587 if InArray:\r
588 raise BadExpression(ERR_ARRAY_ELE % self._Token)\r
589 return self._Token\r
590\r
591 self.__SkipWS()\r
592 Expr = self._Expr[self._Idx:]\r
593 if not Expr.startswith(','):\r
594 return self._Token\r
595\r
596 NList = self._LiteralToken\r
597 while Expr.startswith(','):\r
598 NList += ','\r
599 self._Idx += 1\r
600 self.__SkipWS()\r
601 self._GetSingleToken()\r
602 if not self.__IsHexLiteral():\r
603 raise BadExpression(ERR_ARRAY_ELE % self._Token)\r
604 NList += self._LiteralToken\r
605 self.__SkipWS()\r
606 Expr = self._Expr[self._Idx:]\r
607 self._Token = self._LiteralToken = NList\r
608 return self._Token\r
609\r
610 def __IsHexLiteral(self):\r
611 if self._LiteralToken.startswith('{') and \\r
612 self._LiteralToken.endswith('}'):\r
613 return True\r
614\r
56326323 615 if gHexPattern.match(self._LiteralToken):\r
82a6a960
BF
616 Token = self._LiteralToken[2:]\r
617 Token = Token.lstrip('0')\r
618 if not Token:\r
619 self._LiteralToken = '0x0'\r
620 else:\r
621 self._LiteralToken = '0x' + Token.lower()\r
622 return True\r
623 return False\r
624\r
625 def _GetToken(self):\r
626 return self.__GetNList()\r
627\r
628 @staticmethod\r
629 def __IsIdChar(Ch):\r
630 return Ch in '._/:' or Ch.isalnum()\r
631\r
632 # Parse operand\r
633 def _GetSingleToken(self):\r
634 self.__SkipWS()\r
635 Expr = self._Expr[self._Idx:]\r
636 if Expr.startswith('L"'):\r
637 # Skip L\r
638 self._Idx += 1\r
639 UStr = self.__GetString()\r
640 self._Token = 'L"' + UStr + '"'\r
641 return self._Token\r
642\r
643 self._Token = ''\r
644 if Expr:\r
645 Ch = Expr[0]\r
b1a9e404 646 Match = gGuidPattern.match(Expr)\r
82a6a960
BF
647 if Match and not Expr[Match.end():Match.end() + 1].isalnum() \\r
648 and Expr[Match.end():Match.end() + 1] != '_':\r
649 self._Idx += Match.end()\r
650 self._Token = Expr[0:Match.end()]\r
651 return self._Token\r
652 elif self.__IsIdChar(Ch):\r
653 return self.__GetIdToken()\r
654 elif Ch == '(' or Ch == ')':\r
655 self._Idx += 1\r
656 self._Token = Ch\r
657 return self._Token\r
658\r
659 raise BadExpression(ERR_VALID_TOKEN % Expr)\r
660\r
661 # Parse operator\r
662 def _GetOperator(self):\r
663 self.__SkipWS()\r
664 LegalOpLst = ['&&', '||', '!=', '==', '>=', '<='] + self.NonLetterOpLst\r
665\r
666 self._Token = ''\r
667 Expr = self._Expr[self._Idx:]\r
668\r
669 # Reach end of expression\r
670 if not Expr:\r
671 return ''\r
672\r
673 # Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not\r
674 if Expr[0].isalpha():\r
675 return self.__GetIdToken(True)\r
676\r
677 # Start to get regular operator: +, -, <, > ...\r
678 if Expr[0] not in self.NonLetterOpLst:\r
679 return ''\r
680\r
681 OpToken = ''\r
682 for Ch in Expr:\r
683 if Ch in self.NonLetterOpLst:\r
684 if '!' == Ch and OpToken:\r
685 break\r
686 self._Idx += 1\r
687 OpToken += Ch\r
688 else:\r
689 break\r
690\r
691 if OpToken not in LegalOpLst:\r
692 raise BadExpression(ERR_OPERATOR_UNSUPPORT % OpToken)\r
693 self._Token = OpToken\r
694 return OpToken\r