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