## @file
# This file is used to parse meta files
#
-# Copyright (c) 2008, Intel Corporation
-# All rights reserved. This program and the accompanying materials
+# Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
import os
import time
+import copy
import Common.EdkLogger as EdkLogger
from CommonDataClass.DataClass import *
# data type (file content) for specific file type
DataType = {}
+ # Parser objects used to implement singleton
+ MetaFiles = {}
+
+ ## Factory method
+ #
+ # One file, one parser object. This factory method makes sure that there's
+ # only one object constructed for one meta file.
+ #
+ # @param Class class object of real AutoGen class
+ # (InfParser, DecParser or DscParser)
+ # @param FilePath The path of meta file
+ # @param *args The specific class related parameters
+ # @param **kwargs The specific class related dict parameters
+ #
+ def __new__(Class, FilePath, *args, **kwargs):
+ if FilePath in Class.MetaFiles:
+ return Class.MetaFiles[FilePath]
+ else:
+ ParserObject = super(MetaFileParser, Class).__new__(Class)
+ Class.MetaFiles[FilePath] = ParserObject
+ return ParserObject
+
## Constructor of MetaFileParser
#
# Initialize object of MetaFileParser
# @param From ID from which the data comes (for !INCLUDE directive)
#
def __init__(self, FilePath, FileType, Table, Macros=None, Owner=-1, From=-1):
+ # prevent re-initialization
+ if hasattr(self, "_Table"):
+ return
self._Table = Table
self._FileType = FileType
self.MetaFile = FilePath
self._FileDir = os.path.dirname(self.MetaFile)
- self._Macros = {}
+ self._Macros = copy.copy(Macros)
+ self._Macros["WORKSPACE"] = os.environ["WORKSPACE"]
# for recursive parsing
self._Owner = Owner
## Set parsing complete flag in both class and table
def _Done(self):
self._Finished = True
- self._Table.SetEndFlag()
+ ## Do not set end flag when processing included files
+ if self._From == -1:
+ self._Table.SetEndFlag()
## Return the table containg parsed data
#
if TokenList[0] == '':
EdkLogger.error('Parser', FORMAT_INVALID, "No macro name given",
ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
- if len(TokenList) == 1:
- self._Macros[TokenList[0]] = ''
- else:
- # keep the macro definition for later use
- self._Macros[TokenList[0]] = ReplaceMacro(TokenList[1], self._Macros, False)
+
+ # Macros defined in the command line override ones defined in the meta-data file
+ if not TokenList[0] in self._Macros:
+ if len(TokenList) == 1:
+ self._Macros[TokenList[0]] = ''
+ else:
+ # keep the macro definition for later use
+ self._Macros[TokenList[0]] = ReplaceMacro(TokenList[1], self._Macros, False)
return TokenList[0], self._Macros[TokenList[0]]
-1,
0
)
+ if IsFindBlockComment:
+ EdkLogger.error("Parser", FORMAT_INVALID, "Open block comments (starting with /*) are expected to end with */",
+ File=self.MetaFile)
self._Done()
## Data parser for the format in which there's path
## [FixedPcd], [FeaturePcd], [PatchPcd], [Pcd] and [PcdEx] sections parser
def _PcdParser(self):
TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
- self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
+ ValueList = GetSplitValueList(TokenList[0], TAB_SPLIT)
+ if len(ValueList) != 2:
+ EdkLogger.error('Parser', FORMAT_INVALID, "Illegal token space GUID and PCD name format",
+ ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<PcdCName>)",
+ File=self.MetaFile, Line=self._LineIndex+1)
+ self._ValueList[0:1] = ValueList
if len(TokenList) > 1:
self._ValueList[2] = TokenList[1]
if self._ValueList[0] == '' or self._ValueList[1] == '':
# sections which allow "!include" directive
_IncludeAllowedSection = [
+ TAB_COMMON_DEFINES.upper(),
TAB_LIBRARIES.upper(),
TAB_LIBRARY_CLASSES.upper(),
TAB_SKUIDS.upper(),
continue
self._CurrentLine = Line
self._LineIndex = Index
-
+ if self._InSubsection and self._Owner == -1:
+ self._Owner = self._LastItem
+
# section header
if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
self._SectionHeaderParser()
continue
# file private macros
elif Line.upper().startswith('DEFINE '):
- self._MacroParser()
+ (Name, Value) = self._MacroParser()
+ # Make the defined macro in DSC [Defines] section also
+ # available for FDF file.
+ if self._SectionName == TAB_COMMON_DEFINES.upper():
+ self._LastItem = self._Store(
+ MODEL_META_DATA_GLOBAL_DEFINE,
+ Name,
+ Value,
+ '',
+ 'COMMON',
+ 'COMMON',
+ self._Owner,
+ self._From,
+ self._LineIndex+1,
+ -1,
+ self._LineIndex+1,
+ -1,
+ self._Enabled
+ )
continue
elif Line.upper().startswith('EDK_GLOBAL '):
(Name, Value) = self._MacroParser()
if self._InSubsection:
SectionType = self._SubsectionType
SectionName = self._SubsectionName
- if self._Owner == -1:
- self._Owner = self._LastItem
else:
SectionType = self._SectionType
SectionName = self._SectionName
if TokenList[0] in ['FLASH_DEFINITION', 'OUTPUT_DIRECTORY']:
TokenList[1] = NormPath(TokenList[1], self._Macros)
self._ValueList[0:len(TokenList)] = TokenList
+ # Treat elements in the [defines] section as global macros for FDF file.
+ self._LastItem = self._Store(
+ MODEL_META_DATA_GLOBAL_DEFINE,
+ TokenList[0],
+ TokenList[1],
+ '',
+ 'COMMON',
+ 'COMMON',
+ self._Owner,
+ self._From,
+ self._LineIndex+1,
+ -1,
+ self._LineIndex+1,
+ -1,
+ self._Enabled
+ )
## <subsection_header> parser
def _SubsectionHeaderParser(self):
EdkLogger.error("Parser", FORMAT_INVALID, File=self.MetaFile, Line=self._LineIndex+1,
ExtraData="'!include' is not allowed under section [%s]" % self._SectionName)
# the included file must be relative to the parsing file
- IncludedFile = os.path.join(self._FileDir, self._ValueList[1])
+ IncludedFile = os.path.join(self._FileDir, NormPath(self._ValueList[1], self._Macros))
Parser = DscParser(IncludedFile, self._FileType, self._Table, self._Macros, From=self._LastItem)
# set the parser status with current status
Parser._SectionName = self._SectionName
except:
EdkLogger.error("Parser", PARSER_ERROR, File=self.MetaFile, Line=self._LineIndex+1,
ExtraData="Failed to parse content in file %s" % IncludedFile)
+ # insert an imaginary token in the DSC table to indicate its external dependency on another file
+ self._Store(MODEL_EXTERNAL_DEPENDENCY, IncludedFile, str(os.stat(IncludedFile)[8]), "")
# update current status with sub-parser's status
self._SectionName = Parser._SectionName
self._SectionType = Parser._SectionType
self._Scope = Parser._Scope
self._Enabled = Parser._Enabled
+ self._Macros.update(Parser._Macros)
else:
if DirectiveName in ["!IF", "!IFDEF", "!IFNDEF"]:
# evaluate the expression
else:
self._Enabled = len(self._Eval)
- ## Evaludate the value of expression in "if/ifdef/ifndef" directives
+ ## Evaluate the Token for its value; for now only macros are supported.
+ def _EvaluateToken(self, TokenName, Expression):
+ if TokenName.startswith("$(") and TokenName.endswith(")"):
+ Name = TokenName[2:-1]
+ return self._Macros.get(Name)
+ else:
+ EdkLogger.error('Parser', FORMAT_INVALID, "Unknown operand '%(Token)s', "
+ "please use '$(%(Token)s)' if '%(Token)s' is a macro" % {"Token" : TokenName},
+ File=self.MetaFile, Line=self._LineIndex+1, ExtraData=Expression)
+
+ ## Evaluate the value of expression in "if/ifdef/ifndef" directives
def _Evaluate(self, Expression):
TokenList = Expression.split()
TokenNumber = len(TokenList)
# one operand, guess it's just a macro name
if TokenNumber == 1:
- return TokenList[0] in self._Macros
+ TokenValue = self._EvaluateToken(TokenList[0], Expression)
+ return TokenValue != None
# two operands, suppose it's "!xxx" format
elif TokenNumber == 2:
Op = TokenList[0]
return self._OP_[Op](Value)
# three operands
elif TokenNumber == 3:
- Name = TokenList[0]
- if Name not in self._Macros:
+ TokenValue = self._EvaluateToken(TokenList[0], Expression)
+ if TokenValue == None:
return False
Value = TokenList[2]
if Value[0] in ["'", '"'] and Value[-1] in ["'", '"']:
if Op not in self._OP_:
EdkLogger.error('Parser', FORMAT_INVALID, "Unsupported operator [%s]" % Op, File=self.MetaFile,
Line=self._LineIndex+1, ExtraData=Expression)
- return self._OP_[Op](self._Macros[Name], Value)
+ return self._OP_[Op](TokenValue, Value)
else:
EdkLogger.error('Parser', FORMAT_INVALID, File=self.MetaFile, Line=self._LineIndex+1,
ExtraData=Expression)
# [PcdsDynamicHii]
#
def _PcdParser(self):
- TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
+ TokenList = GetSplitValueList(ReplaceMacro(self._CurrentLine, self._Macros), TAB_VALUE_SPLIT, 1)
self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
if len(TokenList) == 2:
self._ValueList[2] = TokenList[1]
#
def __init__(self, FilePath, FileType, Table, Macro=None):
MetaFileParser.__init__(self, FilePath, FileType, Table, Macro, -1)
+ self._Comments = []
## Parser starter
def Start(self):
EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
for Index in range(0, len(self._Content)):
- Line = CleanString(self._Content[Index])
+ Line, Comment = CleanString2(self._Content[Index])
+ self._CurrentLine = Line
+ self._LineIndex = Index
+
+ # save comment for later use
+ if Comment:
+ self._Comments.append((Comment, self._LineIndex+1))
# skip empty line
if Line == '':
continue
- self._CurrentLine = Line
- self._LineIndex = Index
# section header
if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
self._SectionHeaderParser()
+ self._Comments = []
continue
elif Line.startswith('DEFINE '):
self._MacroParser()
continue
elif len(self._SectionType) == 0:
+ self._Comments = []
continue
# section content
self._ValueList = ['','','']
self._SectionParser[self._SectionType[0]](self)
if self._ValueList == None:
+ self._Comments = []
continue
#
-1,
0
)
+ for Comment, LineNo in self._Comments:
+ self._Store(
+ MODEL_META_DATA_COMMENT,
+ Comment,
+ self._ValueList[0],
+ self._ValueList[1],
+ Arch,
+ ModuleType,
+ self._LastItem,
+ LineNo,
+ -1,
+ LineNo,
+ -1,
+ 0
+ )
+ self._Comments = []
self._Done()
## Section header parser
if not IsValid:
EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine,
File=self.MetaFile, Line=self._LineIndex+1)
- self._ValueList[2] = TokenList[1]
+
+ self._ValueList[2] = ValueList[0].strip() + '|' + ValueList[1].strip() + '|' + ValueList[2].strip()
_SectionParser = {
MODEL_META_DATA_HEADER : MetaFileParser._DefineParser,