codetools: c parser: implemented parsing function parameters

git-svn-id: trunk@14569 -
This commit is contained in:
mattias 2008-03-18 13:38:22 +00:00
parent 261b5cdc0f
commit fb6acb3313
2 changed files with 128 additions and 25 deletions

View File

@ -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

View File

@ -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