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