| ## @file | |
| # preprocess source file | |
| # | |
| # Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR> | |
| # | |
| # This program and the accompanying materials | |
| # are licensed and made available under the terms and conditions of the BSD License | |
| # which accompanies this distribution. The full text of the license may be found at | |
| # http://opensource.org/licenses/bsd-license.php | |
| # | |
| # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| # | |
| ## | |
| # Import Modules | |
| # | |
| import sys | |
| import Common.LongFilePathOs as os | |
| import re | |
| import CodeFragmentCollector | |
| import FileProfile | |
| from CommonDataClass import DataClass | |
| from Common import EdkLogger | |
| from EotToolError import * | |
| import EotGlobalData | |
| # Global Dicts | |
| IncludeFileListDict = {} | |
| IncludePathListDict = {} | |
| ComplexTypeDict = {} | |
| SUDict = {} | |
| ## GetFuncDeclPattern() method | |
| # | |
| # Get the pattern of function declaration | |
| # | |
| # @return p: the pattern of function declaration | |
| # | |
| def GetFuncDeclPattern(): | |
| p = re.compile(r'(EFIAPI|EFI_BOOT_SERVICE|EFI_RUNTIME_SERVICE)?\s*[_\w]+\s*\(.*\).*', re.DOTALL) | |
| return p | |
| ## GetArrayPattern() method | |
| # | |
| # Get the pattern of array | |
| # | |
| # @return p: the pattern of array | |
| # | |
| def GetArrayPattern(): | |
| p = re.compile(r'[_\w]*\s*[\[.*\]]+') | |
| return p | |
| ## GetTypedefFuncPointerPattern() method | |
| # | |
| # Get the pattern of function pointer | |
| # | |
| # @return p: the pattern of function pointer | |
| # | |
| def GetTypedefFuncPointerPattern(): | |
| p = re.compile('[_\w\s]*\([\w\s]*\*+\s*[_\w]+\s*\)\s*\(.*\)', re.DOTALL) | |
| return p | |
| ## GetDB() method | |
| # | |
| # Get global database instance | |
| # | |
| # @return EotGlobalData.gDb: the global database instance | |
| # | |
| def GetDB(): | |
| return EotGlobalData.gDb | |
| ## PrintErrorMsg() method | |
| # | |
| # print error message | |
| # | |
| # @param ErrorType: Type of error | |
| # @param Msg: Error message | |
| # @param TableName: table name of error found | |
| # @param ItemId: id of item | |
| # | |
| def PrintErrorMsg(ErrorType, Msg, TableName, ItemId): | |
| Msg = Msg.replace('\n', '').replace('\r', '') | |
| MsgPartList = Msg.split() | |
| Msg = '' | |
| for Part in MsgPartList: | |
| Msg += Part | |
| Msg += ' ' | |
| GetDB().TblReport.Insert(ErrorType, OtherMsg = Msg, BelongsToTable = TableName, BelongsToItem = ItemId) | |
| ## GetIdType() method | |
| # | |
| # Find type of input string | |
| # | |
| # @param Str: String to be parsed | |
| # | |
| # @return Type: The type of the string | |
| # | |
| def GetIdType(Str): | |
| Type = DataClass.MODEL_UNKNOWN | |
| Str = Str.replace('#', '# ') | |
| List = Str.split() | |
| if List[1] == 'include': | |
| Type = DataClass.MODEL_IDENTIFIER_INCLUDE | |
| elif List[1] == 'define': | |
| Type = DataClass.MODEL_IDENTIFIER_MACRO_DEFINE | |
| elif List[1] == 'ifdef': | |
| Type = DataClass.MODEL_IDENTIFIER_MACRO_IFDEF | |
| elif List[1] == 'ifndef': | |
| Type = DataClass.MODEL_IDENTIFIER_MACRO_IFNDEF | |
| elif List[1] == 'endif': | |
| Type = DataClass.MODEL_IDENTIFIER_MACRO_ENDIF | |
| elif List[1] == 'pragma': | |
| Type = DataClass.MODEL_IDENTIFIER_MACRO_PROGMA | |
| else: | |
| Type = DataClass.MODEL_UNKNOWN | |
| return Type | |
| ## GetIdentifierList() method | |
| # | |
| # Get id of all files | |
| # | |
| # @return IdList: The list of all id of files | |
| # | |
| def GetIdentifierList(): | |
| IdList = [] | |
| for pp in FileProfile.PPDirectiveList: | |
| Type = GetIdType(pp.Content) | |
| IdPP = DataClass.IdentifierClass(-1, '', '', '', pp.Content, Type, -1, -1, pp.StartPos[0],pp.StartPos[1],pp.EndPos[0],pp.EndPos[1]) | |
| IdList.append(IdPP) | |
| for ae in FileProfile.AssignmentExpressionList: | |
| 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]) | |
| IdList.append(IdAE) | |
| FuncDeclPattern = GetFuncDeclPattern() | |
| ArrayPattern = GetArrayPattern() | |
| for var in FileProfile.VariableDeclarationList: | |
| DeclText = var.Declarator.strip() | |
| while DeclText.startswith('*'): | |
| var.Modifier += '*' | |
| DeclText = DeclText.lstrip('*').strip() | |
| var.Declarator = DeclText | |
| if FuncDeclPattern.match(var.Declarator): | |
| DeclSplitList = var.Declarator.split('(') | |
| FuncName = DeclSplitList[0] | |
| FuncNamePartList = FuncName.split() | |
| if len(FuncNamePartList) > 1: | |
| FuncName = FuncNamePartList[-1] | |
| Index = 0 | |
| while Index < len(FuncNamePartList) - 1: | |
| var.Modifier += ' ' + FuncNamePartList[Index] | |
| var.Declarator = var.Declarator.lstrip().lstrip(FuncNamePartList[Index]) | |
| Index += 1 | |
| 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]) | |
| IdList.append(IdVar) | |
| continue | |
| if var.Declarator.find('{') == -1: | |
| for decl in var.Declarator.split(','): | |
| DeclList = decl.split('=') | |
| Name = DeclList[0].strip() | |
| if ArrayPattern.match(Name): | |
| LSBPos = var.Declarator.find('[') | |
| var.Modifier += ' ' + Name[LSBPos:] | |
| Name = Name[0:LSBPos] | |
| 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]) | |
| IdList.append(IdVar) | |
| else: | |
| DeclList = var.Declarator.split('=') | |
| Name = DeclList[0].strip() | |
| if ArrayPattern.match(Name): | |
| LSBPos = var.Declarator.find('[') | |
| var.Modifier += ' ' + Name[LSBPos:] | |
| Name = Name[0:LSBPos] | |
| 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]) | |
| IdList.append(IdVar) | |
| for enum in FileProfile.EnumerationDefinitionList: | |
| LBPos = enum.Content.find('{') | |
| RBPos = enum.Content.find('}') | |
| Name = enum.Content[4:LBPos].strip() | |
| Value = enum.Content[LBPos+1:RBPos] | |
| IdEnum = DataClass.IdentifierClass(-1, '', '', Name, Value, DataClass.MODEL_IDENTIFIER_ENUMERATE, -1, -1, enum.StartPos[0],enum.StartPos[1],enum.EndPos[0],enum.EndPos[1]) | |
| IdList.append(IdEnum) | |
| for su in FileProfile.StructUnionDefinitionList: | |
| Type = DataClass.MODEL_IDENTIFIER_STRUCTURE | |
| SkipLen = 6 | |
| if su.Content.startswith('union'): | |
| Type = DataClass.MODEL_IDENTIFIER_UNION | |
| SkipLen = 5 | |
| LBPos = su.Content.find('{') | |
| RBPos = su.Content.find('}') | |
| if LBPos == -1 or RBPos == -1: | |
| Name = su.Content[SkipLen:].strip() | |
| Value = '' | |
| else: | |
| Name = su.Content[SkipLen:LBPos].strip() | |
| Value = su.Content[LBPos+1:RBPos] | |
| IdPE = DataClass.IdentifierClass(-1, '', '', Name, Value, Type, -1, -1, su.StartPos[0],su.StartPos[1],su.EndPos[0],su.EndPos[1]) | |
| IdList.append(IdPE) | |
| TdFuncPointerPattern = GetTypedefFuncPointerPattern() | |
| for td in FileProfile.TypedefDefinitionList: | |
| Modifier = '' | |
| Name = td.ToType | |
| Value = td.FromType | |
| if TdFuncPointerPattern.match(td.ToType): | |
| Modifier = td.FromType | |
| LBPos = td.ToType.find('(') | |
| TmpStr = td.ToType[LBPos+1:].strip() | |
| StarPos = TmpStr.find('*') | |
| if StarPos != -1: | |
| Modifier += ' ' + TmpStr[0:StarPos] | |
| while TmpStr[StarPos] == '*': | |
| Modifier += ' ' + '*' | |
| StarPos += 1 | |
| TmpStr = TmpStr[StarPos:].strip() | |
| RBPos = TmpStr.find(')') | |
| Name = TmpStr[0:RBPos] | |
| Value = 'FP' + TmpStr[RBPos + 1:] | |
| 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]) | |
| IdList.append(IdTd) | |
| for funcCall in FileProfile.FunctionCallingList: | |
| 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]) | |
| IdList.append(IdFC) | |
| return IdList | |
| ## GetParamList() method | |
| # | |
| # Get a list of parameters | |
| # | |
| # @param FuncDeclarator: Function declarator | |
| # @param FuncNameLine: Line number of function name | |
| # @param FuncNameOffset: Offset of function name | |
| # | |
| # @return ParamIdList: A list of parameters | |
| # | |
| def GetParamList(FuncDeclarator, FuncNameLine = 0, FuncNameOffset = 0): | |
| ParamIdList = [] | |
| DeclSplitList = FuncDeclarator.split('(') | |
| if len(DeclSplitList) < 2: | |
| return ParamIdList | |
| FuncName = DeclSplitList[0] | |
| ParamStr = DeclSplitList[1].rstrip(')') | |
| LineSkipped = 0 | |
| OffsetSkipped = 0 | |
| Start = 0 | |
| while FuncName.find('\n', Start) != -1: | |
| LineSkipped += 1 | |
| OffsetSkipped = 0 | |
| Start += FuncName.find('\n', Start) | |
| Start += 1 | |
| OffsetSkipped += len(FuncName[Start:]) | |
| OffsetSkipped += 1 #skip '(' | |
| ParamBeginLine = FuncNameLine + LineSkipped | |
| ParamBeginOffset = OffsetSkipped | |
| for p in ParamStr.split(','): | |
| ListP = p.split() | |
| if len(ListP) == 0: | |
| continue | |
| ParamName = ListP[-1] | |
| DeclText = ParamName.strip() | |
| RightSpacePos = p.rfind(ParamName) | |
| ParamModifier = p[0:RightSpacePos] | |
| if ParamName == 'OPTIONAL': | |
| if ParamModifier == '': | |
| ParamModifier += ' ' + 'OPTIONAL' | |
| DeclText = '' | |
| else: | |
| ParamName = ListP[-2] | |
| DeclText = ParamName.strip() | |
| RightSpacePos = p.rfind(ParamName) | |
| ParamModifier = p[0:RightSpacePos] | |
| ParamModifier += 'OPTIONAL' | |
| while DeclText.startswith('*'): | |
| ParamModifier += ' ' + '*' | |
| DeclText = DeclText.lstrip('*').strip() | |
| ParamName = DeclText | |
| Start = 0 | |
| while p.find('\n', Start) != -1: | |
| LineSkipped += 1 | |
| OffsetSkipped = 0 | |
| Start += p.find('\n', Start) | |
| Start += 1 | |
| OffsetSkipped += len(p[Start:]) | |
| ParamEndLine = ParamBeginLine + LineSkipped | |
| ParamEndOffset = OffsetSkipped | |
| IdParam = DataClass.IdentifierClass(-1, ParamModifier, '', ParamName, '', DataClass.MODEL_IDENTIFIER_PARAMETER, -1, -1, ParamBeginLine, ParamBeginOffset, ParamEndLine, ParamEndOffset) | |
| ParamIdList.append(IdParam) | |
| ParamBeginLine = ParamEndLine | |
| ParamBeginOffset = OffsetSkipped + 1 #skip ',' | |
| return ParamIdList | |
| ## GetFunctionList() | |
| # | |
| # Get a list of functions | |
| # | |
| # @return FuncObjList: A list of function objects | |
| # | |
| def GetFunctionList(): | |
| FuncObjList = [] | |
| for FuncDef in FileProfile.FunctionDefinitionList: | |
| ParamIdList = [] | |
| DeclText = FuncDef.Declarator.strip() | |
| while DeclText.startswith('*'): | |
| FuncDef.Modifier += '*' | |
| DeclText = DeclText.lstrip('*').strip() | |
| FuncDef.Declarator = FuncDef.Declarator.lstrip('*') | |
| DeclSplitList = FuncDef.Declarator.split('(') | |
| if len(DeclSplitList) < 2: | |
| continue | |
| FuncName = DeclSplitList[0] | |
| FuncNamePartList = FuncName.split() | |
| if len(FuncNamePartList) > 1: | |
| FuncName = FuncNamePartList[-1] | |
| Index = 0 | |
| while Index < len(FuncNamePartList) - 1: | |
| FuncDef.Modifier += ' ' + FuncNamePartList[Index] | |
| Index += 1 | |
| 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, []) | |
| FuncObjList.append(FuncObj) | |
| return FuncObjList | |
| ## CreateCCodeDB() method | |
| # | |
| # Create database for all c code | |
| # | |
| # @param FileNameList: A list of all c code file names | |
| # | |
| def CreateCCodeDB(FileNameList): | |
| FileObjList = [] | |
| ParseErrorFileList = [] | |
| ParsedFiles = {} | |
| for FullName in FileNameList: | |
| if os.path.splitext(FullName)[1] in ('.h', '.c'): | |
| if FullName.lower() in ParsedFiles: | |
| continue | |
| ParsedFiles[FullName.lower()] = 1 | |
| EdkLogger.info("Parsing " + FullName) | |
| model = FullName.endswith('c') and DataClass.MODEL_FILE_C or DataClass.MODEL_FILE_H | |
| collector = CodeFragmentCollector.CodeFragmentCollector(FullName) | |
| try: | |
| collector.ParseFile() | |
| except: | |
| ParseErrorFileList.append(FullName) | |
| BaseName = os.path.basename(FullName) | |
| DirName = os.path.dirname(FullName) | |
| Ext = os.path.splitext(BaseName)[1].lstrip('.') | |
| ModifiedTime = os.path.getmtime(FullName) | |
| FileObj = DataClass.FileClass(-1, BaseName, Ext, DirName, FullName, model, ModifiedTime, GetFunctionList(), GetIdentifierList(), []) | |
| FileObjList.append(FileObj) | |
| collector.CleanFileProfileBuffer() | |
| if len(ParseErrorFileList) > 0: | |
| EdkLogger.info("Found unrecoverable error during parsing:\n\t%s\n" % "\n\t".join(ParseErrorFileList)) | |
| Db = EotGlobalData.gDb | |
| for file in FileObjList: | |
| Db.InsertOneFile(file) | |
| Db.UpdateIdentifierBelongsToFunction() | |
| ## | |
| # | |
| # This acts like the main() function for the script, unless it is 'import'ed into another | |
| # script. | |
| # | |
| if __name__ == '__main__': | |
| EdkLogger.Initialize() | |
| EdkLogger.SetLevel(EdkLogger.QUIET) | |
| CollectSourceCodeDataIntoDB(sys.argv[1]) | |
| print 'Done!' |