1## @file 2# This file is used to parse DEC file. It will consumed by DecParser 3# 4# Copyright (c) 2011 - 2014, 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''' 14DecParser 15''' 16## Import modules 17# 18import Logger.Log as Logger 19from Logger.ToolError import FILE_PARSE_FAILURE 20from Logger.ToolError import FILE_OPEN_FAILURE 21from Logger import StringTable as ST 22from Logger.ToolError import FORMAT_INVALID 23 24import Library.DataType as DT 25from Library.ParserValidate import IsValidToken 26from Library.ParserValidate import IsValidPath 27from Library.ParserValidate import IsValidCFormatGuid 28from Library.ParserValidate import IsValidIdString 29from Library.ParserValidate import IsValidUserId 30from Library.ParserValidate import IsValidArch 31from Library.ParserValidate import IsValidWord 32from Library.ParserValidate import IsValidDecVersionVal 33from Parser.DecParserMisc import TOOL_NAME 34from Parser.DecParserMisc import CleanString 35from Parser.DecParserMisc import IsValidPcdDatum 36from Parser.DecParserMisc import ParserHelper 37from Parser.DecParserMisc import StripRoot 38from Parser.DecParserMisc import VERSION_PATTERN 39from Parser.DecParserMisc import CVAR_PATTERN 40from Parser.DecParserMisc import PCD_TOKEN_PATTERN 41from Parser.DecParserMisc import MACRO_PATTERN 42from Parser.DecParserMisc import FileContent 43from Object.Parser.DecObject import _DecComments 44from Object.Parser.DecObject import DecDefineObject 45from Object.Parser.DecObject import DecDefineItemObject 46from Object.Parser.DecObject import DecIncludeObject 47from Object.Parser.DecObject import DecIncludeItemObject 48from Object.Parser.DecObject import DecLibraryclassObject 49from Object.Parser.DecObject import DecLibraryclassItemObject 50from Object.Parser.DecObject import DecGuidObject 51from Object.Parser.DecObject import DecPpiObject 52from Object.Parser.DecObject import DecProtocolObject 53from Object.Parser.DecObject import DecGuidItemObject 54from Object.Parser.DecObject import DecUserExtensionObject 55from Object.Parser.DecObject import DecUserExtensionItemObject 56from Object.Parser.DecObject import DecPcdObject 57from Object.Parser.DecObject import DecPcdItemObject 58from Library.Misc import GuidStructureStringToGuidString 59from Library.Misc import CheckGuidRegFormat 60from Library.String import ReplaceMacro 61from Library.String import GetSplitValueList 62from Library.String import gMACRO_PATTERN 63from Library.String import ConvertSpecialChar 64from Library.CommentParsing import ParsePcdErrorCode 65 66## 67# _DecBase class for parsing 68# 69class _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# 388class _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# 493class _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# 512class _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# 551class _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# 628class _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# 696class _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# 738class 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 RawData = FileContent(DecFile, Content) 746 747 _DecComments.__init__(self) 748 _DecBase.__init__(self, RawData) 749 750 self.BinaryHeadComment = [] 751 self.PcdErrorCommentDict = {} 752 753 self._Define = _DecDefine(RawData) 754 self._Include = _DecInclude(RawData) 755 self._Guid = _DecGuid(RawData) 756 self._LibClass = _DecLibraryclass(RawData) 757 self._Pcd = _DecPcd(RawData) 758 self._UserEx = _DecUserExtension(RawData) 759 760 # 761 # DEC file supported data types (one type per section) 762 # 763 self._SectionParser = { 764 DT.TAB_DEC_DEFINES.upper() : self._Define, 765 DT.TAB_INCLUDES.upper() : self._Include, 766 DT.TAB_LIBRARY_CLASSES.upper() : self._LibClass, 767 DT.TAB_GUIDS.upper() : self._Guid, 768 DT.TAB_PPIS.upper() : self._Guid, 769 DT.TAB_PROTOCOLS.upper() : self._Guid, 770 DT.TAB_PCDS_FIXED_AT_BUILD_NULL.upper() : self._Pcd, 771 DT.TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper() : self._Pcd, 772 DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() : self._Pcd, 773 DT.TAB_PCDS_DYNAMIC_NULL.upper() : self._Pcd, 774 DT.TAB_PCDS_DYNAMIC_EX_NULL.upper() : self._Pcd, 775 DT.TAB_USER_EXTENSIONS.upper() : self._UserEx 776 } 777 778 if Parse: 779 self.ParseDecComment() 780 self.Parse() 781 # 782 # Parsing done, check required fields 783 # 784 self.CheckRequiredFields() 785 786 def CheckRequiredFields(self): 787 for SectionParser in self._SectionParser.values(): 788 if not SectionParser.CheckRequiredFields(): 789 return False 790 return True 791 792 ## 793 # Parse DEC file 794 # 795 def ParseDecComment(self): 796 IsFileHeader = False 797 IsBinaryHeader = False 798 FileHeaderLineIndex = -1 799 BinaryHeaderLineIndex = -1 800 TokenSpaceGuidCName = '' 801 802 # 803 # Parse PCD error comment section 804 # 805 while not self._RawData.IsEndOfFile(): 806 self._RawData.CurrentLine = self._RawData.GetNextLine() 807 if self._RawData.CurrentLine.startswith(DT.TAB_COMMENT_SPLIT) and \ 808 DT.TAB_SECTION_START in self._RawData.CurrentLine and \ 809 DT.TAB_SECTION_END in self._RawData.CurrentLine: 810 self._RawData.CurrentLine = self._RawData.CurrentLine.replace(DT.TAB_COMMENT_SPLIT, '').strip() 811 812 if self._RawData.CurrentLine[0] == DT.TAB_SECTION_START and \ 813 self._RawData.CurrentLine[-1] == DT.TAB_SECTION_END: 814 RawSection = self._RawData.CurrentLine[1:-1].strip() 815 if RawSection.upper().startswith(DT.TAB_PCD_ERROR.upper()+'.'): 816 TokenSpaceGuidCName = RawSection.split(DT.TAB_PCD_ERROR+'.')[1].strip() 817 continue 818 819 if TokenSpaceGuidCName and self._RawData.CurrentLine.startswith(DT.TAB_COMMENT_SPLIT): 820 self._RawData.CurrentLine = self._RawData.CurrentLine.replace(DT.TAB_COMMENT_SPLIT, '').strip() 821 if self._RawData.CurrentLine != '': 822 if DT.TAB_VALUE_SPLIT not in self._RawData.CurrentLine: 823 self._LoggerError(ST.ERR_DECPARSE_PCDERRORMSG_MISS_VALUE_SPLIT) 824 825 PcdErrorNumber, PcdErrorMsg = GetSplitValueList(self._RawData.CurrentLine, DT.TAB_VALUE_SPLIT, 1) 826 PcdErrorNumber = ParsePcdErrorCode(PcdErrorNumber, self._RawData.Filename, self._RawData.LineIndex) 827 if not PcdErrorMsg.strip(): 828 self._LoggerError(ST.ERR_DECPARSE_PCD_MISS_ERRORMSG) 829 830 self.PcdErrorCommentDict[(TokenSpaceGuidCName, PcdErrorNumber)] = PcdErrorMsg.strip() 831 else: 832 TokenSpaceGuidCName = '' 833 834 self._RawData.LineIndex = 0 835 self._RawData.CurrentLine = '' 836 self._RawData.NextLine = '' 837 838 while not self._RawData.IsEndOfFile(): 839 Line, Comment = CleanString(self._RawData.GetNextLine()) 840 841 # 842 # Header must be pure comment 843 # 844 if Line != '': 845 self._RawData.UndoNextLine() 846 break 847 848 if Comment and Comment.startswith(DT.TAB_SPECIAL_COMMENT) and Comment.find(DT.TAB_HEADER_COMMENT) > 0 \ 849 and not Comment[2:Comment.find(DT.TAB_HEADER_COMMENT)].strip(): 850 IsFileHeader = True 851 IsBinaryHeader = False 852 FileHeaderLineIndex = self._RawData.LineIndex 853 854 # 855 # Get license information before '@file' 856 # 857 if not IsFileHeader and not IsBinaryHeader and Comment and Comment.startswith(DT.TAB_COMMENT_SPLIT) and \ 858 DT.TAB_BINARY_HEADER_COMMENT not in Comment: 859 self._HeadComment.append((Comment, self._RawData.LineIndex)) 860 861 if Comment and IsFileHeader and \ 862 not(Comment.startswith(DT.TAB_SPECIAL_COMMENT) \ 863 and Comment.find(DT.TAB_BINARY_HEADER_COMMENT) > 0): 864 self._HeadComment.append((Comment, self._RawData.LineIndex)) 865 # 866 # Double '#' indicates end of header comments 867 # 868 if (not Comment or Comment == DT.TAB_SPECIAL_COMMENT) and IsFileHeader: 869 IsFileHeader = False 870 continue 871 872 if Comment and Comment.startswith(DT.TAB_SPECIAL_COMMENT) \ 873 and Comment.find(DT.TAB_BINARY_HEADER_COMMENT) > 0: 874 IsBinaryHeader = True 875 IsFileHeader = False 876 BinaryHeaderLineIndex = self._RawData.LineIndex 877 878 if Comment and IsBinaryHeader: 879 self.BinaryHeadComment.append((Comment, self._RawData.LineIndex)) 880 # 881 # Double '#' indicates end of header comments 882 # 883 if (not Comment or Comment == DT.TAB_SPECIAL_COMMENT) and IsBinaryHeader: 884 IsBinaryHeader = False 885 break 886 887 if FileHeaderLineIndex > -1 and not IsFileHeader and not IsBinaryHeader: 888 break 889 890 if FileHeaderLineIndex > BinaryHeaderLineIndex and FileHeaderLineIndex > -1 and BinaryHeaderLineIndex > -1: 891 self._LoggerError(ST.ERR_BINARY_HEADER_ORDER) 892 893 if FileHeaderLineIndex == -1: 894# self._LoggerError(ST.ERR_NO_SOURCE_HEADER) 895 Logger.Error(TOOL_NAME, FORMAT_INVALID, 896 ST.ERR_NO_SOURCE_HEADER, 897 File=self._RawData.Filename) 898 return 899 900 def _StopCurrentParsing(self, Line): 901 return False 902 903 def _ParseItem(self): 904 self._SectionHeaderParser() 905 if len(self._RawData.CurrentScope) == 0: 906 self._LoggerError(ST.ERR_DECPARSE_SECTION_EMPTY) 907 SectionObj = self._SectionParser[self._RawData.CurrentScope[0][0]] 908 SectionObj.BlockStart() 909 SectionObj.Parse() 910 return SectionObj.GetDataObject() 911 912 def _UserExtentionSectionParser(self): 913 self._RawData.CurrentScope = [] 914 ArchList = set() 915 Section = self._RawData.CurrentLine[1:-1] 916 Par = ParserHelper(Section, self._RawData.Filename) 917 while not Par.End(): 918 # 919 # User extention 920 # 921 Token = Par.GetToken() 922 if Token.upper() != DT.TAB_USER_EXTENSIONS.upper(): 923 self._LoggerError(ST.ERR_DECPARSE_SECTION_UE) 924 UserExtension = Token.upper() 925 Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex) 926 927 # 928 # UserID 929 # 930 Token = Par.GetToken() 931 if not IsValidUserId(Token): 932 self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_USERID) 933 UserId = Token 934 Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex) 935 # 936 # IdString 937 # 938 Token = Par.GetToken() 939 if not IsValidIdString(Token): 940 self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_IDSTRING) 941 IdString = Token 942 Arch = 'COMMON' 943 if Par.Expect(DT.TAB_SPLIT): 944 Token = Par.GetToken() 945 Arch = Token.upper() 946 if not IsValidArch(Arch): 947 self._LoggerError(ST.ERR_DECPARSE_ARCH) 948 ArchList.add(Arch) 949 if [UserExtension, UserId, IdString, Arch] not in \ 950 self._RawData.CurrentScope: 951 self._RawData.CurrentScope.append( 952 [UserExtension, UserId, IdString, Arch] 953 ) 954 if not Par.Expect(DT.TAB_COMMA_SPLIT): 955 break 956 elif Par.End(): 957 self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMA) 958 Par.AssertEnd(ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex) 959 if 'COMMON' in ArchList and len(ArchList) > 1: 960 self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON) 961 962 ## Section header parser 963 # 964 # The section header is always in following format: 965 # 966 # [section_name.arch<.platform|module_type>] 967 # 968 def _SectionHeaderParser(self): 969 if self._RawData.CurrentLine[0] != DT.TAB_SECTION_START or self._RawData.CurrentLine[-1] != DT.TAB_SECTION_END: 970 self._LoggerError(ST.ERR_DECPARSE_SECTION_IDENTIFY) 971 972 RawSection = self._RawData.CurrentLine[1:-1].strip().upper() 973 # 974 # Check defines section which is only allowed to occur once and 975 # no arch can be followed 976 # 977 if RawSection.startswith(DT.TAB_DEC_DEFINES.upper()): 978 if RawSection != DT.TAB_DEC_DEFINES.upper(): 979 self._LoggerError(ST.ERR_DECPARSE_DEFINE_SECNAME) 980 # 981 # Check user extension section 982 # 983 if RawSection.startswith(DT.TAB_USER_EXTENSIONS.upper()): 984 return self._UserExtentionSectionParser() 985 self._RawData.CurrentScope = [] 986 SectionNames = [] 987 ArchList = set() 988 for Item in GetSplitValueList(RawSection, DT.TAB_COMMA_SPLIT): 989 if Item == '': 990 self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine) 991 992 ItemList = GetSplitValueList(Item, DT.TAB_SPLIT) 993 # 994 # different types of PCD are permissible in one section 995 # 996 SectionName = ItemList[0] 997 if SectionName not in self._SectionParser: 998 self._LoggerError(ST.ERR_DECPARSE_SECTION_UNKNOW % SectionName) 999 if SectionName not in SectionNames: 1000 SectionNames.append(SectionName) 1001 # 1002 # In DEC specification, all section headers have at most two part: 1003 # SectionName.Arch except UserExtention 1004 # 1005 if len(ItemList) > 2: 1006 self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBTOOMANY % Item) 1007 1008 if DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() in SectionNames and len(SectionNames) > 1: 1009 self._LoggerError(ST.ERR_DECPARSE_SECTION_FEATUREFLAG % DT.TAB_PCDS_FEATURE_FLAG_NULL) 1010 # 1011 # S1 is always Arch 1012 # 1013 if len(ItemList) > 1: 1014 Str1 = ItemList[1] 1015 if not IsValidArch(Str1): 1016 self._LoggerError(ST.ERR_DECPARSE_ARCH) 1017 else: 1018 Str1 = 'COMMON' 1019 ArchList.add(Str1) 1020 1021 if [SectionName, Str1] not in self._RawData.CurrentScope: 1022 self._RawData.CurrentScope.append([SectionName, Str1]) 1023 # 1024 # 'COMMON' must not be used with specific ARCHs at the same section 1025 # 1026 if 'COMMON' in ArchList and len(ArchList) > 1: 1027 self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON) 1028 if len(SectionNames) == 0: 1029 self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine) 1030 if len(SectionNames) != 1: 1031 for Sec in SectionNames: 1032 if not Sec.startswith(DT.TAB_PCDS.upper()): 1033 self._LoggerError(ST.ERR_DECPARSE_SECTION_NAME % str(SectionNames)) 1034 1035 def GetDefineSectionMacro(self): 1036 return self._Define.GetLocalMacro() 1037 def GetDefineSectionObject(self): 1038 return self._Define.GetDataObject() 1039 def GetIncludeSectionObject(self): 1040 return self._Include.GetDataObject() 1041 def GetGuidSectionObject(self): 1042 return self._Guid.GetGuidObject() 1043 def GetProtocolSectionObject(self): 1044 return self._Guid.GetProtocolObject() 1045 def GetPpiSectionObject(self): 1046 return self._Guid.GetPpiObject() 1047 def GetLibraryClassSectionObject(self): 1048 return self._LibClass.GetDataObject() 1049 def GetPcdSectionObject(self): 1050 return self._Pcd.GetDataObject() 1051 def GetUserExtensionSectionObject(self): 1052 return self._UserEx.GetDataObject() 1053 def GetPackageSpecification(self): 1054 return self._Define.GetDataObject().GetPackageSpecification() 1055 def GetPackageName(self): 1056 return self._Define.GetDataObject().GetPackageName() 1057 def GetPackageGuid(self): 1058 return self._Define.GetDataObject().GetPackageGuid() 1059 def GetPackageVersion(self): 1060 return self._Define.GetDataObject().GetPackageVersion() 1061 def GetPackageUniFile(self): 1062 return self._Define.GetDataObject().GetPackageUniFile() 1063