]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/UPT/Parser/DecParser.py
This patch is going to:
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Parser / DecParser.py
1 ## @file
2 # This file is used to parse DEC file. It will consumed by DecParser
3 #
4 # Copyright (c) 2011 - 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 '''
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 Parser.DecParserMisc import TOOL_NAME
33 from Parser.DecParserMisc import CleanString
34 from Parser.DecParserMisc import IsValidPcdDatum
35 from Parser.DecParserMisc import ParserHelper
36 from Parser.DecParserMisc import StripRoot
37 from Parser.DecParserMisc import VERSION_PATTERN
38 from Parser.DecParserMisc import CVAR_PATTERN
39 from Parser.DecParserMisc import PCD_TOKEN_PATTERN
40 from Parser.DecParserMisc import MACRO_PATTERN
41 from Parser.DecParserMisc import FileContent
42 from Object.Parser.DecObject import _DecComments
43 from Object.Parser.DecObject import DecDefineObject
44 from Object.Parser.DecObject import DecDefineItemObject
45 from Object.Parser.DecObject import DecIncludeObject
46 from Object.Parser.DecObject import DecIncludeItemObject
47 from Object.Parser.DecObject import DecLibraryclassObject
48 from Object.Parser.DecObject import DecLibraryclassItemObject
49 from Object.Parser.DecObject import DecGuidObject
50 from Object.Parser.DecObject import DecPpiObject
51 from Object.Parser.DecObject import DecProtocolObject
52 from Object.Parser.DecObject import DecGuidItemObject
53 from Object.Parser.DecObject import DecUserExtensionObject
54 from Object.Parser.DecObject import DecUserExtensionItemObject
55 from Object.Parser.DecObject import DecPcdObject
56 from Object.Parser.DecObject import DecPcdItemObject
57 from Library.Misc import GuidStructureStringToGuidString
58 from Library.Misc import CheckGuidRegFormat
59 from Library.String import ReplaceMacro
60 from Library.String import GetSplitValueList
61 from Library.String import gMACRO_PATTERN
62 from Library.String import ConvertSpecialChar
63 from Library.CommentParsing import ParsePcdErrorCode
64
65 ##
66 # _DecBase class for parsing
67 #
68 class _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 #
387 class _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 #
491 class _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 #
510 class _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 #
549 class _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 #
626 class _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 #
694 class _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 #
736 class 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()