]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/UPT/Parser/DecParser.py
Sync BaseTools Branch (version r2271) to EDKII main trunk.
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Parser / DecParser.py
CommitLineData
4234283c
LG
1## @file\r
2# This file is used to parse DEC file. It will consumed by DecParser\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
14DecParser\r
15'''\r
16## Import modules\r
17#\r
18import Logger.Log as Logger\r
19from Logger.ToolError import FILE_PARSE_FAILURE\r
20from Logger.ToolError import FILE_OPEN_FAILURE\r
21from Logger import StringTable as ST\r
22\r
23import Library.DataType as DT\r
24from Library.ParserValidate import IsValidToken\r
25from Library.ParserValidate import IsValidPath\r
26from Library.ParserValidate import IsValidCFormatGuid\r
27from Library.ParserValidate import IsValidIdString\r
28from Library.ParserValidate import IsValidUserId\r
29from Library.ParserValidate import IsValidArch\r
30from Library.ParserValidate import IsValidWord\r
31from Parser.DecParserMisc import TOOL_NAME\r
32from Parser.DecParserMisc import CleanString\r
33from Parser.DecParserMisc import IsValidPcdDatum\r
34from Parser.DecParserMisc import ParserHelper\r
35from Parser.DecParserMisc import StripRoot\r
36from Parser.DecParserMisc import VERSION_PATTERN\r
37from Parser.DecParserMisc import CVAR_PATTERN\r
38from Parser.DecParserMisc import PCD_TOKEN_PATTERN\r
39from Parser.DecParserMisc import MACRO_PATTERN\r
40from Parser.DecParserMisc import FileContent\r
41from Object.Parser.DecObject import _DecComments\r
42from Object.Parser.DecObject import DecDefineObject\r
43from Object.Parser.DecObject import DecDefineItemObject\r
44from Object.Parser.DecObject import DecIncludeObject\r
45from Object.Parser.DecObject import DecIncludeItemObject\r
46from Object.Parser.DecObject import DecLibraryclassObject\r
47from Object.Parser.DecObject import DecLibraryclassItemObject\r
48from Object.Parser.DecObject import DecGuidObject\r
49from Object.Parser.DecObject import DecPpiObject\r
50from Object.Parser.DecObject import DecProtocolObject\r
51from Object.Parser.DecObject import DecGuidItemObject\r
52from Object.Parser.DecObject import DecUserExtensionObject\r
53from Object.Parser.DecObject import DecUserExtensionItemObject\r
54from Object.Parser.DecObject import DecPcdObject\r
55from Object.Parser.DecObject import DecPcdItemObject\r
56from Library.Misc import GuidStructureStringToGuidString\r
57from Library.Misc import CheckGuidRegFormat\r
58from Library.String import ReplaceMacro\r
59from Library.String import GetSplitValueList\r
60from Library.String import gMACRO_PATTERN\r
61from Library.String import ConvertSpecialChar\r
62\r
63##\r
64# _DecBase class for parsing\r
65#\r
66class _DecBase:\r
67 def __init__(self, RawData):\r
68 self._RawData = RawData\r
69 self._ItemDict = {}\r
70 self._LocalMacro = {}\r
71 #\r
72 # Data parsed by 'self' are saved to this object\r
73 #\r
74 self.ItemObject = None\r
75 \r
76 def GetDataObject(self):\r
77 return self.ItemObject\r
78 \r
79 ## BlockStart\r
80 #\r
81 # Called if a new section starts\r
82 #\r
83 def BlockStart(self):\r
84 self._LocalMacro = {}\r
85 \r
86 ## _CheckReDefine\r
87 #\r
88 # @param Key: to be checked if multi-defined\r
89 # @param Scope: Format: [[SectionName, Arch], ...]. \r
90 # If scope is none, use global scope\r
91 #\r
92 def _CheckReDefine(self, Key, Scope = None):\r
93 if not Scope:\r
94 Scope = self._RawData.CurrentScope\r
95 return\r
96 \r
97 SecArch = []\r
98 #\r
99 # Copy scope to SecArch, avoid Scope be changed outside\r
100 #\r
101 SecArch[0:1] = Scope[:]\r
102 if Key not in self._ItemDict:\r
103 self._ItemDict[Key] = [[SecArch, self._RawData.LineIndex]]\r
104 return\r
105 \r
106 for Value in self._ItemDict[Key]:\r
107 for SubValue in Scope:\r
108 #\r
109 # If current is common section\r
110 #\r
111 if SubValue[-1] == 'COMMON':\r
112 for Other in Value[0]:\r
113 # Key in common cannot be redefined in other arches\r
114 # [:-1] means stripping arch info\r
115 if Other[:-1] == SubValue[:-1]:\r
116 self._LoggerError(ST.ERR_DECPARSE_REDEFINE % (Key, Value[1]))\r
117 return\r
118 continue\r
119 CommonScope = []\r
120 CommonScope[0:1] = SubValue\r
121 CommonScope[-1] = 'COMMON'\r
122 #\r
123 # Cannot be redefined if this key already defined in COMMON Or defined in same arch\r
124 #\r
125 if SubValue in Value[0] or CommonScope in Value[0]:\r
126 self._LoggerError(ST.ERR_DECPARSE_REDEFINE % (Key, Value[1]))\r
127 return\r
128 self._ItemDict[Key].append([SecArch, self._RawData.LineIndex])\r
129 \r
130 ## CheckRequiredFields\r
131 # Some sections need to check if some fields exist, define section for example\r
132 # Derived class can re-implement, top parser will call this function after all parsing done\r
133 # \r
134 def CheckRequiredFields(self):\r
135 if self._RawData:\r
136 pass\r
137 return True\r
138 \r
139 ## IsItemRequired\r
140 # In DEC spec, sections must have at least one statement except user \r
141 # extension.\r
142 # For example: "[guids" [<attribs>] "]" <EOL> <statements>+\r
143 # sub class can override this method to indicate if statement is a must.\r
144 #\r
145 def _IsStatementRequired(self):\r
146 if self._RawData:\r
147 pass\r
148 return False\r
149 \r
150 def _LoggerError(self, ErrorString):\r
151 Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, \r
152 Line = self._RawData.LineIndex,\r
153 ExtraData=ErrorString + ST.ERR_DECPARSE_LINE % self._RawData.CurrentLine)\r
154 \r
155 def _ReplaceMacro(self, String):\r
156 if gMACRO_PATTERN.findall(String):\r
157 String = ReplaceMacro(String, self._LocalMacro, False,\r
158 FileName = self._RawData.Filename,\r
159 Line = ['', self._RawData.LineIndex])\r
160 String = ReplaceMacro(String, self._RawData.Macros, False,\r
161 FileName = self._RawData.Filename,\r
162 Line = ['', self._RawData.LineIndex])\r
163 MacroUsed = gMACRO_PATTERN.findall(String)\r
164 if MacroUsed:\r
165 Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE,\r
166 File=self._RawData.Filename, \r
167 Line = self._RawData.LineIndex,\r
168 ExtraData = ST.ERR_DECPARSE_MACRO_RESOLVE % (str(MacroUsed), String))\r
169 return String\r
170 \r
171 def _MacroParser(self, String):\r
172 TokenList = GetSplitValueList(String, ' ', 1)\r
173 if len(TokenList) < 2 or TokenList[1] == '':\r
174 self._LoggerError(ST.ERR_DECPARSE_MACRO_PAIR)\r
175\r
176 TokenList = GetSplitValueList(TokenList[1], DT.TAB_EQUAL_SPLIT, 1)\r
177 if TokenList[0] == '':\r
178 self._LoggerError(ST.ERR_DECPARSE_MACRO_NAME)\r
179 elif not IsValidToken(MACRO_PATTERN, TokenList[0]):\r
180 self._LoggerError(ST.ERR_DECPARSE_MACRO_NAME_UPPER % TokenList[0])\r
181 \r
182 if len(TokenList) == 1:\r
183 self._LocalMacro[TokenList[0]] = ''\r
184 else:\r
185 self._LocalMacro[TokenList[0]] = self._ReplaceMacro(TokenList[1])\r
186 \r
187 ## _ParseItem\r
188 #\r
189 # Parse specified item, this function must be derived by subclass\r
190 #\r
191 def _ParseItem(self):\r
192 if self._RawData:\r
193 pass\r
194 #\r
195 # Should never be called\r
196 #\r
197 return None\r
198\r
199 \r
200 ## _TailCommentStrategy\r
201 #\r
202 # This function can be derived to parse tail comment\r
203 # default is it will not consume any lines\r
204 #\r
205 # @param Comment: Comment of current line\r
206 #\r
207 def _TailCommentStrategy(self, Comment):\r
208 if Comment:\r
209 pass\r
210 if self._RawData:\r
211 pass\r
212 return False\r
213 \r
214 ## _StopCurrentParsing\r
215 #\r
216 # Called in Parse if current parsing should be stopped when encounter some\r
217 # keyword\r
218 # Default is section start and end\r
219 #\r
220 # @param Line: Current line\r
221 #\r
222 def _StopCurrentParsing(self, Line):\r
223 if self._RawData:\r
224 pass\r
225 return Line[0] == DT.TAB_SECTION_START and Line[-1] == DT.TAB_SECTION_END\r
226 \r
227 ## _TryBackSlash\r
228 #\r
229 # Split comment and DEC content, concatenate lines if end of char is '\'\r
230 #\r
231 # @param ProcessedLine: ProcessedLine line\r
232 # @param ProcessedComments: ProcessedComments line\r
233 #\r
234 def _TryBackSlash(self, ProcessedLine, ProcessedComments):\r
235 CatLine = ''\r
236 Comment = ''\r
237 Line = ProcessedLine\r
238 CommentList = ProcessedComments\r
239 while not self._RawData.IsEndOfFile():\r
240 if Line == '':\r
241 self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY)\r
242 break\r
243 \r
244 if Comment:\r
245 CommentList.append((Comment, self._RawData.LineIndex))\r
246 if Line[-1] != DT.TAB_SLASH:\r
247 CatLine += Line\r
248 break\r
249 elif len(Line) < 2 or Line[-2] != ' ':\r
250 self._LoggerError(ST.ERR_DECPARSE_BACKSLASH)\r
251 else:\r
252 CatLine += Line[:-1]\r
253 Line, Comment = CleanString(self._RawData.GetNextLine())\r
254 #\r
255 # Reach end of content\r
256 #\r
257 if self._RawData.IsEndOfFile():\r
258 if not CatLine:\r
259 if ProcessedLine[-1] == DT.TAB_SLASH:\r
260 self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY)\r
261 CatLine = ProcessedLine\r
262 else:\r
263 if not Line or Line[-1] == DT.TAB_SLASH:\r
264 self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY)\r
265 CatLine += Line\r
266 \r
267 self._RawData.CurrentLine = self._ReplaceMacro(CatLine)\r
268 return CatLine, CommentList\r
269 \r
270 ## Parse\r
271 # This is a template method in which other member functions which might \r
272 # override by sub class are called. It is responsible for reading file \r
273 # line by line, and call other member functions to parse. This function\r
274 # should not be re-implement by sub class.\r
275 #\r
276 def Parse(self):\r
277 HeadComments = []\r
278 TailComments = []\r
279 \r
280 #======================================================================\r
281 # CurComments may pointer to HeadComments or TailComments\r
282 #======================================================================\r
283 CurComments = HeadComments\r
284 CurObj = None\r
285 ItemNum = 0\r
286 FromBuf = False\r
287 \r
288 #======================================================================\r
289 # Used to report error information if empty section found\r
290 #======================================================================\r
291 Index = self._RawData.LineIndex\r
292 LineStr = self._RawData.CurrentLine\r
293 while not self._RawData.IsEndOfFile() or self._RawData.NextLine:\r
294 if self._RawData.NextLine:\r
295 #==============================================================\r
296 # Have processed line in buffer\r
297 #==============================================================\r
298 Line = self._RawData.NextLine\r
299 HeadComments.extend(self._RawData.HeadComment)\r
300 TailComments.extend(self._RawData.TailComment)\r
301 self._RawData.ResetNext()\r
302 Comment = ''\r
303 FromBuf = True\r
304 else:\r
305 #==============================================================\r
306 # No line in buffer, read next line\r
307 #==============================================================\r
308 Line, Comment = CleanString(self._RawData.GetNextLine())\r
309 FromBuf = False\r
310 if Line:\r
311 if not FromBuf and CurObj and TailComments:\r
312 #==========================================================\r
313 # Set tail comments to previous statement if not empty.\r
314 #==========================================================\r
315 CurObj.SetTailComment(CurObj.GetTailComment()+TailComments)\r
316 \r
317 if not FromBuf:\r
318 del TailComments[:]\r
319 CurComments = TailComments\r
320 Comments = []\r
321 if Comment:\r
322 Comments = [(Comment, self._RawData.LineIndex)]\r
323 \r
324 #==============================================================\r
325 # Try if last char of line has backslash\r
326 #==============================================================\r
327 Line, Comments = self._TryBackSlash(Line, Comments)\r
328 CurComments.extend(Comments)\r
329 \r
330 #==============================================================\r
331 # Macro found\r
332 #==============================================================\r
333 if Line.startswith('DEFINE '):\r
334 self._MacroParser(Line)\r
335 del HeadComments[:]\r
336 del TailComments[:]\r
337 CurComments = HeadComments\r
338 continue\r
339 \r
340 if self._StopCurrentParsing(Line):\r
341 #==========================================================\r
342 # This line does not belong to this parse,\r
343 # Save it, can be used by next parse\r
344 #==========================================================\r
345 self._RawData.SetNext(Line, HeadComments, TailComments)\r
346 break\r
347 \r
348 Obj = self._ParseItem()\r
349 ItemNum += 1\r
350 if Obj:\r
351 Obj.SetHeadComment(Obj.GetHeadComment()+HeadComments)\r
352 Obj.SetTailComment(Obj.GetTailComment()+TailComments)\r
353 del HeadComments[:]\r
354 del TailComments[:]\r
355 CurObj = Obj\r
356 else:\r
357 CurObj = None\r
358 else:\r
359 if id(CurComments) == id(TailComments):\r
360 #==========================================================\r
361 # Check if this comment belongs to tail comment\r
362 #==========================================================\r
363 if not self._TailCommentStrategy(Comment):\r
364 CurComments = HeadComments\r
365\r
366 if Comment:\r
367 CurComments.append(((Comment, self._RawData.LineIndex)))\r
368 else:\r
369 del CurComments[:]\r
370 \r
371 if self._IsStatementRequired() and ItemNum == 0:\r
372 Logger.Error(\r
373 TOOL_NAME, FILE_PARSE_FAILURE,\r
374 File=self._RawData.Filename,\r
375 Line=Index,\r
376 ExtraData=ST.ERR_DECPARSE_STATEMENT_EMPTY % LineStr\r
377 )\r
378\r
379## _DecDefine\r
380# Parse define section\r
381#\r
382class _DecDefine(_DecBase):\r
383 def __init__(self, RawData):\r
384 _DecBase.__init__(self, RawData)\r
385 self.ItemObject = DecDefineObject(RawData.Filename)\r
386 self._LocalMacro = self._RawData.Macros\r
387 self._DefSecNum = 0\r
388 \r
389 #\r
390 # Each field has a function to validate\r
391 #\r
392 self.DefineValidation = {\r
393 DT.TAB_DEC_DEFINES_DEC_SPECIFICATION : self._SetDecSpecification,\r
394 DT.TAB_DEC_DEFINES_PACKAGE_NAME : self._SetPackageName,\r
395 DT.TAB_DEC_DEFINES_PACKAGE_GUID : self._SetPackageGuid,\r
396 DT.TAB_DEC_DEFINES_PACKAGE_VERSION : self._SetPackageVersion,\r
397 }\r
398 \r
399 def BlockStart(self):\r
400 self._DefSecNum += 1\r
401 if self._DefSecNum > 1:\r
402 self._LoggerError(ST.ERR_DECPARSE_DEFINE_MULTISEC)\r
403 \r
404 ## CheckRequiredFields\r
405 #\r
406 # Check required fields: DEC_SPECIFICATION, PACKAGE_NAME\r
407 # PACKAGE_GUID, PACKAGE_VERSION\r
408 #\r
409 def CheckRequiredFields(self):\r
410 Ret = False\r
411 if self.ItemObject.GetPackageSpecification() == '':\r
412 Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, \r
413 ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION)\r
414 elif self.ItemObject.GetPackageName() == '':\r
415 Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, \r
416 ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_NAME)\r
417 elif self.ItemObject.GetPackageGuid() == '':\r
418 Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, \r
419 ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_GUID)\r
420 elif self.ItemObject.GetPackageVersion() == '':\r
421 Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, \r
422 ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_VERSION)\r
423 else:\r
424 Ret = True\r
425 return Ret\r
426 \r
427 def _ParseItem(self):\r
428 Line = self._RawData.CurrentLine\r
429 TokenList = GetSplitValueList(Line, DT.TAB_EQUAL_SPLIT, 1)\r
430 if TokenList[0] == DT.TAB_DEC_DEFINES_PKG_UNI_FILE:\r
431 pass\r
432 elif len(TokenList) < 2:\r
433 self._LoggerError(ST.ERR_DECPARSE_DEFINE_FORMAT)\r
434 elif TokenList[0] not in self.DefineValidation:\r
435 self._LoggerError(ST.ERR_DECPARSE_DEFINE_UNKNOWKEY % TokenList[0])\r
436 else:\r
437 self.DefineValidation[TokenList[0]](TokenList[1])\r
438 \r
439 DefineItem = DecDefineItemObject()\r
440 if TokenList[0] != DT.TAB_DEC_DEFINES_PKG_UNI_FILE:\r
441 DefineItem.Key = TokenList[0]\r
442 DefineItem.Value = TokenList[1]\r
443 self.ItemObject.AddItem(DefineItem, self._RawData.CurrentScope)\r
444 return DefineItem\r
445 \r
446 def _SetDecSpecification(self, Token):\r
447 if self.ItemObject.GetPackageSpecification():\r
448 self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION)\r
449 if not IsValidToken('0[xX][0-9a-fA-F]{8}', Token):\r
450 self._LoggerError(ST.ERR_DECPARSE_DEFINE_SPEC)\r
451 self.ItemObject.SetPackageSpecification(Token)\r
452 \r
453 def _SetPackageName(self, Token):\r
454 if self.ItemObject.GetPackageName():\r
455 self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_NAME)\r
456 if not IsValidWord(Token):\r
457 self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGNAME)\r
458 self.ItemObject.SetPackageName(Token)\r
459 \r
460 def _SetPackageGuid(self, Token):\r
461 if self.ItemObject.GetPackageGuid():\r
462 self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_GUID)\r
463 if not CheckGuidRegFormat(Token):\r
464 self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGGUID)\r
465 self.ItemObject.SetPackageGuid(Token)\r
466 \r
467 def _SetPackageVersion(self, Token):\r
468 if self.ItemObject.GetPackageVersion():\r
469 self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_VERSION)\r
470 if not IsValidToken(VERSION_PATTERN, Token):\r
471 self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGVERSION)\r
472 else:\r
473 if not DT.TAB_SPLIT in Token:\r
474 Token = Token + '.0'\r
475 self.ItemObject._PkgVersion = Token\r
476\r
477## _DecInclude\r
478#\r
479# Parse include section\r
480#\r
481class _DecInclude(_DecBase):\r
482 def __init__(self, RawData):\r
483 _DecBase.__init__(self, RawData)\r
484 self.ItemObject = DecIncludeObject(RawData.Filename)\r
485 \r
486 def _ParseItem(self):\r
487 Line = self._RawData.CurrentLine\r
488 \r
489 if not IsValidPath(Line, self._RawData.PackagePath):\r
490 self._LoggerError(ST.ERR_DECPARSE_INCLUDE % Line) \r
491 \r
492 Item = DecIncludeItemObject(StripRoot(self._RawData.PackagePath, Line), self._RawData.PackagePath)\r
493 self.ItemObject.AddItem(Item, self._RawData.CurrentScope)\r
494 return Item\r
495\r
496## _DecLibraryclass\r
497#\r
498# Parse library class section\r
499#\r
500class _DecLibraryclass(_DecBase):\r
501 def __init__(self, RawData):\r
502 _DecBase.__init__(self, RawData)\r
503 self.ItemObject = DecLibraryclassObject(RawData.Filename)\r
504 \r
505 def _ParseItem(self):\r
506 Line = self._RawData.CurrentLine\r
507 TokenList = GetSplitValueList(Line, DT.TAB_VALUE_SPLIT)\r
508 if len(TokenList) != 2:\r
509 self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_SPLIT) \r
510 if TokenList[0] == '' or TokenList[1] == '':\r
511 self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_EMPTY)\r
512 if not IsValidToken('[A-Z][0-9A-Za-z]*', TokenList[0]):\r
513 self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_LIB)\r
514 \r
515 self._CheckReDefine(TokenList[0])\r
516 \r
517 Value = TokenList[1]\r
518 #\r
519 # Must end with .h\r
520 #\r
521 if not Value.endswith('.h'):\r
522 self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_PATH_EXT)\r
523 \r
524 #\r
525 # Path must be existed\r
526 #\r
527 if not IsValidPath(Value, self._RawData.PackagePath):\r
528 self._LoggerError(ST.ERR_DECPARSE_INCLUDE % Value)\r
529 \r
530 Item = DecLibraryclassItemObject(TokenList[0], StripRoot(self._RawData.PackagePath, Value),\r
531 self._RawData.PackagePath)\r
532 self.ItemObject.AddItem(Item, self._RawData.CurrentScope)\r
533 return Item\r
534\r
535## _DecPcd\r
536#\r
537# Parse PCD section\r
538#\r
539class _DecPcd(_DecBase):\r
540 def __init__(self, RawData):\r
541 _DecBase.__init__(self, RawData)\r
542 self.ItemObject = DecPcdObject(RawData.Filename)\r
543 #\r
544 # Used to check duplicate token\r
545 # Key is token space and token number (integer), value is C name\r
546 #\r
547 self.TokenMap = {}\r
548 \r
549 def _ParseItem(self):\r
550 Line = self._RawData.CurrentLine\r
551 TokenList = Line.split(DT.TAB_VALUE_SPLIT)\r
552 if len(TokenList) < 4:\r
553 self._LoggerError(ST.ERR_DECPARSE_PCD_SPLIT)\r
554 \r
555 #\r
556 # Token space guid C name\r
557 #\r
558 PcdName = GetSplitValueList(TokenList[0], DT.TAB_SPLIT)\r
559 if len(PcdName) != 2 or PcdName[0] == '' or PcdName[1] == '':\r
560 self._LoggerError(ST.ERR_DECPARSE_PCD_NAME)\r
561 \r
562 Guid = PcdName[0]\r
563 if not IsValidToken(CVAR_PATTERN, Guid):\r
564 self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_GUID)\r
565 \r
566 #\r
567 # PCD C name\r
568 #\r
569 CName = PcdName[1]\r
570 if not IsValidToken(CVAR_PATTERN, CName):\r
571 self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_PCDCNAME)\r
572 \r
573 self._CheckReDefine(Guid + DT.TAB_SPLIT + CName)\r
574 \r
575 #\r
576 # Default value, may be C array, string or number\r
577 #\r
578 Data = DT.TAB_VALUE_SPLIT.join(TokenList[1:-2]).strip()\r
579 \r
580 #\r
581 # PCD data type\r
582 #\r
583 DataType = TokenList[-2].strip()\r
584 Valid, Cause = IsValidPcdDatum(DataType, Data)\r
585 if not Valid:\r
586 self._LoggerError(Cause)\r
587 PcdType = self._RawData.CurrentScope[0][0]\r
588 if PcdType == DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() and DataType != 'BOOLEAN':\r
589 self._LoggerError(ST.ERR_DECPARSE_PCD_FEATUREFLAG)\r
590 #\r
591 # Token value is the last element in list.\r
592 #\r
593 Token = TokenList[-1].strip()\r
594 if not IsValidToken(PCD_TOKEN_PATTERN, Token):\r
595 self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN % Token)\r
596 elif not Token.startswith('0x') and not Token.startswith('0X'):\r
597 if long(Token) > 4294967295:\r
598 self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN_INT % Token)\r
599 Token = hex(long(Token))[:-1]\r
600 \r
601 IntToken = long(Token, 0)\r
602 if (Guid, IntToken) in self.TokenMap:\r
603 if self.TokenMap[Guid, IntToken] != CName:\r
604 self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN_UNIQUE%(Token))\r
605 else:\r
606 self.TokenMap[Guid, IntToken] = CName\r
607 \r
608 Item = DecPcdItemObject(Guid, CName, Data, DataType, Token)\r
609 self.ItemObject.AddItem(Item, self._RawData.CurrentScope)\r
610 return Item\r
611 \r
612## _DecGuid\r
613#\r
614# Parse GUID, PPI, Protocol section\r
615#\r
616class _DecGuid(_DecBase):\r
617 def __init__(self, RawData):\r
618 _DecBase.__init__(self, RawData)\r
619 self.GuidObj = DecGuidObject(RawData.Filename)\r
620 self.PpiObj = DecPpiObject(RawData.Filename)\r
621 self.ProtocolObj = DecProtocolObject(RawData.Filename)\r
622 self.ObjectDict = \\r
623 {\r
624 DT.TAB_GUIDS.upper() : self.GuidObj,\r
625 DT.TAB_PPIS.upper() : self.PpiObj,\r
626 DT.TAB_PROTOCOLS.upper() : self.ProtocolObj\r
627 }\r
628 \r
629 def GetDataObject(self):\r
630 if self._RawData.CurrentScope:\r
631 return self.ObjectDict[self._RawData.CurrentScope[0][0]]\r
632 return None\r
633 \r
634 def GetGuidObject(self):\r
635 return self.GuidObj\r
636 \r
637 def GetPpiObject(self):\r
638 return self.PpiObj\r
639 \r
640 def GetProtocolObject(self):\r
641 return self.ProtocolObj\r
642 \r
643 def _ParseItem(self):\r
644 Line = self._RawData.CurrentLine\r
645 TokenList = GetSplitValueList(Line, DT.TAB_EQUAL_SPLIT, 1)\r
646 if len(TokenList) < 2:\r
647 self._LoggerError(ST.ERR_DECPARSE_CGUID)\r
648 if TokenList[0] == '':\r
649 self._LoggerError(ST.ERR_DECPARSE_CGUID_NAME)\r
650 if TokenList[1] == '':\r
651 self._LoggerError(ST.ERR_DECPARSE_CGUID_GUID)\r
652 if not IsValidToken(CVAR_PATTERN, TokenList[0]):\r
653 self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_GUID)\r
654 \r
655 self._CheckReDefine(TokenList[0])\r
656 \r
657 if TokenList[1][0] != '{':\r
658 if not CheckGuidRegFormat(TokenList[1]):\r
659 self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGGUID)\r
660 GuidString = TokenList[1]\r
661 else:\r
662 #\r
663 # Convert C format GUID to GUID string and Simple error check\r
664 #\r
665 GuidString = GuidStructureStringToGuidString(TokenList[1])\r
666 if TokenList[1][0] != '{' or TokenList[1][-1] != '}' or GuidString == '':\r
667 self._LoggerError(ST.ERR_DECPARSE_CGUID_GUIDFORMAT)\r
668 \r
669 #\r
670 # Check C format GUID\r
671 #\r
672 if not IsValidCFormatGuid(TokenList[1]):\r
673 self._LoggerError(ST.ERR_DECPARSE_CGUID_GUIDFORMAT)\r
674\r
675 Item = DecGuidItemObject(TokenList[0], TokenList[1], GuidString)\r
676 ItemObject = self.ObjectDict[self._RawData.CurrentScope[0][0]]\r
677 ItemObject.AddItem(Item, self._RawData.CurrentScope)\r
678 return Item\r
679\r
680## _DecUserExtension\r
681#\r
682# Parse user extention section\r
683#\r
684class _DecUserExtension(_DecBase):\r
685 def __init__(self, RawData):\r
686 _DecBase.__init__(self, RawData)\r
687 self.ItemObject = DecUserExtensionObject(RawData.Filename)\r
688 self._Headers = []\r
689 self._CurItems = []\r
690 \r
691 def BlockStart(self):\r
692 self._CurItems = []\r
693 for Header in self._RawData.CurrentScope:\r
694 if Header in self._Headers:\r
695 self._LoggerError(ST.ERR_DECPARSE_UE_DUPLICATE)\r
696 else:\r
697 self._Headers.append(Header)\r
698 \r
699 for Item in self._CurItems:\r
700 if Item.UserId == Header[1] and Item.IdString == Header[2]:\r
701 Item.ArchAndModuleType.append(Header[3])\r
702 break\r
703 else:\r
704 Item = DecUserExtensionItemObject()\r
705 Item.UserId = Header[1]\r
706 Item.IdString = Header[2]\r
707 Item.ArchAndModuleType.append(Header[3])\r
708 self._CurItems.append(Item)\r
709 self.ItemObject.AddItem(Item, None)\r
710 self._LocalMacro = {}\r
711 \r
712 def _ParseItem(self):\r
713 Line = self._RawData.CurrentLine\r
714 Item = None\r
715 for Item in self._CurItems:\r
716 if Item.UserString:\r
717 Item.UserString = '\n'.join([Item.UserString, Line])\r
718 else:\r
719 Item.UserString = Line\r
720 return Item\r
721\r
722## Dec\r
723#\r
724# Top dec parser\r
725#\r
726class Dec(_DecBase, _DecComments): \r
727 def __init__(self, DecFile, Parse = True): \r
728 try:\r
729 Content = ConvertSpecialChar(open(DecFile, 'rb').readlines())\r
730 except BaseException:\r
731 Logger.Error(TOOL_NAME, FILE_OPEN_FAILURE, File=DecFile,\r
732 ExtraData=ST.ERR_DECPARSE_FILEOPEN % DecFile)\r
733 RawData = FileContent(DecFile, Content)\r
734 \r
735 _DecComments.__init__(self)\r
736 _DecBase.__init__(self, RawData)\r
737 \r
738 self._Define = _DecDefine(RawData)\r
739 self._Include = _DecInclude(RawData)\r
740 self._Guid = _DecGuid(RawData)\r
741 self._LibClass = _DecLibraryclass(RawData)\r
742 self._Pcd = _DecPcd(RawData)\r
743 self._UserEx = _DecUserExtension(RawData)\r
744 \r
745 #\r
746 # DEC file supported data types (one type per section)\r
747 #\r
748 self._SectionParser = {\r
749 DT.TAB_DEC_DEFINES.upper() : self._Define,\r
750 DT.TAB_INCLUDES.upper() : self._Include,\r
751 DT.TAB_LIBRARY_CLASSES.upper() : self._LibClass,\r
752 DT.TAB_GUIDS.upper() : self._Guid,\r
753 DT.TAB_PPIS.upper() : self._Guid,\r
754 DT.TAB_PROTOCOLS.upper() : self._Guid,\r
755 DT.TAB_PCDS_FIXED_AT_BUILD_NULL.upper() : self._Pcd,\r
756 DT.TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper() : self._Pcd,\r
757 DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() : self._Pcd,\r
758 DT.TAB_PCDS_DYNAMIC_NULL.upper() : self._Pcd,\r
759 DT.TAB_PCDS_DYNAMIC_EX_NULL.upper() : self._Pcd,\r
760 DT.TAB_USER_EXTENSIONS.upper() : self._UserEx\r
761 }\r
762\r
763 if Parse:\r
764 self.ParseDecComment()\r
765 self.Parse()\r
766 #\r
767 # Parsing done, check required fields\r
768 #\r
769 self.CheckRequiredFields()\r
770 \r
771 def CheckRequiredFields(self):\r
772 for SectionParser in self._SectionParser.values():\r
773 if not SectionParser.CheckRequiredFields():\r
774 return False\r
775 return True\r
776 \r
777 ##\r
778 # Parse DEC file\r
779 #\r
780 def ParseDecComment(self):\r
781 while not self._RawData.IsEndOfFile():\r
782 Line, Comment = CleanString(self._RawData.GetNextLine())\r
783 #\r
784 # Header must be pure comment\r
785 #\r
786 if Line != '':\r
787 self._RawData.UndoNextLine()\r
788 break\r
789 \r
790 if Comment:\r
791 self._HeadComment.append((Comment, self._RawData.LineIndex))\r
792 #\r
793 # Double '#' indicates end of header comments\r
794 #\r
795 if not Comment or Comment == DT.TAB_SPECIAL_COMMENT:\r
796 break\r
797 \r
798 return\r
799 \r
800 def _StopCurrentParsing(self, Line):\r
801 return False\r
802 \r
803 def _ParseItem(self):\r
804 self._SectionHeaderParser()\r
805 if len(self._RawData.CurrentScope) == 0:\r
806 self._LoggerError(ST.ERR_DECPARSE_SECTION_EMPTY)\r
807\r
808 SectionObj = self._SectionParser[self._RawData.CurrentScope[0][0]]\r
809\r
810 SectionObj.BlockStart()\r
811 SectionObj.Parse()\r
812 \r
813 return SectionObj.GetDataObject()\r
814\r
815 def _UserExtentionSectionParser(self):\r
816 self._RawData.CurrentScope = []\r
817 ArchList = set()\r
818 Section = self._RawData.CurrentLine[1:-1]\r
819 \r
820 Par = ParserHelper(Section, self._RawData.Filename)\r
821 while not Par.End():\r
822 #\r
823 # User extention\r
824 #\r
825 Token = Par.GetToken()\r
826 if Token.upper() != DT.TAB_USER_EXTENSIONS.upper():\r
827 self._LoggerError(ST.ERR_DECPARSE_SECTION_UE)\r
828 UserExtension = Token.upper()\r
829\r
830 Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)\r
831 #\r
832 # UserID\r
833 #\r
834 Token = Par.GetToken()\r
835 if not IsValidUserId(Token):\r
836 self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_USERID)\r
837 UserId = Token\r
838 \r
839 Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)\r
840 #\r
841 # IdString\r
842 #\r
843 Token = Par.GetToken()\r
844 if not IsValidIdString(Token):\r
845 self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_IDSTRING)\r
846 IdString = Token\r
847 \r
848 Arch = 'COMMON'\r
849 if Par.Expect(DT.TAB_SPLIT):\r
850 Token = Par.GetToken()\r
851 Arch = Token.upper()\r
852 if not IsValidArch(Arch):\r
853 self._LoggerError(ST.ERR_DECPARSE_ARCH)\r
854 ArchList.add(Arch)\r
855 \r
856 if [UserExtension, UserId, IdString, Arch] not in \\r
857 self._RawData.CurrentScope:\r
858 self._RawData.CurrentScope.append(\r
859 [UserExtension, UserId, IdString, Arch]\r
860 )\r
861 \r
862 if not Par.Expect(DT.TAB_COMMA_SPLIT):\r
863 break\r
864 elif Par.End():\r
865 self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMA)\r
866 \r
867 Par.AssertEnd(ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)\r
868 \r
869 if 'COMMON' in ArchList and len(ArchList) > 1:\r
870 self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON)\r
871 \r
872 ## Section header parser\r
873 #\r
874 # The section header is always in following format:\r
875 #\r
876 # [section_name.arch<.platform|module_type>]\r
877 #\r
878 def _SectionHeaderParser(self):\r
879 if self._RawData.CurrentLine[0] != DT.TAB_SECTION_START or self._RawData.CurrentLine[-1] != DT.TAB_SECTION_END:\r
880 self._LoggerError(ST.ERR_DECPARSE_SECTION_IDENTIFY)\r
881 \r
882 RawSection = self._RawData.CurrentLine[1:-1].strip().upper()\r
883 \r
884 #\r
885 # Check defines section which is only allowed to occur once and\r
886 # no arch can be followed\r
887 #\r
888 if RawSection.startswith(DT.TAB_DEC_DEFINES.upper()):\r
889 if RawSection != DT.TAB_DEC_DEFINES.upper():\r
890 self._LoggerError(ST.ERR_DECPARSE_DEFINE_SECNAME)\r
891 \r
892 #\r
893 # Check user extension section\r
894 #\r
895 if RawSection.startswith(DT.TAB_USER_EXTENSIONS.upper()):\r
896 return self._UserExtentionSectionParser()\r
897 \r
898 self._RawData.CurrentScope = []\r
899 SectionNames = []\r
900 ArchList = set()\r
901 for Item in GetSplitValueList(RawSection, DT.TAB_COMMA_SPLIT):\r
902 if Item == '':\r
903 self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine)\r
904\r
905 ItemList = GetSplitValueList(Item, DT.TAB_SPLIT)\r
906\r
907 #\r
908 # different types of PCD are permissible in one section\r
909 #\r
910 SectionName = ItemList[0]\r
911 if SectionName not in self._SectionParser:\r
912 self._LoggerError(ST.ERR_DECPARSE_SECTION_UNKNOW % SectionName)\r
913 \r
914 if SectionName not in SectionNames:\r
915 SectionNames.append(SectionName)\r
916 \r
917 #\r
918 # In DEC specification, all section headers have at most two part:\r
919 # SectionName.Arch except UserExtention\r
920 #\r
921 if len(ItemList) > 2:\r
922 self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBTOOMANY % Item)\r
923\r
924 if DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() in SectionNames and len(SectionNames) > 1:\r
925 self._LoggerError(ST.ERR_DECPARSE_SECTION_FEATUREFLAG % DT.TAB_PCDS_FEATURE_FLAG_NULL) \r
926 #\r
927 # S1 is always Arch\r
928 #\r
929 if len(ItemList) > 1:\r
930 Str1 = ItemList[1]\r
931 if not IsValidArch(Str1):\r
932 self._LoggerError(ST.ERR_DECPARSE_ARCH)\r
933 else:\r
934 Str1 = 'COMMON'\r
935 ArchList.add(Str1)\r
936\r
937 if [SectionName, Str1] not in self._RawData.CurrentScope:\r
938 self._RawData.CurrentScope.append([SectionName, Str1])\r
939 #\r
940 # 'COMMON' must not be used with specific ARCHs at the same section\r
941 #\r
942 if 'COMMON' in ArchList and len(ArchList) > 1:\r
943 self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON)\r
944 \r
945 if len(SectionNames) == 0:\r
946 self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine)\r
947 if len(SectionNames) != 1:\r
948 for Sec in SectionNames:\r
949 if not Sec.startswith(DT.TAB_PCDS.upper()):\r
950 self._LoggerError(ST.ERR_DECPARSE_SECTION_NAME % str(SectionNames))\r
951 \r
952 def GetDefineSectionObject(self):\r
953 return self._Define.GetDataObject()\r
954 \r
955 def GetIncludeSectionObject(self):\r
956 return self._Include.GetDataObject()\r
957 \r
958 def GetGuidSectionObject(self):\r
959 return self._Guid.GetGuidObject()\r
960 \r
961 def GetProtocolSectionObject(self):\r
962 return self._Guid.GetProtocolObject()\r
963 \r
964 def GetPpiSectionObject(self):\r
965 return self._Guid.GetPpiObject()\r
966 \r
967 def GetLibraryClassSectionObject(self):\r
968 return self._LibClass.GetDataObject()\r
969 \r
970 def GetPcdSectionObject(self):\r
971 return self._Pcd.GetDataObject()\r
972 \r
973 def GetUserExtensionSectionObject(self):\r
974 return self._UserEx.GetDataObject()\r
975 \r
976 def GetPackageSpecification(self):\r
977 return self._Define.GetDataObject().GetPackageSpecification()\r
978 \r
979 def GetPackageName(self):\r
980 return self._Define.GetDataObject().GetPackageName()\r
981 \r
982 def GetPackageGuid(self):\r
983 return self._Define.GetDataObject().GetPackageGuid()\r
984 \r
985 def GetPackageVersion(self):\r
986 return self._Define.GetDataObject().GetPackageVersion()\r
987 \r
988 def GetPackageUniFile(self):\r
989 return self._Define.GetDataObject().GetPackageUniFile()\r