mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-23 13:29:47 +02:00
codetools: c parser: implemented parsing function parameters
git-svn-id: trunk@14569 -
This commit is contained in:
parent
261b5cdc0f
commit
fb6acb3313
@ -62,7 +62,8 @@ const
|
|||||||
ccnFunction = 11+ccnBase;// e.g. int i()
|
ccnFunction = 11+ccnBase;// e.g. int i()
|
||||||
ccnName = 12+ccnBase;// e.g. i
|
ccnName = 12+ccnBase;// e.g. i
|
||||||
ccnFuncParamList = 13+ccnBase;// e.g. ()
|
ccnFuncParamList = 13+ccnBase;// e.g. ()
|
||||||
ccnStatementBlock = 14+ccnBase;// e.g. {}
|
ccnFuncParameter = 14+ccnBase;// e.g. ()
|
||||||
|
ccnStatementBlock = 15+ccnBase;// e.g. {}
|
||||||
|
|
||||||
type
|
type
|
||||||
TCCodeParserTool = class;
|
TCCodeParserTool = class;
|
||||||
@ -97,6 +98,7 @@ type
|
|||||||
procedure CloseNodes;
|
procedure CloseNodes;
|
||||||
|
|
||||||
procedure ReadVariable;
|
procedure ReadVariable;
|
||||||
|
procedure ReadParameterList;
|
||||||
procedure ReadEnum;
|
procedure ReadEnum;
|
||||||
procedure ReadStruct;
|
procedure ReadStruct;
|
||||||
procedure ReadUnion;
|
procedure ReadUnion;
|
||||||
@ -180,6 +182,7 @@ type
|
|||||||
WithDirectives: boolean = false): string;
|
WithDirectives: boolean = false): string;
|
||||||
function ExtractFunctionResultType(FuncNode: TCodeTreeNode;
|
function ExtractFunctionResultType(FuncNode: TCodeTreeNode;
|
||||||
WithDirectives: boolean = false): string;
|
WithDirectives: boolean = false): string;
|
||||||
|
function IsPointerToFunction(FuncNode: TCodeTreeNode): boolean;
|
||||||
function ExtractEnumBlockName(EnumBlockNode: TCodeTreeNode): string;
|
function ExtractEnumBlockName(EnumBlockNode: TCodeTreeNode): string;
|
||||||
function ExtractEnumIDName(EnumIDNode: TCodeTreeNode): string;
|
function ExtractEnumIDName(EnumIDNode: TCodeTreeNode): string;
|
||||||
function ExtractEnumIDValue(EnumIDNode: TCodeTreeNode;
|
function ExtractEnumIDValue(EnumIDNode: TCodeTreeNode;
|
||||||
@ -224,6 +227,7 @@ begin
|
|||||||
ccnFunction : Result:='function';
|
ccnFunction : Result:='function';
|
||||||
ccnName : Result:='name';
|
ccnName : Result:='name';
|
||||||
ccnFuncParamList : Result:='function-param-list';
|
ccnFuncParamList : Result:='function-param-list';
|
||||||
|
ccnFuncParameter : Result:='function-parameter';
|
||||||
ccnStatementBlock: Result:='statement-block';
|
ccnStatementBlock: Result:='statement-block';
|
||||||
else Result:='?('+IntToStr(Desc)+')';
|
else Result:='?('+IntToStr(Desc)+')';
|
||||||
end;
|
end;
|
||||||
@ -752,28 +756,25 @@ begin
|
|||||||
// this is a function => read parameter list
|
// this is a function => read parameter list
|
||||||
IsFunction:=true;
|
IsFunction:=true;
|
||||||
MainNode.Desc:=ccnFunction;
|
MainNode.Desc:=ccnFunction;
|
||||||
CreateChildNode(ccnFuncParamList);
|
ReadParameterList;
|
||||||
ReadTilBracketClose(true);
|
ReadNextAtom;
|
||||||
CurNode.EndPos:=SrcPos;
|
|
||||||
EndChildNode;
|
|
||||||
if CurNode.Parent.Desc=ccnTypedef then begin
|
if CurNode.Parent.Desc=ccnTypedef then begin
|
||||||
if AtomIsChar('{') then
|
if AtomIsChar('{') then
|
||||||
RaiseException('typedef can not have a statement block');
|
RaiseException('typedef can not have a statement block');
|
||||||
end else begin
|
end else begin
|
||||||
ReadNextAtom;
|
|
||||||
if AtomIsChar('{') then begin
|
if AtomIsChar('{') then begin
|
||||||
// read statements {}
|
// read statements {}
|
||||||
CreateChildNode(ccnStatementBlock);
|
CreateChildNode(ccnStatementBlock);
|
||||||
ReadTilBracketClose(true);
|
ReadTilBracketClose(true);
|
||||||
CurNode.EndPos:=SrcPos;
|
CurNode.EndPos:=SrcPos;
|
||||||
EndChildNode;
|
EndChildNode;
|
||||||
|
ReadNextAtom;
|
||||||
end else if not AtomIsChar(';') then begin
|
end else if not AtomIsChar(';') then begin
|
||||||
// functions without statements are external and must end with a semicolon
|
// functions without statements are external and must end with a semicolon
|
||||||
RaiseExpectedButAtomFound(';');
|
RaiseExpectedButAtomFound(';');
|
||||||
end;
|
end;
|
||||||
NeedEnd:=false;
|
NeedEnd:=false;
|
||||||
end;
|
end;
|
||||||
ReadNextAtom;
|
|
||||||
end else if AtomIsChar('[') then begin
|
end else if AtomIsChar('[') then begin
|
||||||
// read array brackets
|
// read array brackets
|
||||||
while AtomIsChar('[') do begin
|
while AtomIsChar('[') do begin
|
||||||
@ -802,6 +803,40 @@ begin
|
|||||||
EndChildNode;
|
EndChildNode;
|
||||||
end;
|
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);
|
procedure TCCodeParserTool.RaiseException(const AMessage: string; ReportPos: integer);
|
||||||
begin
|
begin
|
||||||
LastErrorMsg:=AMessage;
|
LastErrorMsg:=AMessage;
|
||||||
@ -1320,6 +1355,29 @@ begin
|
|||||||
end;
|
end;
|
||||||
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
|
function TCCodeParserTool.ExtractEnumBlockName(EnumBlockNode: TCodeTreeNode
|
||||||
): string;
|
): string;
|
||||||
var
|
var
|
||||||
|
@ -115,7 +115,7 @@ type
|
|||||||
function CreateAutoGeneratedH2PNode(var PascalName: string; CNode: TCodeTreeNode;
|
function CreateAutoGeneratedH2PNode(var PascalName: string; CNode: TCodeTreeNode;
|
||||||
PascalDesc: TCodeTreeNodeDesc; const PascalCode: string;
|
PascalDesc: TCodeTreeNodeDesc; const PascalCode: string;
|
||||||
ParentNode: TH2PNode = nil; IsGlobal: boolean = true): TH2PNode;
|
ParentNode: TH2PNode = nil; IsGlobal: boolean = true): TH2PNode;
|
||||||
function GetTypeForVarType(CVarNode: TCodeTreeNode;
|
function GetH2PNodeForComplexType(CNode: TCodeTreeNode;
|
||||||
CreateIfNotExists: boolean = true): TH2PNode;
|
CreateIfNotExists: boolean = true): TH2PNode;
|
||||||
function CreatePascalNameFromCCode(const CCode: string;
|
function CreatePascalNameFromCCode(const CCode: string;
|
||||||
StartPos: integer = 1;
|
StartPos: integer = 1;
|
||||||
@ -283,6 +283,9 @@ var
|
|||||||
NextCNode: TCodeTreeNode;
|
NextCNode: TCodeTreeNode;
|
||||||
TypeH2PNode: TH2PNode;
|
TypeH2PNode: TH2PNode;
|
||||||
CurValue: String;
|
CurValue: String;
|
||||||
|
StatementNode: TCodeTreeNode;
|
||||||
|
Ok: Boolean;
|
||||||
|
IsPointerToFunction: Boolean;
|
||||||
begin
|
begin
|
||||||
//DebugLn(['TH2PasTool.BuildH2PTree ParentNode=',ParentNode.DescAsString]);
|
//DebugLn(['TH2PasTool.BuildH2PTree ParentNode=',ParentNode.DescAsString]);
|
||||||
if ParentNode<>nil then
|
if ParentNode<>nil then
|
||||||
@ -306,7 +309,7 @@ begin
|
|||||||
SimpleType:=GetSimplePascalTypeOfCVar(CNode);
|
SimpleType:=GetSimplePascalTypeOfCVar(CNode);
|
||||||
if SimpleType='' then begin
|
if SimpleType='' then begin
|
||||||
// this variable has a complex type
|
// this variable has a complex type
|
||||||
TypeH2PNode:=GetTypeForVarType(CNode);
|
TypeH2PNode:=GetH2PNodeForComplexType(CNode);
|
||||||
if TypeH2PNode<>nil then
|
if TypeH2PNode<>nil then
|
||||||
SimpleType:=TypeH2PNode.PascalName;
|
SimpleType:=TypeH2PNode.PascalName;
|
||||||
end;
|
end;
|
||||||
@ -315,7 +318,53 @@ begin
|
|||||||
ParentNode,ParentNode=nil);
|
ParentNode,ParentNode=nil);
|
||||||
DebugLn(['TH2PasTool.BuildH2PTree added: ',H2PNode.DescAsString]);
|
DebugLn(['TH2PasTool.BuildH2PTree added: ',H2PNode.DescAsString]);
|
||||||
end else begin
|
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;
|
||||||
end;
|
end;
|
||||||
ccnEnumBlock:
|
ccnEnumBlock:
|
||||||
@ -361,17 +410,6 @@ begin
|
|||||||
// build recursively
|
// build recursively
|
||||||
BuildH2PTree(TypeH2PNode);
|
BuildH2PTree(TypeH2PNode);
|
||||||
end;
|
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;
|
end;
|
||||||
// next C node
|
// next C node
|
||||||
if (ParentNode<>nil) and (not ParentNode.CNode.HasAsChild(NextCNode)) then
|
if (ParentNode<>nil) and (not ParentNode.CNode.HasAsChild(NextCNode)) then
|
||||||
@ -491,7 +529,7 @@ begin
|
|||||||
inc(i);
|
inc(i);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TH2PasTool.GetTypeForVarType(CVarNode: TCodeTreeNode;
|
function TH2PasTool.GetH2PNodeForComplexType(CNode: TCodeTreeNode;
|
||||||
CreateIfNotExists: boolean): TH2PNode;
|
CreateIfNotExists: boolean): TH2PNode;
|
||||||
var
|
var
|
||||||
CCode: String;
|
CCode: String;
|
||||||
@ -512,12 +550,19 @@ var
|
|||||||
NeedH2PNode: Boolean;
|
NeedH2PNode: Boolean;
|
||||||
begin
|
begin
|
||||||
Result:=nil;
|
Result:=nil;
|
||||||
if (CVarNode.FirstChild<>nil)
|
if (CNode.Desc=ccnVariable)
|
||||||
and (CVarNode.FirstChild.Desc=ccnUnion) then begin
|
and (CNode.FirstChild<>nil)
|
||||||
|
and (CNode.FirstChild.Desc=ccnUnion) then begin
|
||||||
// ToDo: union
|
// ToDo: union
|
||||||
end else begin
|
end else begin
|
||||||
SubH2PNode:=nil;
|
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,'"']);
|
DebugLn(['TH2PasTool.GetTypeForVarType CCode="',CCode,'"']);
|
||||||
{ int[][3] -> array of array[0..2] of cint
|
{ int[][3] -> array of array[0..2] of cint
|
||||||
char** -> PPchar
|
char** -> PPchar
|
||||||
|
Loading…
Reference in New Issue
Block a user