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