1. Add logic to force MetaFileParser as singleton
[mirror/efi/basetools/.git] / Source / Python / Workspace / MetaFileParser.py
1 ## @file
2 # This file is used to parse meta files
3 #
4 # Copyright (c) 2008 - 2010, Intel Corporation
5 # All rights reserved. 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 os
18 import time
19 import copy
20
21 import Common.EdkLogger as EdkLogger
22 from CommonDataClass.DataClass import *
23 from Common.DataType import *
24 from Common.String import *
25 from Common.Misc import Blist, GuidStructureStringToGuidString, CheckPcdDatum
26
27 ## Base class of parser
28 #
29 #  This class is used for derivation purpose. The specific parser for one kind
30 # type file must derive this class and implement some public interfaces.
31 #
32 #   @param      FilePath        The path of platform description file
33 #   @param      FileType        The raw data of DSC file
34 #   @param      Table           Database used to retrieve module/package information
35 #   @param      Macros          Macros used for replacement in file
36 #   @param      Owner           Owner ID (for sub-section parsing)
37 #   @param      From            ID from which the data comes (for !INCLUDE directive)
38 #
39 class MetaFileParser(object):
40     # data type (file content) for specific file type
41     DataType = {}
42
43     # Parser objects used to implement singleton
44     MetaFiles = {}
45
46     ## Factory method
47     #
48     # One file, one parser object. This factory method makes sure that there's
49     # only one object constructed for one meta file.
50     #
51     #   @param  Class           class object of real AutoGen class
52     #                           (InfParser, DecParser or DscParser)
53     #   @param  FilePath        The path of meta file
54     #   @param  *args           The specific class related parameters
55     #   @param  **kwargs        The specific class related dict parameters
56     #
57     def __new__(Class, FilePath, *args, **kwargs):
58         if FilePath in Class.MetaFiles:
59             return Class.MetaFiles[FilePath]
60         else:
61             ParserObject = super(MetaFileParser, Class).__new__(Class)
62             Class.MetaFiles[FilePath] = ParserObject
63             return ParserObject
64
65     ## Constructor of MetaFileParser
66     #
67     #  Initialize object of MetaFileParser
68     #
69     #   @param      FilePath        The path of platform description file
70     #   @param      FileType        The raw data of DSC file
71     #   @param      Table           Database used to retrieve module/package information
72     #   @param      Macros          Macros used for replacement in file
73     #   @param      Owner           Owner ID (for sub-section parsing)
74     #   @param      From            ID from which the data comes (for !INCLUDE directive)
75     #
76     def __init__(self, FilePath, FileType, Table, Macros=None, Owner=-1, From=-1):
77         # prevent re-initialization
78         if hasattr(self, "_Table"):
79             return
80         self._Table = Table
81         self._FileType = FileType
82         self.MetaFile = FilePath
83         self._FileDir = os.path.dirname(self.MetaFile)
84         self._Macros = copy.copy(Macros)
85
86         # for recursive parsing
87         self._Owner = Owner
88         self._From = From
89
90         # parsr status for parsing
91         self._Content = None
92         self._ValueList = ['', '', '', '', '']
93         self._Scope = []
94         self._LineIndex = 0
95         self._CurrentLine = ''
96         self._SectionType = MODEL_UNKNOWN
97         self._SectionName = ''
98         self._InSubsection = False
99         self._SubsectionType = MODEL_UNKNOWN
100         self._SubsectionName = ''
101         self._LastItem = -1
102         self._Enabled = 0
103         self._Finished = False
104
105     ## Store the parsed data in table
106     def _Store(self, *Args):
107         return self._Table.Insert(*Args)
108
109     ## Virtual method for starting parse
110     def Start(self):
111         raise NotImplementedError
112
113     ## Set parsing complete flag in both class and table
114     def _Done(self):
115         self._Finished = True
116         ## Do not set end flag when processing included files
117         if self._From == -1:
118             self._Table.SetEndFlag()
119
120     ## Return the table containg parsed data
121     #
122     #   If the parse complete flag is not set, this method will try to parse the
123     # file before return the table
124     #
125     def _GetTable(self):
126         if not self._Finished:
127             self.Start()
128         return self._Table
129
130     ## Get the parse complete flag
131     def _GetFinished(self):
132         return self._Finished
133
134     ## Set the complete flag
135     def _SetFinished(self, Value):
136         self._Finished = Value
137
138     ## Use [] style to query data in table, just for readability
139     #
140     #   DataInfo = [data_type, scope1(arch), scope2(platform,moduletype)]
141     #
142     def __getitem__(self, DataInfo):
143         if type(DataInfo) != type(()):
144             DataInfo = (DataInfo,)
145         return self.Table.Query(*DataInfo)
146
147     ## Data parser for the common format in different type of file
148     #
149     #   The common format in the meatfile is like
150     #
151     #       xxx1 | xxx2 | xxx3
152     #
153     def _CommonParser(self):
154         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
155         self._ValueList[0:len(TokenList)] = TokenList
156
157     ## Data parser for the format in which there's path
158     #
159     #   Only path can have macro used. So we need to replace them before use.
160     #
161     def _PathParser(self):
162         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
163         self._ValueList[0:len(TokenList)] = TokenList
164         if len(self._Macros) > 0:
165             for Index in range(0, len(self._ValueList)):
166                 Value = self._ValueList[Index]
167                 if Value == None or Value == '':
168                     continue
169                 self._ValueList[Index] = NormPath(Value, self._Macros)
170
171     ## Skip unsupported data
172     def _Skip(self):
173         EdkLogger.warn("Parser", "Unrecognized content", File=self.MetaFile,
174                         Line=self._LineIndex+1, ExtraData=self._CurrentLine);
175         self._ValueList[0:1] = [self._CurrentLine]
176
177     ## Section header parser
178     #
179     #   The section header is always in following format:
180     #
181     #       [section_name.arch<.platform|module_type>]
182     #
183     def _SectionHeaderParser(self):
184         self._Scope = []
185         self._SectionName = ''
186         ArchList = set()
187         for Item in GetSplitValueList(self._CurrentLine[1:-1], TAB_COMMA_SPLIT):
188             if Item == '':
189                 continue
190             ItemList = GetSplitValueList(Item, TAB_SPLIT)
191             # different section should not mix in one section
192             if self._SectionName != '' and self._SectionName != ItemList[0].upper():
193                 EdkLogger.error('Parser', FORMAT_INVALID, "Different section names in the same section",
194                                 File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
195             self._SectionName = ItemList[0].upper()
196             if self._SectionName in self.DataType:
197                 self._SectionType = self.DataType[self._SectionName]
198             else:
199                 self._SectionType = MODEL_UNKNOWN
200                 EdkLogger.warn("Parser", "Unrecognized section", File=self.MetaFile,
201                                 Line=self._LineIndex+1, ExtraData=self._CurrentLine)
202             # S1 is always Arch
203             if len(ItemList) > 1:
204                 S1 = ItemList[1].upper()
205             else:
206                 S1 = 'COMMON'
207             ArchList.add(S1)
208             # S2 may be Platform or ModuleType
209             if len(ItemList) > 2:
210                 S2 = ItemList[2].upper()
211             else:
212                 S2 = 'COMMON'
213             self._Scope.append([S1, S2])
214
215         # 'COMMON' must not be used with specific ARCHs at the same section
216         if 'COMMON' in ArchList and len(ArchList) > 1:
217             EdkLogger.error('Parser', FORMAT_INVALID, "'common' ARCH must not be used with specific ARCHs",
218                             File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
219
220     ## [defines] section parser
221     def _DefineParser(self):
222         TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
223         self._ValueList[0:len(TokenList)] = TokenList
224         if self._ValueList[1] == '':
225             EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",
226                             ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
227
228     ## DEFINE name=value parser
229     def _MacroParser(self):
230         TokenList = GetSplitValueList(self._CurrentLine, ' ', 1)
231         MacroType = TokenList[0]
232         if len(TokenList) < 2 or TokenList[1] == '':
233             EdkLogger.error('Parser', FORMAT_INVALID, "No macro name/value given",
234                             ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
235         TokenList = GetSplitValueList(TokenList[1], TAB_EQUAL_SPLIT, 1)
236         if TokenList[0] == '':
237             EdkLogger.error('Parser', FORMAT_INVALID, "No macro name given",
238                             ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
239
240         # Macros defined in the command line override ones defined in the meta-data file
241         if not TokenList[0] in self._Macros:
242             if len(TokenList) == 1:
243                 self._Macros[TokenList[0]] = ''
244             else:
245                 # keep the macro definition for later use
246                 self._Macros[TokenList[0]] = ReplaceMacro(TokenList[1], self._Macros, False)
247
248         return TokenList[0], self._Macros[TokenList[0]]
249
250     ## [BuildOptions] section parser
251     def _BuildOptionParser(self):
252         TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
253         TokenList2 = GetSplitValueList(TokenList[0], ':', 1)
254         if len(TokenList2) == 2:
255             self._ValueList[0] = TokenList2[0]  # toolchain family
256             self._ValueList[1] = TokenList2[1]  # keys
257         else:
258             self._ValueList[1] = TokenList[0]
259         if len(TokenList) == 2:                 # value
260             self._ValueList[2] = ReplaceMacro(TokenList[1], self._Macros)
261
262         if self._ValueList[1].count('_') != 4:
263             EdkLogger.error(
264                 'Parser',
265                 FORMAT_INVALID,
266                 "'%s' must be in format of <TARGET>_<TOOLCHAIN>_<ARCH>_<TOOL>_FLAGS" % self._ValueList[1],
267                 ExtraData=self._CurrentLine,
268                 File=self.MetaFile,
269                 Line=self._LineIndex+1
270                 )
271
272     _SectionParser  = {}
273     Table           = property(_GetTable)
274     Finished        = property(_GetFinished, _SetFinished)
275
276
277 ## INF file parser class
278 #
279 #   @param      FilePath        The path of platform description file
280 #   @param      FileType        The raw data of DSC file
281 #   @param      Table           Database used to retrieve module/package information
282 #   @param      Macros          Macros used for replacement in file
283 #
284 class InfParser(MetaFileParser):
285     # INF file supported data types (one type per section)
286     DataType = {
287         TAB_UNKNOWN.upper() : MODEL_UNKNOWN,
288         TAB_INF_DEFINES.upper() : MODEL_META_DATA_HEADER,
289         TAB_BUILD_OPTIONS.upper() : MODEL_META_DATA_BUILD_OPTION,
290         TAB_INCLUDES.upper() : MODEL_EFI_INCLUDE,
291         TAB_LIBRARIES.upper() : MODEL_EFI_LIBRARY_INSTANCE,
292         TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS,
293         TAB_PACKAGES.upper() : MODEL_META_DATA_PACKAGE,
294         TAB_NMAKE.upper() : MODEL_META_DATA_NMAKE,
295         TAB_INF_FIXED_PCD.upper() : MODEL_PCD_FIXED_AT_BUILD,
296         TAB_INF_PATCH_PCD.upper() : MODEL_PCD_PATCHABLE_IN_MODULE,
297         TAB_INF_FEATURE_PCD.upper() : MODEL_PCD_FEATURE_FLAG,
298         TAB_INF_PCD_EX.upper() : MODEL_PCD_DYNAMIC_EX,
299         TAB_INF_PCD.upper() : MODEL_PCD_DYNAMIC,
300         TAB_SOURCES.upper() : MODEL_EFI_SOURCE_FILE,
301         TAB_GUIDS.upper() : MODEL_EFI_GUID,
302         TAB_PROTOCOLS.upper() : MODEL_EFI_PROTOCOL,
303         TAB_PPIS.upper() : MODEL_EFI_PPI,
304         TAB_DEPEX.upper() : MODEL_EFI_DEPEX,
305         TAB_BINARIES.upper() : MODEL_EFI_BINARY_FILE,
306         TAB_USER_EXTENSIONS.upper() : MODEL_META_DATA_USER_EXTENSION
307     }
308
309     ## Constructor of InfParser
310     #
311     #  Initialize object of InfParser
312     #
313     #   @param      FilePath        The path of module description file
314     #   @param      FileType        The raw data of DSC file
315     #   @param      Table           Database used to retrieve module/package information
316     #   @param      Macros          Macros used for replacement in file
317     #
318     def __init__(self, FilePath, FileType, Table, Macros=None):
319         MetaFileParser.__init__(self, FilePath, FileType, Table, Macros)
320
321     ## Parser starter
322     def Start(self):
323         NmakeLine = ''
324         try:
325             self._Content = open(self.MetaFile, 'r').readlines()
326         except:
327             EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
328
329         # parse the file line by line
330         IsFindBlockComment = False
331
332         for Index in range(0, len(self._Content)):
333             # skip empty, commented, block commented lines
334             Line = CleanString(self._Content[Index], AllowCppStyleComment=True)
335             NextLine = ''
336             if Index + 1 < len(self._Content):
337                 NextLine = CleanString(self._Content[Index + 1])
338             if Line == '':
339                 continue
340             if Line.find(DataType.TAB_COMMENT_R8_START) > -1:
341                 IsFindBlockComment = True
342                 continue
343             if Line.find(DataType.TAB_COMMENT_R8_END) > -1:
344                 IsFindBlockComment = False
345                 continue
346             if IsFindBlockComment:
347                 continue
348
349             self._LineIndex = Index
350             self._CurrentLine = Line
351
352             # section header
353             if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
354                 self._SectionHeaderParser()
355                 continue
356             # merge two lines specified by '\' in section NMAKE
357             elif self._SectionType == MODEL_META_DATA_NMAKE:
358                 if Line[-1] == '\\':
359                     if NextLine == '':
360                         self._CurrentLine = NmakeLine + Line[0:-1]
361                         NmakeLine = ''
362                     else:
363                         if NextLine[0] == TAB_SECTION_START and NextLine[-1] == TAB_SECTION_END:
364                             self._CurrentLine = NmakeLine + Line[0:-1]
365                             NmakeLine = ''
366                         else:
367                             NmakeLine = NmakeLine + ' ' + Line[0:-1]
368                             continue
369                 else:
370                     self._CurrentLine = NmakeLine + Line
371                     NmakeLine = ''
372             elif Line.upper().startswith('DEFINE '):
373                 # file private macros
374                 self._MacroParser()
375                 continue
376
377             # section content
378             self._ValueList = ['','','']
379             # parse current line, result will be put in self._ValueList
380             self._SectionParser[self._SectionType](self)
381             if self._ValueList == None:
382                 continue
383             #
384             # Model, Value1, Value2, Value3, Arch, Platform, BelongsToItem=-1,
385             # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
386             #
387             for Arch, Platform in self._Scope:
388                 self._Store(self._SectionType,
389                             self._ValueList[0],
390                             self._ValueList[1],
391                             self._ValueList[2],
392                             Arch,
393                             Platform,
394                             self._Owner,
395                             self._LineIndex+1,
396                             -1,
397                             self._LineIndex+1,
398                             -1,
399                             0
400                             )
401         self._Done()
402
403     ## Data parser for the format in which there's path
404     #
405     #   Only path can have macro used. So we need to replace them before use.
406     #
407     def _IncludeParser(self):
408         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
409         self._ValueList[0:len(TokenList)] = TokenList
410         if len(self._Macros) > 0:
411             for Index in range(0, len(self._ValueList)):
412                 Value = self._ValueList[Index]
413                 if Value.upper().find('$(EFI_SOURCE)\Edk'.upper()) > -1 or Value.upper().find('$(EFI_SOURCE)/Edk'.upper()) > -1:
414                     Value = '$(EDK_SOURCE)' + Value[17:]
415                 if Value.find('$(EFI_SOURCE)') > -1 or Value.find('$(EDK_SOURCE)') > -1:
416                     pass
417                 elif Value.startswith('.'):
418                     pass
419                 elif Value.startswith('$('):
420                     pass
421                 else:
422                     Value = '$(EFI_SOURCE)/' + Value
423
424                 if Value == None or Value == '':
425                     continue
426                 self._ValueList[Index] = NormPath(Value, self._Macros)
427
428     ## Parse [Sources] section
429     #
430     #   Only path can have macro used. So we need to replace them before use.
431     #
432     def _SourceFileParser(self):
433         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
434         self._ValueList[0:len(TokenList)] = TokenList
435         # For Acpi tables, remove macro like ' TABLE_NAME=Sata1'
436         if 'COMPONENT_TYPE' in self._Macros:
437             if self._Macros['COMPONENT_TYPE'].upper() == 'ACPITABLE':
438                 self._ValueList[0] = GetSplitValueList(self._ValueList[0], ' ', 1)[0]
439         if self._Macros['BASE_NAME'] == 'Microcode':
440             pass
441         if len(self._Macros) > 0:
442             for Index in range(0, len(self._ValueList)):
443                 Value = self._ValueList[Index]
444                 if Value == None or Value == '':
445                     continue
446                 self._ValueList[Index] = NormPath(Value, self._Macros)
447
448     ## Parse [Binaries] section
449     #
450     #   Only path can have macro used. So we need to replace them before use.
451     #
452     def _BinaryFileParser(self):
453         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 2)
454         if len(TokenList) < 2:
455             EdkLogger.error('Parser', FORMAT_INVALID, "No file type or path specified",
456                             ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
457                             File=self.MetaFile, Line=self._LineIndex+1)
458         if not TokenList[0]:
459             EdkLogger.error('Parser', FORMAT_INVALID, "No file type specified",
460                             ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
461                             File=self.MetaFile, Line=self._LineIndex+1)
462         if not TokenList[1]:
463             EdkLogger.error('Parser', FORMAT_INVALID, "No file path specified",
464                             ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
465                             File=self.MetaFile, Line=self._LineIndex+1)
466         self._ValueList[0:len(TokenList)] = TokenList
467         self._ValueList[1] = NormPath(self._ValueList[1], self._Macros)
468
469     ## [defines] section parser
470     def _DefineParser(self):
471         TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
472         self._ValueList[0:len(TokenList)] = TokenList
473         self._Macros[TokenList[0]] = ReplaceMacro(TokenList[1], self._Macros, False)
474         if self._ValueList[1] == '':
475             EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",
476                             ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
477
478     ## [nmake] section parser (R8.x style only)
479     def _NmakeParser(self):
480         TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
481         self._ValueList[0:len(TokenList)] = TokenList
482         # remove macros
483         self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros, False)
484         # remove self-reference in macro setting
485         #self._ValueList[1] = ReplaceMacro(self._ValueList[1], {self._ValueList[0]:''})
486
487     ## [FixedPcd], [FeaturePcd], [PatchPcd], [Pcd] and [PcdEx] sections parser
488     def _PcdParser(self):
489         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
490         self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
491         if len(TokenList) > 1:
492             self._ValueList[2] = TokenList[1]
493         if self._ValueList[0] == '' or self._ValueList[1] == '':
494             EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
495                             ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<PcdCName>)",
496                             File=self.MetaFile, Line=self._LineIndex+1)
497
498     ## [depex] section parser
499     def _DepexParser(self):
500         self._ValueList[0:1] = [self._CurrentLine]
501
502     _SectionParser = {
503         MODEL_UNKNOWN                   :   MetaFileParser._Skip,
504         MODEL_META_DATA_HEADER          :   _DefineParser,
505         MODEL_META_DATA_BUILD_OPTION    :   MetaFileParser._BuildOptionParser,
506         MODEL_EFI_INCLUDE               :   _IncludeParser,                 # for R8.x modules
507         MODEL_EFI_LIBRARY_INSTANCE      :   MetaFileParser._CommonParser,   # for R8.x modules
508         MODEL_EFI_LIBRARY_CLASS         :   MetaFileParser._PathParser,
509         MODEL_META_DATA_PACKAGE         :   MetaFileParser._PathParser,
510         MODEL_META_DATA_NMAKE           :   _NmakeParser,                   # for R8.x modules
511         MODEL_PCD_FIXED_AT_BUILD        :   _PcdParser,
512         MODEL_PCD_PATCHABLE_IN_MODULE   :   _PcdParser,
513         MODEL_PCD_FEATURE_FLAG          :   _PcdParser,
514         MODEL_PCD_DYNAMIC_EX            :   _PcdParser,
515         MODEL_PCD_DYNAMIC               :   _PcdParser,
516         MODEL_EFI_SOURCE_FILE           :   _SourceFileParser,
517         MODEL_EFI_GUID                  :   MetaFileParser._CommonParser,
518         MODEL_EFI_PROTOCOL              :   MetaFileParser._CommonParser,
519         MODEL_EFI_PPI                   :   MetaFileParser._CommonParser,
520         MODEL_EFI_DEPEX                 :   _DepexParser,
521         MODEL_EFI_BINARY_FILE           :   _BinaryFileParser,
522         MODEL_META_DATA_USER_EXTENSION  :   MetaFileParser._Skip,
523     }
524
525 ## DSC file parser class
526 #
527 #   @param      FilePath        The path of platform description file
528 #   @param      FileType        The raw data of DSC file
529 #   @param      Table           Database used to retrieve module/package information
530 #   @param      Macros          Macros used for replacement in file
531 #   @param      Owner           Owner ID (for sub-section parsing)
532 #   @param      From            ID from which the data comes (for !INCLUDE directive)
533 #
534 class DscParser(MetaFileParser):
535     # DSC file supported data types (one type per section)
536     DataType = {
537         TAB_SKUIDS.upper()                          :   MODEL_EFI_SKU_ID,
538         TAB_LIBRARIES.upper()                       :   MODEL_EFI_LIBRARY_INSTANCE,
539         TAB_LIBRARY_CLASSES.upper()                 :   MODEL_EFI_LIBRARY_CLASS,
540         TAB_BUILD_OPTIONS.upper()                   :   MODEL_META_DATA_BUILD_OPTION,
541         TAB_PCDS_FIXED_AT_BUILD_NULL.upper()        :   MODEL_PCD_FIXED_AT_BUILD,
542         TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper()   :   MODEL_PCD_PATCHABLE_IN_MODULE,
543         TAB_PCDS_FEATURE_FLAG_NULL.upper()          :   MODEL_PCD_FEATURE_FLAG,
544         TAB_PCDS_DYNAMIC_DEFAULT_NULL.upper()       :   MODEL_PCD_DYNAMIC_DEFAULT,
545         TAB_PCDS_DYNAMIC_HII_NULL.upper()           :   MODEL_PCD_DYNAMIC_HII,
546         TAB_PCDS_DYNAMIC_VPD_NULL.upper()           :   MODEL_PCD_DYNAMIC_VPD,
547         TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL.upper()    :   MODEL_PCD_DYNAMIC_EX_DEFAULT,
548         TAB_PCDS_DYNAMIC_EX_HII_NULL.upper()        :   MODEL_PCD_DYNAMIC_EX_HII,
549         TAB_PCDS_DYNAMIC_EX_VPD_NULL.upper()        :   MODEL_PCD_DYNAMIC_EX_VPD,
550         TAB_COMPONENTS.upper()                      :   MODEL_META_DATA_COMPONENT,
551         TAB_COMPONENTS_SOURCE_OVERRIDE_PATH.upper() :   MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH,
552         TAB_DSC_DEFINES.upper()                     :   MODEL_META_DATA_HEADER,
553         TAB_INCLUDE.upper()                         :   MODEL_META_DATA_INCLUDE,
554         TAB_IF.upper()                              :   MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
555         TAB_IF_DEF.upper()                          :   MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
556         TAB_IF_N_DEF.upper()                        :   MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF,
557         TAB_ELSE_IF.upper()                         :   MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF,
558         TAB_ELSE.upper()                            :   MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE,
559         TAB_END_IF.upper()                          :   MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF,
560     }
561
562     # sections which allow "!include" directive
563     _IncludeAllowedSection = [
564         TAB_LIBRARIES.upper(),
565         TAB_LIBRARY_CLASSES.upper(),
566         TAB_SKUIDS.upper(),
567         TAB_COMPONENTS.upper(),
568         TAB_BUILD_OPTIONS.upper(),
569         TAB_PCDS_FIXED_AT_BUILD_NULL.upper(),
570         TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper(),
571         TAB_PCDS_FEATURE_FLAG_NULL.upper(),
572         TAB_PCDS_DYNAMIC_DEFAULT_NULL.upper(),
573         TAB_PCDS_DYNAMIC_HII_NULL.upper(),
574         TAB_PCDS_DYNAMIC_VPD_NULL.upper(),
575         TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL.upper(),
576         TAB_PCDS_DYNAMIC_EX_HII_NULL.upper(),
577         TAB_PCDS_DYNAMIC_EX_VPD_NULL.upper(),
578         ]
579
580     # operators which can be used in "!if/!ifdef/!ifndef" directives
581     _OP_ = {
582         "!"     :   lambda a:   not a,
583         "!="    :   lambda a,b: a!=b,
584         "=="    :   lambda a,b: a==b,
585         ">"     :   lambda a,b: a>b,
586         "<"     :   lambda a,b: a<b,
587         "=>"    :   lambda a,b: a>=b,
588         ">="    :   lambda a,b: a>=b,
589         "<="    :   lambda a,b: a<=b,
590         "=<"    :   lambda a,b: a<=b,
591     }
592
593     ## Constructor of DscParser
594     #
595     #  Initialize object of DscParser
596     #
597     #   @param      FilePath        The path of platform description file
598     #   @param      FileType        The raw data of DSC file
599     #   @param      Table           Database used to retrieve module/package information
600     #   @param      Macros          Macros used for replacement in file
601     #   @param      Owner           Owner ID (for sub-section parsing)
602     #   @param      From            ID from which the data comes (for !INCLUDE directive)
603     #
604     def __init__(self, FilePath, FileType, Table, Macros=None, Owner=-1, From=-1):
605         MetaFileParser.__init__(self, FilePath, FileType, Table, Macros, Owner, From)
606         # to store conditional directive evaluation result
607         self._Eval = Blist()
608
609     ## Parser starter
610     def Start(self):
611         try:
612             if self._Content == None:
613                 self._Content = open(self.MetaFile, 'r').readlines()
614         except:
615             EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
616
617         for Index in range(0, len(self._Content)):
618             Line = CleanString(self._Content[Index])
619             # skip empty line
620             if Line == '':
621                 continue
622             self._CurrentLine = Line
623             self._LineIndex = Index
624             if self._InSubsection and self._Owner == -1:
625                 self._Owner = self._LastItem
626             
627             # section header
628             if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
629                 self._SectionHeaderParser()
630                 continue
631             # subsection ending
632             elif Line[0] == '}':
633                 self._InSubsection = False
634                 self._SubsectionType = MODEL_UNKNOWN
635                 self._SubsectionName = ''
636                 self._Owner = -1
637                 continue
638             # subsection header
639             elif Line[0] == TAB_OPTION_START and Line[-1] == TAB_OPTION_END:
640                 self._SubsectionHeaderParser()
641                 continue
642             # directive line
643             elif Line[0] == '!':
644                 self._DirectiveParser()
645                 continue
646             # file private macros
647             elif Line.upper().startswith('DEFINE '):
648                 self._MacroParser()
649                 continue
650             elif Line.upper().startswith('EDK_GLOBAL '):
651                 (Name, Value) = self._MacroParser()
652                 for Arch, ModuleType in self._Scope:
653                     self._LastItem = self._Store(
654                     MODEL_META_DATA_DEFINE,
655                     Name,
656                     Value,
657                     '',
658                     Arch,
659                     'COMMON',
660                     self._Owner,
661                     self._From,
662                     self._LineIndex+1,
663                     -1,
664                     self._LineIndex+1,
665                     -1,
666                     self._Enabled
667                     )
668                 continue
669
670             # section content
671             if self._InSubsection:
672                 SectionType = self._SubsectionType
673                 SectionName = self._SubsectionName
674             else:
675                 SectionType = self._SectionType
676                 SectionName = self._SectionName
677
678             self._ValueList = ['', '', '']
679             self._SectionParser[SectionType](self)
680             if self._ValueList == None:
681                 continue
682
683             #
684             # Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1,
685             # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
686             #
687             for Arch, ModuleType in self._Scope:
688                 self._LastItem = self._Store(
689                     SectionType,
690                     self._ValueList[0],
691                     self._ValueList[1],
692                     self._ValueList[2],
693                     Arch,
694                     ModuleType,
695                     self._Owner,
696                     self._From,
697                     self._LineIndex+1,
698                     -1,
699                     self._LineIndex+1,
700                     -1,
701                     self._Enabled
702                     )
703         self._Done()
704
705     ## [defines] section parser
706     def _DefineParser(self):
707         TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
708         if len(TokenList) < 2:
709             EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",
710                             ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
711         # 'FLASH_DEFINITION', 'OUTPUT_DIRECTORY' need special processing
712         if TokenList[0] in ['FLASH_DEFINITION', 'OUTPUT_DIRECTORY']:
713             TokenList[1] = NormPath(TokenList[1], self._Macros)
714         self._ValueList[0:len(TokenList)] = TokenList
715
716     ## <subsection_header> parser
717     def _SubsectionHeaderParser(self):
718         self._SubsectionName = self._CurrentLine[1:-1].upper()
719         if self._SubsectionName in self.DataType:
720             self._SubsectionType = self.DataType[self._SubsectionName]
721         else:
722             self._SubsectionType = MODEL_UNKNOWN
723             EdkLogger.warn("Parser", "Unrecognized sub-section", File=self.MetaFile,
724                             Line=self._LineIndex+1, ExtraData=self._CurrentLine)
725
726     ## Directive statement parser
727     def _DirectiveParser(self):
728         self._ValueList = ['','','']
729         TokenList = GetSplitValueList(self._CurrentLine, ' ', 1)
730         self._ValueList[0:len(TokenList)] = TokenList
731         DirectiveName = self._ValueList[0].upper()
732         if DirectiveName not in self.DataType:
733             EdkLogger.error("Parser", FORMAT_INVALID, "Unknown directive [%s]" % DirectiveName,
734                             File=self.MetaFile, Line=self._LineIndex+1)
735         if DirectiveName in ['!IF', '!IFDEF', '!INCLUDE', '!IFNDEF', '!ELSEIF'] and self._ValueList[1] == '':
736             EdkLogger.error("Parser", FORMAT_INVALID, "Missing expression",
737                             File=self.MetaFile, Line=self._LineIndex+1,
738                             ExtraData=self._CurrentLine)
739         # keep the directive in database first
740         self._LastItem = self._Store(
741             self.DataType[DirectiveName],
742             self._ValueList[0],
743             self._ValueList[1],
744             self._ValueList[2],
745             'COMMON',
746             'COMMON',
747             self._Owner,
748             self._From,
749             self._LineIndex + 1,
750             -1,
751             self._LineIndex + 1,
752             -1,
753             0
754             )
755
756         # process the directive
757         if DirectiveName == "!INCLUDE":
758             if not self._SectionName in self._IncludeAllowedSection:
759                 EdkLogger.error("Parser", FORMAT_INVALID, File=self.MetaFile, Line=self._LineIndex+1,
760                                 ExtraData="'!include' is not allowed under section [%s]" % self._SectionName)
761             # the included file must be relative to the parsing file
762             IncludedFile = os.path.join(self._FileDir, self._ValueList[1])
763             Parser = DscParser(IncludedFile, self._FileType, self._Table, self._Macros, From=self._LastItem)
764             # set the parser status with current status
765             Parser._SectionName = self._SectionName
766             Parser._SectionType = self._SectionType
767             Parser._Scope = self._Scope
768             Parser._Enabled = self._Enabled
769             try:
770                 Parser.Start()
771             except:
772                 EdkLogger.error("Parser", PARSER_ERROR, File=self.MetaFile, Line=self._LineIndex+1,
773                                 ExtraData="Failed to parse content in file %s" % IncludedFile)
774             # update current status with sub-parser's status
775             self._SectionName = Parser._SectionName
776             self._SectionType = Parser._SectionType
777             self._Scope       = Parser._Scope
778             self._Enabled     = Parser._Enabled
779         else:
780             if DirectiveName in ["!IF", "!IFDEF", "!IFNDEF"]:
781                 # evaluate the expression
782                 Result = self._Evaluate(self._ValueList[1])
783                 if DirectiveName == "!IFNDEF":
784                     Result = not Result
785                 self._Eval.append(Result)
786             elif DirectiveName in ["!ELSEIF"]:
787                 # evaluate the expression
788                 self._Eval[-1] = (not self._Eval[-1]) & self._Evaluate(self._ValueList[1])
789             elif DirectiveName in ["!ELSE"]:
790                 self._Eval[-1] = not self._Eval[-1]
791             elif DirectiveName in ["!ENDIF"]:
792                 if len(self._Eval) > 0:
793                     self._Eval.pop()
794                 else:
795                     EdkLogger.error("Parser", FORMAT_INVALID, "!IF..[!ELSE]..!ENDIF doesn't match",
796                                     File=self.MetaFile, Line=self._LineIndex+1)
797             if self._Eval.Result == False:
798                 self._Enabled = 0 - len(self._Eval)
799             else:
800                 self._Enabled = len(self._Eval)
801
802     ## Evaludate the value of expression in "if/ifdef/ifndef" directives
803     def _Evaluate(self, Expression):
804         TokenList = Expression.split()
805         TokenNumber = len(TokenList)
806         # one operand, guess it's just a macro name
807         if TokenNumber == 1:
808             return TokenList[0] in self._Macros
809         # two operands, suppose it's "!xxx" format
810         elif TokenNumber == 2:
811             Op = TokenList[0]
812             if Op not in self._OP_:
813                 EdkLogger.error('Parser', FORMAT_INVALID, "Unsupported operator [%s]" % Op, File=self.MetaFile,
814                                 Line=self._LineIndex+1, ExtraData=Expression)
815             if TokenList[1].upper() == 'TRUE':
816                 Value = True
817             else:
818                 Value = False
819             return self._OP_[Op](Value)
820         # three operands
821         elif TokenNumber == 3:
822             Name = TokenList[0]
823             if Name not in self._Macros:
824                 return False
825             Value = TokenList[2]
826             if Value[0] in ["'", '"'] and Value[-1] in ["'", '"']:
827                 Value = Value[1:-1]
828             Op = TokenList[1]
829             if Op not in self._OP_:
830                 EdkLogger.error('Parser', FORMAT_INVALID, "Unsupported operator [%s]" % Op, File=self.MetaFile,
831                                 Line=self._LineIndex+1, ExtraData=Expression)
832             return self._OP_[Op](self._Macros[Name], Value)
833         else:
834             EdkLogger.error('Parser', FORMAT_INVALID, File=self.MetaFile, Line=self._LineIndex+1,
835                             ExtraData=Expression)
836
837     ## PCD sections parser
838     #
839     #   [PcdsFixedAtBuild]
840     #   [PcdsPatchableInModule]
841     #   [PcdsFeatureFlag]
842     #   [PcdsDynamicEx
843     #   [PcdsDynamicExDefault]
844     #   [PcdsDynamicExVpd]
845     #   [PcdsDynamicExHii]
846     #   [PcdsDynamic]
847     #   [PcdsDynamicDefault]
848     #   [PcdsDynamicVpd]
849     #   [PcdsDynamicHii]
850     #
851     def _PcdParser(self):
852         TokenList = GetSplitValueList(ReplaceMacro(self._CurrentLine, self._Macros), TAB_VALUE_SPLIT, 1)
853         self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
854         if len(TokenList) == 2:
855             self._ValueList[2] = TokenList[1]
856         if self._ValueList[0] == '' or self._ValueList[1] == '':
857             EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
858                             ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
859                             File=self.MetaFile, Line=self._LineIndex+1)
860         if self._ValueList[2] == '':
861             EdkLogger.error('Parser', FORMAT_INVALID, "No PCD value given",
862                             ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
863                             File=self.MetaFile, Line=self._LineIndex+1)
864
865     ## [components] section parser
866     def _ComponentParser(self):
867         if self._CurrentLine[-1] == '{':
868             self._ValueList[0] = self._CurrentLine[0:-1].strip()
869             self._InSubsection = True
870         else:
871             self._ValueList[0] = self._CurrentLine
872         if len(self._Macros) > 0:
873             self._ValueList[0] = NormPath(self._ValueList[0], self._Macros)
874
875     def _LibraryClassParser(self):
876         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
877         if len(TokenList) < 2:
878             EdkLogger.error('Parser', FORMAT_INVALID, "No library class or instance specified",
879                             ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
880                             File=self.MetaFile, Line=self._LineIndex+1)
881         if TokenList[0] == '':
882             EdkLogger.error('Parser', FORMAT_INVALID, "No library class specified",
883                             ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
884                             File=self.MetaFile, Line=self._LineIndex+1)
885         if TokenList[1] == '':
886             EdkLogger.error('Parser', FORMAT_INVALID, "No library instance specified",
887                             ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
888                             File=self.MetaFile, Line=self._LineIndex+1)
889         self._ValueList[0:len(TokenList)] = TokenList
890         if len(self._Macros) > 0:
891             self._ValueList[1] = NormPath(self._ValueList[1], self._Macros)
892
893     def _CompponentSourceOverridePathParser(self):
894         if len(self._Macros) > 0:
895             self._ValueList[0] = NormPath(self._CurrentLine, self._Macros)
896
897     _SectionParser = {
898         MODEL_META_DATA_HEADER                         :   _DefineParser,
899         MODEL_EFI_SKU_ID                               :   MetaFileParser._CommonParser,
900         MODEL_EFI_LIBRARY_INSTANCE                     :   MetaFileParser._PathParser,
901         MODEL_EFI_LIBRARY_CLASS                        :   _LibraryClassParser,
902         MODEL_PCD_FIXED_AT_BUILD                       :   _PcdParser,
903         MODEL_PCD_PATCHABLE_IN_MODULE                  :   _PcdParser,
904         MODEL_PCD_FEATURE_FLAG                         :   _PcdParser,
905         MODEL_PCD_DYNAMIC_DEFAULT                      :   _PcdParser,
906         MODEL_PCD_DYNAMIC_HII                          :   _PcdParser,
907         MODEL_PCD_DYNAMIC_VPD                          :   _PcdParser,
908         MODEL_PCD_DYNAMIC_EX_DEFAULT                   :   _PcdParser,
909         MODEL_PCD_DYNAMIC_EX_HII                       :   _PcdParser,
910         MODEL_PCD_DYNAMIC_EX_VPD                       :   _PcdParser,
911         MODEL_META_DATA_COMPONENT                      :   _ComponentParser,
912         MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH :   _CompponentSourceOverridePathParser,
913         MODEL_META_DATA_BUILD_OPTION                   :   MetaFileParser._BuildOptionParser,
914         MODEL_UNKNOWN                                  :   MetaFileParser._Skip,
915         MODEL_META_DATA_USER_EXTENSION                 :   MetaFileParser._Skip,
916     }
917
918 ## DEC file parser class
919 #
920 #   @param      FilePath        The path of platform description file
921 #   @param      FileType        The raw data of DSC file
922 #   @param      Table           Database used to retrieve module/package information
923 #   @param      Macros          Macros used for replacement in file
924 #
925 class DecParser(MetaFileParser):
926     # DEC file supported data types (one type per section)
927     DataType = {
928         TAB_DEC_DEFINES.upper()                     :   MODEL_META_DATA_HEADER,
929         TAB_INCLUDES.upper()                        :   MODEL_EFI_INCLUDE,
930         TAB_LIBRARY_CLASSES.upper()                 :   MODEL_EFI_LIBRARY_CLASS,
931         TAB_GUIDS.upper()                           :   MODEL_EFI_GUID,
932         TAB_PPIS.upper()                            :   MODEL_EFI_PPI,
933         TAB_PROTOCOLS.upper()                       :   MODEL_EFI_PROTOCOL,
934         TAB_PCDS_FIXED_AT_BUILD_NULL.upper()        :   MODEL_PCD_FIXED_AT_BUILD,
935         TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper()   :   MODEL_PCD_PATCHABLE_IN_MODULE,
936         TAB_PCDS_FEATURE_FLAG_NULL.upper()          :   MODEL_PCD_FEATURE_FLAG,
937         TAB_PCDS_DYNAMIC_NULL.upper()               :   MODEL_PCD_DYNAMIC,
938         TAB_PCDS_DYNAMIC_EX_NULL.upper()            :   MODEL_PCD_DYNAMIC_EX,
939     }
940
941     ## Constructor of DecParser
942     #
943     #  Initialize object of DecParser
944     #
945     #   @param      FilePath        The path of platform description file
946     #   @param      FileType        The raw data of DSC file
947     #   @param      Table           Database used to retrieve module/package information
948     #   @param      Macros          Macros used for replacement in file
949     #
950     def __init__(self, FilePath, FileType, Table, Macro=None):
951         MetaFileParser.__init__(self, FilePath, FileType, Table, Macro, -1)
952
953     ## Parser starter
954     def Start(self):
955         try:
956             if self._Content == None:
957                 self._Content = open(self.MetaFile, 'r').readlines()
958         except:
959             EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
960
961         for Index in range(0, len(self._Content)):
962             Line = CleanString(self._Content[Index])
963             # skip empty line
964             if Line == '':
965                 continue
966             self._CurrentLine = Line
967             self._LineIndex = Index
968
969             # section header
970             if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
971                 self._SectionHeaderParser()
972                 continue
973             elif Line.startswith('DEFINE '):
974                 self._MacroParser()
975                 continue
976             elif len(self._SectionType) == 0:
977                 continue
978
979             # section content
980             self._ValueList = ['','','']
981             self._SectionParser[self._SectionType[0]](self)
982             if self._ValueList == None:
983                 continue
984
985             #
986             # Model, Value1, Value2, Value3, Arch, BelongsToItem=-1, LineBegin=-1,
987             # ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, FeatureFlag='', Enabled=-1
988             #
989             for Arch, ModuleType, Type in self._Scope:
990                 self._LastItem = self._Store(
991                     Type,
992                     self._ValueList[0],
993                     self._ValueList[1],
994                     self._ValueList[2],
995                     Arch,
996                     ModuleType,
997                     self._Owner,
998                     self._LineIndex+1,
999                     -1,
1000                     self._LineIndex+1,
1001                     -1,
1002                     0
1003                     )
1004         self._Done()
1005
1006     ## Section header parser
1007     #
1008     #   The section header is always in following format:
1009     #
1010     #       [section_name.arch<.platform|module_type>]
1011     #
1012     def _SectionHeaderParser(self):
1013         self._Scope = []
1014         self._SectionName = ''
1015         self._SectionType = []
1016         ArchList = set()
1017         for Item in GetSplitValueList(self._CurrentLine[1:-1], TAB_COMMA_SPLIT):
1018             if Item == '':
1019                 continue
1020             ItemList = GetSplitValueList(Item, TAB_SPLIT)
1021
1022             # different types of PCD are permissible in one section
1023             self._SectionName = ItemList[0].upper()
1024             if self._SectionName in self.DataType:
1025                 if self.DataType[self._SectionName] not in self._SectionType:
1026                     self._SectionType.append(self.DataType[self._SectionName])
1027             else:
1028                 EdkLogger.warn("Parser", "Unrecognized section", File=self.MetaFile,
1029                                 Line=self._LineIndex+1, ExtraData=self._CurrentLine)
1030                 continue
1031
1032             if MODEL_PCD_FEATURE_FLAG in self._SectionType and len(self._SectionType) > 1:
1033                 EdkLogger.error(
1034                             'Parser',
1035                             FORMAT_INVALID,
1036                             "%s must not be in the same section of other types of PCD" % TAB_PCDS_FEATURE_FLAG_NULL,
1037                             File=self.MetaFile,
1038                             Line=self._LineIndex+1,
1039                             ExtraData=self._CurrentLine
1040                             )
1041             # S1 is always Arch
1042             if len(ItemList) > 1:
1043                 S1 = ItemList[1].upper()
1044             else:
1045                 S1 = 'COMMON'
1046             ArchList.add(S1)
1047             # S2 may be Platform or ModuleType
1048             if len(ItemList) > 2:
1049                 S2 = ItemList[2].upper()
1050             else:
1051                 S2 = 'COMMON'
1052             if [S1, S2, self.DataType[self._SectionName]] not in self._Scope:
1053                 self._Scope.append([S1, S2, self.DataType[self._SectionName]])
1054
1055         # 'COMMON' must not be used with specific ARCHs at the same section
1056         if 'COMMON' in ArchList and len(ArchList) > 1:
1057             EdkLogger.error('Parser', FORMAT_INVALID, "'common' ARCH must not be used with specific ARCHs",
1058                             File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
1059
1060     ## [guids], [ppis] and [protocols] section parser
1061     def _GuidParser(self):
1062         TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
1063         if len(TokenList) < 2:
1064             EdkLogger.error('Parser', FORMAT_INVALID, "No GUID name or value specified",
1065                             ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1066                             File=self.MetaFile, Line=self._LineIndex+1)
1067         if TokenList[0] == '':
1068             EdkLogger.error('Parser', FORMAT_INVALID, "No GUID name specified",
1069                             ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1070                             File=self.MetaFile, Line=self._LineIndex+1)
1071         if TokenList[1] == '':
1072             EdkLogger.error('Parser', FORMAT_INVALID, "No GUID value specified",
1073                             ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1074                             File=self.MetaFile, Line=self._LineIndex+1)
1075         if TokenList[1][0] != '{' or TokenList[1][-1] != '}' or GuidStructureStringToGuidString(TokenList[1]) == '':
1076             EdkLogger.error('Parser', FORMAT_INVALID, "Invalid GUID value format",
1077                             ExtraData=self._CurrentLine + \
1078                                       " (<CName> = <GuidValueInCFormat:{8,4,4,{2,2,2,2,2,2,2,2}}>)",
1079                             File=self.MetaFile, Line=self._LineIndex+1)
1080         self._ValueList[0] = TokenList[0]
1081         self._ValueList[1] = TokenList[1]
1082
1083     ## PCD sections parser
1084     #
1085     #   [PcdsFixedAtBuild]
1086     #   [PcdsPatchableInModule]
1087     #   [PcdsFeatureFlag]
1088     #   [PcdsDynamicEx
1089     #   [PcdsDynamic]
1090     #
1091     def _PcdParser(self):
1092         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
1093         self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
1094         # check PCD information
1095         if self._ValueList[0] == '' or self._ValueList[1] == '':
1096             EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
1097                             ExtraData=self._CurrentLine + \
1098                                       " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1099                             File=self.MetaFile, Line=self._LineIndex+1)
1100         # check PCD datum information
1101         if len(TokenList) < 2 or TokenList[1] == '':
1102             EdkLogger.error('Parser', FORMAT_INVALID, "No PCD Datum information given",
1103                             ExtraData=self._CurrentLine + \
1104                                       " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1105                             File=self.MetaFile, Line=self._LineIndex+1)
1106
1107         ValueList = GetSplitValueList(TokenList[1])
1108         # check if there's enough datum information given
1109         if len(ValueList) != 3:
1110             EdkLogger.error('Parser', FORMAT_INVALID, "Invalid PCD Datum information given",
1111                             ExtraData=self._CurrentLine + \
1112                                       " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1113                             File=self.MetaFile, Line=self._LineIndex+1)
1114         # check default value
1115         if ValueList[0] == '':
1116             EdkLogger.error('Parser', FORMAT_INVALID, "Missing DefaultValue in PCD Datum information",
1117                             ExtraData=self._CurrentLine + \
1118                                       " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1119                             File=self.MetaFile, Line=self._LineIndex+1)
1120         # check datum type
1121         if ValueList[1] == '':
1122             EdkLogger.error('Parser', FORMAT_INVALID, "Missing DatumType in PCD Datum information",
1123                             ExtraData=self._CurrentLine + \
1124                                       " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1125                             File=self.MetaFile, Line=self._LineIndex+1)
1126         # check token of the PCD
1127         if ValueList[2] == '':
1128             EdkLogger.error('Parser', FORMAT_INVALID, "Missing Token in PCD Datum information",
1129                             ExtraData=self._CurrentLine + \
1130                                       " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1131                             File=self.MetaFile, Line=self._LineIndex+1)
1132         # check format of default value against the datum type
1133         IsValid, Cause = CheckPcdDatum(ValueList[1], ValueList[0])
1134         if not IsValid:
1135             EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine,
1136                             File=self.MetaFile, Line=self._LineIndex+1)
1137
1138         self._ValueList[2] = ValueList[0].strip() + '|' + ValueList[1].strip() + '|' + ValueList[2].strip()
1139
1140     _SectionParser = {
1141         MODEL_META_DATA_HEADER          :   MetaFileParser._DefineParser,
1142         MODEL_EFI_INCLUDE               :   MetaFileParser._PathParser,
1143         MODEL_EFI_LIBRARY_CLASS         :   MetaFileParser._PathParser,
1144         MODEL_EFI_GUID                  :   _GuidParser,
1145         MODEL_EFI_PPI                   :   _GuidParser,
1146         MODEL_EFI_PROTOCOL              :   _GuidParser,
1147         MODEL_PCD_FIXED_AT_BUILD        :   _PcdParser,
1148         MODEL_PCD_PATCHABLE_IN_MODULE   :   _PcdParser,
1149         MODEL_PCD_FEATURE_FLAG          :   _PcdParser,
1150         MODEL_PCD_DYNAMIC               :   _PcdParser,
1151         MODEL_PCD_DYNAMIC_EX            :   _PcdParser,
1152         MODEL_UNKNOWN                   :   MetaFileParser._Skip,
1153         MODEL_META_DATA_USER_EXTENSION  :   MetaFileParser._Skip,
1154     }
1155
1156 ##
1157 #
1158 # This acts like the main() function for the script, unless it is 'import'ed into another
1159 # script.
1160 #
1161 if __name__ == '__main__':
1162     pass
1163