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