]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/UPT/Parser/DecParserMisc.py
Revert BaseTools: PYTHON3 migration
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Parser / DecParserMisc.py
CommitLineData
4234283c
LG
1## @file\r
2# This file is used to define helper class and function for DEC parser\r
3#\r
f7496d71 4# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
4234283c 5#\r
f7496d71
LG
6# This program and the accompanying materials are licensed and made available\r
7# under the terms and conditions of the BSD License which accompanies this\r
8# distribution. The full text of the license may be found at\r
4234283c
LG
9# http://opensource.org/licenses/bsd-license.php\r
10#\r
11# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14'''\r
15DecParserMisc\r
16'''\r
17\r
18## Import modules\r
19#\r
20import os\r
21import Logger.Log as Logger\r
22from Logger.ToolError import FILE_PARSE_FAILURE\r
23from Logger import StringTable as ST\r
24from Library.DataType import TAB_COMMENT_SPLIT\r
25from Library.DataType import TAB_COMMENT_EDK1_SPLIT\r
26from Library.ExpressionValidate import IsValidBareCString\r
27from Library.ParserValidate import IsValidCFormatGuid\r
421ccda3 28from Library.ExpressionValidate import IsValidFeatureFlagExp\r
4234283c
LG
29from Library.ExpressionValidate import IsValidLogicalExpr\r
30from Library.ExpressionValidate import IsValidStringTest\r
31from Library.Misc import CheckGuidRegFormat\r
32\r
33TOOL_NAME = 'DecParser'\r
34VERSION_PATTERN = '[0-9]+(\.[0-9]+)?'\r
35CVAR_PATTERN = '[_a-zA-Z][a-zA-Z0-9_]*'\r
36PCD_TOKEN_PATTERN = '(0[xX]0*[a-fA-F0-9]{1,8})|([0-9]+)'\r
37MACRO_PATTERN = '[A-Z][_A-Z0-9]*'\r
38\r
39## FileContent\r
40# Class to hold DEC file information\r
41#\r
42class FileContent:\r
43 def __init__(self, Filename, FileContent2):\r
44 self.Filename = Filename\r
45 self.PackagePath, self.PackageFile = os.path.split(Filename)\r
46 self.LineIndex = 0\r
47 self.CurrentLine = ''\r
48 self.NextLine = ''\r
49 self.HeadComment = []\r
50 self.TailComment = []\r
51 self.CurrentScope = None\r
52 self.Content = FileContent2\r
53 self.Macros = {}\r
54 self.FileLines = len(FileContent2)\r
55\r
56 def GetNextLine(self):\r
57 if self.LineIndex >= self.FileLines:\r
58 return ''\r
59 Line = self.Content[self.LineIndex]\r
60 self.LineIndex += 1\r
61 return Line\r
62\r
63 def UndoNextLine(self):\r
64 if self.LineIndex > 0:\r
65 self.LineIndex -= 1\r
66\r
67 def ResetNext(self):\r
68 self.HeadComment = []\r
69 self.TailComment = []\r
70 self.NextLine = ''\r
71\r
72 def SetNext(self, Line, HeadComment, TailComment):\r
73 self.NextLine = Line\r
74 self.HeadComment = HeadComment\r
75 self.TailComment = TailComment\r
76\r
77 def IsEndOfFile(self):\r
78 return self.LineIndex >= self.FileLines\r
79\r
80\r
81## StripRoot\r
82#\r
83# Strip root path\r
84#\r
85# @param Root: Root must be absolute path\r
86# @param Path: Path to be stripped\r
87#\r
88def StripRoot(Root, Path):\r
89 OrigPath = Path\r
90 Root = os.path.normpath(Root)\r
91 Path = os.path.normpath(Path)\r
92 if not os.path.isabs(Root):\r
93 return OrigPath\r
94 if Path.startswith(Root):\r
95 Path = Path[len(Root):]\r
96 if Path and Path[0] == os.sep:\r
97 Path = Path[1:]\r
98 return Path\r
99 return OrigPath\r
100\r
101## CleanString\r
102#\r
103# Split comments in a string\r
104# Remove spaces\r
105#\r
106# @param Line: The string to be cleaned\r
f7496d71 107# @param CommentCharacter: Comment char, used to ignore comment content,\r
4234283c
LG
108# default is DataType.TAB_COMMENT_SPLIT\r
109#\r
110def CleanString(Line, CommentCharacter=TAB_COMMENT_SPLIT, \\r
111 AllowCppStyleComment=False):\r
112 #\r
113 # remove whitespace\r
114 #\r
115 Line = Line.strip()\r
116 #\r
117 # Replace EDK1's comment character\r
118 #\r
119 if AllowCppStyleComment:\r
120 Line = Line.replace(TAB_COMMENT_EDK1_SPLIT, CommentCharacter)\r
121 #\r
122 # separate comments and statements\r
123 #\r
124 Comment = ''\r
125 InQuote = False\r
126 for Index in range(0, len(Line)):\r
127 if Line[Index] == '"':\r
128 InQuote = not InQuote\r
129 continue\r
130 if Line[Index] == CommentCharacter and not InQuote:\r
131 Comment = Line[Index:].strip()\r
132 Line = Line[0:Index].strip()\r
133 break\r
134\r
135 return Line, Comment\r
136\r
137\r
421ccda3 138## IsValidNumValUint8\r
4234283c 139#\r
421ccda3 140# Check if Token is NumValUint8: <NumValUint8> ::= {<ShortNum>} {<UINT8>} {<Expression>}\r
4234283c
LG
141#\r
142# @param Token: Token to be checked\r
143#\r
421ccda3
HC
144def IsValidNumValUint8(Token):\r
145 Valid = True\r
146 Cause = ""\r
147 TokenValue = None\r
4234283c 148 Token = Token.strip()\r
421ccda3
HC
149 if Token.lower().startswith('0x'):\r
150 Base = 16\r
151 else:\r
152 Base = 10\r
4234283c 153 try:\r
1ccc4d89 154 TokenValue = long(Token, Base)\r
4234283c 155 except BaseException:\r
421ccda3
HC
156 Valid, Cause = IsValidLogicalExpr(Token, True)\r
157 if Cause:\r
158 pass\r
159 if not Valid:\r
4234283c 160 return False\r
421ccda3
HC
161 if TokenValue and (TokenValue < 0 or TokenValue > 0xFF):\r
162 return False\r
163 else:\r
164 return True\r
4234283c
LG
165\r
166## IsValidNList\r
167#\r
421ccda3
HC
168# Check if Value has the format of <NumValUint8> ["," <NumValUint8>]{0,}\r
169# <NumValUint8> ::= {<ShortNum>} {<UINT8>} {<Expression>}\r
4234283c
LG
170#\r
171# @param Value: Value to be checked\r
172#\r
173def IsValidNList(Value):\r
174 Par = ParserHelper(Value)\r
175 if Par.End():\r
176 return False\r
177 while not Par.End():\r
421ccda3
HC
178 Token = Par.GetToken(',')\r
179 if not IsValidNumValUint8(Token):\r
4234283c
LG
180 return False\r
181 if Par.Expect(','):\r
182 if Par.End():\r
183 return False\r
184 continue\r
185 else:\r
186 break\r
187 return Par.End()\r
188\r
189## IsValidCArray\r
190#\r
191# check Array is valid\r
192#\r
193# @param Array: The input Array\r
194#\r
195def IsValidCArray(Array):\r
196 Par = ParserHelper(Array)\r
197 if not Par.Expect('{'):\r
198 return False\r
199 if Par.End():\r
200 return False\r
201 while not Par.End():\r
421ccda3 202 Token = Par.GetToken(',}')\r
4234283c 203 #\r
421ccda3 204 # ShortNum, UINT8, Expression\r
4234283c 205 #\r
421ccda3 206 if not IsValidNumValUint8(Token):\r
4234283c
LG
207 return False\r
208 if Par.Expect(','):\r
209 if Par.End():\r
210 return False\r
211 continue\r
212 elif Par.Expect('}'):\r
213 #\r
214 # End of C array\r
215 #\r
216 break\r
217 else:\r
218 return False\r
219 return Par.End()\r
220\r
221## IsValidPcdDatum\r
222#\r
223# check PcdDatum is valid\r
224#\r
225# @param Type: The pcd Type\r
226# @param Value: The pcd Value\r
227#\r
228def IsValidPcdDatum(Type, Value):\r
421ccda3
HC
229 if not Value:\r
230 return False, ST.ERR_DECPARSE_PCD_VALUE_EMPTY\r
231 Valid = True\r
232 Cause = ""\r
4234283c
LG
233 if Type not in ["UINT8", "UINT16", "UINT32", "UINT64", "VOID*", "BOOLEAN"]:\r
234 return False, ST.ERR_DECPARSE_PCD_TYPE\r
235 if Type == "VOID*":\r
236 if not ((Value.startswith('L"') or Value.startswith('"') and \\r
237 Value.endswith('"'))\r
238 or (IsValidCArray(Value)) or (IsValidCFormatGuid(Value)) \\r
239 or (IsValidNList(Value)) or (CheckGuidRegFormat(Value))\r
240 ):\r
241 return False, ST.ERR_DECPARSE_PCD_VOID % (Value, Type)\r
242 RealString = Value[Value.find('"') + 1 :-1]\r
243 if RealString:\r
244 if not IsValidBareCString(RealString):\r
245 return False, ST.ERR_DECPARSE_PCD_VOID % (Value, Type)\r
246 elif Type == 'BOOLEAN':\r
247 if Value in ['TRUE', 'FALSE', 'true', 'false', 'True', 'False',\r
248 '0x1', '0x01', '1', '0x0', '0x00', '0']:\r
249 return True, ""\r
421ccda3 250 Valid, Cause = IsValidStringTest(Value, True)\r
4234283c 251 if not Valid:\r
421ccda3 252 Valid, Cause = IsValidFeatureFlagExp(Value, True)\r
4234283c
LG
253 if not Valid:\r
254 return False, Cause\r
255 else:\r
256 if Value and (Value[0] == '-' or Value[0] == '+'):\r
257 return False, ST.ERR_DECPARSE_PCD_INT_NEGTIVE % (Value, Type)\r
258 try:\r
259 StrVal = Value\r
260 if Value and not Value.startswith('0x') \\r
261 and not Value.startswith('0X'):\r
262 Value = Value.lstrip('0')\r
263 if not Value:\r
264 return True, ""\r
1ccc4d89 265 Value = long(Value, 0)\r
4234283c
LG
266 TypeLenMap = {\r
267 #\r
268 # 0x00 - 0xff\r
269 #\r
270 'UINT8' : 2,\r
271 #\r
272 # 0x0000 - 0xffff\r
273 #\r
274 'UINT16' : 4,\r
275 #\r
276 # 0x00000000 - 0xffffffff\r
277 #\r
278 'UINT32' : 8,\r
279 #\r
280 # 0x0 - 0xffffffffffffffff\r
281 #\r
282 'UINT64' : 16\r
283 }\r
284 HexStr = hex(Value)\r
285 #\r
286 # First two chars of HexStr are 0x and tail char is L\r
287 #\r
288 if TypeLenMap[Type] < len(HexStr) - 3:\r
289 return False, ST.ERR_DECPARSE_PCD_INT_EXCEED % (StrVal, Type)\r
290 except BaseException:\r
421ccda3
HC
291 Valid, Cause = IsValidLogicalExpr(Value, True)\r
292 if not Valid:\r
293 return False, Cause\r
f7496d71 294\r
4234283c
LG
295 return True, ""\r
296\r
297## ParserHelper\r
298#\r
299class ParserHelper:\r
300 def __init__(self, String, File=''):\r
301 self._String = String\r
302 self._StrLen = len(String)\r
303 self._Index = 0\r
304 self._File = File\r
305\r
306 ## End\r
307 #\r
308 # End\r
309 #\r
310 def End(self):\r
311 self.__SkipWhitespace()\r
312 return self._Index >= self._StrLen\r
313\r
314 ## __SkipWhitespace\r
315 #\r
316 # Skip whitespace\r
317 #\r
318 def __SkipWhitespace(self):\r
319 for Char in self._String[self._Index:]:\r
320 if Char not in ' \t':\r
321 break\r
322 self._Index += 1\r
323\r
324 ## Expect\r
325 #\r
326 # Expect char in string\r
327 #\r
328 # @param ExpectChar: char expected in index of string\r
329 #\r
330 def Expect(self, ExpectChar):\r
331 self.__SkipWhitespace()\r
332 for Char in self._String[self._Index:]:\r
333 if Char != ExpectChar:\r
334 return False\r
335 else:\r
336 self._Index += 1\r
337 return True\r
338 #\r
339 # Index out of bound of String\r
340 #\r
341 return False\r
342\r
343 ## GetToken\r
344 #\r
345 # Get token until encounter StopChar, front whitespace is consumed\r
346 #\r
347 # @param StopChar: Get token until encounter char in StopChar\r
348 # @param StkipPair: Only can be ' or ", StopChar in SkipPair are skipped\r
349 #\r
350 def GetToken(self, StopChar='.,|\t ', SkipPair='"'):\r
351 self.__SkipWhitespace()\r
352 PreIndex = self._Index\r
353 InQuote = False\r
354 LastChar = ''\r
355 for Char in self._String[self._Index:]:\r
356 if Char == SkipPair and LastChar != '\\':\r
357 InQuote = not InQuote\r
358 if Char in StopChar and not InQuote:\r
359 break\r
360 self._Index += 1\r
361 if Char == '\\' and LastChar == '\\':\r
362 LastChar = ''\r
363 else:\r
364 LastChar = Char\r
365 return self._String[PreIndex:self._Index]\r
366\r
367 ## AssertChar\r
368 #\r
f7496d71 369 # Assert char at current index of string is AssertChar, or will report\r
4234283c
LG
370 # error message\r
371 #\r
372 # @param AssertChar: AssertChar\r
373 # @param ErrorString: ErrorString\r
374 # @param ErrorLineNum: ErrorLineNum\r
375 #\r
376 def AssertChar(self, AssertChar, ErrorString, ErrorLineNum):\r
377 if not self.Expect(AssertChar):\r
378 Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._File,\r
379 Line=ErrorLineNum, ExtraData=ErrorString)\r
380\r
381 ## AssertEnd\r
382 #\r
383 # @param ErrorString: ErrorString\r
384 # @param ErrorLineNum: ErrorLineNum\r
385 #\r
386 def AssertEnd(self, ErrorString, ErrorLineNum):\r
387 self.__SkipWhitespace()\r
388 if self._Index != self._StrLen:\r
389 Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._File,\r
390 Line=ErrorLineNum, ExtraData=ErrorString)\r