Added doxygen comments
[people/mcb30/basetools.git] / Source / Python / Workspace / MetaFileParser.py
1 ## @file\r
2 # This file is used to parse meta files\r
3 #\r
4 # Copyright (c) 2008, Intel Corporation\r
5 # All rights reserved. This program and the accompanying materials\r
6 # are licensed and made available under the terms and conditions of the BSD License\r
7 # which accompanies this distribution.  The full text of the license may be found at\r
8 # http://opensource.org/licenses/bsd-license.php\r
9 #\r
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 #\r
13 \r
14 ##\r
15 # Import Modules\r
16 #\r
17 import os\r
18 import time\r
19 \r
20 import Common.EdkLogger as EdkLogger\r
21 from CommonDataClass.DataClass import *\r
22 from Common.DataType import *\r
23 from Common.String import *\r
24 from Common.Misc import Blist\r
25 \r
26 ## Base class of parser\r
27 #\r
28 #  This class is used for derivation purpose. The specific parser for one kind\r
29 # type file must derive this class and implement some public interfaces.\r
30 #\r
31 #   @param      FilePath        The path of platform description file\r
32 #   @param      FileType        The raw data of DSC file\r
33 #   @param      Table           Database used to retrieve module/package information\r
34 #   @param      Macros          Macros used for replacement in file\r
35 #   @param      Owner           Owner ID (for sub-section parsing)\r
36 #   @param      From            ID from which the data comes (for !INCLUDE directive)\r
37 #\r
38 class MetaFileParser(object):\r
39     # data type (file content) for specific file type\r
40     DataType = {}\r
41 \r
42     ## Constructor of MetaFileParser\r
43     #\r
44     #  Initialize object of MetaFileParser\r
45     #\r
46     #   @param      FilePath        The path of platform description file\r
47     #   @param      FileType        The raw data of DSC file\r
48     #   @param      Table           Database used to retrieve module/package information\r
49     #   @param      Macros          Macros used for replacement in file\r
50     #   @param      Owner           Owner ID (for sub-section parsing)\r
51     #   @param      From            ID from which the data comes (for !INCLUDE directive)\r
52     #\r
53     def __init__(self, FilePath, FileType, Table, Macros={}, Owner=-1, From=-1):\r
54         self._Table = Table\r
55         self._FileType = FileType\r
56         self._FilePath = FilePath\r
57         self._FileDir = os.path.dirname(self._FilePath)\r
58         self._Macros = Macros\r
59         # for recursive parsing \r
60         self._Owner = Owner\r
61         self._From = From\r
62 \r
63         # parsr status for parsing\r
64         self._Content = None\r
65         self._ValueList = ['', '', '', '', '']\r
66         self._Scope = []\r
67         self._LineIndex = 0\r
68         self._CurrentLine = ''\r
69         self._SectionType = MODEL_UNKNOWN\r
70         self._SectionName = ''\r
71         self._InSubsection = False\r
72         self._SubsectionType = MODEL_UNKNOWN\r
73         self._SubsectionName = ''\r
74         self._LastItem = -1\r
75         self._Enabled = 0\r
76         self._Finished = False\r
77 \r
78     ## Store the parsed data in table\r
79     def _Store(self, *Args):\r
80         return self._Table.Insert(*Args)\r
81 \r
82     ## Virtual method for starting parse\r
83     def Start(self):\r
84         raise NotImplementedError \r
85 \r
86     ## Set parsing complete flag in both class and table\r
87     def _Done(self):\r
88         self._Finished = True\r
89         self._Table.SetEndFlag()\r
90 \r
91     ## Return the table containg parsed data\r
92     #\r
93     #   If the parse complete flag is not set, this method will try to parse the\r
94     # file before return the table\r
95     # \r
96     def _GetTable(self):\r
97         if not self._Finished:\r
98             self.Start()\r
99         return self._Table\r
100 \r
101     ## Get the parse complete flag\r
102     def _GetFinished(self):\r
103         return self._Finished\r
104 \r
105     ## Set the complete flag\r
106     def _SetFinished(self, Value):\r
107         self._Finished = Value\r
108 \r
109     ## Use [] style to query data in table, just for readability\r
110     # \r
111     #   DataInfo = [data_type, scope1(arch), scope2(platform,moduletype)]\r
112     # \r
113     def __getitem__(self, DataInfo):\r
114         if type(DataInfo) != type(()):\r
115             DataInfo = (DataInfo,)\r
116         return self.Table.Query(*DataInfo)\r
117 \r
118     ## Data parser for the common format in different type of file\r
119     #\r
120     #   The common format in the meatfile is like\r
121     # \r
122     #       xxx1 | xxx2 | xxx3\r
123     # \r
124     def _CommonParser(self):\r
125         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)\r
126         self._ValueList[0:len(TokenList)] = TokenList\r
127 \r
128     ## Data parser for the format in which there's path\r
129     #\r
130     #   Only path can have macro used. So we need to replace them before use.\r
131     # \r
132     def _PathParser(self):\r
133         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)\r
134         self._ValueList[0:len(TokenList)] = TokenList\r
135         if len(self._Macros) > 0:\r
136             for Index in range(0, len(self._ValueList)):\r
137                 Value = self._ValueList[Index]\r
138                 if Value == None or Value == '':\r
139                     continue\r
140                 self._ValueList[Index] = NormPath(Value, self._Macros)\r
141 \r
142     ## Skip unsupported data\r
143     def _Skip(self):\r
144         self._ValueList[0:1] = [self._CurrentLine]\r
145 \r
146     ## Section header parser\r
147     #\r
148     #   The section header is always in following format:\r
149     # \r
150     #       [section_name.arch<.platform|module_type>]\r
151     # \r
152     def _SectionHeaderParser(self):\r
153         self._Scope = []\r
154         self._SectionName = ''\r
155         ArchList = set()\r
156         for Item in GetSplitValueList(self._CurrentLine[1:-1], TAB_COMMA_SPLIT):\r
157             ItemList = GetSplitValueList(Item, TAB_SPLIT)\r
158             # different section should not mix in one section\r
159             if self._SectionName != '' and self._SectionName != ItemList[0].upper():\r
160                 EdkLogger.error('Parser', FORMAT_INVALID, "Different section names in the same section",\r
161                                 File=self._FilePath, Line=self._LineIndex+1, ExtraData=self._CurrentLine)\r
162             self._SectionName = ItemList[0].upper()\r
163             if self._SectionName in self.DataType:\r
164                 self._SectionType = self.DataType[self._SectionName]\r
165             else:\r
166                 self._SectionType = MODEL_UNKNOWN\r
167             # S1 is always Arch\r
168             if len(ItemList) > 1:\r
169                 S1 = ItemList[1].upper()\r
170             else:\r
171                 S1 = 'COMMON'\r
172             ArchList.add(S1)\r
173             # S2 may be Platform or ModuleType\r
174             if len(ItemList) > 2:\r
175                 S2 = ItemList[2].upper()\r
176             else:\r
177                 S2 = 'COMMON'\r
178             self._Scope.append([S1, S2])\r
179 \r
180         # 'COMMON' must not be used with specific ARCHs at the same section\r
181         if 'COMMON' in ArchList and len(ArchList) > 1:\r
182             EdkLogger.error('Parser', FORMAT_INVALID, "'common' ARCH must not be used with specific ARCHs",\r
183                             File=self._FilePath, Line=self._LineIndex+1, ExtraData=self._CurrentLine)\r
184 \r
185     ## [defines] section parser\r
186     def _DefineParser(self):\r
187         TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)\r
188         self._ValueList[0:len(TokenList)] = TokenList\r
189         if self._ValueList[1] == '':\r
190             EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",\r
191                             ExtraData=self._CurrentLine, File=self._FilePath, Line=self._LineIndex+1)\r
192 \r
193     ## DEFINE name=value parser\r
194     def _MacroParser(self):\r
195         TokenList = GetSplitValueList(self._CurrentLine, ' ', 1)\r
196         if len(TokenList) < 2 or TokenList[1] == '':\r
197             EdkLogger.error('Parser', FORMAT_INVALID, "No macro name/value given",\r
198                             ExtraData=self._CurrentLine, File=self._FilePath, Line=self._LineIndex+1)\r
199         TokenList = GetSplitValueList(TokenList[1], TAB_EQUAL_SPLIT, 1)\r
200         if len(TokenList) < 1:\r
201             return\r
202         if self._Macros == None:\r
203             self._Macros = {}\r
204         # keep the macro definition for later use\r
205         self._Macros[TokenList[0]] = TokenList[1]\r
206 \r
207     _SectionParser  = {}\r
208     Table           = property(_GetTable)\r
209     Finished        = property(_GetFinished, _SetFinished)\r
210 \r
211 \r
212 ## INF file parser class\r
213 #\r
214 #   @param      FilePath        The path of platform description file\r
215 #   @param      FileType        The raw data of DSC file\r
216 #   @param      Table           Database used to retrieve module/package information\r
217 #   @param      Macros          Macros used for replacement in file\r
218 #\r
219 class InfParser(MetaFileParser):\r
220     # INF file supported data types (one type per section)\r
221     DataType = {\r
222         TAB_UNKNOWN.upper() : MODEL_UNKNOWN,\r
223         TAB_INF_DEFINES.upper() : MODEL_META_DATA_HEADER,\r
224         TAB_BUILD_OPTIONS.upper() : MODEL_META_DATA_BUILD_OPTION,\r
225         TAB_INCLUDES.upper() : MODEL_EFI_INCLUDE,\r
226         TAB_LIBRARIES.upper() : MODEL_EFI_LIBRARY_INSTANCE,\r
227         TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS,\r
228         TAB_PACKAGES.upper() : MODEL_META_DATA_PACKAGE,\r
229         TAB_NMAKE.upper() : MODEL_META_DATA_NMAKE,\r
230         TAB_INF_FIXED_PCD.upper() : MODEL_PCD_FIXED_AT_BUILD,\r
231         TAB_INF_PATCH_PCD.upper() : MODEL_PCD_PATCHABLE_IN_MODULE,\r
232         TAB_INF_FEATURE_PCD.upper() : MODEL_PCD_FEATURE_FLAG,\r
233         TAB_INF_PCD_EX.upper() : MODEL_PCD_DYNAMIC_EX,\r
234         TAB_INF_PCD.upper() : MODEL_PCD_DYNAMIC,\r
235         TAB_SOURCES.upper() : MODEL_EFI_SOURCE_FILE,\r
236         TAB_GUIDS.upper() : MODEL_EFI_GUID,\r
237         TAB_PROTOCOLS.upper() : MODEL_EFI_PROTOCOL,\r
238         TAB_PPIS.upper() : MODEL_EFI_PPI,\r
239         TAB_DEPEX.upper() : MODEL_EFI_DEPEX,\r
240         TAB_BINARIES.upper() : MODEL_EFI_BINARY_FILE,\r
241         TAB_USER_EXTENSIONS.upper() : MODEL_META_DATA_USER_EXTENSION\r
242     }\r
243 \r
244     ## Constructor of InfParser\r
245     #\r
246     #  Initialize object of InfParser\r
247     #\r
248     #   @param      FilePath        The path of module description file\r
249     #   @param      FileType        The raw data of DSC file\r
250     #   @param      Table           Database used to retrieve module/package information\r
251     #   @param      Macros          Macros used for replacement in file\r
252     #\r
253     def __init__(self, FilePath, FileType, Table, Macros={}):\r
254         MetaFileParser.__init__(self, FilePath, FileType, Table, Macros)\r
255 \r
256     ## Parser starter\r
257     def Start(self):\r
258         try:\r
259             self._Content = open(self._FilePath, 'r').readlines()\r
260         except:\r
261             EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self._FilePath)\r
262 \r
263         # parse the file line by line\r
264         for Index in range(0, len(self._Content)):\r
265             Line = CleanString(self._Content[Index])\r
266             if Line == '':\r
267                 continue\r
268             self._CurrentLine = Line\r
269             self._LineIndex = Index\r
270 \r
271             # section header\r
272             if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:\r
273                 self._SectionHeaderParser()\r
274                 continue\r
275             elif Line.upper().startswith('DEFINE '):\r
276                 # file private macros\r
277                 self._MacroParser()\r
278                 continue\r
279 \r
280             # section content\r
281             self._ValueList = ['','','']\r
282             # parse current line, result will be put in self._ValueList\r
283             self._SectionParser[self._SectionType](self)\r
284             if self._ValueList == None:\r
285                 continue\r
286             # \r
287             # Model, Value1, Value2, Value3, Arch, Platform, BelongsToItem=-1, \r
288             # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1\r
289             # \r
290             for Arch, Platform in self._Scope:\r
291                 self._Store(self._SectionType,\r
292                             self._ValueList[0],\r
293                             self._ValueList[1],\r
294                             self._ValueList[2],\r
295                             Arch,\r
296                             Platform,\r
297                             self._Owner,\r
298                             self._LineIndex+1,\r
299                             -1,\r
300                             self._LineIndex+1,\r
301                             -1,\r
302                             0\r
303                             )\r
304         self._Done()\r
305 \r
306     ## [BuildOptions] section parser\r
307     def _BuildOptionParser(self):\r
308         TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)\r
309         TokenList2 = GetSplitValueList(TokenList[0], ':', 1)\r
310         if len(TokenList2) == 2:\r
311             self._ValueList[0] = TokenList2[0]\r
312             self._ValueList[1] = TokenList2[1]\r
313         else:\r
314             self._ValueList[1] = TokenList[0]\r
315         self._ValueList[2] = ReplaceMacro(TokenList[1], self._Macros)\r
316 \r
317     ## [nmake] section parser (R8.x style only)\r
318     def _NmakeParser(self):\r
319         TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)\r
320         self._ValueList[0:len(TokenList)] = TokenList\r
321         # remove self-reference in macro setting\r
322         self._ValueList[1] = ReplaceMacro(self._ValueList[1], {self._ValueList[0]:''})\r
323 \r
324     ## [FixedPcd], [FeaturePcd], [PatchPcd], [Pcd] and [PcdEx] sections parser\r
325     def _PcdParser(self):\r
326         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)\r
327         self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)\r
328         if len(TokenList) > 1:\r
329             self._ValueList[2] = TokenList[1]\r
330         if self._ValueList[0] == '' or self._ValueList[1] == '':\r
331             EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",\r
332                             ExtraData=self._CurrentLine, File=self._FilePath, Line=self._LineIndex+1)\r
333 \r
334     ## [depex] section parser\r
335     def _DepexParser(self):\r
336         self._ValueList[0:1] = [self._CurrentLine]\r
337 \r
338     _SectionParser = {\r
339         MODEL_UNKNOWN                   :   MetaFileParser._Skip,\r
340         MODEL_META_DATA_HEADER          :   MetaFileParser._DefineParser,\r
341         MODEL_META_DATA_BUILD_OPTION    :   _BuildOptionParser,\r
342         MODEL_EFI_INCLUDE               :   MetaFileParser._PathParser,     # for R8.x modules\r
343         MODEL_EFI_LIBRARY_INSTANCE      :   MetaFileParser._CommonParser,   # for R8.x modules\r
344         MODEL_EFI_LIBRARY_CLASS         :   MetaFileParser._PathParser,\r
345         MODEL_META_DATA_PACKAGE         :   MetaFileParser._PathParser,\r
346         MODEL_META_DATA_NMAKE           :   _NmakeParser,                   # for R8.x modules\r
347         MODEL_PCD_FIXED_AT_BUILD        :   _PcdParser,\r
348         MODEL_PCD_PATCHABLE_IN_MODULE   :   _PcdParser,\r
349         MODEL_PCD_FEATURE_FLAG          :   _PcdParser,\r
350         MODEL_PCD_DYNAMIC_EX            :   _PcdParser,\r
351         MODEL_PCD_DYNAMIC               :   _PcdParser,\r
352         MODEL_EFI_SOURCE_FILE           :   MetaFileParser._PathParser,\r
353         MODEL_EFI_GUID                  :   MetaFileParser._CommonParser,\r
354         MODEL_EFI_PROTOCOL              :   MetaFileParser._CommonParser,\r
355         MODEL_EFI_PPI                   :   MetaFileParser._CommonParser,\r
356         MODEL_EFI_DEPEX                 :   _DepexParser,\r
357         MODEL_EFI_BINARY_FILE           :   MetaFileParser._PathParser,\r
358         MODEL_META_DATA_USER_EXTENSION  :   MetaFileParser._Skip,\r
359     }\r
360 \r
361 ## DSC file parser class\r
362 #\r
363 #   @param      FilePath        The path of platform description file\r
364 #   @param      FileType        The raw data of DSC file\r
365 #   @param      Table           Database used to retrieve module/package information\r
366 #   @param      Macros          Macros used for replacement in file\r
367 #   @param      Owner           Owner ID (for sub-section parsing)\r
368 #   @param      From            ID from which the data comes (for !INCLUDE directive)\r
369 #\r
370 class DscParser(MetaFileParser):\r
371     # DSC file supported data types (one type per section)\r
372     DataType = {\r
373         TAB_SKUIDS.upper()                          :   MODEL_EFI_SKU_ID,\r
374         TAB_LIBRARIES.upper()                       :   MODEL_EFI_LIBRARY_INSTANCE,\r
375         TAB_LIBRARY_CLASSES.upper()                 :   MODEL_EFI_LIBRARY_CLASS,\r
376         TAB_BUILD_OPTIONS.upper()                   :   MODEL_META_DATA_BUILD_OPTION,\r
377         TAB_PCDS_FIXED_AT_BUILD_NULL.upper()        :   MODEL_PCD_FIXED_AT_BUILD,\r
378         TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper()   :   MODEL_PCD_PATCHABLE_IN_MODULE,\r
379         TAB_PCDS_FEATURE_FLAG_NULL.upper()          :   MODEL_PCD_FEATURE_FLAG,\r
380         TAB_PCDS_DYNAMIC_DEFAULT_NULL.upper()       :   MODEL_PCD_DYNAMIC_DEFAULT,\r
381         TAB_PCDS_DYNAMIC_HII_NULL.upper()           :   MODEL_PCD_DYNAMIC_HII,\r
382         TAB_PCDS_DYNAMIC_VPD_NULL.upper()           :   MODEL_PCD_DYNAMIC_VPD,\r
383         TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL.upper()    :   MODEL_PCD_DYNAMIC_EX_DEFAULT,\r
384         TAB_PCDS_DYNAMIC_EX_HII_NULL.upper()        :   MODEL_PCD_DYNAMIC_EX_HII,\r
385         TAB_PCDS_DYNAMIC_EX_VPD_NULL.upper()        :   MODEL_PCD_DYNAMIC_EX_VPD,\r
386         TAB_COMPONENTS.upper()                      :   MODEL_META_DATA_COMPONENT,\r
387         TAB_DSC_DEFINES.upper()                     :   MODEL_META_DATA_HEADER,\r
388         TAB_INCLUDE.upper()                         :   MODEL_META_DATA_INCLUDE,\r
389         TAB_IF.upper()                              :   MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,\r
390         TAB_IF_DEF.upper()                          :   MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,\r
391         TAB_IF_N_DEF.upper()                        :   MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF,\r
392         TAB_ELSE_IF.upper()                         :   MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF,\r
393         TAB_ELSE.upper()                            :   MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE,\r
394         TAB_END_IF.upper()                          :   MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF,\r
395     }\r
396 \r
397     # sections which allow "!include" directive\r
398     _IncludeAllowedSection = [\r
399         TAB_LIBRARIES.upper(), \r
400         TAB_LIBRARY_CLASSES.upper(), \r
401         TAB_SKUIDS.upper(),\r
402         TAB_COMPONENTS.upper(),\r
403         TAB_BUILD_OPTIONS.upper(),\r
404         TAB_PCDS_FIXED_AT_BUILD_NULL.upper(),\r
405         TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper(),\r
406         TAB_PCDS_FEATURE_FLAG_NULL.upper(),\r
407         TAB_PCDS_DYNAMIC_DEFAULT_NULL.upper(),\r
408         TAB_PCDS_DYNAMIC_HII_NULL.upper(),\r
409         TAB_PCDS_DYNAMIC_VPD_NULL.upper(),\r
410         TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL.upper(),\r
411         TAB_PCDS_DYNAMIC_EX_HII_NULL.upper(),\r
412         TAB_PCDS_DYNAMIC_EX_VPD_NULL.upper(),\r
413         ]\r
414 \r
415     # operators which can be used in "!if/!ifdef/!ifndef" directives\r
416     _OP_ = {\r
417         "!"     :   lambda a:   not a,\r
418         "!="    :   lambda a,b: a!=b,\r
419         "=="    :   lambda a,b: a==b,\r
420         ">"     :   lambda a,b: a>b,\r
421         "<"     :   lambda a,b: a<b,\r
422         "=>"    :   lambda a,b: a>=b,\r
423         ">="    :   lambda a,b: a>=b,\r
424         "<="    :   lambda a,b: a<=b,\r
425         "=<"    :   lambda a,b: a<=b,\r
426     }\r
427 \r
428     ## Constructor of DscParser\r
429     #\r
430     #  Initialize object of DscParser\r
431     #\r
432     #   @param      FilePath        The path of platform description file\r
433     #   @param      FileType        The raw data of DSC file\r
434     #   @param      Table           Database used to retrieve module/package information\r
435     #   @param      Macros          Macros used for replacement in file\r
436     #   @param      Owner           Owner ID (for sub-section parsing)\r
437     #   @param      From            ID from which the data comes (for !INCLUDE directive)\r
438     #\r
439     def __init__(self, FilePath, FileType, Table, Macros={}, Owner=-1, From=-1):\r
440         MetaFileParser.__init__(self, FilePath, FileType, Table, Macros, Owner, From)\r
441         # to store conditional directive evaluation result\r
442         self._Eval = Blist()\r
443 \r
444     ## Parser starter\r
445     def Start(self):\r
446         try:\r
447             if self._Content == None:\r
448                 self._Content = open(self._FilePath, 'r').readlines()\r
449         except:\r
450             EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self._FilePath)\r
451 \r
452         for Index in range(0, len(self._Content)):\r
453             Line = CleanString(self._Content[Index])\r
454             # skip empty line\r
455             if Line == '':\r
456                 continue\r
457             self._CurrentLine = Line\r
458             self._LineIndex = Index\r
459 \r
460             # section header\r
461             if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:\r
462                 self._SectionHeaderParser()\r
463                 continue\r
464             # subsection ending\r
465             elif Line[0] == '}':\r
466                 self._InSubsection = False\r
467                 self._Owner = -1\r
468                 continue\r
469             # subsection header\r
470             elif Line[0] == TAB_OPTION_START and Line[-1] == TAB_OPTION_END:\r
471                 self._SubsectionHeaderParser()\r
472                 continue\r
473             # directive line\r
474             elif Line[0] == '!':\r
475                 self._DirectiveParser()\r
476                 continue\r
477             # file private macros\r
478             elif Line.upper().startswith('DEFINE '):\r
479                 self._MacroParser()\r
480                 continue\r
481 \r
482             # section content\r
483             if self._InSubsection:\r
484                 SectionType = self._SubsectionType\r
485                 SectionName = self._SubsectionName\r
486                 if self._Owner == -1:\r
487                     self._Owner = self._LastItem\r
488             else:\r
489                 SectionType = self._SectionType\r
490                 SectionName = self._SectionName\r
491             self._ValueList = ['', '', '']\r
492             self._SectionParser[SectionType](self)\r
493             if self._ValueList == None:\r
494                 continue\r
495 \r
496             # \r
497             # Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1, \r
498             # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1\r
499             # \r
500             for Arch, ModuleType in self._Scope:\r
501                 self._LastItem = self._Store(\r
502                     SectionType,\r
503                     self._ValueList[0],\r
504                     self._ValueList[1],\r
505                     self._ValueList[2],\r
506                     Arch,\r
507                     ModuleType,\r
508                     self._Owner,\r
509                     self._From,\r
510                     self._LineIndex+1,\r
511                     -1,\r
512                     self._LineIndex+1,\r
513                     -1,\r
514                     self._Enabled\r
515                     )\r
516         self._Done()\r
517 \r
518     ## [defines] section parser\r
519     def _DefineParser(self):\r
520         TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)\r
521         if len(TokenList) < 2:\r
522             EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",\r
523                             ExtraData=self._CurrentLine, File=self._FilePath, Line=self._LineIndex+1)\r
524         # 'FLASH_DEFINITION', 'OUTPUT_DIRECTORY' need special processing\r
525         if TokenList[0] in ['FLASH_DEFINITION', 'OUTPUT_DIRECTORY']:\r
526             TokenList[1] = NormPath(TokenList[1], self._Macros)\r
527         self._ValueList[0:len(TokenList)] = TokenList    \r
528 \r
529     ## <subsection_header> parser\r
530     def _SubsectionHeaderParser(self):\r
531         self._SubsectionName = self._CurrentLine[1:-1].upper()\r
532         if self._SubsectionName in self.DataType:\r
533             self._SubsectionType = self.DataType[self._SubsectionName]\r
534         else:\r
535             self._SubsectionType = MODEL_UNKNOWN\r
536 \r
537     ## Directive statement parser\r
538     def _DirectiveParser(self):\r
539         self._ValueList = ['','','']\r
540         TokenList = GetSplitValueList(self._CurrentLine, ' ', 1)\r
541         self._ValueList[0:len(TokenList)] = TokenList\r
542         if self._ValueList[1] == '':\r
543             EdkLogger.error("Parser", FORMAT_INVALID, "Missing expression", \r
544                             File=self._FilePath, Line=self._LineIndex+1,\r
545                             ExtraData=self._CurrentLine)\r
546         DirectiveName = self._ValueList[0].upper()\r
547         # keep the directive in database first\r
548         self._LastItem = self._Store(\r
549             self.DataType[DirectiveName],\r
550             self._ValueList[0],\r
551             self._ValueList[1],\r
552             self._ValueList[2],\r
553             'COMMON',\r
554             'COMMON',\r
555             self._Owner,\r
556             self._LineIndex + 1,\r
557             -1,\r
558             self._LineIndex + 1,\r
559             -1,\r
560             0\r
561             )\r
562         # process the directive\r
563         if DirectiveName == "!INCLUDE":\r
564             if not self._SectionName in self._IncludeAllowedSection:\r
565                 EdkLogger.error("Parser", FORMAT_INVALID, File=self._FilePath, Line=self._LineIndex+1,\r
566                                 ExtraData="'!include' is not allowed under section [%s]" % self._SectionName)\r
567             # the included file must be relative to the parsing file\r
568             IncludedFile = os.path.join(self._FileDir, self._ValueList[1])\r
569             Parser = DscParser(IncludedFile, self._FileType, self._Table, self._Macros, From=self._LastItem)\r
570             # set the parser status with current status\r
571             Parser._SectionName = self._SectionName\r
572             Parser._SectionType = self._SectionType\r
573             Parser._Scope = self._Scope\r
574             Parser._Enabled = self._Enabled\r
575             try:\r
576                 Parser.Start()\r
577             except:\r
578                 EdkLogger.error("Parser", PARSER_ERROR, File=self._FilePath, Line=self._LineIndex+1,\r
579                                 ExtraData="Failed to parse content in file %s" % IncludedFile)\r
580             # update current status with sub-parser's status\r
581             self._SectionName = Parser._SectionName\r
582             self._SectionType = Parser._SectionType\r
583             self._Scope       = Parser._Scope\r
584             self._Enabled     = Parser._Enabled\r
585         else:\r
586             if DirectiveName in ["!IF", "!IFDEF", "!IFNDEF"]:\r
587                 # evaluate the expression\r
588                 Result = self._Evaluate(self._ValueList[1])\r
589                 if DirectiveName == "!IFNDEF":\r
590                     Result = not Result\r
591                 self._Eval.append(Result)\r
592             elif DirectiveName in ["!ELSEIF"]:\r
593                 # evaluate the expression\r
594                 self._Eval[-1] = (not self._Eval[-1]) & self._Evaluate(self._ValueList[1])\r
595             elif DirectiveName in ["!ELSE"]:\r
596                 self._Eval[-1] = not self._Eval[-1]\r
597             elif DirectiveName in ["!ENDIF"]:\r
598                 if len(self._Eval) > 0:\r
599                     self._Eval.pop()\r
600                 else:\r
601                     EdkLogger.error("Parser", FORMAT_INVALID, "!IF..[!ELSE]..!ENDIF doesn't match",\r
602                                     File=self._FilePath, Line=self._LineIndex+1)\r
603             if self._Eval.Result == False:\r
604                 self._Enabled = 0 - len(self._Eval)\r
605             else:\r
606                 self._Enabled = len(self._Eval)\r
607 \r
608     ## Evaludate the value of expression in "if/ifdef/ifndef" directives\r
609     def _Evaluate(self, Expression):\r
610         TokenList = Expression.split()\r
611         TokenNumber = len(TokenList)\r
612         # one operand, guess it's just a macro name\r
613         if TokenNumber == 1:\r
614             return TokenList[0] in self._Macros\r
615         # two operands, suppose it's "!xxx" format\r
616         elif TokenNumber == 2:\r
617             Op = TokenList[0]\r
618             if Op not in self._OP_:\r
619                 EdkLogger.error('Parser', FORMAT_INVALID, "Unsupported operator", File=self._FilePath,\r
620                                 Line=self._LineIndex+1, ExtraData=Expression)\r
621             if TokenList[1].upper() == 'TRUE':\r
622                 Value = True\r
623             else:\r
624                 Value = False\r
625             return self._OP_[Op](Value)\r
626         # three operands\r
627         elif TokenNumber == 3:\r
628             Name = TokenList[0]\r
629             if Name not in self._Macros:\r
630                 return False\r
631             Value = TokenList[2]\r
632             if Value[0] in ["'", '"']:\r
633                 Value = Value[1:-1]\r
634             Op = TokenList[1]\r
635             return self._OP_[Op](self._Macros[Macro], Value)\r
636         else:\r
637             EdkLogger.error('Parser', FORMAT_INVALID, File=self._FilePath, Line=self._LineIndex+1,\r
638                             ExtraData=Expression)\r
639 \r
640     ## [BuildOptions] section parser\r
641     def _BuildOptionParser(self):\r
642         TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)\r
643         TokenList2 = GetSplitValueList(TokenList[0], ':', 1)\r
644         if len(TokenList2) == 2:\r
645             self._ValueList[0] = TokenList2[0]\r
646             self._ValueList[1] = TokenList2[1]\r
647         else:\r
648             self._ValueList[1] = TokenList[0]\r
649         self._ValueList[2] = ReplaceMacro(TokenList[1], self._Macros)\r
650 \r
651     ## PCD sections parser \r
652     # \r
653     #   [PcdsFixedAtBuild]\r
654     #   [PcdsPatchableInModule]\r
655     #   [PcdsFeatureFlag]\r
656     #   [PcdsDynamicEx\r
657     #   [PcdsDynamicExDefault]\r
658     #   [PcdsDynamicExVpd]\r
659     #   [PcdsDynamicExHii]\r
660     #   [PcdsDynamic]\r
661     #   [PcdsDynamicDefault]\r
662     #   [PcdsDynamicVpd]\r
663     #   [PcdsDynamicHii]\r
664     # \r
665     def _PcdParser(self):\r
666         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)\r
667         self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)\r
668         self._ValueList[2] = TokenList[1]\r
669         if self._ValueList[0] == '' or self._ValueList[1] == '':\r
670             EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",\r
671                             ExtraData=self._CurrentLine, File=self._FilePath, Line=self._LineIndex+1)\r
672         if self._ValueList[2] == '':\r
673             EdkLogger.error('Parser', FORMAT_INVALID, "No PCD value given",\r
674                             ExtraData=self._CurrentLine, File=self._FilePath, Line=self._LineIndex+1)\r
675 \r
676     ## [components] section parser\r
677     def _ComponentParser(self):        \r
678         if self._CurrentLine[-1] == '{':\r
679             self._InSubsection = True\r
680             self._ValueList[0] = self._CurrentLine[0:-1].strip()\r
681         else:\r
682             self._ValueList[0] = self._CurrentLine\r
683         if len(self._Macros) > 0:\r
684             self._ValueList[0] = NormPath(self._ValueList[0], self._Macros)\r
685 \r
686     _SectionParser = {\r
687         MODEL_META_DATA_HEADER          :   MetaFileParser._DefineParser,\r
688         MODEL_EFI_SKU_ID                :   MetaFileParser._CommonParser,\r
689         MODEL_EFI_LIBRARY_INSTANCE      :   MetaFileParser._PathParser,\r
690         MODEL_EFI_LIBRARY_CLASS         :   MetaFileParser._PathParser,\r
691         MODEL_PCD_FIXED_AT_BUILD        :   _PcdParser,\r
692         MODEL_PCD_PATCHABLE_IN_MODULE   :   _PcdParser,\r
693         MODEL_PCD_FEATURE_FLAG          :   _PcdParser,\r
694         MODEL_PCD_DYNAMIC_DEFAULT       :   _PcdParser,\r
695         MODEL_PCD_DYNAMIC_HII           :   _PcdParser,\r
696         MODEL_PCD_DYNAMIC_VPD           :   _PcdParser,\r
697         MODEL_PCD_DYNAMIC_EX_DEFAULT    :   _PcdParser,\r
698         MODEL_PCD_DYNAMIC_EX_HII        :   _PcdParser,\r
699         MODEL_PCD_DYNAMIC_EX_VPD        :   _PcdParser,\r
700         MODEL_META_DATA_COMPONENT       :   _ComponentParser,\r
701         MODEL_META_DATA_BUILD_OPTION    :   _BuildOptionParser,\r
702         MODEL_UNKNOWN                   :   MetaFileParser._Skip,\r
703         MODEL_META_DATA_USER_EXTENSION  :   MetaFileParser._Skip,\r
704     }\r
705 \r
706 ## DEC file parser class\r
707 #\r
708 #   @param      FilePath        The path of platform description file\r
709 #   @param      FileType        The raw data of DSC file\r
710 #   @param      Table           Database used to retrieve module/package information\r
711 #   @param      Macros          Macros used for replacement in file\r
712 #\r
713 class DecParser(MetaFileParser):\r
714     # DEC file supported data types (one type per section)\r
715     DataType = {\r
716         TAB_DEC_DEFINES.upper()                     :   MODEL_META_DATA_HEADER,\r
717         TAB_INCLUDES.upper()                        :   MODEL_EFI_INCLUDE,\r
718         TAB_LIBRARY_CLASSES.upper()                 :   MODEL_EFI_LIBRARY_CLASS,\r
719         TAB_GUIDS.upper()                           :   MODEL_EFI_GUID,\r
720         TAB_PPIS.upper()                            :   MODEL_EFI_PPI,\r
721         TAB_PROTOCOLS.upper()                       :   MODEL_EFI_PROTOCOL,\r
722         TAB_PCDS_FIXED_AT_BUILD_NULL.upper()        :   MODEL_PCD_FIXED_AT_BUILD,\r
723         TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper()   :   MODEL_PCD_PATCHABLE_IN_MODULE,\r
724         TAB_PCDS_FEATURE_FLAG_NULL.upper()          :   MODEL_PCD_FEATURE_FLAG,\r
725         TAB_PCDS_DYNAMIC_NULL.upper()               :   MODEL_PCD_DYNAMIC,\r
726         TAB_PCDS_DYNAMIC_EX_NULL.upper()            :   MODEL_PCD_DYNAMIC_EX,\r
727     }\r
728 \r
729     ## Constructor of DecParser\r
730     #\r
731     #  Initialize object of DecParser\r
732     #\r
733     #   @param      FilePath        The path of platform description file\r
734     #   @param      FileType        The raw data of DSC file\r
735     #   @param      Table           Database used to retrieve module/package information\r
736     #   @param      Macros          Macros used for replacement in file\r
737     #\r
738     def __init__(self, FilePath, FileType, Table, Macro={}):\r
739         MetaFileParser.__init__(self, FilePath, FileType, Table, Macro, -1)\r
740 \r
741     ## Parser starter\r
742     def Start(self):\r
743         try:\r
744             if self._Content == None:\r
745                 self._Content = open(self._FilePath, 'r').readlines()\r
746         except:\r
747             EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self._FilePath)\r
748 \r
749         for Index in range(0, len(self._Content)):\r
750             Line = CleanString(self._Content[Index])\r
751             # skip empty line\r
752             if Line == '':\r
753                 continue\r
754             self._CurrentLine = Line\r
755             self._LineIndex = Index\r
756 \r
757             # section header\r
758             if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:\r
759                 self._SectionHeaderParser()\r
760                 continue\r
761             elif Line.startswith('DEFINE '):\r
762                 self._MacroParser()\r
763                 continue\r
764 \r
765             # section content\r
766             self._ValueList = ['','','']\r
767             self._SectionParser[self._SectionType](self)\r
768             if self._ValueList == None:\r
769                 continue\r
770 \r
771             # \r
772             # Model, Value1, Value2, Value3, Arch, BelongsToItem=-1, LineBegin=-1, \r
773             # ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, FeatureFlag='', Enabled=-1\r
774             # \r
775             for Arch, ModuleType in self._Scope:\r
776                 self._LastItem = self._Store(\r
777                     self._SectionType,\r
778                     self._ValueList[0],\r
779                     self._ValueList[1],\r
780                     self._ValueList[2],\r
781                     Arch,\r
782                     ModuleType,\r
783                     self._Owner,\r
784                     self._LineIndex+1,\r
785                     -1,\r
786                     self._LineIndex+1,\r
787                     -1,\r
788                     0\r
789                     )\r
790         self._Done()\r
791 \r
792     ## [guids], [ppis] and [protocols] section parser\r
793     def _GuidParser(self):\r
794         TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)\r
795         if len(TokenList) < 2:\r
796             EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",\r
797                             ExtraData=self._CurrentLine, File=self._FilePath, Line=self._LineIndex+1)\r
798         self._ValueList[0] = TokenList[0]\r
799         self._ValueList[1] = TokenList[1]\r
800 \r
801     ## PCD sections parser \r
802     # \r
803     #   [PcdsFixedAtBuild]\r
804     #   [PcdsPatchableInModule]\r
805     #   [PcdsFeatureFlag]\r
806     #   [PcdsDynamicEx\r
807     #   [PcdsDynamic]\r
808     # \r
809     def _PcdParser(self):\r
810         TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)\r
811         self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)\r
812         self._ValueList[2] = TokenList[1]\r
813         if self._ValueList[0] == '' or self._ValueList[1] == '':\r
814             EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",\r
815                             ExtraData=self._CurrentLine, File=self._FilePath, Line=self._LineIndex+1)\r
816         if self._ValueList[2] == '':\r
817             EdkLogger.error('Parser', FORMAT_INVALID, "No PCD Datum information given",\r
818                             ExtraData=self._CurrentLine, File=self._FilePath, Line=self._LineIndex+1)\r
819 \r
820     _SectionParser = {\r
821         MODEL_META_DATA_HEADER          :   MetaFileParser._DefineParser,\r
822         MODEL_EFI_INCLUDE               :   MetaFileParser._PathParser,\r
823         MODEL_EFI_LIBRARY_CLASS         :   MetaFileParser._PathParser,\r
824         MODEL_EFI_GUID                  :   _GuidParser,\r
825         MODEL_EFI_PPI                   :   _GuidParser,\r
826         MODEL_EFI_PROTOCOL              :   _GuidParser,\r
827         MODEL_PCD_FIXED_AT_BUILD        :   _PcdParser,\r
828         MODEL_PCD_PATCHABLE_IN_MODULE   :   _PcdParser,\r
829         MODEL_PCD_FEATURE_FLAG          :   _PcdParser,\r
830         MODEL_PCD_DYNAMIC               :   _PcdParser,\r
831         MODEL_PCD_DYNAMIC_EX            :   _PcdParser,\r
832         MODEL_UNKNOWN                   :   MetaFileParser._Skip,\r
833         MODEL_META_DATA_USER_EXTENSION  :   MetaFileParser._Skip,\r
834     }\r
835 \r
836 ##\r
837 #\r
838 # This acts like the main() function for the script, unless it is 'import'ed into another\r
839 # script.\r
840 #\r
841 if __name__ == '__main__':\r
842     pass\r
843 \r