BaseTools: Use absolute import in Eot
[mirror_edk2.git] / BaseTools / Source / Python / Eot / c.py
1 ## @file
2 # preprocess source file
3 #
4 # Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
5 #
6 # This program and the accompanying materials
7 # are licensed and made available under the terms and conditions of the BSD License
8 # which accompanies this 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 ##
16 # Import Modules
17 #
18 from __future__ import print_function
19 from __future__ import absolute_import
20 import sys
21 import Common.LongFilePathOs as os
22 import re
23 from . import CodeFragmentCollector
24 from . import FileProfile
25 from CommonDataClass import DataClass
26 from Common import EdkLogger
27 from .EotToolError import *
28 from . import EotGlobalData
29
30 # Global Dicts
31 IncludeFileListDict = {}
32 IncludePathListDict = {}
33 ComplexTypeDict = {}
34 SUDict = {}
35
36 ## GetFuncDeclPattern() method
37 #
38 # Get the pattern of function declaration
39 #
40 # @return p: the pattern of function declaration
41 #
42 def GetFuncDeclPattern():
43 p = re.compile(r'(EFIAPI|EFI_BOOT_SERVICE|EFI_RUNTIME_SERVICE)?\s*[_\w]+\s*\(.*\).*', re.DOTALL)
44 return p
45
46 ## GetArrayPattern() method
47 #
48 # Get the pattern of array
49 #
50 # @return p: the pattern of array
51 #
52 def GetArrayPattern():
53 p = re.compile(r'[_\w]*\s*[\[.*\]]+')
54 return p
55
56 ## GetTypedefFuncPointerPattern() method
57 #
58 # Get the pattern of function pointer
59 #
60 # @return p: the pattern of function pointer
61 #
62 def GetTypedefFuncPointerPattern():
63 p = re.compile('[_\w\s]*\([\w\s]*\*+\s*[_\w]+\s*\)\s*\(.*\)', re.DOTALL)
64 return p
65
66 ## GetDB() method
67 #
68 # Get global database instance
69 #
70 # @return EotGlobalData.gDb: the global database instance
71 #
72 def GetDB():
73 return EotGlobalData.gDb
74
75 ## PrintErrorMsg() method
76 #
77 # print error message
78 #
79 # @param ErrorType: Type of error
80 # @param Msg: Error message
81 # @param TableName: table name of error found
82 # @param ItemId: id of item
83 #
84 def PrintErrorMsg(ErrorType, Msg, TableName, ItemId):
85 Msg = Msg.replace('\n', '').replace('\r', '')
86 MsgPartList = Msg.split()
87 Msg = ''
88 for Part in MsgPartList:
89 Msg += Part
90 Msg += ' '
91 GetDB().TblReport.Insert(ErrorType, OtherMsg = Msg, BelongsToTable = TableName, BelongsToItem = ItemId)
92
93 ## GetIdType() method
94 #
95 # Find type of input string
96 #
97 # @param Str: String to be parsed
98 #
99 # @return Type: The type of the string
100 #
101 def GetIdType(Str):
102 Type = DataClass.MODEL_UNKNOWN
103 Str = Str.replace('#', '# ')
104 List = Str.split()
105 if List[1] == 'include':
106 Type = DataClass.MODEL_IDENTIFIER_INCLUDE
107 elif List[1] == 'define':
108 Type = DataClass.MODEL_IDENTIFIER_MACRO_DEFINE
109 elif List[1] == 'ifdef':
110 Type = DataClass.MODEL_IDENTIFIER_MACRO_IFDEF
111 elif List[1] == 'ifndef':
112 Type = DataClass.MODEL_IDENTIFIER_MACRO_IFNDEF
113 elif List[1] == 'endif':
114 Type = DataClass.MODEL_IDENTIFIER_MACRO_ENDIF
115 elif List[1] == 'pragma':
116 Type = DataClass.MODEL_IDENTIFIER_MACRO_PROGMA
117 else:
118 Type = DataClass.MODEL_UNKNOWN
119 return Type
120
121 ## GetIdentifierList() method
122 #
123 # Get id of all files
124 #
125 # @return IdList: The list of all id of files
126 #
127 def GetIdentifierList():
128 IdList = []
129
130 for pp in FileProfile.PPDirectiveList:
131 Type = GetIdType(pp.Content)
132 IdPP = DataClass.IdentifierClass(-1, '', '', '', pp.Content, Type, -1, -1, pp.StartPos[0], pp.StartPos[1], pp.EndPos[0], pp.EndPos[1])
133 IdList.append(IdPP)
134
135 for ae in FileProfile.AssignmentExpressionList:
136 IdAE = DataClass.IdentifierClass(-1, ae.Operator, '', ae.Name, ae.Value, DataClass.MODEL_IDENTIFIER_ASSIGNMENT_EXPRESSION, -1, -1, ae.StartPos[0], ae.StartPos[1], ae.EndPos[0], ae.EndPos[1])
137 IdList.append(IdAE)
138
139 FuncDeclPattern = GetFuncDeclPattern()
140 ArrayPattern = GetArrayPattern()
141 for var in FileProfile.VariableDeclarationList:
142 DeclText = var.Declarator.strip()
143 while DeclText.startswith('*'):
144 var.Modifier += '*'
145 DeclText = DeclText.lstrip('*').strip()
146 var.Declarator = DeclText
147 if FuncDeclPattern.match(var.Declarator):
148 DeclSplitList = var.Declarator.split('(')
149 FuncName = DeclSplitList[0]
150 FuncNamePartList = FuncName.split()
151 if len(FuncNamePartList) > 1:
152 FuncName = FuncNamePartList[-1]
153 Index = 0
154 while Index < len(FuncNamePartList) - 1:
155 var.Modifier += ' ' + FuncNamePartList[Index]
156 var.Declarator = var.Declarator.lstrip().lstrip(FuncNamePartList[Index])
157 Index += 1
158 IdVar = DataClass.IdentifierClass(-1, var.Modifier, '', var.Declarator, '', DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION, -1, -1, var.StartPos[0], var.StartPos[1], var.EndPos[0], var.EndPos[1])
159 IdList.append(IdVar)
160 continue
161
162 if var.Declarator.find('{') == -1:
163 for decl in var.Declarator.split(','):
164 DeclList = decl.split('=')
165 Name = DeclList[0].strip()
166 if ArrayPattern.match(Name):
167 LSBPos = var.Declarator.find('[')
168 var.Modifier += ' ' + Name[LSBPos:]
169 Name = Name[0:LSBPos]
170
171 IdVar = DataClass.IdentifierClass(-1, var.Modifier, '', Name, (len(DeclList) > 1 and [DeclList[1]]or [''])[0], DataClass.MODEL_IDENTIFIER_VARIABLE, -1, -1, var.StartPos[0], var.StartPos[1], var.EndPos[0], var.EndPos[1])
172 IdList.append(IdVar)
173 else:
174 DeclList = var.Declarator.split('=')
175 Name = DeclList[0].strip()
176 if ArrayPattern.match(Name):
177 LSBPos = var.Declarator.find('[')
178 var.Modifier += ' ' + Name[LSBPos:]
179 Name = Name[0:LSBPos]
180 IdVar = DataClass.IdentifierClass(-1, var.Modifier, '', Name, (len(DeclList) > 1 and [DeclList[1]]or [''])[0], DataClass.MODEL_IDENTIFIER_VARIABLE, -1, -1, var.StartPos[0], var.StartPos[1], var.EndPos[0], var.EndPos[1])
181 IdList.append(IdVar)
182
183 for enum in FileProfile.EnumerationDefinitionList:
184 LBPos = enum.Content.find('{')
185 RBPos = enum.Content.find('}')
186 Name = enum.Content[4:LBPos].strip()
187 Value = enum.Content[LBPos+1:RBPos]
188 IdEnum = DataClass.IdentifierClass(-1, '', '', Name, Value, DataClass.MODEL_IDENTIFIER_ENUMERATE, -1, -1, enum.StartPos[0], enum.StartPos[1], enum.EndPos[0], enum.EndPos[1])
189 IdList.append(IdEnum)
190
191 for su in FileProfile.StructUnionDefinitionList:
192 Type = DataClass.MODEL_IDENTIFIER_STRUCTURE
193 SkipLen = 6
194 if su.Content.startswith('union'):
195 Type = DataClass.MODEL_IDENTIFIER_UNION
196 SkipLen = 5
197 LBPos = su.Content.find('{')
198 RBPos = su.Content.find('}')
199 if LBPos == -1 or RBPos == -1:
200 Name = su.Content[SkipLen:].strip()
201 Value = ''
202 else:
203 Name = su.Content[SkipLen:LBPos].strip()
204 Value = su.Content[LBPos+1:RBPos]
205 IdPE = DataClass.IdentifierClass(-1, '', '', Name, Value, Type, -1, -1, su.StartPos[0], su.StartPos[1], su.EndPos[0], su.EndPos[1])
206 IdList.append(IdPE)
207
208 TdFuncPointerPattern = GetTypedefFuncPointerPattern()
209 for td in FileProfile.TypedefDefinitionList:
210 Modifier = ''
211 Name = td.ToType
212 Value = td.FromType
213 if TdFuncPointerPattern.match(td.ToType):
214 Modifier = td.FromType
215 LBPos = td.ToType.find('(')
216 TmpStr = td.ToType[LBPos+1:].strip()
217 StarPos = TmpStr.find('*')
218 if StarPos != -1:
219 Modifier += ' ' + TmpStr[0:StarPos]
220 while TmpStr[StarPos] == '*':
221 Modifier += ' ' + '*'
222 StarPos += 1
223 TmpStr = TmpStr[StarPos:].strip()
224 RBPos = TmpStr.find(')')
225 Name = TmpStr[0:RBPos]
226 Value = 'FP' + TmpStr[RBPos + 1:]
227
228 IdTd = DataClass.IdentifierClass(-1, Modifier, '', Name, Value, DataClass.MODEL_IDENTIFIER_TYPEDEF, -1, -1, td.StartPos[0], td.StartPos[1], td.EndPos[0], td.EndPos[1])
229 IdList.append(IdTd)
230
231 for funcCall in FileProfile.FunctionCallingList:
232 IdFC = DataClass.IdentifierClass(-1, '', '', funcCall.FuncName, funcCall.ParamList, DataClass.MODEL_IDENTIFIER_FUNCTION_CALLING, -1, -1, funcCall.StartPos[0], funcCall.StartPos[1], funcCall.EndPos[0], funcCall.EndPos[1])
233 IdList.append(IdFC)
234 return IdList
235
236 ## GetParamList() method
237 #
238 # Get a list of parameters
239 #
240 # @param FuncDeclarator: Function declarator
241 # @param FuncNameLine: Line number of function name
242 # @param FuncNameOffset: Offset of function name
243 #
244 # @return ParamIdList: A list of parameters
245 #
246 def GetParamList(FuncDeclarator, FuncNameLine = 0, FuncNameOffset = 0):
247 ParamIdList = []
248 DeclSplitList = FuncDeclarator.split('(')
249 if len(DeclSplitList) < 2:
250 return ParamIdList
251 FuncName = DeclSplitList[0]
252 ParamStr = DeclSplitList[1].rstrip(')')
253 LineSkipped = 0
254 OffsetSkipped = 0
255 Start = 0
256 while FuncName.find('\n', Start) != -1:
257 LineSkipped += 1
258 OffsetSkipped = 0
259 Start += FuncName.find('\n', Start)
260 Start += 1
261 OffsetSkipped += len(FuncName[Start:])
262 OffsetSkipped += 1 #skip '('
263 ParamBeginLine = FuncNameLine + LineSkipped
264 ParamBeginOffset = OffsetSkipped
265 for p in ParamStr.split(','):
266 ListP = p.split()
267 if len(ListP) == 0:
268 continue
269 ParamName = ListP[-1]
270 DeclText = ParamName.strip()
271 RightSpacePos = p.rfind(ParamName)
272 ParamModifier = p[0:RightSpacePos]
273 if ParamName == 'OPTIONAL':
274 if ParamModifier == '':
275 ParamModifier += ' ' + 'OPTIONAL'
276 DeclText = ''
277 else:
278 ParamName = ListP[-2]
279 DeclText = ParamName.strip()
280 RightSpacePos = p.rfind(ParamName)
281 ParamModifier = p[0:RightSpacePos]
282 ParamModifier += 'OPTIONAL'
283 while DeclText.startswith('*'):
284 ParamModifier += ' ' + '*'
285 DeclText = DeclText.lstrip('*').strip()
286 ParamName = DeclText
287
288 Start = 0
289 while p.find('\n', Start) != -1:
290 LineSkipped += 1
291 OffsetSkipped = 0
292 Start += p.find('\n', Start)
293 Start += 1
294 OffsetSkipped += len(p[Start:])
295
296 ParamEndLine = ParamBeginLine + LineSkipped
297 ParamEndOffset = OffsetSkipped
298 IdParam = DataClass.IdentifierClass(-1, ParamModifier, '', ParamName, '', DataClass.MODEL_IDENTIFIER_PARAMETER, -1, -1, ParamBeginLine, ParamBeginOffset, ParamEndLine, ParamEndOffset)
299 ParamIdList.append(IdParam)
300 ParamBeginLine = ParamEndLine
301 ParamBeginOffset = OffsetSkipped + 1 #skip ','
302
303 return ParamIdList
304
305 ## GetFunctionList()
306 #
307 # Get a list of functions
308 #
309 # @return FuncObjList: A list of function objects
310 #
311 def GetFunctionList():
312 FuncObjList = []
313 for FuncDef in FileProfile.FunctionDefinitionList:
314 ParamIdList = []
315 DeclText = FuncDef.Declarator.strip()
316 while DeclText.startswith('*'):
317 FuncDef.Modifier += '*'
318 DeclText = DeclText.lstrip('*').strip()
319
320 FuncDef.Declarator = FuncDef.Declarator.lstrip('*')
321 DeclSplitList = FuncDef.Declarator.split('(')
322 if len(DeclSplitList) < 2:
323 continue
324
325 FuncName = DeclSplitList[0]
326 FuncNamePartList = FuncName.split()
327 if len(FuncNamePartList) > 1:
328 FuncName = FuncNamePartList[-1]
329 Index = 0
330 while Index < len(FuncNamePartList) - 1:
331 FuncDef.Modifier += ' ' + FuncNamePartList[Index]
332 Index += 1
333
334 FuncObj = DataClass.FunctionClass(-1, FuncDef.Declarator, FuncDef.Modifier, FuncName.strip(), '', FuncDef.StartPos[0], FuncDef.StartPos[1], FuncDef.EndPos[0], FuncDef.EndPos[1], FuncDef.LeftBracePos[0], FuncDef.LeftBracePos[1], -1, ParamIdList, [])
335 FuncObjList.append(FuncObj)
336
337 return FuncObjList
338
339 ## CreateCCodeDB() method
340 #
341 # Create database for all c code
342 #
343 # @param FileNameList: A list of all c code file names
344 #
345 def CreateCCodeDB(FileNameList):
346 FileObjList = []
347 ParseErrorFileList = []
348 ParsedFiles = {}
349 for FullName in FileNameList:
350 if os.path.splitext(FullName)[1] in ('.h', '.c'):
351 if FullName.lower() in ParsedFiles:
352 continue
353 ParsedFiles[FullName.lower()] = 1
354 EdkLogger.info("Parsing " + FullName)
355 model = FullName.endswith('c') and DataClass.MODEL_FILE_C or DataClass.MODEL_FILE_H
356 collector = CodeFragmentCollector.CodeFragmentCollector(FullName)
357 try:
358 collector.ParseFile()
359 except:
360 ParseErrorFileList.append(FullName)
361 BaseName = os.path.basename(FullName)
362 DirName = os.path.dirname(FullName)
363 Ext = os.path.splitext(BaseName)[1].lstrip('.')
364 ModifiedTime = os.path.getmtime(FullName)
365 FileObj = DataClass.FileClass(-1, BaseName, Ext, DirName, FullName, model, ModifiedTime, GetFunctionList(), GetIdentifierList(), [])
366 FileObjList.append(FileObj)
367 collector.CleanFileProfileBuffer()
368
369 if len(ParseErrorFileList) > 0:
370 EdkLogger.info("Found unrecoverable error during parsing:\n\t%s\n" % "\n\t".join(ParseErrorFileList))
371
372 Db = EotGlobalData.gDb
373 for file in FileObjList:
374 Db.InsertOneFile(file)
375
376 Db.UpdateIdentifierBelongsToFunction()
377
378 ##
379 #
380 # This acts like the main() function for the script, unless it is 'import'ed into another
381 # script.
382 #
383 if __name__ == '__main__':
384
385 EdkLogger.Initialize()
386 EdkLogger.SetLevel(EdkLogger.QUIET)
387 CollectSourceCodeDataIntoDB(sys.argv[1])
388
389 print('Done!')