mirror of https://github.com/acidanthera/audk.git
990 lines
38 KiB
Python
990 lines
38 KiB
Python
|
## @file
|
||
|
# This file is used to parse DEC file. It will consumed by DecParser
|
||
|
#
|
||
|
# Copyright (c) 2011, 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
|
||
|
#
|
||
|
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||
|
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||
|
'''
|
||
|
DecParser
|
||
|
'''
|
||
|
## Import modules
|
||
|
#
|
||
|
import Logger.Log as Logger
|
||
|
from Logger.ToolError import FILE_PARSE_FAILURE
|
||
|
from Logger.ToolError import FILE_OPEN_FAILURE
|
||
|
from Logger import StringTable as ST
|
||
|
|
||
|
import Library.DataType as DT
|
||
|
from Library.ParserValidate import IsValidToken
|
||
|
from Library.ParserValidate import IsValidPath
|
||
|
from Library.ParserValidate import IsValidCFormatGuid
|
||
|
from Library.ParserValidate import IsValidIdString
|
||
|
from Library.ParserValidate import IsValidUserId
|
||
|
from Library.ParserValidate import IsValidArch
|
||
|
from Library.ParserValidate import IsValidWord
|
||
|
from Parser.DecParserMisc import TOOL_NAME
|
||
|
from Parser.DecParserMisc import CleanString
|
||
|
from Parser.DecParserMisc import IsValidPcdDatum
|
||
|
from Parser.DecParserMisc import ParserHelper
|
||
|
from Parser.DecParserMisc import StripRoot
|
||
|
from Parser.DecParserMisc import VERSION_PATTERN
|
||
|
from Parser.DecParserMisc import CVAR_PATTERN
|
||
|
from Parser.DecParserMisc import PCD_TOKEN_PATTERN
|
||
|
from Parser.DecParserMisc import MACRO_PATTERN
|
||
|
from Parser.DecParserMisc import FileContent
|
||
|
from Object.Parser.DecObject import _DecComments
|
||
|
from Object.Parser.DecObject import DecDefineObject
|
||
|
from Object.Parser.DecObject import DecDefineItemObject
|
||
|
from Object.Parser.DecObject import DecIncludeObject
|
||
|
from Object.Parser.DecObject import DecIncludeItemObject
|
||
|
from Object.Parser.DecObject import DecLibraryclassObject
|
||
|
from Object.Parser.DecObject import DecLibraryclassItemObject
|
||
|
from Object.Parser.DecObject import DecGuidObject
|
||
|
from Object.Parser.DecObject import DecPpiObject
|
||
|
from Object.Parser.DecObject import DecProtocolObject
|
||
|
from Object.Parser.DecObject import DecGuidItemObject
|
||
|
from Object.Parser.DecObject import DecUserExtensionObject
|
||
|
from Object.Parser.DecObject import DecUserExtensionItemObject
|
||
|
from Object.Parser.DecObject import DecPcdObject
|
||
|
from Object.Parser.DecObject import DecPcdItemObject
|
||
|
from Library.Misc import GuidStructureStringToGuidString
|
||
|
from Library.Misc import CheckGuidRegFormat
|
||
|
from Library.String import ReplaceMacro
|
||
|
from Library.String import GetSplitValueList
|
||
|
from Library.String import gMACRO_PATTERN
|
||
|
from Library.String import ConvertSpecialChar
|
||
|
|
||
|
##
|
||
|
# _DecBase class for parsing
|
||
|
#
|
||
|
class _DecBase:
|
||
|
def __init__(self, RawData):
|
||
|
self._RawData = RawData
|
||
|
self._ItemDict = {}
|
||
|
self._LocalMacro = {}
|
||
|
#
|
||
|
# Data parsed by 'self' are saved to this object
|
||
|
#
|
||
|
self.ItemObject = None
|
||
|
|
||
|
def GetDataObject(self):
|
||
|
return self.ItemObject
|
||
|
|
||
|
## BlockStart
|
||
|
#
|
||
|
# Called if a new section starts
|
||
|
#
|
||
|
def BlockStart(self):
|
||
|
self._LocalMacro = {}
|
||
|
|
||
|
## _CheckReDefine
|
||
|
#
|
||
|
# @param Key: to be checked if multi-defined
|
||
|
# @param Scope: Format: [[SectionName, Arch], ...].
|
||
|
# If scope is none, use global scope
|
||
|
#
|
||
|
def _CheckReDefine(self, Key, Scope = None):
|
||
|
if not Scope:
|
||
|
Scope = self._RawData.CurrentScope
|
||
|
return
|
||
|
|
||
|
SecArch = []
|
||
|
#
|
||
|
# Copy scope to SecArch, avoid Scope be changed outside
|
||
|
#
|
||
|
SecArch[0:1] = Scope[:]
|
||
|
if Key not in self._ItemDict:
|
||
|
self._ItemDict[Key] = [[SecArch, self._RawData.LineIndex]]
|
||
|
return
|
||
|
|
||
|
for Value in self._ItemDict[Key]:
|
||
|
for SubValue in Scope:
|
||
|
#
|
||
|
# If current is common section
|
||
|
#
|
||
|
if SubValue[-1] == 'COMMON':
|
||
|
for Other in Value[0]:
|
||
|
# Key in common cannot be redefined in other arches
|
||
|
# [:-1] means stripping arch info
|
||
|
if Other[:-1] == SubValue[:-1]:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_REDEFINE % (Key, Value[1]))
|
||
|
return
|
||
|
continue
|
||
|
CommonScope = []
|
||
|
CommonScope[0:1] = SubValue
|
||
|
CommonScope[-1] = 'COMMON'
|
||
|
#
|
||
|
# Cannot be redefined if this key already defined in COMMON Or defined in same arch
|
||
|
#
|
||
|
if SubValue in Value[0] or CommonScope in Value[0]:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_REDEFINE % (Key, Value[1]))
|
||
|
return
|
||
|
self._ItemDict[Key].append([SecArch, self._RawData.LineIndex])
|
||
|
|
||
|
## CheckRequiredFields
|
||
|
# Some sections need to check if some fields exist, define section for example
|
||
|
# Derived class can re-implement, top parser will call this function after all parsing done
|
||
|
#
|
||
|
def CheckRequiredFields(self):
|
||
|
if self._RawData:
|
||
|
pass
|
||
|
return True
|
||
|
|
||
|
## IsItemRequired
|
||
|
# In DEC spec, sections must have at least one statement except user
|
||
|
# extension.
|
||
|
# For example: "[guids" [<attribs>] "]" <EOL> <statements>+
|
||
|
# sub class can override this method to indicate if statement is a must.
|
||
|
#
|
||
|
def _IsStatementRequired(self):
|
||
|
if self._RawData:
|
||
|
pass
|
||
|
return False
|
||
|
|
||
|
def _LoggerError(self, ErrorString):
|
||
|
Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename,
|
||
|
Line = self._RawData.LineIndex,
|
||
|
ExtraData=ErrorString + ST.ERR_DECPARSE_LINE % self._RawData.CurrentLine)
|
||
|
|
||
|
def _ReplaceMacro(self, String):
|
||
|
if gMACRO_PATTERN.findall(String):
|
||
|
String = ReplaceMacro(String, self._LocalMacro, False,
|
||
|
FileName = self._RawData.Filename,
|
||
|
Line = ['', self._RawData.LineIndex])
|
||
|
String = ReplaceMacro(String, self._RawData.Macros, False,
|
||
|
FileName = self._RawData.Filename,
|
||
|
Line = ['', self._RawData.LineIndex])
|
||
|
MacroUsed = gMACRO_PATTERN.findall(String)
|
||
|
if MacroUsed:
|
||
|
Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE,
|
||
|
File=self._RawData.Filename,
|
||
|
Line = self._RawData.LineIndex,
|
||
|
ExtraData = ST.ERR_DECPARSE_MACRO_RESOLVE % (str(MacroUsed), String))
|
||
|
return String
|
||
|
|
||
|
def _MacroParser(self, String):
|
||
|
TokenList = GetSplitValueList(String, ' ', 1)
|
||
|
if len(TokenList) < 2 or TokenList[1] == '':
|
||
|
self._LoggerError(ST.ERR_DECPARSE_MACRO_PAIR)
|
||
|
|
||
|
TokenList = GetSplitValueList(TokenList[1], DT.TAB_EQUAL_SPLIT, 1)
|
||
|
if TokenList[0] == '':
|
||
|
self._LoggerError(ST.ERR_DECPARSE_MACRO_NAME)
|
||
|
elif not IsValidToken(MACRO_PATTERN, TokenList[0]):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_MACRO_NAME_UPPER % TokenList[0])
|
||
|
|
||
|
if len(TokenList) == 1:
|
||
|
self._LocalMacro[TokenList[0]] = ''
|
||
|
else:
|
||
|
self._LocalMacro[TokenList[0]] = self._ReplaceMacro(TokenList[1])
|
||
|
|
||
|
## _ParseItem
|
||
|
#
|
||
|
# Parse specified item, this function must be derived by subclass
|
||
|
#
|
||
|
def _ParseItem(self):
|
||
|
if self._RawData:
|
||
|
pass
|
||
|
#
|
||
|
# Should never be called
|
||
|
#
|
||
|
return None
|
||
|
|
||
|
|
||
|
## _TailCommentStrategy
|
||
|
#
|
||
|
# This function can be derived to parse tail comment
|
||
|
# default is it will not consume any lines
|
||
|
#
|
||
|
# @param Comment: Comment of current line
|
||
|
#
|
||
|
def _TailCommentStrategy(self, Comment):
|
||
|
if Comment:
|
||
|
pass
|
||
|
if self._RawData:
|
||
|
pass
|
||
|
return False
|
||
|
|
||
|
## _StopCurrentParsing
|
||
|
#
|
||
|
# Called in Parse if current parsing should be stopped when encounter some
|
||
|
# keyword
|
||
|
# Default is section start and end
|
||
|
#
|
||
|
# @param Line: Current line
|
||
|
#
|
||
|
def _StopCurrentParsing(self, Line):
|
||
|
if self._RawData:
|
||
|
pass
|
||
|
return Line[0] == DT.TAB_SECTION_START and Line[-1] == DT.TAB_SECTION_END
|
||
|
|
||
|
## _TryBackSlash
|
||
|
#
|
||
|
# Split comment and DEC content, concatenate lines if end of char is '\'
|
||
|
#
|
||
|
# @param ProcessedLine: ProcessedLine line
|
||
|
# @param ProcessedComments: ProcessedComments line
|
||
|
#
|
||
|
def _TryBackSlash(self, ProcessedLine, ProcessedComments):
|
||
|
CatLine = ''
|
||
|
Comment = ''
|
||
|
Line = ProcessedLine
|
||
|
CommentList = ProcessedComments
|
||
|
while not self._RawData.IsEndOfFile():
|
||
|
if Line == '':
|
||
|
self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY)
|
||
|
break
|
||
|
|
||
|
if Comment:
|
||
|
CommentList.append((Comment, self._RawData.LineIndex))
|
||
|
if Line[-1] != DT.TAB_SLASH:
|
||
|
CatLine += Line
|
||
|
break
|
||
|
elif len(Line) < 2 or Line[-2] != ' ':
|
||
|
self._LoggerError(ST.ERR_DECPARSE_BACKSLASH)
|
||
|
else:
|
||
|
CatLine += Line[:-1]
|
||
|
Line, Comment = CleanString(self._RawData.GetNextLine())
|
||
|
#
|
||
|
# Reach end of content
|
||
|
#
|
||
|
if self._RawData.IsEndOfFile():
|
||
|
if not CatLine:
|
||
|
if ProcessedLine[-1] == DT.TAB_SLASH:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY)
|
||
|
CatLine = ProcessedLine
|
||
|
else:
|
||
|
if not Line or Line[-1] == DT.TAB_SLASH:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_BACKSLASH_EMPTY)
|
||
|
CatLine += Line
|
||
|
|
||
|
self._RawData.CurrentLine = self._ReplaceMacro(CatLine)
|
||
|
return CatLine, CommentList
|
||
|
|
||
|
## Parse
|
||
|
# This is a template method in which other member functions which might
|
||
|
# override by sub class are called. It is responsible for reading file
|
||
|
# line by line, and call other member functions to parse. This function
|
||
|
# should not be re-implement by sub class.
|
||
|
#
|
||
|
def Parse(self):
|
||
|
HeadComments = []
|
||
|
TailComments = []
|
||
|
|
||
|
#======================================================================
|
||
|
# CurComments may pointer to HeadComments or TailComments
|
||
|
#======================================================================
|
||
|
CurComments = HeadComments
|
||
|
CurObj = None
|
||
|
ItemNum = 0
|
||
|
FromBuf = False
|
||
|
|
||
|
#======================================================================
|
||
|
# Used to report error information if empty section found
|
||
|
#======================================================================
|
||
|
Index = self._RawData.LineIndex
|
||
|
LineStr = self._RawData.CurrentLine
|
||
|
while not self._RawData.IsEndOfFile() or self._RawData.NextLine:
|
||
|
if self._RawData.NextLine:
|
||
|
#==============================================================
|
||
|
# Have processed line in buffer
|
||
|
#==============================================================
|
||
|
Line = self._RawData.NextLine
|
||
|
HeadComments.extend(self._RawData.HeadComment)
|
||
|
TailComments.extend(self._RawData.TailComment)
|
||
|
self._RawData.ResetNext()
|
||
|
Comment = ''
|
||
|
FromBuf = True
|
||
|
else:
|
||
|
#==============================================================
|
||
|
# No line in buffer, read next line
|
||
|
#==============================================================
|
||
|
Line, Comment = CleanString(self._RawData.GetNextLine())
|
||
|
FromBuf = False
|
||
|
if Line:
|
||
|
if not FromBuf and CurObj and TailComments:
|
||
|
#==========================================================
|
||
|
# Set tail comments to previous statement if not empty.
|
||
|
#==========================================================
|
||
|
CurObj.SetTailComment(CurObj.GetTailComment()+TailComments)
|
||
|
|
||
|
if not FromBuf:
|
||
|
del TailComments[:]
|
||
|
CurComments = TailComments
|
||
|
Comments = []
|
||
|
if Comment:
|
||
|
Comments = [(Comment, self._RawData.LineIndex)]
|
||
|
|
||
|
#==============================================================
|
||
|
# Try if last char of line has backslash
|
||
|
#==============================================================
|
||
|
Line, Comments = self._TryBackSlash(Line, Comments)
|
||
|
CurComments.extend(Comments)
|
||
|
|
||
|
#==============================================================
|
||
|
# Macro found
|
||
|
#==============================================================
|
||
|
if Line.startswith('DEFINE '):
|
||
|
self._MacroParser(Line)
|
||
|
del HeadComments[:]
|
||
|
del TailComments[:]
|
||
|
CurComments = HeadComments
|
||
|
continue
|
||
|
|
||
|
if self._StopCurrentParsing(Line):
|
||
|
#==========================================================
|
||
|
# This line does not belong to this parse,
|
||
|
# Save it, can be used by next parse
|
||
|
#==========================================================
|
||
|
self._RawData.SetNext(Line, HeadComments, TailComments)
|
||
|
break
|
||
|
|
||
|
Obj = self._ParseItem()
|
||
|
ItemNum += 1
|
||
|
if Obj:
|
||
|
Obj.SetHeadComment(Obj.GetHeadComment()+HeadComments)
|
||
|
Obj.SetTailComment(Obj.GetTailComment()+TailComments)
|
||
|
del HeadComments[:]
|
||
|
del TailComments[:]
|
||
|
CurObj = Obj
|
||
|
else:
|
||
|
CurObj = None
|
||
|
else:
|
||
|
if id(CurComments) == id(TailComments):
|
||
|
#==========================================================
|
||
|
# Check if this comment belongs to tail comment
|
||
|
#==========================================================
|
||
|
if not self._TailCommentStrategy(Comment):
|
||
|
CurComments = HeadComments
|
||
|
|
||
|
if Comment:
|
||
|
CurComments.append(((Comment, self._RawData.LineIndex)))
|
||
|
else:
|
||
|
del CurComments[:]
|
||
|
|
||
|
if self._IsStatementRequired() and ItemNum == 0:
|
||
|
Logger.Error(
|
||
|
TOOL_NAME, FILE_PARSE_FAILURE,
|
||
|
File=self._RawData.Filename,
|
||
|
Line=Index,
|
||
|
ExtraData=ST.ERR_DECPARSE_STATEMENT_EMPTY % LineStr
|
||
|
)
|
||
|
|
||
|
## _DecDefine
|
||
|
# Parse define section
|
||
|
#
|
||
|
class _DecDefine(_DecBase):
|
||
|
def __init__(self, RawData):
|
||
|
_DecBase.__init__(self, RawData)
|
||
|
self.ItemObject = DecDefineObject(RawData.Filename)
|
||
|
self._LocalMacro = self._RawData.Macros
|
||
|
self._DefSecNum = 0
|
||
|
|
||
|
#
|
||
|
# Each field has a function to validate
|
||
|
#
|
||
|
self.DefineValidation = {
|
||
|
DT.TAB_DEC_DEFINES_DEC_SPECIFICATION : self._SetDecSpecification,
|
||
|
DT.TAB_DEC_DEFINES_PACKAGE_NAME : self._SetPackageName,
|
||
|
DT.TAB_DEC_DEFINES_PACKAGE_GUID : self._SetPackageGuid,
|
||
|
DT.TAB_DEC_DEFINES_PACKAGE_VERSION : self._SetPackageVersion,
|
||
|
}
|
||
|
|
||
|
def BlockStart(self):
|
||
|
self._DefSecNum += 1
|
||
|
if self._DefSecNum > 1:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_DEFINE_MULTISEC)
|
||
|
|
||
|
## CheckRequiredFields
|
||
|
#
|
||
|
# Check required fields: DEC_SPECIFICATION, PACKAGE_NAME
|
||
|
# PACKAGE_GUID, PACKAGE_VERSION
|
||
|
#
|
||
|
def CheckRequiredFields(self):
|
||
|
Ret = False
|
||
|
if self.ItemObject.GetPackageSpecification() == '':
|
||
|
Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename,
|
||
|
ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION)
|
||
|
elif self.ItemObject.GetPackageName() == '':
|
||
|
Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename,
|
||
|
ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_NAME)
|
||
|
elif self.ItemObject.GetPackageGuid() == '':
|
||
|
Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename,
|
||
|
ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_GUID)
|
||
|
elif self.ItemObject.GetPackageVersion() == '':
|
||
|
Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._RawData.Filename,
|
||
|
ExtraData=ST.ERR_DECPARSE_DEFINE_REQUIRED % DT.TAB_DEC_DEFINES_PACKAGE_VERSION)
|
||
|
else:
|
||
|
Ret = True
|
||
|
return Ret
|
||
|
|
||
|
def _ParseItem(self):
|
||
|
Line = self._RawData.CurrentLine
|
||
|
TokenList = GetSplitValueList(Line, DT.TAB_EQUAL_SPLIT, 1)
|
||
|
if TokenList[0] == DT.TAB_DEC_DEFINES_PKG_UNI_FILE:
|
||
|
pass
|
||
|
elif len(TokenList) < 2:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_DEFINE_FORMAT)
|
||
|
elif TokenList[0] not in self.DefineValidation:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_DEFINE_UNKNOWKEY % TokenList[0])
|
||
|
else:
|
||
|
self.DefineValidation[TokenList[0]](TokenList[1])
|
||
|
|
||
|
DefineItem = DecDefineItemObject()
|
||
|
if TokenList[0] != DT.TAB_DEC_DEFINES_PKG_UNI_FILE:
|
||
|
DefineItem.Key = TokenList[0]
|
||
|
DefineItem.Value = TokenList[1]
|
||
|
self.ItemObject.AddItem(DefineItem, self._RawData.CurrentScope)
|
||
|
return DefineItem
|
||
|
|
||
|
def _SetDecSpecification(self, Token):
|
||
|
if self.ItemObject.GetPackageSpecification():
|
||
|
self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_DEC_SPECIFICATION)
|
||
|
if not IsValidToken('0[xX][0-9a-fA-F]{8}', Token):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_DEFINE_SPEC)
|
||
|
self.ItemObject.SetPackageSpecification(Token)
|
||
|
|
||
|
def _SetPackageName(self, Token):
|
||
|
if self.ItemObject.GetPackageName():
|
||
|
self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_NAME)
|
||
|
if not IsValidWord(Token):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGNAME)
|
||
|
self.ItemObject.SetPackageName(Token)
|
||
|
|
||
|
def _SetPackageGuid(self, Token):
|
||
|
if self.ItemObject.GetPackageGuid():
|
||
|
self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_GUID)
|
||
|
if not CheckGuidRegFormat(Token):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGGUID)
|
||
|
self.ItemObject.SetPackageGuid(Token)
|
||
|
|
||
|
def _SetPackageVersion(self, Token):
|
||
|
if self.ItemObject.GetPackageVersion():
|
||
|
self._LoggerError(ST.ERR_DECPARSE_DEFINE_DEFINED % DT.TAB_DEC_DEFINES_PACKAGE_VERSION)
|
||
|
if not IsValidToken(VERSION_PATTERN, Token):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGVERSION)
|
||
|
else:
|
||
|
if not DT.TAB_SPLIT in Token:
|
||
|
Token = Token + '.0'
|
||
|
self.ItemObject._PkgVersion = Token
|
||
|
|
||
|
## _DecInclude
|
||
|
#
|
||
|
# Parse include section
|
||
|
#
|
||
|
class _DecInclude(_DecBase):
|
||
|
def __init__(self, RawData):
|
||
|
_DecBase.__init__(self, RawData)
|
||
|
self.ItemObject = DecIncludeObject(RawData.Filename)
|
||
|
|
||
|
def _ParseItem(self):
|
||
|
Line = self._RawData.CurrentLine
|
||
|
|
||
|
if not IsValidPath(Line, self._RawData.PackagePath):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_INCLUDE % Line)
|
||
|
|
||
|
Item = DecIncludeItemObject(StripRoot(self._RawData.PackagePath, Line), self._RawData.PackagePath)
|
||
|
self.ItemObject.AddItem(Item, self._RawData.CurrentScope)
|
||
|
return Item
|
||
|
|
||
|
## _DecLibraryclass
|
||
|
#
|
||
|
# Parse library class section
|
||
|
#
|
||
|
class _DecLibraryclass(_DecBase):
|
||
|
def __init__(self, RawData):
|
||
|
_DecBase.__init__(self, RawData)
|
||
|
self.ItemObject = DecLibraryclassObject(RawData.Filename)
|
||
|
|
||
|
def _ParseItem(self):
|
||
|
Line = self._RawData.CurrentLine
|
||
|
TokenList = GetSplitValueList(Line, DT.TAB_VALUE_SPLIT)
|
||
|
if len(TokenList) != 2:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_SPLIT)
|
||
|
if TokenList[0] == '' or TokenList[1] == '':
|
||
|
self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_EMPTY)
|
||
|
if not IsValidToken('[A-Z][0-9A-Za-z]*', TokenList[0]):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_LIB)
|
||
|
|
||
|
self._CheckReDefine(TokenList[0])
|
||
|
|
||
|
Value = TokenList[1]
|
||
|
#
|
||
|
# Must end with .h
|
||
|
#
|
||
|
if not Value.endswith('.h'):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_LIBCLASS_PATH_EXT)
|
||
|
|
||
|
#
|
||
|
# Path must be existed
|
||
|
#
|
||
|
if not IsValidPath(Value, self._RawData.PackagePath):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_INCLUDE % Value)
|
||
|
|
||
|
Item = DecLibraryclassItemObject(TokenList[0], StripRoot(self._RawData.PackagePath, Value),
|
||
|
self._RawData.PackagePath)
|
||
|
self.ItemObject.AddItem(Item, self._RawData.CurrentScope)
|
||
|
return Item
|
||
|
|
||
|
## _DecPcd
|
||
|
#
|
||
|
# Parse PCD section
|
||
|
#
|
||
|
class _DecPcd(_DecBase):
|
||
|
def __init__(self, RawData):
|
||
|
_DecBase.__init__(self, RawData)
|
||
|
self.ItemObject = DecPcdObject(RawData.Filename)
|
||
|
#
|
||
|
# Used to check duplicate token
|
||
|
# Key is token space and token number (integer), value is C name
|
||
|
#
|
||
|
self.TokenMap = {}
|
||
|
|
||
|
def _ParseItem(self):
|
||
|
Line = self._RawData.CurrentLine
|
||
|
TokenList = Line.split(DT.TAB_VALUE_SPLIT)
|
||
|
if len(TokenList) < 4:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_PCD_SPLIT)
|
||
|
|
||
|
#
|
||
|
# Token space guid C name
|
||
|
#
|
||
|
PcdName = GetSplitValueList(TokenList[0], DT.TAB_SPLIT)
|
||
|
if len(PcdName) != 2 or PcdName[0] == '' or PcdName[1] == '':
|
||
|
self._LoggerError(ST.ERR_DECPARSE_PCD_NAME)
|
||
|
|
||
|
Guid = PcdName[0]
|
||
|
if not IsValidToken(CVAR_PATTERN, Guid):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_GUID)
|
||
|
|
||
|
#
|
||
|
# PCD C name
|
||
|
#
|
||
|
CName = PcdName[1]
|
||
|
if not IsValidToken(CVAR_PATTERN, CName):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_PCDCNAME)
|
||
|
|
||
|
self._CheckReDefine(Guid + DT.TAB_SPLIT + CName)
|
||
|
|
||
|
#
|
||
|
# Default value, may be C array, string or number
|
||
|
#
|
||
|
Data = DT.TAB_VALUE_SPLIT.join(TokenList[1:-2]).strip()
|
||
|
|
||
|
#
|
||
|
# PCD data type
|
||
|
#
|
||
|
DataType = TokenList[-2].strip()
|
||
|
Valid, Cause = IsValidPcdDatum(DataType, Data)
|
||
|
if not Valid:
|
||
|
self._LoggerError(Cause)
|
||
|
PcdType = self._RawData.CurrentScope[0][0]
|
||
|
if PcdType == DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() and DataType != 'BOOLEAN':
|
||
|
self._LoggerError(ST.ERR_DECPARSE_PCD_FEATUREFLAG)
|
||
|
#
|
||
|
# Token value is the last element in list.
|
||
|
#
|
||
|
Token = TokenList[-1].strip()
|
||
|
if not IsValidToken(PCD_TOKEN_PATTERN, Token):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN % Token)
|
||
|
elif not Token.startswith('0x') and not Token.startswith('0X'):
|
||
|
if long(Token) > 4294967295:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN_INT % Token)
|
||
|
Token = hex(long(Token))[:-1]
|
||
|
|
||
|
IntToken = long(Token, 0)
|
||
|
if (Guid, IntToken) in self.TokenMap:
|
||
|
if self.TokenMap[Guid, IntToken] != CName:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_PCD_TOKEN_UNIQUE%(Token))
|
||
|
else:
|
||
|
self.TokenMap[Guid, IntToken] = CName
|
||
|
|
||
|
Item = DecPcdItemObject(Guid, CName, Data, DataType, Token)
|
||
|
self.ItemObject.AddItem(Item, self._RawData.CurrentScope)
|
||
|
return Item
|
||
|
|
||
|
## _DecGuid
|
||
|
#
|
||
|
# Parse GUID, PPI, Protocol section
|
||
|
#
|
||
|
class _DecGuid(_DecBase):
|
||
|
def __init__(self, RawData):
|
||
|
_DecBase.__init__(self, RawData)
|
||
|
self.GuidObj = DecGuidObject(RawData.Filename)
|
||
|
self.PpiObj = DecPpiObject(RawData.Filename)
|
||
|
self.ProtocolObj = DecProtocolObject(RawData.Filename)
|
||
|
self.ObjectDict = \
|
||
|
{
|
||
|
DT.TAB_GUIDS.upper() : self.GuidObj,
|
||
|
DT.TAB_PPIS.upper() : self.PpiObj,
|
||
|
DT.TAB_PROTOCOLS.upper() : self.ProtocolObj
|
||
|
}
|
||
|
|
||
|
def GetDataObject(self):
|
||
|
if self._RawData.CurrentScope:
|
||
|
return self.ObjectDict[self._RawData.CurrentScope[0][0]]
|
||
|
return None
|
||
|
|
||
|
def GetGuidObject(self):
|
||
|
return self.GuidObj
|
||
|
|
||
|
def GetPpiObject(self):
|
||
|
return self.PpiObj
|
||
|
|
||
|
def GetProtocolObject(self):
|
||
|
return self.ProtocolObj
|
||
|
|
||
|
def _ParseItem(self):
|
||
|
Line = self._RawData.CurrentLine
|
||
|
TokenList = GetSplitValueList(Line, DT.TAB_EQUAL_SPLIT, 1)
|
||
|
if len(TokenList) < 2:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_CGUID)
|
||
|
if TokenList[0] == '':
|
||
|
self._LoggerError(ST.ERR_DECPARSE_CGUID_NAME)
|
||
|
if TokenList[1] == '':
|
||
|
self._LoggerError(ST.ERR_DECPARSE_CGUID_GUID)
|
||
|
if not IsValidToken(CVAR_PATTERN, TokenList[0]):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_PCD_CVAR_GUID)
|
||
|
|
||
|
self._CheckReDefine(TokenList[0])
|
||
|
|
||
|
if TokenList[1][0] != '{':
|
||
|
if not CheckGuidRegFormat(TokenList[1]):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_DEFINE_PKGGUID)
|
||
|
GuidString = TokenList[1]
|
||
|
else:
|
||
|
#
|
||
|
# Convert C format GUID to GUID string and Simple error check
|
||
|
#
|
||
|
GuidString = GuidStructureStringToGuidString(TokenList[1])
|
||
|
if TokenList[1][0] != '{' or TokenList[1][-1] != '}' or GuidString == '':
|
||
|
self._LoggerError(ST.ERR_DECPARSE_CGUID_GUIDFORMAT)
|
||
|
|
||
|
#
|
||
|
# Check C format GUID
|
||
|
#
|
||
|
if not IsValidCFormatGuid(TokenList[1]):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_CGUID_GUIDFORMAT)
|
||
|
|
||
|
Item = DecGuidItemObject(TokenList[0], TokenList[1], GuidString)
|
||
|
ItemObject = self.ObjectDict[self._RawData.CurrentScope[0][0]]
|
||
|
ItemObject.AddItem(Item, self._RawData.CurrentScope)
|
||
|
return Item
|
||
|
|
||
|
## _DecUserExtension
|
||
|
#
|
||
|
# Parse user extention section
|
||
|
#
|
||
|
class _DecUserExtension(_DecBase):
|
||
|
def __init__(self, RawData):
|
||
|
_DecBase.__init__(self, RawData)
|
||
|
self.ItemObject = DecUserExtensionObject(RawData.Filename)
|
||
|
self._Headers = []
|
||
|
self._CurItems = []
|
||
|
|
||
|
def BlockStart(self):
|
||
|
self._CurItems = []
|
||
|
for Header in self._RawData.CurrentScope:
|
||
|
if Header in self._Headers:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_UE_DUPLICATE)
|
||
|
else:
|
||
|
self._Headers.append(Header)
|
||
|
|
||
|
for Item in self._CurItems:
|
||
|
if Item.UserId == Header[1] and Item.IdString == Header[2]:
|
||
|
Item.ArchAndModuleType.append(Header[3])
|
||
|
break
|
||
|
else:
|
||
|
Item = DecUserExtensionItemObject()
|
||
|
Item.UserId = Header[1]
|
||
|
Item.IdString = Header[2]
|
||
|
Item.ArchAndModuleType.append(Header[3])
|
||
|
self._CurItems.append(Item)
|
||
|
self.ItemObject.AddItem(Item, None)
|
||
|
self._LocalMacro = {}
|
||
|
|
||
|
def _ParseItem(self):
|
||
|
Line = self._RawData.CurrentLine
|
||
|
Item = None
|
||
|
for Item in self._CurItems:
|
||
|
if Item.UserString:
|
||
|
Item.UserString = '\n'.join([Item.UserString, Line])
|
||
|
else:
|
||
|
Item.UserString = Line
|
||
|
return Item
|
||
|
|
||
|
## Dec
|
||
|
#
|
||
|
# Top dec parser
|
||
|
#
|
||
|
class Dec(_DecBase, _DecComments):
|
||
|
def __init__(self, DecFile, Parse = True):
|
||
|
try:
|
||
|
Content = ConvertSpecialChar(open(DecFile, 'rb').readlines())
|
||
|
except BaseException:
|
||
|
Logger.Error(TOOL_NAME, FILE_OPEN_FAILURE, File=DecFile,
|
||
|
ExtraData=ST.ERR_DECPARSE_FILEOPEN % DecFile)
|
||
|
RawData = FileContent(DecFile, Content)
|
||
|
|
||
|
_DecComments.__init__(self)
|
||
|
_DecBase.__init__(self, RawData)
|
||
|
|
||
|
self._Define = _DecDefine(RawData)
|
||
|
self._Include = _DecInclude(RawData)
|
||
|
self._Guid = _DecGuid(RawData)
|
||
|
self._LibClass = _DecLibraryclass(RawData)
|
||
|
self._Pcd = _DecPcd(RawData)
|
||
|
self._UserEx = _DecUserExtension(RawData)
|
||
|
|
||
|
#
|
||
|
# DEC file supported data types (one type per section)
|
||
|
#
|
||
|
self._SectionParser = {
|
||
|
DT.TAB_DEC_DEFINES.upper() : self._Define,
|
||
|
DT.TAB_INCLUDES.upper() : self._Include,
|
||
|
DT.TAB_LIBRARY_CLASSES.upper() : self._LibClass,
|
||
|
DT.TAB_GUIDS.upper() : self._Guid,
|
||
|
DT.TAB_PPIS.upper() : self._Guid,
|
||
|
DT.TAB_PROTOCOLS.upper() : self._Guid,
|
||
|
DT.TAB_PCDS_FIXED_AT_BUILD_NULL.upper() : self._Pcd,
|
||
|
DT.TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper() : self._Pcd,
|
||
|
DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() : self._Pcd,
|
||
|
DT.TAB_PCDS_DYNAMIC_NULL.upper() : self._Pcd,
|
||
|
DT.TAB_PCDS_DYNAMIC_EX_NULL.upper() : self._Pcd,
|
||
|
DT.TAB_USER_EXTENSIONS.upper() : self._UserEx
|
||
|
}
|
||
|
|
||
|
if Parse:
|
||
|
self.ParseDecComment()
|
||
|
self.Parse()
|
||
|
#
|
||
|
# Parsing done, check required fields
|
||
|
#
|
||
|
self.CheckRequiredFields()
|
||
|
|
||
|
def CheckRequiredFields(self):
|
||
|
for SectionParser in self._SectionParser.values():
|
||
|
if not SectionParser.CheckRequiredFields():
|
||
|
return False
|
||
|
return True
|
||
|
|
||
|
##
|
||
|
# Parse DEC file
|
||
|
#
|
||
|
def ParseDecComment(self):
|
||
|
while not self._RawData.IsEndOfFile():
|
||
|
Line, Comment = CleanString(self._RawData.GetNextLine())
|
||
|
#
|
||
|
# Header must be pure comment
|
||
|
#
|
||
|
if Line != '':
|
||
|
self._RawData.UndoNextLine()
|
||
|
break
|
||
|
|
||
|
if Comment:
|
||
|
self._HeadComment.append((Comment, self._RawData.LineIndex))
|
||
|
#
|
||
|
# Double '#' indicates end of header comments
|
||
|
#
|
||
|
if not Comment or Comment == DT.TAB_SPECIAL_COMMENT:
|
||
|
break
|
||
|
|
||
|
return
|
||
|
|
||
|
def _StopCurrentParsing(self, Line):
|
||
|
return False
|
||
|
|
||
|
def _ParseItem(self):
|
||
|
self._SectionHeaderParser()
|
||
|
if len(self._RawData.CurrentScope) == 0:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_SECTION_EMPTY)
|
||
|
|
||
|
SectionObj = self._SectionParser[self._RawData.CurrentScope[0][0]]
|
||
|
|
||
|
SectionObj.BlockStart()
|
||
|
SectionObj.Parse()
|
||
|
|
||
|
return SectionObj.GetDataObject()
|
||
|
|
||
|
def _UserExtentionSectionParser(self):
|
||
|
self._RawData.CurrentScope = []
|
||
|
ArchList = set()
|
||
|
Section = self._RawData.CurrentLine[1:-1]
|
||
|
|
||
|
Par = ParserHelper(Section, self._RawData.Filename)
|
||
|
while not Par.End():
|
||
|
#
|
||
|
# User extention
|
||
|
#
|
||
|
Token = Par.GetToken()
|
||
|
if Token.upper() != DT.TAB_USER_EXTENSIONS.upper():
|
||
|
self._LoggerError(ST.ERR_DECPARSE_SECTION_UE)
|
||
|
UserExtension = Token.upper()
|
||
|
|
||
|
Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)
|
||
|
#
|
||
|
# UserID
|
||
|
#
|
||
|
Token = Par.GetToken()
|
||
|
if not IsValidUserId(Token):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_USERID)
|
||
|
UserId = Token
|
||
|
|
||
|
Par.AssertChar(DT.TAB_SPLIT, ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)
|
||
|
#
|
||
|
# IdString
|
||
|
#
|
||
|
Token = Par.GetToken()
|
||
|
if not IsValidIdString(Token):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_SECTION_UE_IDSTRING)
|
||
|
IdString = Token
|
||
|
|
||
|
Arch = 'COMMON'
|
||
|
if Par.Expect(DT.TAB_SPLIT):
|
||
|
Token = Par.GetToken()
|
||
|
Arch = Token.upper()
|
||
|
if not IsValidArch(Arch):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_ARCH)
|
||
|
ArchList.add(Arch)
|
||
|
|
||
|
if [UserExtension, UserId, IdString, Arch] not in \
|
||
|
self._RawData.CurrentScope:
|
||
|
self._RawData.CurrentScope.append(
|
||
|
[UserExtension, UserId, IdString, Arch]
|
||
|
)
|
||
|
|
||
|
if not Par.Expect(DT.TAB_COMMA_SPLIT):
|
||
|
break
|
||
|
elif Par.End():
|
||
|
self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMA)
|
||
|
|
||
|
Par.AssertEnd(ST.ERR_DECPARSE_SECTION_UE, self._RawData.LineIndex)
|
||
|
|
||
|
if 'COMMON' in ArchList and len(ArchList) > 1:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON)
|
||
|
|
||
|
## Section header parser
|
||
|
#
|
||
|
# The section header is always in following format:
|
||
|
#
|
||
|
# [section_name.arch<.platform|module_type>]
|
||
|
#
|
||
|
def _SectionHeaderParser(self):
|
||
|
if self._RawData.CurrentLine[0] != DT.TAB_SECTION_START or self._RawData.CurrentLine[-1] != DT.TAB_SECTION_END:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_SECTION_IDENTIFY)
|
||
|
|
||
|
RawSection = self._RawData.CurrentLine[1:-1].strip().upper()
|
||
|
|
||
|
#
|
||
|
# Check defines section which is only allowed to occur once and
|
||
|
# no arch can be followed
|
||
|
#
|
||
|
if RawSection.startswith(DT.TAB_DEC_DEFINES.upper()):
|
||
|
if RawSection != DT.TAB_DEC_DEFINES.upper():
|
||
|
self._LoggerError(ST.ERR_DECPARSE_DEFINE_SECNAME)
|
||
|
|
||
|
#
|
||
|
# Check user extension section
|
||
|
#
|
||
|
if RawSection.startswith(DT.TAB_USER_EXTENSIONS.upper()):
|
||
|
return self._UserExtentionSectionParser()
|
||
|
|
||
|
self._RawData.CurrentScope = []
|
||
|
SectionNames = []
|
||
|
ArchList = set()
|
||
|
for Item in GetSplitValueList(RawSection, DT.TAB_COMMA_SPLIT):
|
||
|
if Item == '':
|
||
|
self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine)
|
||
|
|
||
|
ItemList = GetSplitValueList(Item, DT.TAB_SPLIT)
|
||
|
|
||
|
#
|
||
|
# different types of PCD are permissible in one section
|
||
|
#
|
||
|
SectionName = ItemList[0]
|
||
|
if SectionName not in self._SectionParser:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_SECTION_UNKNOW % SectionName)
|
||
|
|
||
|
if SectionName not in SectionNames:
|
||
|
SectionNames.append(SectionName)
|
||
|
|
||
|
#
|
||
|
# In DEC specification, all section headers have at most two part:
|
||
|
# SectionName.Arch except UserExtention
|
||
|
#
|
||
|
if len(ItemList) > 2:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBTOOMANY % Item)
|
||
|
|
||
|
if DT.TAB_PCDS_FEATURE_FLAG_NULL.upper() in SectionNames and len(SectionNames) > 1:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_SECTION_FEATUREFLAG % DT.TAB_PCDS_FEATURE_FLAG_NULL)
|
||
|
#
|
||
|
# S1 is always Arch
|
||
|
#
|
||
|
if len(ItemList) > 1:
|
||
|
Str1 = ItemList[1]
|
||
|
if not IsValidArch(Str1):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_ARCH)
|
||
|
else:
|
||
|
Str1 = 'COMMON'
|
||
|
ArchList.add(Str1)
|
||
|
|
||
|
if [SectionName, Str1] not in self._RawData.CurrentScope:
|
||
|
self._RawData.CurrentScope.append([SectionName, Str1])
|
||
|
#
|
||
|
# 'COMMON' must not be used with specific ARCHs at the same section
|
||
|
#
|
||
|
if 'COMMON' in ArchList and len(ArchList) > 1:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_SECTION_COMMON)
|
||
|
|
||
|
if len(SectionNames) == 0:
|
||
|
self._LoggerError(ST.ERR_DECPARSE_SECTION_SUBEMPTY % self._RawData.CurrentLine)
|
||
|
if len(SectionNames) != 1:
|
||
|
for Sec in SectionNames:
|
||
|
if not Sec.startswith(DT.TAB_PCDS.upper()):
|
||
|
self._LoggerError(ST.ERR_DECPARSE_SECTION_NAME % str(SectionNames))
|
||
|
|
||
|
def GetDefineSectionObject(self):
|
||
|
return self._Define.GetDataObject()
|
||
|
|
||
|
def GetIncludeSectionObject(self):
|
||
|
return self._Include.GetDataObject()
|
||
|
|
||
|
def GetGuidSectionObject(self):
|
||
|
return self._Guid.GetGuidObject()
|
||
|
|
||
|
def GetProtocolSectionObject(self):
|
||
|
return self._Guid.GetProtocolObject()
|
||
|
|
||
|
def GetPpiSectionObject(self):
|
||
|
return self._Guid.GetPpiObject()
|
||
|
|
||
|
def GetLibraryClassSectionObject(self):
|
||
|
return self._LibClass.GetDataObject()
|
||
|
|
||
|
def GetPcdSectionObject(self):
|
||
|
return self._Pcd.GetDataObject()
|
||
|
|
||
|
def GetUserExtensionSectionObject(self):
|
||
|
return self._UserEx.GetDataObject()
|
||
|
|
||
|
def GetPackageSpecification(self):
|
||
|
return self._Define.GetDataObject().GetPackageSpecification()
|
||
|
|
||
|
def GetPackageName(self):
|
||
|
return self._Define.GetDataObject().GetPackageName()
|
||
|
|
||
|
def GetPackageGuid(self):
|
||
|
return self._Define.GetDataObject().GetPackageGuid()
|
||
|
|
||
|
def GetPackageVersion(self):
|
||
|
return self._Define.GetDataObject().GetPackageVersion()
|
||
|
|
||
|
def GetPackageUniFile(self):
|
||
|
return self._Define.GetDataObject().GetPackageUniFile()
|