2 # This file is used to define helper class and function for DEC parser
4 # Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
6 # This program and the accompanying materials are licensed and made available
7 # under the terms and conditions of the BSD License which accompanies this
8 # distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 import Logger
.Log
as Logger
22 from Logger
.ToolError
import FILE_PARSE_FAILURE
23 from Logger
import StringTable
as ST
24 from Library
.DataType
import TAB_COMMENT_SPLIT
25 from Library
.DataType
import TAB_COMMENT_EDK1_SPLIT
26 from Library
.ExpressionValidate
import IsValidBareCString
27 from Library
.ParserValidate
import IsValidCFormatGuid
28 from Library
.ExpressionValidate
import IsValidLogicalExpr
29 from Library
.ExpressionValidate
import IsValidStringTest
30 from Library
.Misc
import CheckGuidRegFormat
32 TOOL_NAME
= 'DecParser'
33 VERSION_PATTERN
= '[0-9]+(\.[0-9]+)?'
34 CVAR_PATTERN
= '[_a-zA-Z][a-zA-Z0-9_]*'
35 PCD_TOKEN_PATTERN
= '(0[xX]0*[a-fA-F0-9]{1,8})|([0-9]+)'
36 MACRO_PATTERN
= '[A-Z][_A-Z0-9]*'
39 # Class to hold DEC file information
42 def __init__(self
, Filename
, FileContent2
):
43 self
.Filename
= Filename
44 self
.PackagePath
, self
.PackageFile
= os
.path
.split(Filename
)
50 self
.CurrentScope
= None
51 self
.Content
= FileContent2
53 self
.FileLines
= len(FileContent2
)
55 def GetNextLine(self
):
56 if self
.LineIndex
>= self
.FileLines
:
58 Line
= self
.Content
[self
.LineIndex
]
62 def UndoNextLine(self
):
63 if self
.LineIndex
> 0:
71 def SetNext(self
, Line
, HeadComment
, TailComment
):
73 self
.HeadComment
= HeadComment
74 self
.TailComment
= TailComment
76 def IsEndOfFile(self
):
77 return self
.LineIndex
>= self
.FileLines
84 # @param Root: Root must be absolute path
85 # @param Path: Path to be stripped
87 def StripRoot(Root
, Path
):
89 Root
= os
.path
.normpath(Root
)
90 Path
= os
.path
.normpath(Path
)
91 if not os
.path
.isabs(Root
):
93 if Path
.startswith(Root
):
94 Path
= Path
[len(Root
):]
95 if Path
and Path
[0] == os
.sep
:
102 # Split comments in a string
105 # @param Line: The string to be cleaned
106 # @param CommentCharacter: Comment char, used to ignore comment content,
107 # default is DataType.TAB_COMMENT_SPLIT
109 def CleanString(Line
, CommentCharacter
=TAB_COMMENT_SPLIT
, \
110 AllowCppStyleComment
=False):
116 # Replace EDK1's comment character
118 if AllowCppStyleComment
:
119 Line
= Line
.replace(TAB_COMMENT_EDK1_SPLIT
, CommentCharacter
)
121 # separate comments and statements
125 for Index
in range(0, len(Line
)):
126 if Line
[Index
] == '"':
127 InQuote
= not InQuote
129 if Line
[Index
] == CommentCharacter
and not InQuote
:
130 Comment
= Line
[Index
:].strip()
131 Line
= Line
[0:Index
].strip()
139 # Check if Token is HexByte: <HexByte> ::= 0x <HexDigit>{1,2}
141 # @param Token: Token to be checked
143 def IsValidHexByte(Token
):
144 Token
= Token
.strip()
145 if not Token
.lower().startswith('0x') or not (len(Token
) < 5 and len(Token
) > 2):
148 Token
= long(Token
, 0)
149 except BaseException
:
155 # Check if Value has the format of <HexByte> ["," <HexByte>]{0,}
156 # <HexByte> ::= "0x" <HexDigit>{1,2}
158 # @param Value: Value to be checked
160 def IsValidNList(Value
):
161 Par
= ParserHelper(Value
)
165 Token
= Par
.GetToken(',\t ')
166 if not IsValidHexByte(Token
):
178 # check Array is valid
180 # @param Array: The input Array
182 def IsValidCArray(Array
):
183 Par
= ParserHelper(Array
)
184 if not Par
.Expect('{'):
189 Token
= Par
.GetToken(',}\t ')
193 if not IsValidHexByte(Token
):
199 elif Par
.Expect('}'):
210 # check PcdDatum is valid
212 # @param Type: The pcd Type
213 # @param Value: The pcd Value
215 def IsValidPcdDatum(Type
, Value
):
216 if Type
not in ["UINT8", "UINT16", "UINT32", "UINT64", "VOID*", "BOOLEAN"]:
217 return False, ST
.ERR_DECPARSE_PCD_TYPE
219 if not ((Value
.startswith('L"') or Value
.startswith('"') and \
221 or (IsValidCArray(Value
)) or (IsValidCFormatGuid(Value
)) \
222 or (IsValidNList(Value
)) or (CheckGuidRegFormat(Value
))
224 return False, ST
.ERR_DECPARSE_PCD_VOID
% (Value
, Type
)
225 RealString
= Value
[Value
.find('"') + 1 :-1]
227 if not IsValidBareCString(RealString
):
228 return False, ST
.ERR_DECPARSE_PCD_VOID
% (Value
, Type
)
229 elif Type
== 'BOOLEAN':
230 if Value
in ['TRUE', 'FALSE', 'true', 'false', 'True', 'False',
231 '0x1', '0x01', '1', '0x0', '0x00', '0']:
233 Valid
, Cause
= IsValidStringTest(Value
)
235 Valid
, Cause
= IsValidLogicalExpr(Value
)
239 if Value
and (Value
[0] == '-' or Value
[0] == '+'):
240 return False, ST
.ERR_DECPARSE_PCD_INT_NEGTIVE
% (Value
, Type
)
243 if Value
and not Value
.startswith('0x') \
244 and not Value
.startswith('0X'):
245 Value
= Value
.lstrip('0')
248 Value
= long(Value
, 0)
259 # 0x00000000 - 0xffffffff
263 # 0x0 - 0xffffffffffffffff
269 # First two chars of HexStr are 0x and tail char is L
271 if TypeLenMap
[Type
] < len(HexStr
) - 3:
272 return False, ST
.ERR_DECPARSE_PCD_INT_EXCEED
% (StrVal
, Type
)
273 except BaseException
:
274 return False, ST
.ERR_DECPARSE_PCD_INT
% (Value
, Type
)
281 def __init__(self
, String
, File
=''):
282 self
._String
= String
283 self
._StrLen
= len(String
)
292 self
.__SkipWhitespace
()
293 return self
._Index
>= self
._StrLen
299 def __SkipWhitespace(self
):
300 for Char
in self
._String
[self
._Index
:]:
301 if Char
not in ' \t':
307 # Expect char in string
309 # @param ExpectChar: char expected in index of string
311 def Expect(self
, ExpectChar
):
312 self
.__SkipWhitespace
()
313 for Char
in self
._String
[self
._Index
:]:
314 if Char
!= ExpectChar
:
320 # Index out of bound of String
326 # Get token until encounter StopChar, front whitespace is consumed
328 # @param StopChar: Get token until encounter char in StopChar
329 # @param StkipPair: Only can be ' or ", StopChar in SkipPair are skipped
331 def GetToken(self
, StopChar
='.,|\t ', SkipPair
='"'):
332 self
.__SkipWhitespace
()
333 PreIndex
= self
._Index
336 for Char
in self
._String
[self
._Index
:]:
337 if Char
== SkipPair
and LastChar
!= '\\':
338 InQuote
= not InQuote
339 if Char
in StopChar
and not InQuote
:
342 if Char
== '\\' and LastChar
== '\\':
346 return self
._String
[PreIndex
:self
._Index
]
350 # Assert char at current index of string is AssertChar, or will report
353 # @param AssertChar: AssertChar
354 # @param ErrorString: ErrorString
355 # @param ErrorLineNum: ErrorLineNum
357 def AssertChar(self
, AssertChar
, ErrorString
, ErrorLineNum
):
358 if not self
.Expect(AssertChar
):
359 Logger
.Error(TOOL_NAME
, FILE_PARSE_FAILURE
, File
=self
._File
,
360 Line
=ErrorLineNum
, ExtraData
=ErrorString
)
364 # @param ErrorString: ErrorString
365 # @param ErrorLineNum: ErrorLineNum
367 def AssertEnd(self
, ErrorString
, ErrorLineNum
):
368 self
.__SkipWhitespace
()
369 if self
._Index
!= self
._StrLen
:
370 Logger
.Error(TOOL_NAME
, FILE_PARSE_FAILURE
, File
=self
._File
,
371 Line
=ErrorLineNum
, ExtraData
=ErrorString
)