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