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