]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py
BaseTools/Ecc: Add a checkpoint for invalid UNI file.
[mirror_edk2.git] / BaseTools / Source / Python / Ecc / MetaFileWorkspace / MetaFileParser.py
1 ## @file
2 # This file is used to parse meta files
3 #
4 # Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
9 #
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 #
13
14 ##
15 # Import Modules
16 #
17 import Common.LongFilePathOs as os
18 import re
19 import time
20 import copy
21
22 import Common.EdkLogger as EdkLogger
23 import Common.GlobalData as GlobalData
24 import EccGlobalData
25
26 from CommonDataClass.DataClass import *
27 from Common.DataType import *
28 from Common.String import *
29 from Common.Misc import GuidStructureStringToGuidString, CheckPcdDatum, PathClass, AnalyzePcdData
30 from Common.Expression import *
31 from CommonDataClass.Exceptions import *
32
33 from MetaFileTable import MetaFileStorage
34 from GenFds.FdfParser import FdfParser
35 from Common.LongFilePathSupport import OpenLongFilePath as open
36 from Common.LongFilePathSupport import CodecOpenLongFilePath
37
38 ## A decorator used to parse macro definition
39 def ParseMacro(Parser):
40 def MacroParser(self):
41 Match = gMacroDefPattern.match(self._CurrentLine)
42 if not Match:
43 # Not 'DEFINE/EDK_GLOBAL' statement, call decorated method
44 Parser(self)
45 return
46
47 TokenList = GetSplitValueList(self._CurrentLine[Match.end(1):], TAB_EQUAL_SPLIT, 1)
48 # Syntax check
49 if not TokenList[0]:
50 EdkLogger.error('Parser', FORMAT_INVALID, "No macro name given",
51 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
52 if len(TokenList) < 2:
53 TokenList.append('')
54
55 Type = Match.group(1)
56 Name, Value = TokenList
57 # Global macros can be only defined via environment variable
58 if Name in GlobalData.gGlobalDefines:
59 EdkLogger.error('Parser', FORMAT_INVALID, "%s can only be defined via environment variable" % Name,
60 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
61 # Only upper case letters, digit and '_' are allowed
62 if not gMacroNamePattern.match(Name):
63 EdkLogger.error('Parser', FORMAT_INVALID, "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
64 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
65
66 Value = ReplaceMacro(Value, self._Macros)
67 self._ItemType = MODEL_META_DATA_DEFINE
68 # DEFINE defined macros
69 if Type == TAB_DSC_DEFINES_DEFINE:
70 if type(self) == DecParser:
71 if MODEL_META_DATA_HEADER in self._SectionType:
72 self._FileLocalMacros[Name] = Value
73 else:
74 for Scope in self._Scope:
75 self._SectionsMacroDict.setdefault((Scope[2], Scope[0], Scope[1]), {})[Name] = Value
76 elif self._SectionType == MODEL_META_DATA_HEADER:
77 self._FileLocalMacros[Name] = Value
78 else:
79 SectionDictKey = self._SectionType, self._Scope[0][0], self._Scope[0][1]
80 if SectionDictKey not in self._SectionsMacroDict:
81 self._SectionsMacroDict[SectionDictKey] = {}
82 SectionLocalMacros = self._SectionsMacroDict[SectionDictKey]
83 SectionLocalMacros[Name] = Value
84 # EDK_GLOBAL defined macros
85 elif type(self) != DscParser:
86 EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL can only be used in .dsc file",
87 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
88 elif self._SectionType != MODEL_META_DATA_HEADER:
89 EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL can only be used under [Defines] section",
90 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
91 elif (Name in self._FileLocalMacros) and (self._FileLocalMacros[Name] != Value):
92 EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL defined a macro with the same name and different value as one defined by 'DEFINE'",
93 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
94
95 self._ValueList = [Type, Name, Value]
96
97 return MacroParser
98
99 ## Base class of parser
100 #
101 # This class is used for derivation purpose. The specific parser for one kind
102 # type file must derive this class and implement some public interfaces.
103 #
104 # @param FilePath The path of platform description file
105 # @param FileType The raw data of DSC file
106 # @param Table Database used to retrieve module/package information
107 # @param Macros Macros used for replacement in file
108 # @param Owner Owner ID (for sub-section parsing)
109 # @param From ID from which the data comes (for !INCLUDE directive)
110 #
111 class MetaFileParser(object):
112 # data type (file content) for specific file type
113 DataType = {}
114
115 # Parser objects used to implement singleton
116 MetaFiles = {}
117
118 ## Factory method
119 #
120 # One file, one parser object. This factory method makes sure that there's
121 # only one object constructed for one meta file.
122 #
123 # @param Class class object of real AutoGen class
124 # (InfParser, DecParser or DscParser)
125 # @param FilePath The path of meta file
126 # @param *args The specific class related parameters
127 # @param **kwargs The specific class related dict parameters
128 #
129 def __new__(Class, FilePath, *args, **kwargs):
130 if FilePath in Class.MetaFiles:
131 return Class.MetaFiles[FilePath]
132 else:
133 ParserObject = super(MetaFileParser, Class).__new__(Class)
134 Class.MetaFiles[FilePath] = ParserObject
135 return ParserObject
136
137 ## Constructor of MetaFileParser
138 #
139 # Initialize object of MetaFileParser
140 #
141 # @param FilePath The path of platform description file
142 # @param FileType The raw data of DSC file
143 # @param Table Database used to retrieve module/package information
144 # @param Macros Macros used for replacement in file
145 # @param Owner Owner ID (for sub-section parsing)
146 # @param From ID from which the data comes (for !INCLUDE directive)
147 #
148 def __init__(self, FilePath, FileType, Table, Owner=-1, From=-1):
149 self._Table = Table
150 self._RawTable = Table
151 self._FileType = FileType
152 self.MetaFile = FilePath
153 self._Defines = {}
154 self._FileLocalMacros = {}
155 self._SectionsMacroDict = {}
156
157 # for recursive parsing
158 self._Owner = [Owner]
159 self._From = From
160
161 # parsr status for parsing
162 self._ValueList = ['', '', '', '', '']
163 self._Scope = []
164 self._LineIndex = 0
165 self._CurrentLine = ''
166 self._SectionType = MODEL_UNKNOWN
167 self._SectionName = ''
168 self._InSubsection = False
169 self._SubsectionType = MODEL_UNKNOWN
170 self._SubsectionName = ''
171 self._ItemType = MODEL_UNKNOWN
172 self._LastItem = -1
173 self._Enabled = 0
174 self._Finished = False
175 self._PostProcessed = False
176 # Different version of meta-file has different way to parse.
177 self._Version = 0
178 # UNI object and extra UNI object
179 self._UniObj = None
180 self._UniExtraObj = None
181
182 ## Store the parsed data in table
183 def _Store(self, *Args):
184 return self._Table.Insert(*Args)
185
186 ## Virtual method for starting parse
187 def Start(self):
188 raise NotImplementedError
189
190 ## Notify a post-process is needed
191 def DoPostProcess(self):
192 self._PostProcessed = False
193
194 ## Set parsing complete flag in both class and table
195 def _Done(self):
196 self._Finished = True
197 ## Do not set end flag when processing included files
198 if self._From == -1:
199 self._Table.SetEndFlag()
200
201 def _PostProcess(self):
202 self._PostProcessed = True
203
204 ## Get the parse complete flag
205 def _GetFinished(self):
206 return self._Finished
207
208 ## Set the complete flag
209 def _SetFinished(self, Value):
210 self._Finished = Value
211
212 ## Use [] style to query data in table, just for readability
213 #
214 # DataInfo = [data_type, scope1(arch), scope2(platform/moduletype)]
215 #
216 def __getitem__(self, DataInfo):
217 if type(DataInfo) != type(()):
218 DataInfo = (DataInfo,)
219
220 # Parse the file first, if necessary
221 if not self._Finished:
222 if self._RawTable.IsIntegrity():
223 self._Finished = True
224 else:
225 self._Table = self._RawTable
226 self._PostProcessed = False
227 self.Start()
228
229 # No specific ARCH or Platform given, use raw data
230 if self._RawTable and (len(DataInfo) == 1 or DataInfo[1] == None):
231 return self._RawTable.Query(*DataInfo)
232
233 # Do post-process if necessary
234 if not self._PostProcessed:
235 self._PostProcess()
236
237 return self._Table.Query(*DataInfo)
238
239 ## Data parser for the common format in different type of file
240 #
241 # The common format in the meatfile is like
242 #
243 # xxx1 | xxx2 | xxx3
244 #
245 @ParseMacro
246 def _CommonParser(self):
247 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
248 self._ValueList[0:len(TokenList)] = TokenList
249
250 ## Data parser for the format in which there's path
251 #
252 # Only path can have macro used. So we need to replace them before use.
253 #
254 @ParseMacro
255 def _PathParser(self):
256 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
257 self._ValueList[0:len(TokenList)] = TokenList
258 # Don't do macro replacement for dsc file at this point
259 if type(self) != DscParser:
260 Macros = self._Macros
261 self._ValueList = [ReplaceMacro(Value, Macros) for Value in self._ValueList]
262
263 ## Skip unsupported data
264 def _Skip(self):
265 if self._SectionName == TAB_USER_EXTENSIONS.upper() and self._CurrentLine.upper().endswith('.UNI'):
266 if EccGlobalData.gConfig.UniCheckHelpInfo == '1' or EccGlobalData.gConfig.UniCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
267 ExtraUni = self._CurrentLine.strip()
268 ExtraUniFile = os.path.join(os.path.dirname(self.MetaFile), ExtraUni)
269 IsModuleUni = self.MetaFile.upper().endswith('.INF')
270 self._UniExtraObj = UniParser(ExtraUniFile, IsExtraUni=True, IsModuleUni=IsModuleUni)
271 self._UniExtraObj.Start()
272 else:
273 EdkLogger.warn("Parser", "Unrecognized content", File=self.MetaFile,
274 Line=self._LineIndex + 1, ExtraData=self._CurrentLine);
275 self._ValueList[0:1] = [self._CurrentLine]
276
277 ## Section header parser
278 #
279 # The section header is always in following format:
280 #
281 # [section_name.arch<.platform|module_type>]
282 #
283 def _SectionHeaderParser(self):
284 self._Scope = []
285 self._SectionName = ''
286 ArchList = set()
287 for Item in GetSplitValueList(self._CurrentLine[1:-1], TAB_COMMA_SPLIT):
288 if Item == '':
289 continue
290 ItemList = GetSplitValueList(Item, TAB_SPLIT)
291 # different section should not mix in one section
292 if self._SectionName != '' and self._SectionName != ItemList[0].upper():
293 EdkLogger.error('Parser', FORMAT_INVALID, "Different section names in the same section",
294 File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
295 self._SectionName = ItemList[0].upper()
296 if self._SectionName in self.DataType:
297 self._SectionType = self.DataType[self._SectionName]
298 else:
299 self._SectionType = MODEL_UNKNOWN
300 EdkLogger.warn("Parser", "Unrecognized section", File=self.MetaFile,
301 Line=self._LineIndex+1, ExtraData=self._CurrentLine)
302 # S1 is always Arch
303 if len(ItemList) > 1:
304 S1 = ItemList[1].upper()
305 else:
306 S1 = 'COMMON'
307 ArchList.add(S1)
308 # S2 may be Platform or ModuleType
309 if len(ItemList) > 2:
310 S2 = ItemList[2].upper()
311 else:
312 S2 = 'COMMON'
313 self._Scope.append([S1, S2])
314
315 # 'COMMON' must not be used with specific ARCHs at the same section
316 if 'COMMON' in ArchList and len(ArchList) > 1:
317 EdkLogger.error('Parser', FORMAT_INVALID, "'common' ARCH must not be used with specific ARCHs",
318 File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
319 # If the section information is needed later, it should be stored in database
320 self._ValueList[0] = self._SectionName
321
322 ## [defines] section parser
323 @ParseMacro
324 def _DefineParser(self):
325 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
326 self._ValueList[1:len(TokenList)] = TokenList
327 if not self._ValueList[1]:
328 EdkLogger.error('Parser', FORMAT_INVALID, "No name specified",
329 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
330 if not self._ValueList[2]:
331 EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",
332 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
333
334 self._ValueList = [ReplaceMacro(Value, self._Macros) for Value in self._ValueList]
335 Name, Value = self._ValueList[1], self._ValueList[2]
336 # Sometimes, we need to make differences between EDK and EDK2 modules
337 if Name == 'INF_VERSION':
338 try:
339 self._Version = int(Value, 0)
340 except:
341 EdkLogger.error('Parser', FORMAT_INVALID, "Invalid version number",
342 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
343 elif Name == 'MODULE_UNI_FILE':
344 UniFile = os.path.join(os.path.dirname(self.MetaFile), Value)
345 if os.path.exists(UniFile):
346 self._UniObj = UniParser(UniFile, IsExtraUni=False, IsModuleUni=True)
347 self._UniObj.Start()
348 else:
349 EdkLogger.error('Parser', FILE_NOT_FOUND, "Module UNI file %s is missing." % Value,
350 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1,
351 RaiseError=False)
352 elif Name == 'PACKAGE_UNI_FILE':
353 UniFile = os.path.join(os.path.dirname(self.MetaFile), Value)
354 if os.path.exists(UniFile):
355 self._UniObj = UniParser(UniFile, IsExtraUni=False, IsModuleUni=False)
356
357 if type(self) == InfParser and self._Version < 0x00010005:
358 # EDK module allows using defines as macros
359 self._FileLocalMacros[Name] = Value
360 self._Defines[Name] = Value
361
362 ## [BuildOptions] section parser
363 @ParseMacro
364 def _BuildOptionParser(self):
365 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
366 TokenList2 = GetSplitValueList(TokenList[0], ':', 1)
367 if len(TokenList2) == 2:
368 self._ValueList[0] = TokenList2[0] # toolchain family
369 self._ValueList[1] = TokenList2[1] # keys
370 else:
371 self._ValueList[1] = TokenList[0]
372 if len(TokenList) == 2 and type(self) != DscParser: # value
373 self._ValueList[2] = ReplaceMacro(TokenList[1], self._Macros)
374
375 if self._ValueList[1].count('_') != 4:
376 EdkLogger.error(
377 'Parser',
378 FORMAT_INVALID,
379 "'%s' must be in format of <TARGET>_<TOOLCHAIN>_<ARCH>_<TOOL>_FLAGS" % self._ValueList[1],
380 ExtraData=self._CurrentLine,
381 File=self.MetaFile,
382 Line=self._LineIndex+1
383 )
384
385 def _GetMacros(self):
386 Macros = {}
387 Macros.update(self._FileLocalMacros)
388 Macros.update(self._GetApplicableSectionMacro())
389 return Macros
390
391
392 ## Get section Macros that are applicable to current line, which may come from other sections
393 ## that share the same name while scope is wider
394 def _GetApplicableSectionMacro(self):
395 Macros = {}
396 for Scope1, Scope2 in [("COMMON", "COMMON"), ("COMMON", self._Scope[0][1]),
397 (self._Scope[0][0], "COMMON"), (self._Scope[0][0], self._Scope[0][1])]:
398 if (self._SectionType, Scope1, Scope2) in self._SectionsMacroDict:
399 Macros.update(self._SectionsMacroDict[(self._SectionType, Scope1, Scope2)])
400 return Macros
401
402 _SectionParser = {}
403 Finished = property(_GetFinished, _SetFinished)
404 _Macros = property(_GetMacros)
405
406
407 ## INF file parser class
408 #
409 # @param FilePath The path of platform description file
410 # @param FileType The raw data of DSC file
411 # @param Table Database used to retrieve module/package information
412 # @param Macros Macros used for replacement in file
413 #
414 class InfParser(MetaFileParser):
415 # INF file supported data types (one type per section)
416 DataType = {
417 TAB_UNKNOWN.upper() : MODEL_UNKNOWN,
418 TAB_INF_DEFINES.upper() : MODEL_META_DATA_HEADER,
419 TAB_DSC_DEFINES_DEFINE : MODEL_META_DATA_DEFINE,
420 TAB_BUILD_OPTIONS.upper() : MODEL_META_DATA_BUILD_OPTION,
421 TAB_INCLUDES.upper() : MODEL_EFI_INCLUDE,
422 TAB_LIBRARIES.upper() : MODEL_EFI_LIBRARY_INSTANCE,
423 TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS,
424 TAB_PACKAGES.upper() : MODEL_META_DATA_PACKAGE,
425 TAB_NMAKE.upper() : MODEL_META_DATA_NMAKE,
426 TAB_INF_FIXED_PCD.upper() : MODEL_PCD_FIXED_AT_BUILD,
427 TAB_INF_PATCH_PCD.upper() : MODEL_PCD_PATCHABLE_IN_MODULE,
428 TAB_INF_FEATURE_PCD.upper() : MODEL_PCD_FEATURE_FLAG,
429 TAB_INF_PCD_EX.upper() : MODEL_PCD_DYNAMIC_EX,
430 TAB_INF_PCD.upper() : MODEL_PCD_DYNAMIC,
431 TAB_SOURCES.upper() : MODEL_EFI_SOURCE_FILE,
432 TAB_GUIDS.upper() : MODEL_EFI_GUID,
433 TAB_PROTOCOLS.upper() : MODEL_EFI_PROTOCOL,
434 TAB_PPIS.upper() : MODEL_EFI_PPI,
435 TAB_DEPEX.upper() : MODEL_EFI_DEPEX,
436 TAB_BINARIES.upper() : MODEL_EFI_BINARY_FILE,
437 TAB_USER_EXTENSIONS.upper() : MODEL_META_DATA_USER_EXTENSION
438 }
439
440 ## Constructor of InfParser
441 #
442 # Initialize object of InfParser
443 #
444 # @param FilePath The path of module description file
445 # @param FileType The raw data of DSC file
446 # @param Table Database used to retrieve module/package information
447 # @param Macros Macros used for replacement in file
448 #
449 def __init__(self, FilePath, FileType, Table):
450 # prevent re-initialization
451 if hasattr(self, "_Table"):
452 return
453 MetaFileParser.__init__(self, FilePath, FileType, Table)
454 self.TblFile = EccGlobalData.gDb.TblFile
455 self.FileID = -1
456
457 ## Parser starter
458 def Start(self):
459 NmakeLine = ''
460 Content = ''
461 Usage = ''
462 try:
463 Content = open(str(self.MetaFile), 'r').readlines()
464 except:
465 EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
466 #
467 # Insert a record for file
468 #
469 Filename = NormPath(self.MetaFile)
470 FileID = self.TblFile.GetFileId(Filename)
471 if FileID:
472 self.FileID = FileID
473 else:
474 self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_INF)
475
476 # parse the file line by line
477 IsFindBlockComment = False
478
479 for Index in range(0, len(Content)):
480 if self._SectionType in [MODEL_EFI_GUID,
481 MODEL_EFI_PROTOCOL,
482 MODEL_EFI_PPI,
483 MODEL_PCD_FIXED_AT_BUILD,
484 MODEL_PCD_PATCHABLE_IN_MODULE,
485 MODEL_PCD_FEATURE_FLAG,
486 MODEL_PCD_DYNAMIC_EX,
487 MODEL_PCD_DYNAMIC]:
488 Line = Content[Index].strip()
489 if Line.startswith(TAB_SPECIAL_COMMENT):
490 Usage += ' ' + Line[Line.find(TAB_SPECIAL_COMMENT):]
491 continue
492 elif Line.startswith(TAB_COMMENT_SPLIT):
493 continue
494 elif Line.find(TAB_COMMENT_SPLIT) > 0:
495 Usage += ' ' + Line[Line.find(TAB_COMMENT_SPLIT):]
496 Line = Line[:Line.find(TAB_COMMENT_SPLIT)]
497 else:
498 # skip empty, commented, block commented lines
499 Line = CleanString(Content[Index], AllowCppStyleComment=True)
500 Usage = ''
501 NextLine = ''
502 if Index + 1 < len(Content):
503 NextLine = CleanString(Content[Index + 1])
504 if Line == '':
505 continue
506 if Line.find(DataType.TAB_COMMENT_EDK_START) > -1:
507 IsFindBlockComment = True
508 continue
509 if Line.find(DataType.TAB_COMMENT_EDK_END) > -1:
510 IsFindBlockComment = False
511 continue
512 if IsFindBlockComment:
513 continue
514
515 self._LineIndex = Index
516 self._CurrentLine = Line
517
518 # section header
519 if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
520 self._SectionHeaderParser()
521 # Check invalid sections
522 if self._Version < 0x00010005:
523 if self._SectionType in [MODEL_META_DATA_BUILD_OPTION,
524 MODEL_EFI_LIBRARY_CLASS,
525 MODEL_META_DATA_PACKAGE,
526 MODEL_PCD_FIXED_AT_BUILD,
527 MODEL_PCD_PATCHABLE_IN_MODULE,
528 MODEL_PCD_FEATURE_FLAG,
529 MODEL_PCD_DYNAMIC_EX,
530 MODEL_PCD_DYNAMIC,
531 MODEL_EFI_GUID,
532 MODEL_EFI_PROTOCOL,
533 MODEL_EFI_PPI,
534 MODEL_META_DATA_USER_EXTENSION]:
535 EdkLogger.error('Parser', FORMAT_INVALID,
536 "Section [%s] is not allowed in inf file without version" % (self._SectionName),
537 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
538 elif self._SectionType in [MODEL_EFI_INCLUDE,
539 MODEL_EFI_LIBRARY_INSTANCE,
540 MODEL_META_DATA_NMAKE]:
541 EdkLogger.error('Parser', FORMAT_INVALID,
542 "Section [%s] is not allowed in inf file with version 0x%08x" % (self._SectionName, self._Version),
543 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
544 continue
545 # merge two lines specified by '\' in section NMAKE
546 elif self._SectionType == MODEL_META_DATA_NMAKE:
547 if Line[-1] == '\\':
548 if NextLine == '':
549 self._CurrentLine = NmakeLine + Line[0:-1]
550 NmakeLine = ''
551 else:
552 if NextLine[0] == TAB_SECTION_START and NextLine[-1] == TAB_SECTION_END:
553 self._CurrentLine = NmakeLine + Line[0:-1]
554 NmakeLine = ''
555 else:
556 NmakeLine = NmakeLine + ' ' + Line[0:-1]
557 continue
558 else:
559 self._CurrentLine = NmakeLine + Line
560 NmakeLine = ''
561
562 # section content
563 self._ValueList = ['','','']
564 # parse current line, result will be put in self._ValueList
565 self._SectionParser[self._SectionType](self)
566 if self._ValueList == None or self._ItemType == MODEL_META_DATA_DEFINE:
567 self._ItemType = -1
568 continue
569 #
570 # Model, Value1, Value2, Value3, Arch, Platform, BelongsToItem=-1,
571 # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
572 #
573 self._ValueList[0] = self._ValueList[0].replace('/', '\\')
574 Usage = Usage.strip()
575 for Arch, Platform in self._Scope:
576 self._Store(self._SectionType,
577 self._ValueList[0],
578 self._ValueList[1],
579 self._ValueList[2],
580 Arch,
581 Platform,
582 self._Owner[-1],
583 self.FileID,
584 self._LineIndex+1,
585 -1,
586 self._LineIndex+1,
587 -1,
588 0,
589 Usage
590 )
591 Usage = ''
592 if IsFindBlockComment:
593 EdkLogger.error("Parser", FORMAT_INVALID, "Open block comments (starting with /*) are expected to end with */",
594 File=self.MetaFile)
595 self._Done()
596
597 ## Data parser for the format in which there's path
598 #
599 # Only path can have macro used. So we need to replace them before use.
600 #
601 def _IncludeParser(self):
602 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
603 self._ValueList[0:len(TokenList)] = TokenList
604 Macros = self._Macros
605 if Macros:
606 for Index in range(0, len(self._ValueList)):
607 Value = self._ValueList[Index]
608 if not Value:
609 continue
610
611 if Value.upper().find('$(EFI_SOURCE)\Edk'.upper()) > -1 or Value.upper().find('$(EFI_SOURCE)/Edk'.upper()) > -1:
612 Value = '$(EDK_SOURCE)' + Value[17:]
613 if Value.find('$(EFI_SOURCE)') > -1 or Value.find('$(EDK_SOURCE)') > -1:
614 pass
615 elif Value.startswith('.'):
616 pass
617 elif Value.startswith('$('):
618 pass
619 else:
620 Value = '$(EFI_SOURCE)/' + Value
621
622 self._ValueList[Index] = ReplaceMacro(Value, Macros)
623
624 ## Parse [Sources] section
625 #
626 # Only path can have macro used. So we need to replace them before use.
627 #
628 @ParseMacro
629 def _SourceFileParser(self):
630 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
631 self._ValueList[0:len(TokenList)] = TokenList
632 Macros = self._Macros
633 # For Acpi tables, remove macro like ' TABLE_NAME=Sata1'
634 if 'COMPONENT_TYPE' in Macros:
635 if self._Defines['COMPONENT_TYPE'].upper() == 'ACPITABLE':
636 self._ValueList[0] = GetSplitValueList(self._ValueList[0], ' ', 1)[0]
637 if self._Defines['BASE_NAME'] == 'Microcode':
638 pass
639 self._ValueList = [ReplaceMacro(Value, Macros) for Value in self._ValueList]
640
641 ## Parse [Binaries] section
642 #
643 # Only path can have macro used. So we need to replace them before use.
644 #
645 @ParseMacro
646 def _BinaryFileParser(self):
647 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 2)
648 if len(TokenList) < 2:
649 EdkLogger.error('Parser', FORMAT_INVALID, "No file type or path specified",
650 ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
651 File=self.MetaFile, Line=self._LineIndex+1)
652 if not TokenList[0]:
653 EdkLogger.error('Parser', FORMAT_INVALID, "No file type specified",
654 ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
655 File=self.MetaFile, Line=self._LineIndex+1)
656 if not TokenList[1]:
657 EdkLogger.error('Parser', FORMAT_INVALID, "No file path specified",
658 ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
659 File=self.MetaFile, Line=self._LineIndex+1)
660 self._ValueList[0:len(TokenList)] = TokenList
661 self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros)
662
663 ## [nmake] section parser (Edk.x style only)
664 def _NmakeParser(self):
665 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
666 self._ValueList[0:len(TokenList)] = TokenList
667 # remove macros
668 self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros)
669 # remove self-reference in macro setting
670 #self._ValueList[1] = ReplaceMacro(self._ValueList[1], {self._ValueList[0]:''})
671
672 ## [FixedPcd], [FeaturePcd], [PatchPcd], [Pcd] and [PcdEx] sections parser
673 @ParseMacro
674 def _PcdParser(self):
675 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
676 ValueList = GetSplitValueList(TokenList[0], TAB_SPLIT)
677 if len(ValueList) != 2:
678 EdkLogger.error('Parser', FORMAT_INVALID, "Illegal token space GUID and PCD name format",
679 ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<PcdCName>)",
680 File=self.MetaFile, Line=self._LineIndex+1)
681 self._ValueList[0:1] = ValueList
682 if len(TokenList) > 1:
683 self._ValueList[2] = TokenList[1]
684 if self._ValueList[0] == '' or self._ValueList[1] == '':
685 EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
686 ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<PcdCName>)",
687 File=self.MetaFile, Line=self._LineIndex+1)
688
689 # if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0.
690 if self._ValueList[2] != '':
691 InfPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
692 if InfPcdValueList[0] in ['True', 'true', 'TRUE']:
693 self._ValueList[2] = TokenList[1].replace(InfPcdValueList[0], '1', 1);
694 elif InfPcdValueList[0] in ['False', 'false', 'FALSE']:
695 self._ValueList[2] = TokenList[1].replace(InfPcdValueList[0], '0', 1);
696
697 ## [depex] section parser
698 @ParseMacro
699 def _DepexParser(self):
700 self._ValueList[0:1] = [self._CurrentLine]
701
702 _SectionParser = {
703 MODEL_UNKNOWN : MetaFileParser._Skip,
704 MODEL_META_DATA_HEADER : MetaFileParser._DefineParser,
705 MODEL_META_DATA_BUILD_OPTION : MetaFileParser._BuildOptionParser,
706 MODEL_EFI_INCLUDE : _IncludeParser, # for Edk.x modules
707 MODEL_EFI_LIBRARY_INSTANCE : MetaFileParser._CommonParser, # for Edk.x modules
708 MODEL_EFI_LIBRARY_CLASS : MetaFileParser._PathParser,
709 MODEL_META_DATA_PACKAGE : MetaFileParser._PathParser,
710 MODEL_META_DATA_NMAKE : _NmakeParser, # for Edk.x modules
711 MODEL_PCD_FIXED_AT_BUILD : _PcdParser,
712 MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser,
713 MODEL_PCD_FEATURE_FLAG : _PcdParser,
714 MODEL_PCD_DYNAMIC_EX : _PcdParser,
715 MODEL_PCD_DYNAMIC : _PcdParser,
716 MODEL_EFI_SOURCE_FILE : _SourceFileParser,
717 MODEL_EFI_GUID : MetaFileParser._CommonParser,
718 MODEL_EFI_PROTOCOL : MetaFileParser._CommonParser,
719 MODEL_EFI_PPI : MetaFileParser._CommonParser,
720 MODEL_EFI_DEPEX : _DepexParser,
721 MODEL_EFI_BINARY_FILE : _BinaryFileParser,
722 MODEL_META_DATA_USER_EXTENSION : MetaFileParser._Skip,
723 }
724
725 ## DSC file parser class
726 #
727 # @param FilePath The path of platform description file
728 # @param FileType The raw data of DSC file
729 # @param Table Database used to retrieve module/package information
730 # @param Macros Macros used for replacement in file
731 # @param Owner Owner ID (for sub-section parsing)
732 # @param From ID from which the data comes (for !INCLUDE directive)
733 #
734 class DscParser(MetaFileParser):
735 # DSC file supported data types (one type per section)
736 DataType = {
737 TAB_SKUIDS.upper() : MODEL_EFI_SKU_ID,
738 TAB_LIBRARIES.upper() : MODEL_EFI_LIBRARY_INSTANCE,
739 TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS,
740 TAB_BUILD_OPTIONS.upper() : MODEL_META_DATA_BUILD_OPTION,
741 TAB_PCDS_FIXED_AT_BUILD_NULL.upper() : MODEL_PCD_FIXED_AT_BUILD,
742 TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper() : MODEL_PCD_PATCHABLE_IN_MODULE,
743 TAB_PCDS_FEATURE_FLAG_NULL.upper() : MODEL_PCD_FEATURE_FLAG,
744 TAB_PCDS_DYNAMIC_DEFAULT_NULL.upper() : MODEL_PCD_DYNAMIC_DEFAULT,
745 TAB_PCDS_DYNAMIC_HII_NULL.upper() : MODEL_PCD_DYNAMIC_HII,
746 TAB_PCDS_DYNAMIC_VPD_NULL.upper() : MODEL_PCD_DYNAMIC_VPD,
747 TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL.upper() : MODEL_PCD_DYNAMIC_EX_DEFAULT,
748 TAB_PCDS_DYNAMIC_EX_HII_NULL.upper() : MODEL_PCD_DYNAMIC_EX_HII,
749 TAB_PCDS_DYNAMIC_EX_VPD_NULL.upper() : MODEL_PCD_DYNAMIC_EX_VPD,
750 TAB_COMPONENTS.upper() : MODEL_META_DATA_COMPONENT,
751 TAB_COMPONENTS_SOURCE_OVERRIDE_PATH.upper() : MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH,
752 TAB_DSC_DEFINES.upper() : MODEL_META_DATA_HEADER,
753 TAB_DSC_DEFINES_DEFINE : MODEL_META_DATA_DEFINE,
754 TAB_DSC_DEFINES_EDKGLOBAL : MODEL_META_DATA_GLOBAL_DEFINE,
755 TAB_INCLUDE.upper() : MODEL_META_DATA_INCLUDE,
756 TAB_IF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
757 TAB_IF_DEF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
758 TAB_IF_N_DEF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF,
759 TAB_ELSE_IF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF,
760 TAB_ELSE.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE,
761 TAB_END_IF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF,
762 TAB_ERROR.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR,
763 }
764
765 # Valid names in define section
766 DefineKeywords = [
767 "DSC_SPECIFICATION",
768 "PLATFORM_NAME",
769 "PLATFORM_GUID",
770 "PLATFORM_VERSION",
771 "SKUID_IDENTIFIER",
772 "PCD_INFO_GENERATION",
773 "SUPPORTED_ARCHITECTURES",
774 "BUILD_TARGETS",
775 "OUTPUT_DIRECTORY",
776 "FLASH_DEFINITION",
777 "BUILD_NUMBER",
778 "RFC_LANGUAGES",
779 "ISO_LANGUAGES",
780 "TIME_STAMP_FILE",
781 "VPD_TOOL_GUID",
782 "FIX_LOAD_TOP_MEMORY_ADDRESS"
783 ]
784
785 SymbolPattern = ValueExpression.SymbolPattern
786
787 ## Constructor of DscParser
788 #
789 # Initialize object of DscParser
790 #
791 # @param FilePath The path of platform description file
792 # @param FileType The raw data of DSC file
793 # @param Table Database used to retrieve module/package information
794 # @param Macros Macros used for replacement in file
795 # @param Owner Owner ID (for sub-section parsing)
796 # @param From ID from which the data comes (for !INCLUDE directive)
797 #
798 def __init__(self, FilePath, FileType, Table, Owner=-1, From=-1):
799 # prevent re-initialization
800 if hasattr(self, "_Table"):
801 return
802 MetaFileParser.__init__(self, FilePath, FileType, Table, Owner, From)
803 self._Version = 0x00010005 # Only EDK2 dsc file is supported
804 # to store conditional directive evaluation result
805 self._DirectiveStack = []
806 self._DirectiveEvalStack = []
807 self._Enabled = 1
808
809 # Final valid replacable symbols
810 self._Symbols = {}
811 #
812 # Map the ID between the original table and new table to track
813 # the owner item
814 #
815 self._IdMapping = {-1:-1}
816
817 self.TblFile = EccGlobalData.gDb.TblFile
818 self.FileID = -1
819
820 ## Parser starter
821 def Start(self):
822 Content = ''
823 try:
824 Content = open(str(self.MetaFile.Path), 'r').readlines()
825 except:
826 EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
827 #
828 # Insert a record for file
829 #
830 Filename = NormPath(self.MetaFile.Path)
831 FileID = self.TblFile.GetFileId(Filename)
832 if FileID:
833 self.FileID = FileID
834 else:
835 self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_DSC)
836
837
838 for Index in range(0, len(Content)):
839 Line = CleanString(Content[Index])
840 # skip empty line
841 if Line == '':
842 continue
843
844 self._CurrentLine = Line
845 self._LineIndex = Index
846 if self._InSubsection and self._Owner[-1] == -1:
847 self._Owner.append(self._LastItem)
848
849 # section header
850 if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
851 self._SectionType = MODEL_META_DATA_SECTION_HEADER
852 # subsection ending
853 elif Line[0] == '}' and self._InSubsection:
854 self._InSubsection = False
855 self._SubsectionType = MODEL_UNKNOWN
856 self._SubsectionName = ''
857 self._Owner[-1] = -1
858 continue
859 # subsection header
860 elif Line[0] == TAB_OPTION_START and Line[-1] == TAB_OPTION_END:
861 self._SubsectionType = MODEL_META_DATA_SUBSECTION_HEADER
862 # directive line
863 elif Line[0] == '!':
864 self._DirectiveParser()
865 continue
866
867 if self._InSubsection:
868 SectionType = self._SubsectionType
869 else:
870 SectionType = self._SectionType
871 self._ItemType = SectionType
872
873 self._ValueList = ['', '', '']
874 self._SectionParser[SectionType](self)
875 if self._ValueList == None:
876 continue
877 #
878 # Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1,
879 # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
880 #
881 for Arch, ModuleType in self._Scope:
882 self._LastItem = self._Store(
883 self._ItemType,
884 self._ValueList[0],
885 self._ValueList[1],
886 self._ValueList[2],
887 Arch,
888 ModuleType,
889 self._Owner[-1],
890 self.FileID,
891 self._From,
892 self._LineIndex+1,
893 -1,
894 self._LineIndex+1,
895 -1,
896 self._Enabled
897 )
898
899 if self._DirectiveStack:
900 Type, Line, Text = self._DirectiveStack[-1]
901 EdkLogger.error('Parser', FORMAT_INVALID, "No matching '!endif' found",
902 ExtraData=Text, File=self.MetaFile, Line=Line)
903 self._Done()
904
905 ## <subsection_header> parser
906 def _SubsectionHeaderParser(self):
907 self._SubsectionName = self._CurrentLine[1:-1].upper()
908 if self._SubsectionName in self.DataType:
909 self._SubsectionType = self.DataType[self._SubsectionName]
910 else:
911 self._SubsectionType = MODEL_UNKNOWN
912 EdkLogger.warn("Parser", "Unrecognized sub-section", File=self.MetaFile,
913 Line=self._LineIndex+1, ExtraData=self._CurrentLine)
914 self._ValueList[0] = self._SubsectionName
915
916 ## Directive statement parser
917 def _DirectiveParser(self):
918 self._ValueList = ['','','']
919 TokenList = GetSplitValueList(self._CurrentLine, ' ', 1)
920 self._ValueList[0:len(TokenList)] = TokenList
921
922 # Syntax check
923 DirectiveName = self._ValueList[0].upper()
924 if DirectiveName not in self.DataType:
925 EdkLogger.error("Parser", FORMAT_INVALID, "Unknown directive [%s]" % DirectiveName,
926 File=self.MetaFile, Line=self._LineIndex+1)
927 if DirectiveName in ['!IF', '!IFDEF', '!INCLUDE', '!IFNDEF', '!ELSEIF'] and self._ValueList[1] == '':
928 EdkLogger.error("Parser", FORMAT_INVALID, "Missing expression",
929 File=self.MetaFile, Line=self._LineIndex+1,
930 ExtraData=self._CurrentLine)
931
932 ItemType = self.DataType[DirectiveName]
933 if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF:
934 # Remove all directives between !if and !endif, including themselves
935 while self._DirectiveStack:
936 # Remove any !else or !elseif
937 DirectiveInfo = self._DirectiveStack.pop()
938 if DirectiveInfo[0] in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
939 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
940 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
941 break
942 else:
943 EdkLogger.error("Parser", FORMAT_INVALID, "Redundant '!endif'",
944 File=self.MetaFile, Line=self._LineIndex+1,
945 ExtraData=self._CurrentLine)
946 elif ItemType != MODEL_META_DATA_INCLUDE:
947 # Break if there's a !else is followed by a !elseif
948 if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF and \
949 self._DirectiveStack and \
950 self._DirectiveStack[-1][0] == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE:
951 EdkLogger.error("Parser", FORMAT_INVALID, "'!elseif' after '!else'",
952 File=self.MetaFile, Line=self._LineIndex+1,
953 ExtraData=self._CurrentLine)
954 self._DirectiveStack.append((ItemType, self._LineIndex+1, self._CurrentLine))
955 elif self._From > 0:
956 EdkLogger.error('Parser', FORMAT_INVALID,
957 "No '!include' allowed in included file",
958 ExtraData=self._CurrentLine, File=self.MetaFile,
959 Line=self._LineIndex+1)
960
961 #
962 # Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1,
963 # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
964 #
965 self._LastItem = self._Store(
966 ItemType,
967 self._ValueList[0],
968 self._ValueList[1],
969 self._ValueList[2],
970 'COMMON',
971 'COMMON',
972 self._Owner[-1],
973 self.FileID,
974 self._From,
975 self._LineIndex+1,
976 -1,
977 self._LineIndex+1,
978 -1,
979 0
980 )
981
982 ## [defines] section parser
983 @ParseMacro
984 def _DefineParser(self):
985 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
986 self._ValueList[1:len(TokenList)] = TokenList
987
988 # Syntax check
989 if not self._ValueList[1]:
990 EdkLogger.error('Parser', FORMAT_INVALID, "No name specified",
991 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
992 if not self._ValueList[2]:
993 EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",
994 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
995 if not self._ValueList[1] in self.DefineKeywords:
996 EdkLogger.error('Parser', FORMAT_INVALID,
997 "Unknown keyword found: %s. "
998 "If this is a macro you must "
999 "add it as a DEFINE in the DSC" % self._ValueList[1],
1000 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
1001 self._Defines[self._ValueList[1]] = self._ValueList[2]
1002 self._ItemType = self.DataType[TAB_DSC_DEFINES.upper()]
1003
1004 @ParseMacro
1005 def _SkuIdParser(self):
1006 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
1007 if len(TokenList) != 2:
1008 EdkLogger.error('Parser', FORMAT_INVALID, "Correct format is '<Integer>|<UiName>'",
1009 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
1010 self._ValueList[0:len(TokenList)] = TokenList
1011
1012 ## Parse Edk style of library modules
1013 def _LibraryInstanceParser(self):
1014 self._ValueList[0] = self._CurrentLine
1015
1016 ## PCD sections parser
1017 #
1018 # [PcdsFixedAtBuild]
1019 # [PcdsPatchableInModule]
1020 # [PcdsFeatureFlag]
1021 # [PcdsDynamicEx
1022 # [PcdsDynamicExDefault]
1023 # [PcdsDynamicExVpd]
1024 # [PcdsDynamicExHii]
1025 # [PcdsDynamic]
1026 # [PcdsDynamicDefault]
1027 # [PcdsDynamicVpd]
1028 # [PcdsDynamicHii]
1029 #
1030 @ParseMacro
1031 def _PcdParser(self):
1032 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
1033 self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
1034 if len(TokenList) == 2:
1035 self._ValueList[2] = TokenList[1]
1036 if self._ValueList[0] == '' or self._ValueList[1] == '':
1037 EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
1038 ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
1039 File=self.MetaFile, Line=self._LineIndex+1)
1040 if self._ValueList[2] == '':
1041 EdkLogger.error('Parser', FORMAT_INVALID, "No PCD value given",
1042 ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
1043 File=self.MetaFile, Line=self._LineIndex+1)
1044 # if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0.
1045 DscPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
1046 if DscPcdValueList[0] in ['True', 'true', 'TRUE']:
1047 self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '1', 1);
1048 elif DscPcdValueList[0] in ['False', 'false', 'FALSE']:
1049 self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '0', 1);
1050
1051 ## [components] section parser
1052 @ParseMacro
1053 def _ComponentParser(self):
1054 if self._CurrentLine[-1] == '{':
1055 self._ValueList[0] = self._CurrentLine[0:-1].strip()
1056 self._InSubsection = True
1057 else:
1058 self._ValueList[0] = self._CurrentLine
1059
1060 ## [LibraryClasses] section
1061 @ParseMacro
1062 def _LibraryClassParser(self):
1063 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
1064 if len(TokenList) < 2:
1065 EdkLogger.error('Parser', FORMAT_INVALID, "No library class or instance specified",
1066 ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1067 File=self.MetaFile, Line=self._LineIndex+1)
1068 if TokenList[0] == '':
1069 EdkLogger.error('Parser', FORMAT_INVALID, "No library class specified",
1070 ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1071 File=self.MetaFile, Line=self._LineIndex+1)
1072 if TokenList[1] == '':
1073 EdkLogger.error('Parser', FORMAT_INVALID, "No library instance specified",
1074 ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1075 File=self.MetaFile, Line=self._LineIndex+1)
1076
1077 self._ValueList[0:len(TokenList)] = TokenList
1078
1079 def _CompponentSourceOverridePathParser(self):
1080 self._ValueList[0] = self._CurrentLine
1081
1082 ## [BuildOptions] section parser
1083 @ParseMacro
1084 def _BuildOptionParser(self):
1085 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
1086 TokenList2 = GetSplitValueList(TokenList[0], ':', 1)
1087 if len(TokenList2) == 2:
1088 self._ValueList[0] = TokenList2[0] # toolchain family
1089 self._ValueList[1] = TokenList2[1] # keys
1090 else:
1091 self._ValueList[1] = TokenList[0]
1092 if len(TokenList) == 2: # value
1093 self._ValueList[2] = TokenList[1]
1094
1095 if self._ValueList[1].count('_') != 4:
1096 EdkLogger.error(
1097 'Parser',
1098 FORMAT_INVALID,
1099 "'%s' must be in format of <TARGET>_<TOOLCHAIN>_<ARCH>_<TOOL>_FLAGS" % self._ValueList[1],
1100 ExtraData=self._CurrentLine,
1101 File=self.MetaFile,
1102 Line=self._LineIndex+1
1103 )
1104
1105 ## Override parent's method since we'll do all macro replacements in parser
1106 def _GetMacros(self):
1107 Macros = dict( [('ARCH','IA32'), ('FAMILY','MSFT'),('TOOL_CHAIN_TAG','VS2008x86'),('TARGET','DEBUG')])
1108 Macros.update(self._FileLocalMacros)
1109 Macros.update(self._GetApplicableSectionMacro())
1110 Macros.update(GlobalData.gEdkGlobal)
1111 Macros.update(GlobalData.gPlatformDefines)
1112 Macros.update(GlobalData.gCommandLineDefines)
1113 # PCD cannot be referenced in macro definition
1114 if self._ItemType not in [MODEL_META_DATA_DEFINE, MODEL_META_DATA_GLOBAL_DEFINE]:
1115 Macros.update(self._Symbols)
1116 return Macros
1117
1118 def _PostProcess(self):
1119 Processer = {
1120 MODEL_META_DATA_SECTION_HEADER : self.__ProcessSectionHeader,
1121 MODEL_META_DATA_SUBSECTION_HEADER : self.__ProcessSubsectionHeader,
1122 MODEL_META_DATA_HEADER : self.__ProcessDefine,
1123 MODEL_META_DATA_DEFINE : self.__ProcessDefine,
1124 MODEL_META_DATA_GLOBAL_DEFINE : self.__ProcessDefine,
1125 MODEL_META_DATA_INCLUDE : self.__ProcessDirective,
1126 MODEL_META_DATA_CONDITIONAL_STATEMENT_IF : self.__ProcessDirective,
1127 MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE : self.__ProcessDirective,
1128 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF : self.__ProcessDirective,
1129 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF : self.__ProcessDirective,
1130 MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF : self.__ProcessDirective,
1131 MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF : self.__ProcessDirective,
1132 MODEL_EFI_SKU_ID : self.__ProcessSkuId,
1133 MODEL_EFI_LIBRARY_INSTANCE : self.__ProcessLibraryInstance,
1134 MODEL_EFI_LIBRARY_CLASS : self.__ProcessLibraryClass,
1135 MODEL_PCD_FIXED_AT_BUILD : self.__ProcessPcd,
1136 MODEL_PCD_PATCHABLE_IN_MODULE : self.__ProcessPcd,
1137 MODEL_PCD_FEATURE_FLAG : self.__ProcessPcd,
1138 MODEL_PCD_DYNAMIC_DEFAULT : self.__ProcessPcd,
1139 MODEL_PCD_DYNAMIC_HII : self.__ProcessPcd,
1140 MODEL_PCD_DYNAMIC_VPD : self.__ProcessPcd,
1141 MODEL_PCD_DYNAMIC_EX_DEFAULT : self.__ProcessPcd,
1142 MODEL_PCD_DYNAMIC_EX_HII : self.__ProcessPcd,
1143 MODEL_PCD_DYNAMIC_EX_VPD : self.__ProcessPcd,
1144 MODEL_META_DATA_COMPONENT : self.__ProcessComponent,
1145 MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH : self.__ProcessSourceOverridePath,
1146 MODEL_META_DATA_BUILD_OPTION : self.__ProcessBuildOption,
1147 MODEL_UNKNOWN : self._Skip,
1148 MODEL_META_DATA_USER_EXTENSION : self._Skip,
1149 MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR : self._Skip,
1150 }
1151
1152 self._RawTable = self._Table
1153 self._Table = MetaFileStorage(self._RawTable.Cur, self.MetaFile, MODEL_FILE_DSC, True)
1154 self._DirectiveStack = []
1155 self._DirectiveEvalStack = []
1156 self._FileWithError = self.MetaFile
1157 self._FileLocalMacros = {}
1158 self._SectionsMacroDict = {}
1159 GlobalData.gPlatformDefines = {}
1160
1161 # Get all macro and PCD which has straitforward value
1162 self.__RetrievePcdValue()
1163 self._Content = self._RawTable.GetAll()
1164 self._ContentIndex = 0
1165 while self._ContentIndex < len(self._Content) :
1166 Id, self._ItemType, V1, V2, V3, S1, S2, Owner, BelongsToFile, self._From, \
1167 LineStart, ColStart, LineEnd, ColEnd, Enabled = self._Content[self._ContentIndex]
1168
1169 if self._From < 0:
1170 self._FileWithError = self.MetaFile
1171
1172 self._ContentIndex += 1
1173
1174 self._Scope = [[S1, S2]]
1175 self._LineIndex = LineStart - 1
1176 self._ValueList = [V1, V2, V3]
1177
1178 try:
1179 Processer[self._ItemType]()
1180 except EvaluationException, Excpt:
1181 #
1182 # Only catch expression evaluation error here. We need to report
1183 # the precise number of line on which the error occurred
1184 #
1185 pass
1186 # EdkLogger.error('Parser', FORMAT_INVALID, "Invalid expression: %s" % str(Excpt),
1187 # File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1188 # Line=self._LineIndex+1)
1189 except MacroException, Excpt:
1190 EdkLogger.error('Parser', FORMAT_INVALID, str(Excpt),
1191 File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1192 Line=self._LineIndex+1)
1193
1194 if self._ValueList == None:
1195 continue
1196
1197 NewOwner = self._IdMapping.get(Owner, -1)
1198 self._Enabled = int((not self._DirectiveEvalStack) or (False not in self._DirectiveEvalStack))
1199 self._LastItem = self._Store(
1200 self._ItemType,
1201 self._ValueList[0],
1202 self._ValueList[1],
1203 self._ValueList[2],
1204 S1,
1205 S2,
1206 NewOwner,
1207 BelongsToFile,
1208 self._From,
1209 self._LineIndex+1,
1210 -1,
1211 self._LineIndex+1,
1212 -1,
1213 self._Enabled
1214 )
1215 self._IdMapping[Id] = self._LastItem
1216
1217 RecordList = self._Table.GetAll()
1218
1219 self._RawTable.Drop()
1220 self._Table.Drop()
1221 for Record in RecordList:
1222 EccGlobalData.gDb.TblDsc.Insert(Record[1],Record[2],Record[3],Record[4],Record[5],Record[6],Record[7],Record[8],Record[9],Record[10],Record[11],Record[12],Record[13],Record[14])
1223 GlobalData.gPlatformDefines.update(self._FileLocalMacros)
1224 self._PostProcessed = True
1225 self._Content = None
1226
1227 def __ProcessSectionHeader(self):
1228 self._SectionName = self._ValueList[0]
1229 if self._SectionName in self.DataType:
1230 self._SectionType = self.DataType[self._SectionName]
1231 else:
1232 self._SectionType = MODEL_UNKNOWN
1233
1234 def __ProcessSubsectionHeader(self):
1235 self._SubsectionName = self._ValueList[0]
1236 if self._SubsectionName in self.DataType:
1237 self._SubsectionType = self.DataType[self._SubsectionName]
1238 else:
1239 self._SubsectionType = MODEL_UNKNOWN
1240
1241 def __RetrievePcdValue(self):
1242 Records = self._RawTable.Query(MODEL_PCD_FEATURE_FLAG, BelongsToItem=-1.0)
1243 for TokenSpaceGuid,PcdName,Value,Dummy2,Dummy3,ID,Line in Records:
1244 Value, DatumType, MaxDatumSize = AnalyzePcdData(Value)
1245 # Only use PCD whose value is straitforward (no macro and PCD)
1246 if self.SymbolPattern.findall(Value):
1247 continue
1248 Name = TokenSpaceGuid + '.' + PcdName
1249 # Don't use PCD with different values.
1250 if Name in self._Symbols and self._Symbols[Name] != Value:
1251 self._Symbols.pop(Name)
1252 continue
1253 self._Symbols[Name] = Value
1254
1255 Records = self._RawTable.Query(MODEL_PCD_FIXED_AT_BUILD, BelongsToItem=-1.0)
1256 for TokenSpaceGuid,PcdName,Value,Dummy2,Dummy3,ID,Line in Records:
1257 Value, DatumType, MaxDatumSize = AnalyzePcdData(Value)
1258 # Only use PCD whose value is straitforward (no macro and PCD)
1259 if self.SymbolPattern.findall(Value):
1260 continue
1261 Name = TokenSpaceGuid+'.'+PcdName
1262 # Don't use PCD with different values.
1263 if Name in self._Symbols and self._Symbols[Name] != Value:
1264 self._Symbols.pop(Name)
1265 continue
1266 self._Symbols[Name] = Value
1267
1268 def __ProcessDefine(self):
1269 if not self._Enabled:
1270 return
1271
1272 Type, Name, Value = self._ValueList
1273 Value = ReplaceMacro(Value, self._Macros, False)
1274 if self._ItemType == MODEL_META_DATA_DEFINE:
1275 if self._SectionType == MODEL_META_DATA_HEADER:
1276 self._FileLocalMacros[Name] = Value
1277 else:
1278 SectionDictKey = self._SectionType, self._Scope[0][0], self._Scope[0][1]
1279 if SectionDictKey not in self._SectionsMacroDict:
1280 self._SectionsMacroDict[SectionDictKey] = {}
1281 SectionLocalMacros = self._SectionsMacroDict[SectionDictKey]
1282 SectionLocalMacros[Name] = Value
1283 elif self._ItemType == MODEL_META_DATA_GLOBAL_DEFINE:
1284 GlobalData.gEdkGlobal[Name] = Value
1285
1286 #
1287 # Keyword in [Defines] section can be used as Macros
1288 #
1289 if (self._ItemType == MODEL_META_DATA_HEADER) and (self._SectionType == MODEL_META_DATA_HEADER):
1290 self._FileLocalMacros[Name] = Value
1291
1292 self._ValueList = [Type, Name, Value]
1293
1294 def __ProcessDirective(self):
1295 Result = None
1296 if self._ItemType in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1297 MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF]:
1298 Macros = self._Macros
1299 Macros.update(GlobalData.gGlobalDefines)
1300 try:
1301 Result = ValueExpression(self._ValueList[1], Macros)()
1302 except SymbolNotFound, Exc:
1303 EdkLogger.debug(EdkLogger.DEBUG_5, str(Exc), self._ValueList[1])
1304 Result = False
1305 except WrnExpression, Excpt:
1306 #
1307 # Catch expression evaluation warning here. We need to report
1308 # the precise number of line and return the evaluation result
1309 #
1310 EdkLogger.warn('Parser', "Suspicious expression: %s" % str(Excpt),
1311 File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1312 Line=self._LineIndex+1)
1313 Result = Excpt.result
1314
1315 if self._ItemType in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1316 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
1317 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
1318 self._DirectiveStack.append(self._ItemType)
1319 if self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_IF:
1320 Result = bool(Result)
1321 else:
1322 Macro = self._ValueList[1]
1323 Macro = Macro[2:-1] if (Macro.startswith("$(") and Macro.endswith(")")) else Macro
1324 Result = Macro in self._Macros
1325 if self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF:
1326 Result = not Result
1327 self._DirectiveEvalStack.append(Result)
1328 elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF:
1329 self._DirectiveStack.append(self._ItemType)
1330 self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1]
1331 self._DirectiveEvalStack.append(bool(Result))
1332 elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE:
1333 self._DirectiveStack[-1] = self._ItemType
1334 self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1]
1335 elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF:
1336 # Back to the nearest !if/!ifdef/!ifndef
1337 while self._DirectiveStack:
1338 self._DirectiveEvalStack.pop()
1339 Directive = self._DirectiveStack.pop()
1340 if Directive in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1341 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
1342 MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE,
1343 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
1344 break
1345 elif self._ItemType == MODEL_META_DATA_INCLUDE:
1346 # The included file must be relative to workspace or same directory as DSC file
1347 __IncludeMacros = {}
1348 #
1349 # Allow using system environment variables in path after !include
1350 #
1351 __IncludeMacros['WORKSPACE'] = GlobalData.gGlobalDefines['WORKSPACE']
1352 if "ECP_SOURCE" in GlobalData.gGlobalDefines.keys():
1353 __IncludeMacros['ECP_SOURCE'] = GlobalData.gGlobalDefines['ECP_SOURCE']
1354 #
1355 # During GenFds phase call DSC parser, will go into this branch.
1356 #
1357 elif "ECP_SOURCE" in GlobalData.gCommandLineDefines.keys():
1358 __IncludeMacros['ECP_SOURCE'] = GlobalData.gCommandLineDefines['ECP_SOURCE']
1359
1360 __IncludeMacros['EFI_SOURCE'] = GlobalData.gGlobalDefines['EFI_SOURCE']
1361 __IncludeMacros['EDK_SOURCE'] = GlobalData.gGlobalDefines['EDK_SOURCE']
1362 #
1363 # Allow using MACROs comes from [Defines] section to keep compatible.
1364 #
1365 __IncludeMacros.update(self._Macros)
1366
1367 IncludedFile = NormPath(ReplaceMacro(self._ValueList[1], __IncludeMacros, RaiseError=True))
1368 #
1369 # First search the include file under the same directory as DSC file
1370 #
1371 IncludedFile1 = PathClass(IncludedFile, self.MetaFile.Dir)
1372 ErrorCode, ErrorInfo1 = IncludedFile1.Validate()
1373 if ErrorCode != 0:
1374 #
1375 # Also search file under the WORKSPACE directory
1376 #
1377 IncludedFile1 = PathClass(IncludedFile, GlobalData.gWorkspace)
1378 ErrorCode, ErrorInfo2 = IncludedFile1.Validate()
1379 if ErrorCode != 0:
1380 EdkLogger.error('parser', ErrorCode, File=self._FileWithError,
1381 Line=self._LineIndex+1, ExtraData=ErrorInfo1 + "\n"+ ErrorInfo2)
1382
1383 self._FileWithError = IncludedFile1
1384
1385 IncludedFileTable = MetaFileStorage(self._Table.Cur, IncludedFile1, MODEL_FILE_DSC, True)
1386 Owner = self._Content[self._ContentIndex-1][0]
1387 Parser = DscParser(IncludedFile1, self._FileType, IncludedFileTable,
1388 Owner=Owner, From=Owner)
1389
1390 # set the parser status with current status
1391 Parser._SectionName = self._SectionName
1392 Parser._SectionType = self._SectionType
1393 Parser._Scope = self._Scope
1394 Parser._Enabled = self._Enabled
1395 # Parse the included file
1396 Parser.Start()
1397
1398 # update current status with sub-parser's status
1399 self._SectionName = Parser._SectionName
1400 self._SectionType = Parser._SectionType
1401 self._Scope = Parser._Scope
1402 self._Enabled = Parser._Enabled
1403
1404 # Insert all records in the table for the included file into dsc file table
1405 Records = IncludedFileTable.GetAll()
1406 if Records:
1407 self._Content[self._ContentIndex:self._ContentIndex] = Records
1408 self._Content.pop(self._ContentIndex-1)
1409 self._ValueList = None
1410 self._ContentIndex -= 1
1411
1412 def __ProcessSkuId(self):
1413 self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=True)
1414 for Value in self._ValueList]
1415
1416 def __ProcessLibraryInstance(self):
1417 self._ValueList = [ReplaceMacro(Value, self._Macros) for Value in self._ValueList]
1418
1419 def __ProcessLibraryClass(self):
1420 self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros, RaiseError=True)
1421
1422 def __ProcessPcd(self):
1423 ValueList = GetSplitValueList(self._ValueList[2])
1424 #
1425 # PCD value can be an expression
1426 #
1427 if len(ValueList) > 1 and ValueList[1] == 'VOID*':
1428 PcdValue = ValueList[0]
1429 try:
1430 ValueList[0] = ValueExpression(PcdValue, self._Macros)(True)
1431 except WrnExpression, Value:
1432 ValueList[0] = Value.result
1433 else:
1434 PcdValue = ValueList[-1]
1435 try:
1436 ValueList[-1] = ValueExpression(PcdValue, self._Macros)(True)
1437 except WrnExpression, Value:
1438 ValueList[-1] = Value.result
1439
1440 if ValueList[-1] == 'True':
1441 ValueList[-1] = '1'
1442 if ValueList[-1] == 'False':
1443 ValueList[-1] = '0'
1444
1445 self._ValueList[2] = '|'.join(ValueList)
1446
1447 def __ProcessComponent(self):
1448 self._ValueList[0] = ReplaceMacro(self._ValueList[0], self._Macros)
1449
1450 def __ProcessSourceOverridePath(self):
1451 self._ValueList[0] = ReplaceMacro(self._ValueList[0], self._Macros)
1452
1453 def __ProcessBuildOption(self):
1454 self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=False)
1455 for Value in self._ValueList]
1456
1457 _SectionParser = {
1458 MODEL_META_DATA_HEADER : _DefineParser,
1459 MODEL_EFI_SKU_ID : _SkuIdParser,
1460 MODEL_EFI_LIBRARY_INSTANCE : _LibraryInstanceParser,
1461 MODEL_EFI_LIBRARY_CLASS : _LibraryClassParser,
1462 MODEL_PCD_FIXED_AT_BUILD : _PcdParser,
1463 MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser,
1464 MODEL_PCD_FEATURE_FLAG : _PcdParser,
1465 MODEL_PCD_DYNAMIC_DEFAULT : _PcdParser,
1466 MODEL_PCD_DYNAMIC_HII : _PcdParser,
1467 MODEL_PCD_DYNAMIC_VPD : _PcdParser,
1468 MODEL_PCD_DYNAMIC_EX_DEFAULT : _PcdParser,
1469 MODEL_PCD_DYNAMIC_EX_HII : _PcdParser,
1470 MODEL_PCD_DYNAMIC_EX_VPD : _PcdParser,
1471 MODEL_META_DATA_COMPONENT : _ComponentParser,
1472 MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH : _CompponentSourceOverridePathParser,
1473 MODEL_META_DATA_BUILD_OPTION : _BuildOptionParser,
1474 MODEL_UNKNOWN : MetaFileParser._Skip,
1475 MODEL_META_DATA_USER_EXTENSION : MetaFileParser._Skip,
1476 MODEL_META_DATA_SECTION_HEADER : MetaFileParser._SectionHeaderParser,
1477 MODEL_META_DATA_SUBSECTION_HEADER : _SubsectionHeaderParser,
1478 }
1479
1480 _Macros = property(_GetMacros)
1481
1482 ## DEC file parser class
1483 #
1484 # @param FilePath The path of platform description file
1485 # @param FileType The raw data of DSC file
1486 # @param Table Database used to retrieve module/package information
1487 # @param Macros Macros used for replacement in file
1488 #
1489 class DecParser(MetaFileParser):
1490 # DEC file supported data types (one type per section)
1491 DataType = {
1492 TAB_DEC_DEFINES.upper() : MODEL_META_DATA_HEADER,
1493 TAB_DSC_DEFINES_DEFINE : MODEL_META_DATA_DEFINE,
1494 TAB_INCLUDES.upper() : MODEL_EFI_INCLUDE,
1495 TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS,
1496 TAB_GUIDS.upper() : MODEL_EFI_GUID,
1497 TAB_PPIS.upper() : MODEL_EFI_PPI,
1498 TAB_PROTOCOLS.upper() : MODEL_EFI_PROTOCOL,
1499 TAB_PCDS_FIXED_AT_BUILD_NULL.upper() : MODEL_PCD_FIXED_AT_BUILD,
1500 TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper() : MODEL_PCD_PATCHABLE_IN_MODULE,
1501 TAB_PCDS_FEATURE_FLAG_NULL.upper() : MODEL_PCD_FEATURE_FLAG,
1502 TAB_PCDS_DYNAMIC_NULL.upper() : MODEL_PCD_DYNAMIC,
1503 TAB_PCDS_DYNAMIC_EX_NULL.upper() : MODEL_PCD_DYNAMIC_EX,
1504 }
1505
1506 ## Constructor of DecParser
1507 #
1508 # Initialize object of DecParser
1509 #
1510 # @param FilePath The path of platform description file
1511 # @param FileType The raw data of DSC file
1512 # @param Table Database used to retrieve module/package information
1513 # @param Macros Macros used for replacement in file
1514 #
1515 def __init__(self, FilePath, FileType, Table):
1516 # prevent re-initialization
1517 if hasattr(self, "_Table"):
1518 return
1519 MetaFileParser.__init__(self, FilePath, FileType, Table)
1520 self._Comments = []
1521 self._Version = 0x00010005 # Only EDK2 dec file is supported
1522 self.TblFile = EccGlobalData.gDb.TblFile
1523 self.FileID = -1
1524
1525 ## Parser starter
1526 def Start(self):
1527 Content = ''
1528 try:
1529 Content = open(str(self.MetaFile), 'r').readlines()
1530 except:
1531 EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
1532
1533 #
1534 # Insert a record for file
1535 #
1536 Filename = NormPath(self.MetaFile)
1537 FileID = self.TblFile.GetFileId(Filename)
1538 if FileID:
1539 self.FileID = FileID
1540 else:
1541 self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_DEC)
1542
1543 for Index in range(0, len(Content)):
1544 Line, Comment = CleanString2(Content[Index])
1545 self._CurrentLine = Line
1546 self._LineIndex = Index
1547
1548 # save comment for later use
1549 if Comment:
1550 self._Comments.append((Comment, self._LineIndex+1))
1551 # skip empty line
1552 if Line == '':
1553 continue
1554
1555 # section header
1556 if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
1557 self._SectionHeaderParser()
1558 self._Comments = []
1559 continue
1560 elif len(self._SectionType) == 0:
1561 self._Comments = []
1562 continue
1563
1564 # section content
1565 self._ValueList = ['','','']
1566 self._SectionParser[self._SectionType[0]](self)
1567 if self._ValueList == None or self._ItemType == MODEL_META_DATA_DEFINE:
1568 self._ItemType = -1
1569 self._Comments = []
1570 continue
1571
1572 #
1573 # Model, Value1, Value2, Value3, Arch, BelongsToItem=-1, LineBegin=-1,
1574 # ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, FeatureFlag='', Enabled=-1
1575 #
1576 for Arch, ModuleType, Type in self._Scope:
1577 self._LastItem = self._Store(
1578 Type,
1579 self._ValueList[0],
1580 self._ValueList[1],
1581 self._ValueList[2],
1582 Arch,
1583 ModuleType,
1584 self._Owner[-1],
1585 self.FileID,
1586 self._LineIndex+1,
1587 -1,
1588 self._LineIndex+1,
1589 -1,
1590 0
1591 )
1592 for Comment, LineNo in self._Comments:
1593 self._Store(
1594 MODEL_META_DATA_COMMENT,
1595 Comment,
1596 self._ValueList[0],
1597 self._ValueList[1],
1598 Arch,
1599 ModuleType,
1600 self._LastItem,
1601 self.FileID,
1602 LineNo,
1603 -1,
1604 LineNo,
1605 -1,
1606 0
1607 )
1608 self._Comments = []
1609 self._Done()
1610
1611 def _GetApplicableSectionMacro(self):
1612 Macros = {}
1613 for S1, S2, SectionType in self._Scope:
1614 for Scope1, Scope2 in [("COMMON", "COMMON"), ("COMMON", S2), (S1, "COMMON"), (S1, S2)]:
1615 if (SectionType, Scope1, Scope2) in self._SectionsMacroDict:
1616 Macros.update(self._SectionsMacroDict[(SectionType, Scope1, Scope2)])
1617 return Macros
1618
1619 ## Section header parser
1620 #
1621 # The section header is always in following format:
1622 #
1623 # [section_name.arch<.platform|module_type>]
1624 #
1625 def _SectionHeaderParser(self):
1626 self._Scope = []
1627 self._SectionName = ''
1628 self._SectionType = []
1629 ArchList = set()
1630 for Item in GetSplitValueList(self._CurrentLine[1:-1], TAB_COMMA_SPLIT):
1631 if Item == '':
1632 continue
1633 ItemList = GetSplitValueList(Item, TAB_SPLIT)
1634
1635 # different types of PCD are permissible in one section
1636 self._SectionName = ItemList[0].upper()
1637 if self._SectionName in self.DataType:
1638 if self.DataType[self._SectionName] not in self._SectionType:
1639 self._SectionType.append(self.DataType[self._SectionName])
1640 else:
1641 EdkLogger.warn("Parser", "Unrecognized section", File=self.MetaFile,
1642 Line=self._LineIndex+1, ExtraData=self._CurrentLine)
1643 continue
1644
1645 if MODEL_PCD_FEATURE_FLAG in self._SectionType and len(self._SectionType) > 1:
1646 EdkLogger.error(
1647 'Parser',
1648 FORMAT_INVALID,
1649 "%s must not be in the same section of other types of PCD" % TAB_PCDS_FEATURE_FLAG_NULL,
1650 File=self.MetaFile,
1651 Line=self._LineIndex+1,
1652 ExtraData=self._CurrentLine
1653 )
1654 # S1 is always Arch
1655 if len(ItemList) > 1:
1656 S1 = ItemList[1].upper()
1657 else:
1658 S1 = 'COMMON'
1659 ArchList.add(S1)
1660 # S2 may be Platform or ModuleType
1661 if len(ItemList) > 2:
1662 S2 = ItemList[2].upper()
1663 else:
1664 S2 = 'COMMON'
1665 if [S1, S2, self.DataType[self._SectionName]] not in self._Scope:
1666 self._Scope.append([S1, S2, self.DataType[self._SectionName]])
1667
1668 # 'COMMON' must not be used with specific ARCHs at the same section
1669 if 'COMMON' in ArchList and len(ArchList) > 1:
1670 EdkLogger.error('Parser', FORMAT_INVALID, "'common' ARCH must not be used with specific ARCHs",
1671 File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
1672
1673 ## [guids], [ppis] and [protocols] section parser
1674 @ParseMacro
1675 def _GuidParser(self):
1676 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
1677 if len(TokenList) < 2:
1678 EdkLogger.error('Parser', FORMAT_INVALID, "No GUID name or value specified",
1679 ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1680 File=self.MetaFile, Line=self._LineIndex+1)
1681 if TokenList[0] == '':
1682 EdkLogger.error('Parser', FORMAT_INVALID, "No GUID name specified",
1683 ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1684 File=self.MetaFile, Line=self._LineIndex+1)
1685 if TokenList[1] == '':
1686 EdkLogger.error('Parser', FORMAT_INVALID, "No GUID value specified",
1687 ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1688 File=self.MetaFile, Line=self._LineIndex+1)
1689 if TokenList[1][0] != '{' or TokenList[1][-1] != '}' or GuidStructureStringToGuidString(TokenList[1]) == '':
1690 EdkLogger.error('Parser', FORMAT_INVALID, "Invalid GUID value format",
1691 ExtraData=self._CurrentLine + \
1692 " (<CName> = <GuidValueInCFormat:{8,4,4,{2,2,2,2,2,2,2,2}}>)",
1693 File=self.MetaFile, Line=self._LineIndex+1)
1694 self._ValueList[0] = TokenList[0]
1695 #Parse the Guid value format
1696 GuidValueList = TokenList[1].strip(' {}').split(',')
1697 Index = 0
1698 HexList = []
1699 if len(GuidValueList) == 11:
1700 for GuidValue in GuidValueList:
1701 GuidValue = GuidValue.strip()
1702 if GuidValue.startswith('0x') or GuidValue.startswith('0X'):
1703 HexList.append('0x' + str(GuidValue[2:]))
1704 Index += 1
1705 continue
1706 else:
1707 if GuidValue.startswith('{'):
1708 HexList.append('0x' + str(GuidValue[3:]))
1709 Index += 1
1710 self._ValueList[1] = "{ %s, %s, %s, { %s, %s, %s, %s, %s, %s, %s, %s }}" % (HexList[0], HexList[1], HexList[2],HexList[3],HexList[4],HexList[5],HexList[6],HexList[7],HexList[8],HexList[9],HexList[10])
1711 else:
1712 EdkLogger.error('Parser', FORMAT_INVALID, "Invalid GUID value format",
1713 ExtraData=self._CurrentLine + \
1714 " (<CName> = <GuidValueInCFormat:{8,4,4,{2,2,2,2,2,2,2,2}}>)",
1715 File=self.MetaFile, Line=self._LineIndex+1)
1716 self._ValueList[0] = ''
1717
1718 ## PCD sections parser
1719 #
1720 # [PcdsFixedAtBuild]
1721 # [PcdsPatchableInModule]
1722 # [PcdsFeatureFlag]
1723 # [PcdsDynamicEx
1724 # [PcdsDynamic]
1725 #
1726 @ParseMacro
1727 def _PcdParser(self):
1728 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
1729 self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
1730 # check PCD information
1731 if self._ValueList[0] == '' or self._ValueList[1] == '':
1732 EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
1733 ExtraData=self._CurrentLine + \
1734 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1735 File=self.MetaFile, Line=self._LineIndex+1)
1736 # check PCD datum information
1737 if len(TokenList) < 2 or TokenList[1] == '':
1738 EdkLogger.error('Parser', FORMAT_INVALID, "No PCD Datum information given",
1739 ExtraData=self._CurrentLine + \
1740 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1741 File=self.MetaFile, Line=self._LineIndex+1)
1742
1743
1744 ValueRe = re.compile(r'^\s*L?\".*\|.*\"')
1745 PtrValue = ValueRe.findall(TokenList[1])
1746
1747 # Has VOID* type string, may contain "|" character in the string.
1748 if len(PtrValue) != 0:
1749 ptrValueList = re.sub(ValueRe, '', TokenList[1])
1750 ValueList = GetSplitValueList(ptrValueList)
1751 ValueList[0] = PtrValue[0]
1752 else:
1753 ValueList = GetSplitValueList(TokenList[1])
1754
1755
1756 # check if there's enough datum information given
1757 if len(ValueList) != 3:
1758 EdkLogger.error('Parser', FORMAT_INVALID, "Invalid PCD Datum information given",
1759 ExtraData=self._CurrentLine + \
1760 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1761 File=self.MetaFile, Line=self._LineIndex+1)
1762 # check default value
1763 if ValueList[0] == '':
1764 EdkLogger.error('Parser', FORMAT_INVALID, "Missing DefaultValue in PCD Datum information",
1765 ExtraData=self._CurrentLine + \
1766 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1767 File=self.MetaFile, Line=self._LineIndex+1)
1768 # check datum type
1769 if ValueList[1] == '':
1770 EdkLogger.error('Parser', FORMAT_INVALID, "Missing DatumType in PCD Datum information",
1771 ExtraData=self._CurrentLine + \
1772 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1773 File=self.MetaFile, Line=self._LineIndex+1)
1774 # check token of the PCD
1775 if ValueList[2] == '':
1776 EdkLogger.error('Parser', FORMAT_INVALID, "Missing Token in PCD Datum information",
1777 ExtraData=self._CurrentLine + \
1778 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1779 File=self.MetaFile, Line=self._LineIndex+1)
1780 # check format of default value against the datum type
1781 IsValid, Cause = CheckPcdDatum(ValueList[1], ValueList[0])
1782 if not IsValid:
1783 EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine,
1784 File=self.MetaFile, Line=self._LineIndex+1)
1785
1786 if ValueList[0] in ['True', 'true', 'TRUE']:
1787 ValueList[0] = '1'
1788 elif ValueList[0] in ['False', 'false', 'FALSE']:
1789 ValueList[0] = '0'
1790
1791 self._ValueList[2] = ValueList[0].strip() + '|' + ValueList[1].strip() + '|' + ValueList[2].strip()
1792
1793 _SectionParser = {
1794 MODEL_META_DATA_HEADER : MetaFileParser._DefineParser,
1795 MODEL_EFI_INCLUDE : MetaFileParser._PathParser,
1796 MODEL_EFI_LIBRARY_CLASS : MetaFileParser._PathParser,
1797 MODEL_EFI_GUID : _GuidParser,
1798 MODEL_EFI_PPI : _GuidParser,
1799 MODEL_EFI_PROTOCOL : _GuidParser,
1800 MODEL_PCD_FIXED_AT_BUILD : _PcdParser,
1801 MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser,
1802 MODEL_PCD_FEATURE_FLAG : _PcdParser,
1803 MODEL_PCD_DYNAMIC : _PcdParser,
1804 MODEL_PCD_DYNAMIC_EX : _PcdParser,
1805 MODEL_UNKNOWN : MetaFileParser._Skip,
1806 MODEL_META_DATA_USER_EXTENSION : MetaFileParser._Skip,
1807 }
1808
1809
1810 ## FdfObject
1811 #
1812 # This class defined basic Fdf object which is used by inheriting
1813 #
1814 # @param object: Inherited from object class
1815 #
1816 class FdfObject(object):
1817 def __init__(self):
1818 object.__init__()
1819
1820 ## Fdf
1821 #
1822 # This class defined the structure used in Fdf object
1823 #
1824 # @param FdfObject: Inherited from FdfObject class
1825 # @param Filename: Input value for Ffilename of Fdf file, default is None
1826 # @param WorkspaceDir: Input value for current workspace directory, default is None
1827 #
1828 class Fdf(FdfObject):
1829 def __init__(self, Filename = None, IsToDatabase = False, WorkspaceDir = None, Database = None):
1830 self.WorkspaceDir = WorkspaceDir
1831 self.IsToDatabase = IsToDatabase
1832
1833 self.Cur = Database.Cur
1834 self.TblFile = Database.TblFile
1835 self.TblFdf = Database.TblFdf
1836 self.FileID = -1
1837 self.FileList = {}
1838
1839 #
1840 # Load Fdf file if filename is not None
1841 #
1842 if Filename != None:
1843 try:
1844 self.LoadFdfFile(Filename)
1845 except Exception:
1846 pass
1847
1848 #
1849 # Insert a FDF file record into database
1850 #
1851 def InsertFile(self, Filename):
1852 FileID = -1
1853 Filename = NormPath(Filename)
1854 if Filename not in self.FileList:
1855 FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_FDF)
1856 self.FileList[Filename] = FileID
1857
1858 return self.FileList[Filename]
1859
1860
1861 ## Load Fdf file
1862 #
1863 # Load the file if it exists
1864 #
1865 # @param Filename: Input value for filename of Fdf file
1866 #
1867 def LoadFdfFile(self, Filename):
1868 FileList = []
1869 #
1870 # Parse Fdf file
1871 #
1872 Filename = NormPath(Filename)
1873 Fdf = FdfParser(Filename)
1874 Fdf.ParseFile()
1875
1876 #
1877 # Insert inf file and pcd information
1878 #
1879 if self.IsToDatabase:
1880 (Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled) = \
1881 (0, '', '', '', 'COMMON', 'COMMON', -1, -1, -1, -1, -1, -1, 0)
1882 for Index in range(0, len(Fdf.Profile.PcdDict)):
1883 pass
1884 for Key in Fdf.Profile.PcdDict.keys():
1885 Model = MODEL_PCD
1886 Value1 = Key[1]
1887 Value2 = Key[0]
1888 FileName = Fdf.Profile.PcdFileLineDict[Key][0]
1889 StartLine = Fdf.Profile.PcdFileLineDict[Key][1]
1890 BelongsToFile = self.InsertFile(FileName)
1891 self.TblFdf.Insert(Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled)
1892 for Index in range(0, len(Fdf.Profile.InfList)):
1893 Model = MODEL_META_DATA_COMPONENT
1894 Value1 = Fdf.Profile.InfList[Index]
1895 Value2 = ''
1896 FileName = Fdf.Profile.InfFileLineList[Index][0]
1897 StartLine = Fdf.Profile.InfFileLineList[Index][1]
1898 BelongsToFile = self.InsertFile(FileName)
1899 self.TblFdf.Insert(Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled)
1900
1901 class UniParser(object):
1902 # IsExtraUni defined the UNI file is Module UNI or extra Module UNI
1903 # IsModuleUni defined the UNI file is Module UNI or Package UNI
1904 def __init__(self, FilePath, IsExtraUni=False, IsModuleUni=True):
1905 self.FilePath = FilePath
1906 self.FileName = os.path.basename(FilePath)
1907 self.IsExtraUni = IsExtraUni
1908 self.IsModuleUni = IsModuleUni
1909 self.FileIn = None
1910 self.Missing = []
1911 self.__read()
1912
1913 def __read(self):
1914 try:
1915 self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode = 'rb', Encoding = 'utf_16').read()
1916 except UnicodeError:
1917 self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode = 'rb', Encoding = 'utf_16_le').read()
1918 except IOError:
1919 self.FileIn = ""
1920
1921 def Start(self):
1922 if self.IsModuleUni:
1923 if self.IsExtraUni:
1924 ModuleName = self.CheckKeyValid('STR_PROPERTIES_MODULE_NAME')
1925 self.PrintLog('STR_PROPERTIES_MODULE_NAME', ModuleName)
1926 else:
1927 ModuleAbstract = self.CheckKeyValid('STR_MODULE_ABSTRACT')
1928 self.PrintLog('STR_MODULE_ABSTRACT', ModuleAbstract)
1929 ModuleDescription = self.CheckKeyValid('STR_MODULE_DESCRIPTION')
1930 self.PrintLog('STR_MODULE_DESCRIPTION', ModuleDescription)
1931 else:
1932 if self.IsExtraUni:
1933 PackageName = self.CheckKeyValid('STR_PROPERTIES_PACKAGE_NAME')
1934 self.PrintLog('STR_PROPERTIES_PACKAGE_NAME', PackageName)
1935 else:
1936 PackageAbstract = self.CheckKeyValid('STR_PACKAGE_ABSTRACT')
1937 self.PrintLog('STR_PACKAGE_ABSTRACT', PackageAbstract)
1938 PackageDescription = self.CheckKeyValid('STR_PACKAGE_DESCRIPTION')
1939 self.PrintLog('STR_PACKAGE_DESCRIPTION', PackageDescription)
1940
1941 def CheckKeyValid(self, Key, Contents=None):
1942 if not Contents:
1943 Contents = self.FileIn
1944 KeyPattern = re.compile('#string\s+%s\s+.*?#language.*?".*?"' % Key, re.S)
1945 if KeyPattern.search(Contents):
1946 return True
1947 return False
1948
1949 def CheckPcdInfo(self, PcdCName):
1950 PromptKey = 'STR_%s_PROMPT' % PcdCName.replace('.', '_')
1951 PcdPrompt = self.CheckKeyValid(PromptKey)
1952 self.PrintLog(PromptKey, PcdPrompt)
1953 HelpKey = 'STR_%s_HELP' % PcdCName.replace('.', '_')
1954 PcdHelp = self.CheckKeyValid(HelpKey)
1955 self.PrintLog(HelpKey, PcdHelp)
1956
1957 def PrintLog(self, Key, Value):
1958 if not Value and Key not in self.Missing:
1959 Msg = '%s is missing in the %s file.' % (Key, self.FileName)
1960 EdkLogger.warn('Parser', Msg)
1961 EccGlobalData.gDb.TblReport.Insert(EccToolError.ERROR_GENERAL_CHECK_UNI_HELP_INFO, OtherMsg=Msg, BelongsToTable='File', BelongsToItem=-2)
1962 self.Missing.append(Key)
1963
1964 ##
1965 #
1966 # This acts like the main() function for the script, unless it is 'import'ed into another
1967 # script.
1968 #
1969 if __name__ == '__main__':
1970 pass
1971