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