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