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()
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

View File

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