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