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