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