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 # 274 # All MACRO values defined by the DEFINE statements in any section 275 # (except [Userextensions] sections for Intel) of the INF or DEC file 276 # must be expanded before processing of the file. 277 # 278 __IsReplaceMacro = True 279 Header = self._RawData.CurrentScope[0] if self._RawData.CurrentScope else None 280 if Header and len(Header) > 2: 281 if Header[0].upper() == 'USEREXTENSIONS' and not (Header[1] == 'TianoCore' and Header[2] == '"ExtraFiles"'): 282 __IsReplaceMacro = False 283 if __IsReplaceMacro: 284 self._RawData.CurrentLine = self._ReplaceMacro(CatLine) 285 else: 286 self._RawData.CurrentLine = CatLine 287 288 return CatLine, CommentList 289 290 ## Parse 291 # This is a template method in which other member functions which might 292 # override by sub class are called. It is responsible for reading file 293 # line by line, and call other member functions to parse. This function 294 # should not be re-implement by sub class. 295 # 296 def Parse(self): 297 HeadComments = [] 298 TailComments = [] 299 300 #====================================================================== 301 # CurComments may pointer to HeadComments or TailComments 302 #====================================================================== 303 CurComments = HeadComments 304 CurObj = None 305 ItemNum = 0 306 FromBuf = False 307 308 #====================================================================== 309 # Used to report error information if empty section found 310 #====================================================================== 311 Index = self._RawData.LineIndex 312 LineStr = self._RawData.CurrentLine 313 while not self._RawData.IsEndOfFile() or self._RawData.NextLine: 314 if self._RawData.NextLine: 315 #============================================================== 316 # Have processed line in buffer 317 #============================================================== 318 Line = self._RawData.NextLine 319 HeadComments.extend(self._RawData.HeadComment) 320 TailComments.extend(self._RawData.TailComment) 321 self._RawData.ResetNext() 322 Comment = '' 323 FromBuf = True 324 else: 325 #============================================================== 326 # No line in buffer, read next line 327 #============================================================== 328 Line, Comment = CleanString(self._RawData.GetNextLine()) 329 FromBuf = False 330 if Line: 331 if not FromBuf and CurObj and TailComments: 332 #========================================================== 333 # Set tail comments to previous statement if not empty. 334 #========================================================== 335 CurObj.SetTailComment(CurObj.GetTailComment()+TailComments) 336 337 if not FromBuf: 338 del TailComments[:] 339 CurComments = TailComments 340 Comments = [] 341 if Comment: 342 Comments = [(Comment, self._RawData.LineIndex)] 343 344 #============================================================== 345 # Try if last char of line has backslash 346 #============================================================== 347 Line, Comments = self._TryBackSlash(Line, Comments) 348 CurComments.extend(Comments) 349 350 #============================================================== 351 # Macro found 352 #============================================================== 353 if Line.startswith('DEFINE '): 354 self._MacroParser(Line) 355 del HeadComments[:] 356 del TailComments[:] 357 CurComments = HeadComments 358 continue 359 360 if self._StopCurrentParsing(Line): 361 #========================================================== 362 # This line does not belong to this parse, 363 # Save it, can be used by next parse 364 #========================================================== 365 self._RawData.SetNext(Line, HeadComments, TailComments) 366 break 367 368 Obj = self._ParseItem() 369 ItemNum += 1 370 if Obj: 371 Obj.SetHeadComment(Obj.GetHeadComment()+HeadComments) 372 Obj.SetTailComment(Obj.GetTailComment()+TailComments) 373 del HeadComments[:] 374 del TailComments[:] 375 CurObj = Obj 376 else: 377 CurObj = None 378 else: 379 if id(CurComments) == id(TailComments): 380 #========================================================== 381 # Check if this comment belongs to tail comment 382 #========================================================== 383 if not self._TailCommentStrategy(Comment): 384 CurComments = HeadComments 385 386 if Comment: 387 CurComments.append(((Comment, self._RawData.LineIndex))) 388 else: 389 del CurComments[:] 390 391 if self._IsStatementRequired() and ItemNum == 0: 392 Logger.Error( 393 TOOL_NAME, FILE_PARSE_FAILURE, 394 File=self._RawData.Filename, 395 Line=Index, 396 ExtraData=ST.ERR_DECPARSE_STATEMENT_EMPTY % LineStr 397 ) 398 399 ## _DecDefine 400 # Parse define section 401 # 402 class _DecDefine(_DecBase): 403 def __init__(self, RawData): 404 _DecBase.__init__(self, RawData) 405 self.ItemObject = DecDefineObject(RawData.Filename) 406 self._LocalMacro = self._RawData.Macros 407 self._DefSecNum = 0 408 409 # 410 # Each field has a function to validate 411 # 412 self.DefineValidation = { 413 DT.TAB_DEC_DEFINES_DEC_SPECIFICATION : self._SetDecSpecification, 414 DT.TAB_DEC_DEFINES_PACKAGE_NAME : self._SetPackageName, 415 DT.TAB_DEC_DEFINES_PACKAGE_GUID : self._SetPackageGuid, 416 DT.TAB_DEC_DEFINES_PACKAGE_VERSION : self._SetPackageVersion, 417 DT.TAB_DEC_DEFINES_PKG_UNI_FILE : self._SetPackageUni, 418 } 419 420 def BlockStart(self): 421 self._DefSecNum += 1 422 if self._DefSecNum > 1: 423 self._LoggerError(ST.ERR_DECPARSE_DEFINE_MULTISEC) 424 425 ## CheckRequiredFields 426 # 427 # Check required fields: DEC_SPECIFICATION, PACKAGE_NAME 428 # PACKAGE_GUID, PACKAGE_VERSION 429 # 430 def CheckRequiredFields(self): 431 Ret = False 432 if self.ItemObject.GetPackageSpecification() == '': 433 Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, 434 ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION) 435 elif self.ItemObject.GetPackageName() == '': 436 Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, 437 ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_NAME) 438 elif self.ItemObject.GetPackageGuid() == '': 439 Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, 440 ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_GUID) 441 elif self.ItemObject.GetPackageVersion() == '': 442 Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename, 443 ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_VERSION) 444 else: 445 Ret = True 446 return Ret 447 448 def _ParseItem(self): 449 Line = self._RawData.CurrentLine 450 TokenList = GetSplitValueList(Line, DT.TAB_EQUAL_SPLIT, 1) 451 if TokenList[0] == DT.TAB_DEC_DEFINES_PKG_UNI_FILE: 452 self.DefineValidation[TokenList[0]](TokenList[1]) 453 elif len(TokenList) < 2: 454 self._LoggerError(ST.ERR_DECPARSE_DEFINE_FORMAT) 455 elif TokenList[0] not in self.DefineValidation: 456 self._LoggerError(ST.ERR_DECPARSE_DEFINE_UNKNOWKEY % TokenList[0]) 457 else: 458 self.DefineValidation[TokenList[0]](TokenList[1]) 459 460 DefineItem = DecDefineItemObject() 461 DefineItem.Key = TokenList[0] 462 DefineItem.Value = TokenList[1] 463 self.ItemObject.AddItem(DefineItem, self._RawData.CurrentScope) 464 return DefineItem 465 466 def _SetDecSpecification(self, Token): 467 if self.ItemObject.GetPackageSpecification(): 468 self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION) 469 if not IsValidToken('0[xX][0-9a-fA-F]{8}', Token): 470 if not IsValidDecVersionVal(Token): 471 self._LoggerError(ST.ERR_DECPARSE_DEFINE_SPEC) 472 self.ItemObject.SetPackageSpecification(Token) 473 474 def _SetPackageName(self, Token): 475 if self.ItemObject.GetPackageName(): 476 self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_NAME) 477 if not IsValidWord(Token): 478 self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGNAME) 479 self.ItemObject.SetPackageName(Token) 480 481 def _SetPackageGuid(self, Token): 482 if self.ItemObject.GetPackageGuid(): 483 self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_GUID) 484 if not CheckGuidRegFormat(Token): 485 self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGGUID) 486 self.ItemObject.SetPackageGuid(Token) 487 488 def _SetPackageVersion(self, Token): 489 if self.ItemObject.GetPackageVersion(): 490 self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_VERSION) 491 if not IsValidToken(VERSION_PATTERN, Token): 492 self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGVERSION) 493 else: 494 if not DT.TAB_SPLIT in Token: 495 Token = Token + '.0' 496 self.ItemObject.SetPackageVersion(Token) 497 498 def _SetPackageUni(self, Token): 499 if self.ItemObject.GetPackageUniFile(): 500 self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PKG_UNI_FILE) 501 self.ItemObject.SetPackageUniFile(Token) 502 503 ## _DecInclude 504 # 505 # Parse include section 506 # 507 class _DecInclude(_DecBase): 508 def __init__(self, RawData): 509 _DecBase.__init__(self, RawData) 510 self.ItemObject = DecIncludeObject(RawData.Filename) 511 512 def _ParseItem(self): 513 Line = self._RawData.CurrentLine 514 515 if not IsValidPath(Line, self._RawData.PackagePath): 516 self._LoggerError(ST.ERR_DECPARSE_INCLUDE % Line) 517 518 Item = DecIncludeItemObject(StripRoot(self._RawData.PackagePath, Line), self._RawData.PackagePath) 519 self.ItemObject.AddItem(Item, self._RawData.CurrentScope) 520 return Item 521 522 ## _DecLibraryclass 523 # 524 # Parse library class section 525 # 526 class _DecLibraryclass(_DecBase): 527 def __init__(self, RawData): 528 _DecBase.__init__(self, RawData) 529 self.ItemObject = DecLibraryclassObject(RawData.Filename) 530 531 def _ParseItem(self): 532 Line = self._RawData.CurrentLine 533 TokenList = GetSplitValueList(Line, DT.TAB_VALUE_SPLIT) 534 if len(TokenList) != 2: 535 self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_SPLIT) 536 if TokenList[0] == '' or TokenList[1] == '': 537 self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_EMPTY) 538 if not IsValidToken('[A-Z][0-9A-Za-z]*', TokenList[0]): 539 self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_LIB) 540 541 self._CheckReDefine(TokenList[0]) 542 543 Value = TokenList[1] 544 # 545 # Must end with .h 546 # 547 if not Value.endswith('.h'): 548 self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_PATH_EXT) 549 550 # 551 # Path must be existed 552 # 553 if not IsValidPath(Value, self._RawData.PackagePath): 554 self._LoggerError(ST.ERR_DECPARSE_INCLUDE % Value) 555 556 Item = DecLibraryclassItemObject(TokenList[0], StripRoot(self._RawData.PackagePath, Value), 557 self._RawData.PackagePath) 558 self.ItemObject.AddItem(Item, self._RawData.CurrentScope) 559 return Item 560 561 ## _DecPcd 562 # 563 # Parse PCD section 564 # 565 class _DecPcd(_DecBase): 566 def __init__(self, RawData): 567 _DecBase.__init__(self, RawData) 568 self.ItemObject = DecPcdObject(RawData.Filename) 569 # 570 # Used to check duplicate token 571 # Key is token space and token number (integer), value is C name 572 # 573 self.TokenMap = {} 574 575 def _ParseItem(self): 576 Line = self._RawData.CurrentLine 577 TokenList = Line.split(DT.TAB_VALUE_SPLIT) 578 if len(TokenList) < 4: 579 self._LoggerError(ST.ERR_DECPARSE_PCD_SPLIT) 580 581 # 582 # Token space guid C name 583 # 584 PcdName = GetSplitValueList(TokenList[0], DT.TAB_SPLIT) 585 if len(PcdName) != 2 or PcdName[0] == '' or PcdName[1] == '': 586 self._LoggerError(ST.ERR_DECPARSE_PCD_NAME) 587 588 Guid = PcdName[0] 589 if not IsValidToken(CVAR_PATTERN, Guid): 590 self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_GUID) 591 592 # 593 # PCD C name 594 # 595 CName = PcdName[1] 596 if not IsValidToken(CVAR_PATTERN, CName): 597 self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_PCDCNAME) 598 599 self._CheckReDefine(Guid + DT.TAB_SPLIT + CName) 600 601 # 602 # Default value, may be C array, string or number 603 # 604 Data = DT.TAB_VALUE_SPLIT.join(TokenList[1:-2]).strip() 605 606 # 607 # PCD data type 608 # 609 DataType = TokenList[-2].strip() 610 Valid, Cause = IsValidPcdDatum(DataType, Data) 611 if not Valid: 612 self._LoggerError(Cause) 613 PcdType = self._RawData.CurrentScope[0][0] 614 if PcdType == DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() and DataType != 'BOOLEAN': 615 self._LoggerError(ST.ERR_DECPARSE_PCD_FEATUREFLAG) 616 # 617 # Token value is the last element in list. 618 # 619 Token = TokenList[-1].strip() 620 if not IsValidToken(PCD_TOKEN_PATTERN, Token): 621 self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN % Token) 622 elif not Token.startswith('0x') and not Token.startswith('0X'): 623 if long(Token) > 4294967295: 624 self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN_INT % Token) 625 Token = hex(long(Token))[:-1] 626 627 IntToken = long(Token, 0) 628 if (Guid, IntToken) in self.TokenMap: 629 if self.TokenMap[Guid, IntToken] != CName: 630 self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN_UNIQUE%(Token)) 631 else: 632 self.TokenMap[Guid, IntToken] = CName 633 634 Item = DecPcdItemObject(Guid, CName, Data, DataType, Token) 635 self.ItemObject.AddItem(Item, self._RawData.CurrentScope) 636 return Item 637 638 ## _DecGuid 639 # 640 # Parse GUID, PPI, Protocol section 641 # 642 class _DecGuid(_DecBase): 643 def __init__(self, RawData): 644 _DecBase.__init__(self, RawData) 645 self.GuidObj = DecGuidObject(RawData.Filename) 646 self.PpiObj = DecPpiObject(RawData.Filename) 647 self.ProtocolObj = DecProtocolObject(RawData.Filename) 648 self.ObjectDict = \ 649 { 650 DT.TAB_GUIDS.upper() : self.GuidObj, 651 DT.TAB_PPIS.upper() : self.PpiObj, 652 DT.TAB_PROTOCOLS.upper() : self.ProtocolObj 653 } 654 655 def GetDataObject(self): 656 if self._RawData.CurrentScope: 657 return self.ObjectDict[self._RawData.CurrentScope[0][0]] 658 return None 659 660 def GetGuidObject(self): 661 return self.GuidObj 662 663 def GetPpiObject(self): 664 return self.PpiObj 665 666 def GetProtocolObject(self): 667 return self.ProtocolObj 668 669 def _ParseItem(self): 670 Line = self._RawData.CurrentLine 671 TokenList = GetSplitValueList(Line, DT.TAB_EQUAL_SPLIT, 1) 672 if len(TokenList) < 2: 673 self._LoggerError(ST.ERR_DECPARSE_CGUID) 674 if TokenList[0] == '': 675 self._LoggerError(ST.ERR_DECPARSE_CGUID_NAME) 676 if TokenList[1] == '': 677 self._LoggerError(ST.ERR_DECPARSE_CGUID_GUID) 678 if not IsValidToken(CVAR_PATTERN, TokenList[0]): 679 self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_GUID) 680 681 self._CheckReDefine(TokenList[0]) 682 683 if TokenList[1][0] != '{': 684 if not CheckGuidRegFormat(TokenList[1]): 685 self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGGUID) 686 GuidString = TokenList[1] 687 else: 688 # 689 # Convert C format GUID to GUID string and Simple error check 690 # 691 GuidString = GuidStructureStringToGuidString(TokenList[1]) 692 if TokenList[1][0] != '{' or TokenList[1][-1] != '}' or GuidString == '': 693 self._LoggerError(ST.ERR_DECPARSE_CGUID_GUIDFORMAT) 694 695 # 696 # Check C format GUID 697 # 698 if not IsValidCFormatGuid(TokenList[1]): 699 self._LoggerError(ST.ERR_DECPARSE_CGUID_GUIDFORMAT) 700 701 Item = DecGuidItemObject(TokenList[0], TokenList[1], GuidString) 702 ItemObject = self.ObjectDict[self._RawData.CurrentScope[0][0]] 703 ItemObject.AddItem(Item, self._RawData.CurrentScope) 704 return Item 705 706 ## _DecUserExtension 707 # 708 # Parse user extention section 709 # 710 class _DecUserExtension(_DecBase): 711 def __init__(self, RawData): 712 _DecBase.__init__(self, RawData) 713 self.ItemObject = DecUserExtensionObject(RawData.Filename) 714 self._Headers = [] 715 self._CurItems = [] 716 717 def BlockStart(self): 718 self._CurItems = [] 719 for Header in self._RawData.CurrentScope: 720 if Header in self._Headers: 721 self._LoggerError(ST.ERR_DECPARSE_UE_DUPLICATE) 722 else: 723 self._Headers.append(Header) 724 725 for Item in self._CurItems: 726 if Item.UserId == Header[1] and Item.IdString == Header[2]: 727 Item.ArchAndModuleType.append(Header[3]) 728 break 729 else: 730 Item = DecUserExtensionItemObject() 731 Item.UserId = Header[1] 732 Item.IdString = Header[2] 733 Item.ArchAndModuleType.append(Header[3]) 734 self._CurItems.append(Item) 735 self.ItemObject.AddItem(Item, None) 736 self._LocalMacro = {} 737 738 def _ParseItem(self): 739 Line = self._RawData.CurrentLine 740 Item = None 741 for Item in self._CurItems: 742 if Item.UserString: 743 Item.UserString = '\n'.join([Item.UserString, Line]) 744 else: 745 Item.UserString = Line 746 return Item 747 748 ## Dec 749 # 750 # Top dec parser 751 # 752 class Dec(_DecBase, _DecComments): 753 def __init__(self, DecFile, Parse = True): 754 try: 755 Content = ConvertSpecialChar(open(DecFile, 'rb').readlines()) 756 except BaseException: 757 Logger.Error(TOOL_NAME, FILE_OPEN_FAILURE, File=DecFile, 758 ExtraData=ST.ERR_DECPARSE_FILEOPEN % DecFile) 759 760 # 761 # Pre-parser for Private section 762 # 763 self._Private = '' 764 __IsFoundPrivate = False 765 NewContent = [] 766 for Line in Content: 767 Line = Line.strip() 768 if Line.startswith(DT.TAB_SECTION_START) and Line.endswith(DT.TAB_PRIVATE + DT.TAB_SECTION_END): 769 __IsFoundPrivate = True 770 if Line.startswith(DT.TAB_SECTION_START) and Line.endswith(DT.TAB_SECTION_END)\ 771 and not Line.endswith(DT.TAB_PRIVATE + DT.TAB_SECTION_END): 772 __IsFoundPrivate = False 773 if __IsFoundPrivate: 774 self._Private += Line + '\r' 775 if not __IsFoundPrivate: 776 NewContent.append(Line + '\r') 777 778 RawData = FileContent(DecFile, NewContent) 779 780 _DecComments.__init__(self) 781 _DecBase.__init__(self, RawData) 782 783 self.BinaryHeadComment = [] 784 self.PcdErrorCommentDict = {} 785 786 self._Define = _DecDefine(RawData) 787 self._Include = _DecInclude(RawData) 788 self._Guid = _DecGuid(RawData) 789 self._LibClass = _DecLibraryclass(RawData) 790 self._Pcd = _DecPcd(RawData) 791 self._UserEx = _DecUserExtension(RawData) 792 793 # 794 # DEC file supported data types (one type per section) 795 # 796 self._SectionParser = { 797 DT.TAB_DEC_DEFINES.upper() : self._Define, 798 DT.TAB_INCLUDES.upper() : self._Include, 799 DT.TAB_LIBRARY_CLASSES.upper() : self._LibClass, 800 DT.TAB_GUIDS.upper() : self._Guid, 801 DT.TAB_PPIS.upper() : self._Guid, 802 DT.TAB_PROTOCOLS.upper() : self._Guid, 803 DT.TAB_PCDS_FIXED_AT_BUILD_NULL.upper() : self._Pcd, 804 DT.TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper() : self._Pcd, 805 DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() : self._Pcd, 806 DT.TAB_PCDS_DYNAMIC_NULL.upper() : self._Pcd, 807 DT.TAB_PCDS_DYNAMIC_EX_NULL.upper() : self._Pcd, 808 DT.TAB_USER_EXTENSIONS.upper() : self._UserEx 809 } 810 811 if Parse: 812 self.ParseDecComment() 813 self.Parse() 814 # 815 # Parsing done, check required fields 816 # 817 self.CheckRequiredFields() 818 819 def CheckRequiredFields(self): 820 for SectionParser in self._SectionParser.values(): 821 if not SectionParser.CheckRequiredFields(): 822 return False 823 return True 824 825 ## 826 # Parse DEC file 827 # 828 def ParseDecComment(self): 829 IsFileHeader = False 830 IsBinaryHeader = False 831 FileHeaderLineIndex = -1 832 BinaryHeaderLineIndex = -1 833 TokenSpaceGuidCName = '' 834 835 # 836 # Parse PCD error comment section 837 # 838 while not self._RawData.IsEndOfFile(): 839 self._RawData.CurrentLine = self._RawData.GetNextLine() 840 if self._RawData.CurrentLine.startswith(DT.TAB_COMMENT_SPLIT) and \ 841 DT.TAB_SECTION_START in self._RawData.CurrentLine and \ 842 DT.TAB_SECTION_END in self._RawData.CurrentLine: 843 self._RawData.CurrentLine = self._RawData.CurrentLine.replace(DT.TAB_COMMENT_SPLIT, '').strip() 844 845 if self._RawData.CurrentLine[0] == DT.TAB_SECTION_START and \ 846 self._RawData.CurrentLine[-1] == DT.TAB_SECTION_END: 847 RawSection = self._RawData.CurrentLine[1:-1].strip() 848 if RawSection.upper().startswith(DT.TAB_PCD_ERROR.upper()+'.'): 849 TokenSpaceGuidCName = RawSection.split(DT.TAB_PCD_ERROR+'.')[1].strip() 850 continue 851 852 if TokenSpaceGuidCName and self._RawData.CurrentLine.startswith(DT.TAB_COMMENT_SPLIT): 853 self._RawData.CurrentLine = self._RawData.CurrentLine.replace(DT.TAB_COMMENT_SPLIT, '').strip() 854 if self._RawData.CurrentLine != '': 855 if DT.TAB_VALUE_SPLIT not in self._RawData.CurrentLine: 856 self._LoggerError(ST.ERR_DECPARSE_PCDERRORMSG_MISS_VALUE_SPLIT) 857 858 PcdErrorNumber, PcdErrorMsg = GetSplitValueList(self._RawData.CurrentLine, DT.TAB_VALUE_SPLIT, 1) 859 PcdErrorNumber = ParsePcdErrorCode(PcdErrorNumber, self._RawData.Filename, self._RawData.LineIndex) 860 if not PcdErrorMsg.strip(): 861 self._LoggerError(ST.ERR_DECPARSE_PCD_MISS_ERRORMSG) 862 863 self.PcdErrorCommentDict[(TokenSpaceGuidCName, PcdErrorNumber)] = PcdErrorMsg.strip() 864 else: 865 TokenSpaceGuidCName = '' 866 867 self._RawData.LineIndex = 0 868 self._RawData.CurrentLine = '' 869 self._RawData.NextLine = '' 870 871 while not self._RawData.IsEndOfFile(): 872 Line, Comment = CleanString(self._RawData.GetNextLine()) 873 874 # 875 # Header must be pure comment 876 # 877 if Line != '': 878 self._RawData.UndoNextLine() 879 break 880 881 if Comment and Comment.startswith(DT.TAB_SPECIAL_COMMENT) and Comment.find(DT.TAB_HEADER_COMMENT) > 0 \ 882 and not Comment[2:Comment.find(DT.TAB_HEADER_COMMENT)].strip(): 883 IsFileHeader = True 884 IsBinaryHeader = False 885 FileHeaderLineIndex = self._RawData.LineIndex 886 887 # 888 # Get license information before '@file' 889 # 890 if not IsFileHeader and not IsBinaryHeader and Comment and Comment.startswith(DT.TAB_COMMENT_SPLIT) and \ 891 DT.TAB_BINARY_HEADER_COMMENT not in Comment: 892 self._HeadComment.append((Comment, self._RawData.LineIndex)) 893 894 if Comment and IsFileHeader and \ 895 not(Comment.startswith(DT.TAB_SPECIAL_COMMENT) \ 896 and Comment.find(DT.TAB_BINARY_HEADER_COMMENT) > 0): 897 self._HeadComment.append((Comment, self._RawData.LineIndex)) 898 # 899 # Double '#' indicates end of header comments 900 # 901 if (not Comment or Comment == DT.TAB_SPECIAL_COMMENT) and IsFileHeader: 902 IsFileHeader = False 903 continue 904 905 if Comment and Comment.startswith(DT.TAB_SPECIAL_COMMENT) \ 906 and Comment.find(DT.TAB_BINARY_HEADER_COMMENT) > 0: 907 IsBinaryHeader = True 908 IsFileHeader = False 909 BinaryHeaderLineIndex = self._RawData.LineIndex 910 911 if Comment and IsBinaryHeader: 912 self.BinaryHeadComment.append((Comment, self._RawData.LineIndex)) 913 # 914 # Double '#' indicates end of header comments 915 # 916 if (not Comment or Comment == DT.TAB_SPECIAL_COMMENT) and IsBinaryHeader: 917 IsBinaryHeader = False 918 break 919 920 if FileHeaderLineIndex > -1 and not IsFileHeader and not IsBinaryHeader: 921 break 922 923 if FileHeaderLineIndex > BinaryHeaderLineIndex and FileHeaderLineIndex > -1 and BinaryHeaderLineIndex > -1: 924 self._LoggerError(ST.ERR_BINARY_HEADER_ORDER) 925 926 if FileHeaderLineIndex == -1: 927 # self._LoggerError(ST.ERR_NO_SOURCE_HEADER) 928 Logger.Error(TOOL_NAME, FORMAT_INVALID, 929 ST.ERR_NO_SOURCE_HEADER, 930 File=self._RawData.Filename) 931 return 932 933 def _StopCurrentParsing(self, Line): 934 return False 935 936 def _ParseItem(self): 937 self._SectionHeaderParser() 938 if len(self._RawData.CurrentScope) == 0: 939 self._LoggerError(ST.ERR_DECPARSE_SECTION_EMPTY) 940 SectionObj = self._SectionParser[self._RawData.CurrentScope[0][0]] 941 SectionObj.BlockStart() 942 SectionObj.Parse() 943 return SectionObj.GetDataObject() 944 945 def _UserExtentionSectionParser(self): 946 self._RawData.CurrentScope = [] 947 ArchList = set() 948 Section = self._RawData.CurrentLine[1:-1] 949 Par = ParserHelper(Section, self._RawData.Filename) 950 while not Par.End(): 951 # 952 # User extention 953 # 954 Token = Par.GetToken() 955 if Token.upper() != DT.TAB_USER_EXTENSIONS.upper(): 956 self._LoggerError(ST.ERR_DECPARSE_SECTION_UE) 957 UserExtension = Token.upper() 958 Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex) 959 960 # 961 # UserID 962 # 963 Token = Par.GetToken() 964 if not IsValidUserId(Token): 965 self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_USERID) 966 UserId = Token 967 Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex) 968 # 969 # IdString 970 # 971 Token = Par.GetToken() 972 if not IsValidIdString(Token): 973 self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_IDSTRING) 974 IdString = Token 975 Arch = 'COMMON' 976 if Par.Expect(DT.TAB_SPLIT): 977 Token = Par.GetToken() 978 Arch = Token.upper() 979 if not IsValidArch(Arch): 980 self._LoggerError(ST.ERR_DECPARSE_ARCH) 981 ArchList.add(Arch) 982 if [UserExtension, UserId, IdString, Arch] not in \ 983 self._RawData.CurrentScope: 984 self._RawData.CurrentScope.append( 985 [UserExtension, UserId, IdString, Arch] 986 ) 987 if not Par.Expect(DT.TAB_COMMA_SPLIT): 988 break 989 elif Par.End(): 990 self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMA) 991 Par.AssertEnd(ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex) 992 if 'COMMON' in ArchList and len(ArchList) > 1: 993 self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON) 994 995 ## Section header parser 996 # 997 # The section header is always in following format: 998 # 999 # [section_name.arch<.platform|module_type>] 1000 # 1001 def _SectionHeaderParser(self): 1002 if self._RawData.CurrentLine[0] != DT.TAB_SECTION_START or self._RawData.CurrentLine[-1] != DT.TAB_SECTION_END: 1003 self._LoggerError(ST.ERR_DECPARSE_SECTION_IDENTIFY) 1004 1005 RawSection = self._RawData.CurrentLine[1:-1].strip().upper() 1006 # 1007 # Check defines section which is only allowed to occur once and 1008 # no arch can be followed 1009 # 1010 if RawSection.startswith(DT.TAB_DEC_DEFINES.upper()): 1011 if RawSection != DT.TAB_DEC_DEFINES.upper(): 1012 self._LoggerError(ST.ERR_DECPARSE_DEFINE_SECNAME) 1013 # 1014 # Check user extension section 1015 # 1016 if RawSection.startswith(DT.TAB_USER_EXTENSIONS.upper()): 1017 return self._UserExtentionSectionParser() 1018 self._RawData.CurrentScope = [] 1019 SectionNames = [] 1020 ArchList = set() 1021 for Item in GetSplitValueList(RawSection, DT.TAB_COMMA_SPLIT): 1022 if Item == '': 1023 self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine) 1024 1025 ItemList = GetSplitValueList(Item, DT.TAB_SPLIT) 1026 # 1027 # different types of PCD are permissible in one section 1028 # 1029 SectionName = ItemList[0] 1030 if SectionName not in self._SectionParser: 1031 self._LoggerError(ST.ERR_DECPARSE_SECTION_UNKNOW % SectionName) 1032 if SectionName not in SectionNames: 1033 SectionNames.append(SectionName) 1034 # 1035 # In DEC specification, all section headers have at most two part: 1036 # SectionName.Arch except UserExtention 1037 # 1038 if len(ItemList) > 2: 1039 self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBTOOMANY % Item) 1040 1041 if DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() in SectionNames and len(SectionNames) > 1: 1042 self._LoggerError(ST.ERR_DECPARSE_SECTION_FEATUREFLAG % DT.TAB_PCDS_FEATURE_FLAG_NULL) 1043 # 1044 # S1 is always Arch 1045 # 1046 if len(ItemList) > 1: 1047 Str1 = ItemList[1] 1048 if not IsValidArch(Str1): 1049 self._LoggerError(ST.ERR_DECPARSE_ARCH) 1050 else: 1051 Str1 = 'COMMON' 1052 ArchList.add(Str1) 1053 1054 if [SectionName, Str1] not in self._RawData.CurrentScope: 1055 self._RawData.CurrentScope.append([SectionName, Str1]) 1056 # 1057 # 'COMMON' must not be used with specific ARCHs at the same section 1058 # 1059 if 'COMMON' in ArchList and len(ArchList) > 1: 1060 self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON) 1061 if len(SectionNames) == 0: 1062 self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine) 1063 if len(SectionNames) != 1: 1064 for Sec in SectionNames: 1065 if not Sec.startswith(DT.TAB_PCDS.upper()): 1066 self._LoggerError(ST.ERR_DECPARSE_SECTION_NAME % str(SectionNames)) 1067 1068 def GetDefineSectionMacro(self): 1069 return self._Define.GetLocalMacro() 1070 def GetDefineSectionObject(self): 1071 return self._Define.GetDataObject() 1072 def GetIncludeSectionObject(self): 1073 return self._Include.GetDataObject() 1074 def GetGuidSectionObject(self): 1075 return self._Guid.GetGuidObject() 1076 def GetProtocolSectionObject(self): 1077 return self._Guid.GetProtocolObject() 1078 def GetPpiSectionObject(self): 1079 return self._Guid.GetPpiObject() 1080 def GetLibraryClassSectionObject(self): 1081 return self._LibClass.GetDataObject() 1082 def GetPcdSectionObject(self): 1083 return self._Pcd.GetDataObject() 1084 def GetUserExtensionSectionObject(self): 1085 return self._UserEx.GetDataObject() 1086 def GetPackageSpecification(self): 1087 return self._Define.GetDataObject().GetPackageSpecification() 1088 def GetPackageName(self): 1089 return self._Define.GetDataObject().GetPackageName() 1090 def GetPackageGuid(self): 1091 return self._Define.GetDataObject().GetPackageGuid() 1092 def GetPackageVersion(self): 1093 return self._Define.GetDataObject().GetPackageVersion() 1094 def GetPackageUniFile(self): 1095 return self._Define.GetDataObject().GetPackageUniFile() 1096 def GetPrivateSections(self): 1097 return self._Private 1098