mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-10 22:16:17 +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()
|
||||
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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user