diff options
Diffstat (limited to 'BaseTools/Source/Python/UPT/Parser/DecParserMisc.py')
| -rw-r--r-- | BaseTools/Source/Python/UPT/Parser/DecParserMisc.py | 728 |
1 files changed, 364 insertions, 364 deletions
diff --git a/BaseTools/Source/Python/UPT/Parser/DecParserMisc.py b/BaseTools/Source/Python/UPT/Parser/DecParserMisc.py index 27990467d1..4731c85c33 100644 --- a/BaseTools/Source/Python/UPT/Parser/DecParserMisc.py +++ b/BaseTools/Source/Python/UPT/Parser/DecParserMisc.py @@ -1,364 +1,364 @@ -## @file
-# This file is used to define helper class and function for DEC parser
-#
-# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-
-'''
-DecParserMisc
-'''
-
-## Import modules
-#
-import os
-import Logger.Log as Logger
-from Logger.ToolError import FILE_PARSE_FAILURE
-from Logger import StringTable as ST
-from Library.DataType import TAB_COMMENT_SPLIT
-from Library.DataType import TAB_COMMENT_EDK1_SPLIT
-from Library.ExpressionValidate import IsValidBareCString
-from Library.ParserValidate import IsValidCFormatGuid
-from Library.ExpressionValidate import IsValidFeatureFlagExp
-from Library.ExpressionValidate import IsValidLogicalExpr
-from Library.ExpressionValidate import IsValidStringTest
-from Library.Misc import CheckGuidRegFormat
-
-TOOL_NAME = 'DecParser'
-VERSION_PATTERN = '[0-9]+(\.[0-9]+)?'
-CVAR_PATTERN = '[_a-zA-Z][a-zA-Z0-9_]*'
-PCD_TOKEN_PATTERN = '(0[xX]0*[a-fA-F0-9]{1,8})|([0-9]+)'
-MACRO_PATTERN = '[A-Z][_A-Z0-9]*'
-
-## FileContent
-# Class to hold DEC file information
-#
-class FileContent:
- def __init__(self, Filename, FileContent2):
- self.Filename = Filename
- self.PackagePath, self.PackageFile = os.path.split(Filename)
- self.LineIndex = 0
- self.CurrentLine = ''
- self.NextLine = ''
- self.HeadComment = []
- self.TailComment = []
- self.CurrentScope = None
- self.Content = FileContent2
- self.Macros = {}
- self.FileLines = len(FileContent2)
-
- def GetNextLine(self):
- if self.LineIndex >= self.FileLines:
- return ''
- Line = self.Content[self.LineIndex]
- self.LineIndex += 1
- return Line
-
- def UndoNextLine(self):
- if self.LineIndex > 0:
- self.LineIndex -= 1
-
- def ResetNext(self):
- self.HeadComment = []
- self.TailComment = []
- self.NextLine = ''
-
- def SetNext(self, Line, HeadComment, TailComment):
- self.NextLine = Line
- self.HeadComment = HeadComment
- self.TailComment = TailComment
-
- def IsEndOfFile(self):
- return self.LineIndex >= self.FileLines
-
-
-## StripRoot
-#
-# Strip root path
-#
-# @param Root: Root must be absolute path
-# @param Path: Path to be stripped
-#
-def StripRoot(Root, Path):
- OrigPath = Path
- Root = os.path.normpath(Root)
- Path = os.path.normpath(Path)
- if not os.path.isabs(Root):
- return OrigPath
- if Path.startswith(Root):
- Path = Path[len(Root):]
- if Path and Path[0] == os.sep:
- Path = Path[1:]
- return Path
- return OrigPath
-
-## CleanString
-#
-# Split comments in a string
-# Remove spaces
-#
-# @param Line: The string to be cleaned
-# @param CommentCharacter: Comment char, used to ignore comment content,
-# default is DataType.TAB_COMMENT_SPLIT
-#
-def CleanString(Line, CommentCharacter=TAB_COMMENT_SPLIT, \
- AllowCppStyleComment=False):
- #
- # remove whitespace
- #
- Line = Line.strip()
- #
- # Replace EDK1's comment character
- #
- if AllowCppStyleComment:
- Line = Line.replace(TAB_COMMENT_EDK1_SPLIT, CommentCharacter)
- #
- # separate comments and statements
- #
- Comment = ''
- InQuote = False
- for Index in range(0, len(Line)):
- if Line[Index] == '"':
- InQuote = not InQuote
- continue
- if Line[Index] == CommentCharacter and not InQuote:
- Comment = Line[Index:].strip()
- Line = Line[0:Index].strip()
- break
-
- return Line, Comment
-
-
-## IsValidNumValUint8
-#
-# Check if Token is NumValUint8: <NumValUint8> ::= {<ShortNum>} {<UINT8>} {<Expression>}
-#
-# @param Token: Token to be checked
-#
-def IsValidNumValUint8(Token):
- Valid = True
- Cause = ""
- TokenValue = None
- Token = Token.strip()
- if Token.lower().startswith('0x'):
- Base = 16
- else:
- Base = 10
- try:
- TokenValue = int(Token, Base)
- except BaseException:
- Valid, Cause = IsValidLogicalExpr(Token, True)
- if Cause:
- pass
- if not Valid:
- return False
- if TokenValue and (TokenValue < 0 or TokenValue > 0xFF):
- return False
- else:
- return True
-
-## IsValidNList
-#
-# Check if Value has the format of <NumValUint8> ["," <NumValUint8>]{0,}
-# <NumValUint8> ::= {<ShortNum>} {<UINT8>} {<Expression>}
-#
-# @param Value: Value to be checked
-#
-def IsValidNList(Value):
- Par = ParserHelper(Value)
- if Par.End():
- return False
- while not Par.End():
- Token = Par.GetToken(',')
- if not IsValidNumValUint8(Token):
- return False
- if Par.Expect(','):
- if Par.End():
- return False
- continue
- else:
- break
- return Par.End()
-
-## IsValidCArray
-#
-# check Array is valid
-#
-# @param Array: The input Array
-#
-def IsValidCArray(Array):
- Par = ParserHelper(Array)
- if not Par.Expect('{'):
- return False
- if Par.End():
- return False
- while not Par.End():
- Token = Par.GetToken(',}')
- #
- # ShortNum, UINT8, Expression
- #
- if not IsValidNumValUint8(Token):
- return False
- if Par.Expect(','):
- if Par.End():
- return False
- continue
- elif Par.Expect('}'):
- #
- # End of C array
- #
- break
- else:
- return False
- return Par.End()
-
-## IsValidPcdDatum
-#
-# check PcdDatum is valid
-#
-# @param Type: The pcd Type
-# @param Value: The pcd Value
-#
-def IsValidPcdDatum(Type, Value):
- if not Value:
- return False, ST.ERR_DECPARSE_PCD_VALUE_EMPTY
- Valid = True
- Cause = ""
- if Type not in ["UINT8", "UINT16", "UINT32", "UINT64", "VOID*", "BOOLEAN"]:
- return False, ST.ERR_DECPARSE_PCD_TYPE
- if Type == "VOID*":
- if not ((Value.startswith('L"') or Value.startswith('"') and \
- Value.endswith('"'))
- or (IsValidCArray(Value)) or (IsValidCFormatGuid(Value)) \
- or (IsValidNList(Value)) or (CheckGuidRegFormat(Value))
- ):
- return False, ST.ERR_DECPARSE_PCD_VOID % (Value, Type)
- RealString = Value[Value.find('"') + 1 :-1]
- if RealString:
- if not IsValidBareCString(RealString):
- return False, ST.ERR_DECPARSE_PCD_VOID % (Value, Type)
- elif Type == 'BOOLEAN':
- if Value in ['TRUE', 'FALSE', 'true', 'false', 'True', 'False',
- '0x1', '0x01', '1', '0x0', '0x00', '0']:
- return True, ""
- Valid, Cause = IsValidStringTest(Value, True)
- if not Valid:
- Valid, Cause = IsValidFeatureFlagExp(Value, True)
- if not Valid:
- return False, Cause
- else:
- if Value and (Value[0] == '-' or Value[0] == '+'):
- return False, ST.ERR_DECPARSE_PCD_INT_NEGTIVE % (Value, Type)
- try:
- StrVal = Value
- if Value and not Value.startswith('0x') \
- and not Value.startswith('0X'):
- Value = Value.lstrip('0')
- if not Value:
- return True, ""
- Value = int(Value, 0)
- MAX_VAL_TYPE = {"BOOLEAN": 0x01, 'UINT8': 0xFF, 'UINT16': 0xFFFF, 'UINT32': 0xFFFFFFFF,
- 'UINT64': 0xFFFFFFFFFFFFFFFF}
- if Value > MAX_VAL_TYPE[Type]:
- return False, ST.ERR_DECPARSE_PCD_INT_EXCEED % (StrVal, Type)
- except BaseException:
- Valid, Cause = IsValidLogicalExpr(Value, True)
- if not Valid:
- return False, Cause
-
- return True, ""
-
-## ParserHelper
-#
-class ParserHelper:
- def __init__(self, String, File=''):
- self._String = String
- self._StrLen = len(String)
- self._Index = 0
- self._File = File
-
- ## End
- #
- # End
- #
- def End(self):
- self.__SkipWhitespace()
- return self._Index >= self._StrLen
-
- ## __SkipWhitespace
- #
- # Skip whitespace
- #
- def __SkipWhitespace(self):
- for Char in self._String[self._Index:]:
- if Char not in ' \t':
- break
- self._Index += 1
-
- ## Expect
- #
- # Expect char in string
- #
- # @param ExpectChar: char expected in index of string
- #
- def Expect(self, ExpectChar):
- self.__SkipWhitespace()
- for Char in self._String[self._Index:]:
- if Char != ExpectChar:
- return False
- else:
- self._Index += 1
- return True
- #
- # Index out of bound of String
- #
- return False
-
- ## GetToken
- #
- # Get token until encounter StopChar, front whitespace is consumed
- #
- # @param StopChar: Get token until encounter char in StopChar
- # @param StkipPair: Only can be ' or ", StopChar in SkipPair are skipped
- #
- def GetToken(self, StopChar='.,|\t ', SkipPair='"'):
- self.__SkipWhitespace()
- PreIndex = self._Index
- InQuote = False
- LastChar = ''
- for Char in self._String[self._Index:]:
- if Char == SkipPair and LastChar != '\\':
- InQuote = not InQuote
- if Char in StopChar and not InQuote:
- break
- self._Index += 1
- if Char == '\\' and LastChar == '\\':
- LastChar = ''
- else:
- LastChar = Char
- return self._String[PreIndex:self._Index]
-
- ## AssertChar
- #
- # Assert char at current index of string is AssertChar, or will report
- # error message
- #
- # @param AssertChar: AssertChar
- # @param ErrorString: ErrorString
- # @param ErrorLineNum: ErrorLineNum
- #
- def AssertChar(self, AssertChar, ErrorString, ErrorLineNum):
- if not self.Expect(AssertChar):
- Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._File,
- Line=ErrorLineNum, ExtraData=ErrorString)
-
- ## AssertEnd
- #
- # @param ErrorString: ErrorString
- # @param ErrorLineNum: ErrorLineNum
- #
- def AssertEnd(self, ErrorString, ErrorLineNum):
- self.__SkipWhitespace()
- if self._Index != self._StrLen:
- Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._File,
- Line=ErrorLineNum, ExtraData=ErrorString)
+## @file +# This file is used to define helper class and function for DEC parser +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent + +''' +DecParserMisc +''' + +## Import modules +# +import os +import Logger.Log as Logger +from Logger.ToolError import FILE_PARSE_FAILURE +from Logger import StringTable as ST +from Library.DataType import TAB_COMMENT_SPLIT +from Library.DataType import TAB_COMMENT_EDK1_SPLIT +from Library.ExpressionValidate import IsValidBareCString +from Library.ParserValidate import IsValidCFormatGuid +from Library.ExpressionValidate import IsValidFeatureFlagExp +from Library.ExpressionValidate import IsValidLogicalExpr +from Library.ExpressionValidate import IsValidStringTest +from Library.Misc import CheckGuidRegFormat + +TOOL_NAME = 'DecParser' +VERSION_PATTERN = '[0-9]+(\.[0-9]+)?' +CVAR_PATTERN = '[_a-zA-Z][a-zA-Z0-9_]*' +PCD_TOKEN_PATTERN = '(0[xX]0*[a-fA-F0-9]{1,8})|([0-9]+)' +MACRO_PATTERN = '[A-Z][_A-Z0-9]*' + +## FileContent +# Class to hold DEC file information +# +class FileContent: + def __init__(self, Filename, FileContent2): + self.Filename = Filename + self.PackagePath, self.PackageFile = os.path.split(Filename) + self.LineIndex = 0 + self.CurrentLine = '' + self.NextLine = '' + self.HeadComment = [] + self.TailComment = [] + self.CurrentScope = None + self.Content = FileContent2 + self.Macros = {} + self.FileLines = len(FileContent2) + + def GetNextLine(self): + if self.LineIndex >= self.FileLines: + return '' + Line = self.Content[self.LineIndex] + self.LineIndex += 1 + return Line + + def UndoNextLine(self): + if self.LineIndex > 0: + self.LineIndex -= 1 + + def ResetNext(self): + self.HeadComment = [] + self.TailComment = [] + self.NextLine = '' + + def SetNext(self, Line, HeadComment, TailComment): + self.NextLine = Line + self.HeadComment = HeadComment + self.TailComment = TailComment + + def IsEndOfFile(self): + return self.LineIndex >= self.FileLines + + +## StripRoot +# +# Strip root path +# +# @param Root: Root must be absolute path +# @param Path: Path to be stripped +# +def StripRoot(Root, Path): + OrigPath = Path + Root = os.path.normpath(Root) + Path = os.path.normpath(Path) + if not os.path.isabs(Root): + return OrigPath + if Path.startswith(Root): + Path = Path[len(Root):] + if Path and Path[0] == os.sep: + Path = Path[1:] + return Path + return OrigPath + +## CleanString +# +# Split comments in a string +# Remove spaces +# +# @param Line: The string to be cleaned +# @param CommentCharacter: Comment char, used to ignore comment content, +# default is DataType.TAB_COMMENT_SPLIT +# +def CleanString(Line, CommentCharacter=TAB_COMMENT_SPLIT, \ + AllowCppStyleComment=False): + # + # remove whitespace + # + Line = Line.strip() + # + # Replace EDK1's comment character + # + if AllowCppStyleComment: + Line = Line.replace(TAB_COMMENT_EDK1_SPLIT, CommentCharacter) + # + # separate comments and statements + # + Comment = '' + InQuote = False + for Index in range(0, len(Line)): + if Line[Index] == '"': + InQuote = not InQuote + continue + if Line[Index] == CommentCharacter and not InQuote: + Comment = Line[Index:].strip() + Line = Line[0:Index].strip() + break + + return Line, Comment + + +## IsValidNumValUint8 +# +# Check if Token is NumValUint8: <NumValUint8> ::= {<ShortNum>} {<UINT8>} {<Expression>} +# +# @param Token: Token to be checked +# +def IsValidNumValUint8(Token): + Valid = True + Cause = "" + TokenValue = None + Token = Token.strip() + if Token.lower().startswith('0x'): + Base = 16 + else: + Base = 10 + try: + TokenValue = int(Token, Base) + except BaseException: + Valid, Cause = IsValidLogicalExpr(Token, True) + if Cause: + pass + if not Valid: + return False + if TokenValue and (TokenValue < 0 or TokenValue > 0xFF): + return False + else: + return True + +## IsValidNList +# +# Check if Value has the format of <NumValUint8> ["," <NumValUint8>]{0,} +# <NumValUint8> ::= {<ShortNum>} {<UINT8>} {<Expression>} +# +# @param Value: Value to be checked +# +def IsValidNList(Value): + Par = ParserHelper(Value) + if Par.End(): + return False + while not Par.End(): + Token = Par.GetToken(',') + if not IsValidNumValUint8(Token): + return False + if Par.Expect(','): + if Par.End(): + return False + continue + else: + break + return Par.End() + +## IsValidCArray +# +# check Array is valid +# +# @param Array: The input Array +# +def IsValidCArray(Array): + Par = ParserHelper(Array) + if not Par.Expect('{'): + return False + if Par.End(): + return False + while not Par.End(): + Token = Par.GetToken(',}') + # + # ShortNum, UINT8, Expression + # + if not IsValidNumValUint8(Token): + return False + if Par.Expect(','): + if Par.End(): + return False + continue + elif Par.Expect('}'): + # + # End of C array + # + break + else: + return False + return Par.End() + +## IsValidPcdDatum +# +# check PcdDatum is valid +# +# @param Type: The pcd Type +# @param Value: The pcd Value +# +def IsValidPcdDatum(Type, Value): + if not Value: + return False, ST.ERR_DECPARSE_PCD_VALUE_EMPTY + Valid = True + Cause = "" + if Type not in ["UINT8", "UINT16", "UINT32", "UINT64", "VOID*", "BOOLEAN"]: + return False, ST.ERR_DECPARSE_PCD_TYPE + if Type == "VOID*": + if not ((Value.startswith('L"') or Value.startswith('"') and \ + Value.endswith('"')) + or (IsValidCArray(Value)) or (IsValidCFormatGuid(Value)) \ + or (IsValidNList(Value)) or (CheckGuidRegFormat(Value)) + ): + return False, ST.ERR_DECPARSE_PCD_VOID % (Value, Type) + RealString = Value[Value.find('"') + 1 :-1] + if RealString: + if not IsValidBareCString(RealString): + return False, ST.ERR_DECPARSE_PCD_VOID % (Value, Type) + elif Type == 'BOOLEAN': + if Value in ['TRUE', 'FALSE', 'true', 'false', 'True', 'False', + '0x1', '0x01', '1', '0x0', '0x00', '0']: + return True, "" + Valid, Cause = IsValidStringTest(Value, True) + if not Valid: + Valid, Cause = IsValidFeatureFlagExp(Value, True) + if not Valid: + return False, Cause + else: + if Value and (Value[0] == '-' or Value[0] == '+'): + return False, ST.ERR_DECPARSE_PCD_INT_NEGTIVE % (Value, Type) + try: + StrVal = Value + if Value and not Value.startswith('0x') \ + and not Value.startswith('0X'): + Value = Value.lstrip('0') + if not Value: + return True, "" + Value = int(Value, 0) + MAX_VAL_TYPE = {"BOOLEAN": 0x01, 'UINT8': 0xFF, 'UINT16': 0xFFFF, 'UINT32': 0xFFFFFFFF, + 'UINT64': 0xFFFFFFFFFFFFFFFF} + if Value > MAX_VAL_TYPE[Type]: + return False, ST.ERR_DECPARSE_PCD_INT_EXCEED % (StrVal, Type) + except BaseException: + Valid, Cause = IsValidLogicalExpr(Value, True) + if not Valid: + return False, Cause + + return True, "" + +## ParserHelper +# +class ParserHelper: + def __init__(self, String, File=''): + self._String = String + self._StrLen = len(String) + self._Index = 0 + self._File = File + + ## End + # + # End + # + def End(self): + self.__SkipWhitespace() + return self._Index >= self._StrLen + + ## __SkipWhitespace + # + # Skip whitespace + # + def __SkipWhitespace(self): + for Char in self._String[self._Index:]: + if Char not in ' \t': + break + self._Index += 1 + + ## Expect + # + # Expect char in string + # + # @param ExpectChar: char expected in index of string + # + def Expect(self, ExpectChar): + self.__SkipWhitespace() + for Char in self._String[self._Index:]: + if Char != ExpectChar: + return False + else: + self._Index += 1 + return True + # + # Index out of bound of String + # + return False + + ## GetToken + # + # Get token until encounter StopChar, front whitespace is consumed + # + # @param StopChar: Get token until encounter char in StopChar + # @param StkipPair: Only can be ' or ", StopChar in SkipPair are skipped + # + def GetToken(self, StopChar='.,|\t ', SkipPair='"'): + self.__SkipWhitespace() + PreIndex = self._Index + InQuote = False + LastChar = '' + for Char in self._String[self._Index:]: + if Char == SkipPair and LastChar != '\\': + InQuote = not InQuote + if Char in StopChar and not InQuote: + break + self._Index += 1 + if Char == '\\' and LastChar == '\\': + LastChar = '' + else: + LastChar = Char + return self._String[PreIndex:self._Index] + + ## AssertChar + # + # Assert char at current index of string is AssertChar, or will report + # error message + # + # @param AssertChar: AssertChar + # @param ErrorString: ErrorString + # @param ErrorLineNum: ErrorLineNum + # + def AssertChar(self, AssertChar, ErrorString, ErrorLineNum): + if not self.Expect(AssertChar): + Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._File, + Line=ErrorLineNum, ExtraData=ErrorString) + + ## AssertEnd + # + # @param ErrorString: ErrorString + # @param ErrorLineNum: ErrorLineNum + # + def AssertEnd(self, ErrorString, ErrorLineNum): + self.__SkipWhitespace() + if self._Index != self._StrLen: + Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._File, + Line=ErrorLineNum, ExtraData=ErrorString) |
