From fb6acb33138b74833a8bf8b2afd332f8564f435f Mon Sep 17 00:00:00 2001 From: mattias Date: Tue, 18 Mar 2008 13:38:22 +0000 Subject: [PATCH] codetools: c parser: implemented parsing function parameters git-svn-id: trunk@14569 - --- components/codetools/ccodeparsertool.pas | 72 +++++++++++++++++++-- components/codetools/h2pastool.pas | 81 ++++++++++++++++++------ 2 files changed, 128 insertions(+), 25 deletions(-) diff --git a/components/codetools/ccodeparsertool.pas b/components/codetools/ccodeparsertool.pas index 8f0e7d7963..df9e089f30 100644 --- a/components/codetools/ccodeparsertool.pas +++ b/components/codetools/ccodeparsertool.pas @@ -62,7 +62,8 @@ const ccnFunction = 11+ccnBase;// e.g. int i() ccnName = 12+ccnBase;// e.g. i ccnFuncParamList = 13+ccnBase;// e.g. () - ccnStatementBlock = 14+ccnBase;// e.g. {} + ccnFuncParameter = 14+ccnBase;// e.g. () + ccnStatementBlock = 15+ccnBase;// e.g. {} type TCCodeParserTool = class; @@ -97,6 +98,7 @@ type procedure CloseNodes; procedure ReadVariable; + procedure ReadParameterList; procedure ReadEnum; procedure ReadStruct; procedure ReadUnion; @@ -180,6 +182,7 @@ type WithDirectives: boolean = false): string; function ExtractFunctionResultType(FuncNode: TCodeTreeNode; WithDirectives: boolean = false): string; + function IsPointerToFunction(FuncNode: TCodeTreeNode): boolean; function ExtractEnumBlockName(EnumBlockNode: TCodeTreeNode): string; function ExtractEnumIDName(EnumIDNode: TCodeTreeNode): string; function ExtractEnumIDValue(EnumIDNode: TCodeTreeNode; @@ -224,6 +227,7 @@ begin ccnFunction : Result:='function'; ccnName : Result:='name'; ccnFuncParamList : Result:='function-param-list'; + ccnFuncParameter : Result:='function-parameter'; ccnStatementBlock: Result:='statement-block'; else Result:='?('+IntToStr(Desc)+')'; end; @@ -752,28 +756,25 @@ begin // this is a function => read parameter list IsFunction:=true; MainNode.Desc:=ccnFunction; - CreateChildNode(ccnFuncParamList); - ReadTilBracketClose(true); - CurNode.EndPos:=SrcPos; - EndChildNode; + ReadParameterList; + ReadNextAtom; if CurNode.Parent.Desc=ccnTypedef then begin if AtomIsChar('{') then RaiseException('typedef can not have a statement block'); end else begin - ReadNextAtom; if AtomIsChar('{') then begin // read statements {} CreateChildNode(ccnStatementBlock); ReadTilBracketClose(true); CurNode.EndPos:=SrcPos; EndChildNode; + ReadNextAtom; end else if not AtomIsChar(';') then begin // functions without statements are external and must end with a semicolon RaiseExpectedButAtomFound(';'); end; NeedEnd:=false; end; - ReadNextAtom; end else if AtomIsChar('[') then begin // read array brackets while AtomIsChar('[') do begin @@ -802,6 +803,40 @@ begin EndChildNode; end; +procedure TCCodeParserTool.ReadParameterList; +// start on (, end on ) +var + StartPos: LongInt; +begin + CreateChildNode(ccnFuncParamList); + StartPos:=AtomStart; + repeat + ReadNextAtom; + if AtomStart>SrcLen then begin + // missing closing bracket + AtomStart:=StartPos; + SrcPos:=AtomStart+1; + RaiseException('closing bracket not found'); + end; + if AtomIs(')') then break; + if AtomIs(',') then + RaiseExpectedButAtomFound('parameter type'); + // read parameter + CreateChildNode(ccnFuncParameter); + repeat + if AtomStart>SrcLen then break; + if AtomIs('(') or AtomIs('[') then + ReadTilBracketClose(true); + if AtomIs(',') or AtomIs(')') then break; + CurNode.EndPos:=SrcPos; + ReadNextAtom; + until false; + EndChildNode; + until AtomIs(')'); + CurNode.EndPos:=SrcPos; + EndChildNode; +end; + procedure TCCodeParserTool.RaiseException(const AMessage: string; ReportPos: integer); begin LastErrorMsg:=AMessage; @@ -1320,6 +1355,29 @@ begin end; end; +function TCCodeParserTool.IsPointerToFunction(FuncNode: TCodeTreeNode + ): boolean; +// for example: int *(*fp)(); +var + NameNode: TCodeTreeNode; +begin + NameNode:=FuncNode.FirstChild; + if (NameNode=nil) or (NameNode.Desc<>ccnName) then exit(false); + MoveCursorToNode(FuncNode); + repeat + ReadNextAtom; + if AtomStart>SrcLen then exit; + if AtomIs('(') then exit(true); + if (IsIdentStartChar[Src[AtomStart]]) + or (AtomIs('*')) then begin + // skip words and * + end else begin + break; + end; + until AtomStart>=NameNode.StartPos; + Result:=false; +end; + function TCCodeParserTool.ExtractEnumBlockName(EnumBlockNode: TCodeTreeNode ): string; var diff --git a/components/codetools/h2pastool.pas b/components/codetools/h2pastool.pas index 19c8057cdb..1d8e0176fc 100644 --- a/components/codetools/h2pastool.pas +++ b/components/codetools/h2pastool.pas @@ -115,7 +115,7 @@ type function CreateAutoGeneratedH2PNode(var PascalName: string; CNode: TCodeTreeNode; PascalDesc: TCodeTreeNodeDesc; const PascalCode: string; ParentNode: TH2PNode = nil; IsGlobal: boolean = true): TH2PNode; - function GetTypeForVarType(CVarNode: TCodeTreeNode; + function GetH2PNodeForComplexType(CNode: TCodeTreeNode; CreateIfNotExists: boolean = true): TH2PNode; function CreatePascalNameFromCCode(const CCode: string; StartPos: integer = 1; @@ -283,6 +283,9 @@ var NextCNode: TCodeTreeNode; TypeH2PNode: TH2PNode; CurValue: String; + StatementNode: TCodeTreeNode; + Ok: Boolean; + IsPointerToFunction: Boolean; begin //DebugLn(['TH2PasTool.BuildH2PTree ParentNode=',ParentNode.DescAsString]); if ParentNode<>nil then @@ -306,7 +309,7 @@ begin SimpleType:=GetSimplePascalTypeOfCVar(CNode); if SimpleType='' then begin // this variable has a complex type - TypeH2PNode:=GetTypeForVarType(CNode); + TypeH2PNode:=GetH2PNodeForComplexType(CNode); if TypeH2PNode<>nil then SimpleType:=TypeH2PNode.PascalName; end; @@ -315,7 +318,53 @@ begin ParentNode,ParentNode=nil); DebugLn(['TH2PasTool.BuildH2PTree added: ',H2PNode.DescAsString]); end else begin - DebugLn(['TH2PasTool.BuildH2PTree invalid Variable Name="',CurName,'" Type="',CurType,'"']); + DebugLn(['TH2PasTool.BuildH2PTree SKIPPING Variable Name="',CurName,'" Type="',CurType,'"']); + end; + end; + ccnFunction: + begin + CurName:=CTool.ExtractFunctionName(CNode); + CurType:=CTool.ExtractFunctionResultType(CNode); + SimpleType:=GetSimplePascalResultTypeOfCFunction(CNode); + IsPointerToFunction:=CTool.IsPointerToFunction(CNode); + StatementNode:=nil; + Ok:=true; + if (CNode.LastChild<>nil) and (CNode.LastChild.Desc=ccnStatementBlock) then + StatementNode:=CNode.LastChild; + DebugLn(['TH2PasTool.BuildH2PTree Function Name="',CurName,'" ResultType="',CurType,'" SimpleType=',SimpleType,' HasStatements=',StatementNode<>nil,' IsPointer=',IsPointerToFunction]); + if StatementNode<>nil then begin + // this function has a body + Ok:=false; + end; + if Ok and (SimpleType='') then begin + // this function has a complex result type + TypeH2PNode:=GetH2PNodeForComplexType(CNode); + if TypeH2PNode<>nil then begin + SimpleType:=TypeH2PNode.PascalName; + end else + Ok:=false; + end; + + NextCNode:=CNode.NextSkipChilds; + if Ok then begin + H2PNode:=CreateH2PNode(CurName,CurName,CNode,ctnProcedure,SimpleType, + ParentNode,ParentNode=nil); + DebugLn(['TH2PasTool.BuildH2PTree added: ',H2PNode.DescAsString]); + CNode:=CNode.FirstChild; + while (CNode<>nil) and (CNode.Desc<>ccnFuncParamList) do + CNode:=CNode.NextBrother; + if CNode<>nil then begin + CNode:=CNode.FirstChild; + while CNode<>nil do begin + if CNode.Desc=ccnFuncParameter then begin + CurType:=CTool.ExtractCode(CNode.StartPos,CNode.EndPos); + DebugLn(['TH2PasTool.BuildH2PTree Parameter="',CurType,'"']); + end; + CNode:=CNode.NextBrother; + end; + end; + end else begin + DebugLn(['TH2PasTool.BuildH2PTree SKIPPING Function Name="',CurName,'" Type="',CurType,'"']); end; end; ccnEnumBlock: @@ -361,17 +410,6 @@ begin // build recursively BuildH2PTree(TypeH2PNode); end; - ccnFunction: - begin - CurName:=CTool.ExtractFunctionName(CNode); - CurType:=CTool.ExtractFunctionResultType(CNode); - SimpleType:=GetSimplePascalResultTypeOfCFunction(CNode); - DebugLn(['TH2PasTool.BuildH2PTree Function Name="',CurName,'" ResultType="',CurType,'" SimpleType=',SimpleType]); - if SimpleType='' then begin - // this variable has a complex type - - end; - end; end; // next C node if (ParentNode<>nil) and (not ParentNode.CNode.HasAsChild(NextCNode)) then @@ -491,7 +529,7 @@ begin inc(i); end; -function TH2PasTool.GetTypeForVarType(CVarNode: TCodeTreeNode; +function TH2PasTool.GetH2PNodeForComplexType(CNode: TCodeTreeNode; CreateIfNotExists: boolean): TH2PNode; var CCode: String; @@ -512,12 +550,19 @@ var NeedH2PNode: Boolean; begin Result:=nil; - if (CVarNode.FirstChild<>nil) - and (CVarNode.FirstChild.Desc=ccnUnion) then begin + if (CNode.Desc=ccnVariable) + and (CNode.FirstChild<>nil) + and (CNode.FirstChild.Desc=ccnUnion) then begin // ToDo: union end else begin SubH2PNode:=nil; - CCode:=CTool.ExtractVariableType(CVarNode); + if CNode.Desc=ccnVariable then + CCode:=CTool.ExtractVariableType(CNode) + else if CNode.Desc=ccnFunction then + CCode:=CTool.ExtractFunctionResultType(CNode) + else + exit; + DebugLn(['TH2PasTool.GetTypeForVarType CCode="',CCode,'"']); { int[][3] -> array of array[0..2] of cint char** -> PPchar