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