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