]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/UPT/Parser/DecParserMisc.py
BaseTools: Clean up source files
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Parser / DecParserMisc.py
1 ## @file
2 # This file is used to define helper class and function for DEC parser
3 #
4 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
5 #
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
10 #
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.
13
14 '''
15 DecParserMisc
16 '''
17
18 ## Import modules
19 #
20 import os
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 IsValidFeatureFlagExp
29 from Library.ExpressionValidate import IsValidLogicalExpr
30 from Library.ExpressionValidate import IsValidStringTest
31 from Library.Misc import CheckGuidRegFormat
32
33 TOOL_NAME = 'DecParser'
34 VERSION_PATTERN = '[0-9]+(\.[0-9]+)?'
35 CVAR_PATTERN = '[_a-zA-Z][a-zA-Z0-9_]*'
36 PCD_TOKEN_PATTERN = '(0[xX]0*[a-fA-F0-9]{1,8})|([0-9]+)'
37 MACRO_PATTERN = '[A-Z][_A-Z0-9]*'
38
39 ## FileContent
40 # Class to hold DEC file information
41 #
42 class FileContent:
43 def __init__(self, Filename, FileContent2):
44 self.Filename = Filename
45 self.PackagePath, self.PackageFile = os.path.split(Filename)
46 self.LineIndex = 0
47 self.CurrentLine = ''
48 self.NextLine = ''
49 self.HeadComment = []
50 self.TailComment = []
51 self.CurrentScope = None
52 self.Content = FileContent2
53 self.Macros = {}
54 self.FileLines = len(FileContent2)
55
56 def GetNextLine(self):
57 if self.LineIndex >= self.FileLines:
58 return ''
59 Line = self.Content[self.LineIndex]
60 self.LineIndex += 1
61 return Line
62
63 def UndoNextLine(self):
64 if self.LineIndex > 0:
65 self.LineIndex -= 1
66
67 def ResetNext(self):
68 self.HeadComment = []
69 self.TailComment = []
70 self.NextLine = ''
71
72 def SetNext(self, Line, HeadComment, TailComment):
73 self.NextLine = Line
74 self.HeadComment = HeadComment
75 self.TailComment = TailComment
76
77 def IsEndOfFile(self):
78 return self.LineIndex >= self.FileLines
79
80
81 ## StripRoot
82 #
83 # Strip root path
84 #
85 # @param Root: Root must be absolute path
86 # @param Path: Path to be stripped
87 #
88 def StripRoot(Root, Path):
89 OrigPath = Path
90 Root = os.path.normpath(Root)
91 Path = os.path.normpath(Path)
92 if not os.path.isabs(Root):
93 return OrigPath
94 if Path.startswith(Root):
95 Path = Path[len(Root):]
96 if Path and Path[0] == os.sep:
97 Path = Path[1:]
98 return Path
99 return OrigPath
100
101 ## CleanString
102 #
103 # Split comments in a string
104 # Remove spaces
105 #
106 # @param Line: The string to be cleaned
107 # @param CommentCharacter: Comment char, used to ignore comment content,
108 # default is DataType.TAB_COMMENT_SPLIT
109 #
110 def CleanString(Line, CommentCharacter=TAB_COMMENT_SPLIT, \
111 AllowCppStyleComment=False):
112 #
113 # remove whitespace
114 #
115 Line = Line.strip()
116 #
117 # Replace EDK1's comment character
118 #
119 if AllowCppStyleComment:
120 Line = Line.replace(TAB_COMMENT_EDK1_SPLIT, CommentCharacter)
121 #
122 # separate comments and statements
123 #
124 Comment = ''
125 InQuote = False
126 for Index in range(0, len(Line)):
127 if Line[Index] == '"':
128 InQuote = not InQuote
129 continue
130 if Line[Index] == CommentCharacter and not InQuote:
131 Comment = Line[Index:].strip()
132 Line = Line[0:Index].strip()
133 break
134
135 return Line, Comment
136
137
138 ## IsValidNumValUint8
139 #
140 # Check if Token is NumValUint8: <NumValUint8> ::= {<ShortNum>} {<UINT8>} {<Expression>}
141 #
142 # @param Token: Token to be checked
143 #
144 def IsValidNumValUint8(Token):
145 Valid = True
146 Cause = ""
147 TokenValue = None
148 Token = Token.strip()
149 if Token.lower().startswith('0x'):
150 Base = 16
151 else:
152 Base = 10
153 try:
154 TokenValue = long(Token, Base)
155 except BaseException:
156 Valid, Cause = IsValidLogicalExpr(Token, True)
157 if Cause:
158 pass
159 if not Valid:
160 return False
161 if TokenValue and (TokenValue < 0 or TokenValue > 0xFF):
162 return False
163 else:
164 return True
165
166 ## IsValidNList
167 #
168 # Check if Value has the format of <NumValUint8> ["," <NumValUint8>]{0,}
169 # <NumValUint8> ::= {<ShortNum>} {<UINT8>} {<Expression>}
170 #
171 # @param Value: Value to be checked
172 #
173 def IsValidNList(Value):
174 Par = ParserHelper(Value)
175 if Par.End():
176 return False
177 while not Par.End():
178 Token = Par.GetToken(',')
179 if not IsValidNumValUint8(Token):
180 return False
181 if Par.Expect(','):
182 if Par.End():
183 return False
184 continue
185 else:
186 break
187 return Par.End()
188
189 ## IsValidCArray
190 #
191 # check Array is valid
192 #
193 # @param Array: The input Array
194 #
195 def IsValidCArray(Array):
196 Par = ParserHelper(Array)
197 if not Par.Expect('{'):
198 return False
199 if Par.End():
200 return False
201 while not Par.End():
202 Token = Par.GetToken(',}')
203 #
204 # ShortNum, UINT8, Expression
205 #
206 if not IsValidNumValUint8(Token):
207 return False
208 if Par.Expect(','):
209 if Par.End():
210 return False
211 continue
212 elif Par.Expect('}'):
213 #
214 # End of C array
215 #
216 break
217 else:
218 return False
219 return Par.End()
220
221 ## IsValidPcdDatum
222 #
223 # check PcdDatum is valid
224 #
225 # @param Type: The pcd Type
226 # @param Value: The pcd Value
227 #
228 def IsValidPcdDatum(Type, Value):
229 if not Value:
230 return False, ST.ERR_DECPARSE_PCD_VALUE_EMPTY
231 Valid = True
232 Cause = ""
233 if Type not in ["UINT8", "UINT16", "UINT32", "UINT64", "VOID*", "BOOLEAN"]:
234 return False, ST.ERR_DECPARSE_PCD_TYPE
235 if Type == "VOID*":
236 if not ((Value.startswith('L"') or Value.startswith('"') and \
237 Value.endswith('"'))
238 or (IsValidCArray(Value)) or (IsValidCFormatGuid(Value)) \
239 or (IsValidNList(Value)) or (CheckGuidRegFormat(Value))
240 ):
241 return False, ST.ERR_DECPARSE_PCD_VOID % (Value, Type)
242 RealString = Value[Value.find('"') + 1 :-1]
243 if RealString:
244 if not IsValidBareCString(RealString):
245 return False, ST.ERR_DECPARSE_PCD_VOID % (Value, Type)
246 elif Type == 'BOOLEAN':
247 if Value in ['TRUE', 'FALSE', 'true', 'false', 'True', 'False',
248 '0x1', '0x01', '1', '0x0', '0x00', '0']:
249 return True, ""
250 Valid, Cause = IsValidStringTest(Value, True)
251 if not Valid:
252 Valid, Cause = IsValidFeatureFlagExp(Value, True)
253 if not Valid:
254 return False, Cause
255 else:
256 if Value and (Value[0] == '-' or Value[0] == '+'):
257 return False, ST.ERR_DECPARSE_PCD_INT_NEGTIVE % (Value, Type)
258 try:
259 StrVal = Value
260 if Value and not Value.startswith('0x') \
261 and not Value.startswith('0X'):
262 Value = Value.lstrip('0')
263 if not Value:
264 return True, ""
265 Value = long(Value, 0)
266 TypeLenMap = {
267 #
268 # 0x00 - 0xff
269 #
270 'UINT8' : 2,
271 #
272 # 0x0000 - 0xffff
273 #
274 'UINT16' : 4,
275 #
276 # 0x00000000 - 0xffffffff
277 #
278 'UINT32' : 8,
279 #
280 # 0x0 - 0xffffffffffffffff
281 #
282 'UINT64' : 16
283 }
284 HexStr = hex(Value)
285 #
286 # First two chars of HexStr are 0x and tail char is L
287 #
288 if TypeLenMap[Type] < len(HexStr) - 3:
289 return False, ST.ERR_DECPARSE_PCD_INT_EXCEED % (StrVal, Type)
290 except BaseException:
291 Valid, Cause = IsValidLogicalExpr(Value, True)
292 if not Valid:
293 return False, Cause
294
295 return True, ""
296
297 ## ParserHelper
298 #
299 class ParserHelper:
300 def __init__(self, String, File=''):
301 self._String = String
302 self._StrLen = len(String)
303 self._Index = 0
304 self._File = File
305
306 ## End
307 #
308 # End
309 #
310 def End(self):
311 self.__SkipWhitespace()
312 return self._Index >= self._StrLen
313
314 ## __SkipWhitespace
315 #
316 # Skip whitespace
317 #
318 def __SkipWhitespace(self):
319 for Char in self._String[self._Index:]:
320 if Char not in ' \t':
321 break
322 self._Index += 1
323
324 ## Expect
325 #
326 # Expect char in string
327 #
328 # @param ExpectChar: char expected in index of string
329 #
330 def Expect(self, ExpectChar):
331 self.__SkipWhitespace()
332 for Char in self._String[self._Index:]:
333 if Char != ExpectChar:
334 return False
335 else:
336 self._Index += 1
337 return True
338 #
339 # Index out of bound of String
340 #
341 return False
342
343 ## GetToken
344 #
345 # Get token until encounter StopChar, front whitespace is consumed
346 #
347 # @param StopChar: Get token until encounter char in StopChar
348 # @param StkipPair: Only can be ' or ", StopChar in SkipPair are skipped
349 #
350 def GetToken(self, StopChar='.,|\t ', SkipPair='"'):
351 self.__SkipWhitespace()
352 PreIndex = self._Index
353 InQuote = False
354 LastChar = ''
355 for Char in self._String[self._Index:]:
356 if Char == SkipPair and LastChar != '\\':
357 InQuote = not InQuote
358 if Char in StopChar and not InQuote:
359 break
360 self._Index += 1
361 if Char == '\\' and LastChar == '\\':
362 LastChar = ''
363 else:
364 LastChar = Char
365 return self._String[PreIndex:self._Index]
366
367 ## AssertChar
368 #
369 # Assert char at current index of string is AssertChar, or will report
370 # error message
371 #
372 # @param AssertChar: AssertChar
373 # @param ErrorString: ErrorString
374 # @param ErrorLineNum: ErrorLineNum
375 #
376 def AssertChar(self, AssertChar, ErrorString, ErrorLineNum):
377 if not self.Expect(AssertChar):
378 Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._File,
379 Line=ErrorLineNum, ExtraData=ErrorString)
380
381 ## AssertEnd
382 #
383 # @param ErrorString: ErrorString
384 # @param ErrorLineNum: ErrorLineNum
385 #
386 def AssertEnd(self, ErrorString, ErrorLineNum):
387 self.__SkipWhitespace()
388 if self._Index != self._StrLen:
389 Logger.Error(TOOL_NAME, FILE_PARSE_FAILURE, File=self._File,
390 Line=ErrorLineNum, ExtraData=ErrorString)