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