codetools: implemented conversion of simple c declarations

git-svn-id: trunk@14553 -
This commit is contained in:
mattias 2008-03-17 15:37:43 +00:00
parent 535542bc52
commit 7593e06d86
3 changed files with 219 additions and 51 deletions

View File

@ -53,13 +53,13 @@ const
ccnDirective = 2+ccnBase;// e.g. "#define a" ,can be multiple lines, without line end ccnDirective = 2+ccnBase;// e.g. "#define a" ,can be multiple lines, without line end
ccnExtern = 3+ccnBase;// e.g. extern "C" {} ccnExtern = 3+ccnBase;// e.g. extern "C" {}
ccnEnumBlock = 4+ccnBase;// e.g. enum {}; ccnEnumBlock = 4+ccnBase;// e.g. enum {};
ccnEnumBlockName = 5+ccnBase;// e.g. enum {}; ccnEnumID = 5+ccnBase;// e.g. name = value;
ccnEnumID = 6+ccnBase;// e.g. name = value; ccnConstant = 6+ccnBase;// e.g. 1
ccnConstant = 7+ccnBase;// e.g. 1 ccnTypedef = 7+ccnBase;// e.g. typedef int TInt;
ccnTypedef = 8+ccnBase;// e.g. typedef int TInt; ccnStruct = 8+ccnBase;// e.g. struct{}
ccnStruct = 9+ccnBase;// e.g. struct{}; ccnUnion = 9+ccnBase;// e.g. union{}
ccnVariable = 10+ccnBase;// e.g. int i ccnVariable = 10+ccnBase;// e.g. int i
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. {} ccnStatementBlock = 14+ccnBase;// e.g. {}
@ -96,11 +96,12 @@ type
procedure EndChildNode; procedure EndChildNode;
procedure CloseNodes; procedure CloseNodes;
procedure ReadVariable;
procedure ReadEnum; procedure ReadEnum;
procedure ReadStruct; procedure ReadStruct;
procedure ReadUnion;
procedure ReadConstant; procedure ReadConstant;
procedure ReadVariable;
procedure RaiseException(const AMessage: string; ReportPos: integer = 0); procedure RaiseException(const AMessage: string; ReportPos: integer = 0);
procedure RaiseExpectedButAtomFound(const AToken: string; ReportPos: integer = 0); procedure RaiseExpectedButAtomFound(const AToken: string; ReportPos: integer = 0);
public public
@ -170,6 +171,7 @@ type
function ExtractCode(StartPos, EndPos: integer; function ExtractCode(StartPos, EndPos: integer;
WithDirectives: boolean = false): string;// extract code without comments WithDirectives: boolean = false): string;// extract code without comments
function GetFirstNameNode(Node: TCodeTreeNode): TCodeTreeNode;
function ExtractVariableName(VarNode: TCodeTreeNode): string; function ExtractVariableName(VarNode: TCodeTreeNode): string;
function ExtractVariableType(VarNode: TCodeTreeNode; function ExtractVariableType(VarNode: TCodeTreeNode;
WithDirectives: boolean = false): string; WithDirectives: boolean = false): string;
@ -210,11 +212,11 @@ begin
ccnDirective : Result:='Directive'; ccnDirective : Result:='Directive';
ccnExtern : Result:='extern block'; ccnExtern : Result:='extern block';
ccnEnumBlock : Result:='enum block'; ccnEnumBlock : Result:='enum block';
ccnEnumBlockName : Result:='enum block name';
ccnEnumID : Result:='enum ID'; ccnEnumID : Result:='enum ID';
ccnConstant : Result:='constant'; ccnConstant : Result:='constant';
ccnTypedef : Result:='typedef'; ccnTypedef : Result:='typedef';
ccnStruct : Result:='struct'; ccnStruct : Result:='struct';
ccnUnion : Result:='union';
ccnVariable : Result:='variable'; ccnVariable : Result:='variable';
ccnFunction : Result:='function'; ccnFunction : Result:='function';
ccnName : Result:='name'; ccnName : Result:='name';
@ -339,7 +341,7 @@ begin
ReadNextAtom; ReadNextAtom;
// read optional name // read optional name
if AtomIsIdentifier then begin if AtomIsIdentifier then begin
CreateChildNode(ccnEnumBlockName); CreateChildNode(ccnName);
EndChildNode; EndChildNode;
ReadNextAtom; ReadNextAtom;
end; end;
@ -378,7 +380,8 @@ begin
end; end;
procedure TCCodeParserTool.ReadStruct; procedure TCCodeParserTool.ReadStruct;
(* Example for NeedIdentifier=false: (* Examples:
As typedef: As typedef:
typedef struct { typedef struct {
uint8_t b[6]; // implicit type uint8_t b[6]; // implicit type
@ -403,6 +406,8 @@ begin
// read variable name // read variable name
if not AtomIsIdentifier then if not AtomIsIdentifier then
RaiseExpectedButAtomFound('identifier'); RaiseExpectedButAtomFound('identifier');
CreateChildNode(ccnName);
EndChildNode;
ReadNextAtom; ReadNextAtom;
end; end;
@ -444,6 +449,48 @@ begin
EndChildNode; EndChildNode;
end; end;
procedure TCCodeParserTool.ReadUnion;
(* Example
union {
uint16_t uuid16;
uint32_t uuid32;
uint128_t uuid128;
} value;
*)
begin
CreateChildNode(ccnUnion);
ReadNextAtom;
if AtomIsChar('{') then begin
// read block {}
repeat
ReadNextAtom;
// read variables
if AtomIsIdentifier then begin
ReadVariable;
ReadNextAtom;
if AtomIsChar('}') then
break
else if AtomIsChar(';') then begin
// next identifier
end else
RaiseExpectedButAtomFound('}');
end else if AtomIsChar('}') then
break
else
RaiseExpectedButAtomFound('identifier');
until false;
end else if AtomIsIdentifier then begin
// using another union
end else
RaiseExpectedButAtomFound('{');
// close node
EndChildNode;
end;
function TCCodeParserTool.TypedefToken: boolean; function TCCodeParserTool.TypedefToken: boolean;
{ examples: { examples:
typedef type name; typedef type name;
@ -607,10 +654,7 @@ begin
// for example: struct structname varname // for example: struct structname varname
ReadNextAtom; ReadNextAtom;
end else if AtomIs('union') then begin end else if AtomIs('union') then begin
ReadNextAtom; ReadUnion;
if not AtomIsChar('{') then
RaiseExpectedButAtomFound('{');
ReadTilBracketClose(true);
end else if IsCCodeFunctionModifier.DoItCaseSensitive(Src,AtomStart,SrcPos-AtomStart) end else if IsCCodeFunctionModifier.DoItCaseSensitive(Src,AtomStart,SrcPos-AtomStart)
then begin then begin
// read function modifiers // read function modifiers
@ -1163,12 +1207,18 @@ begin
Result:=s; Result:=s;
end; end;
function TCCodeParserTool.GetFirstNameNode(Node: TCodeTreeNode): TCodeTreeNode;
begin
Result:=Node.FirstChild;
while (Result<>nil) and (Result.Desc<>ccnName) do Result:=Result.NextBrother;
end;
function TCCodeParserTool.ExtractVariableName(VarNode: TCodeTreeNode): string; function TCCodeParserTool.ExtractVariableName(VarNode: TCodeTreeNode): string;
var var
NameNode: TCodeTreeNode; NameNode: TCodeTreeNode;
begin begin
NameNode:=VarNode.FirstChild; NameNode:=GetFirstNameNode(VarNode);
if (NameNode=nil) or (NameNode.Desc<>ccnName) then if (NameNode=nil) then
Result:='' Result:=''
else else
Result:=copy(Src,NameNode.StartPos,NameNode.EndPos-NameNode.StartPos); Result:=copy(Src,NameNode.StartPos,NameNode.EndPos-NameNode.StartPos);
@ -1180,8 +1230,8 @@ var
NameNode: TCodeTreeNode; NameNode: TCodeTreeNode;
s: String; s: String;
begin begin
NameNode:=VarNode.FirstChild; NameNode:=GetFirstNameNode(VarNode);
if (NameNode=nil) or (NameNode.Desc<>ccnName) then if (NameNode=nil) then
Result:='' Result:=''
else begin else begin
Result:=ExtractCode(VarNode.StartPos,NameNode.StartPos,WithDirectives); Result:=ExtractCode(VarNode.StartPos,NameNode.StartPos,WithDirectives);
@ -1204,8 +1254,8 @@ function TCCodeParserTool.ExtractFunctionName(FuncNode: TCodeTreeNode): string;
var var
NameNode: TCodeTreeNode; NameNode: TCodeTreeNode;
begin begin
NameNode:=FuncNode.FirstChild; NameNode:=GetFirstNameNode(FuncNode);
if (NameNode=nil) or (NameNode.Desc<>ccnName) then if (NameNode=nil) then
Result:='' Result:=''
else else
Result:=copy(Src,NameNode.StartPos,NameNode.EndPos-NameNode.StartPos); Result:=copy(Src,NameNode.StartPos,NameNode.EndPos-NameNode.StartPos);
@ -1216,8 +1266,8 @@ function TCCodeParserTool.ExtractFunctionType(FuncNode: TCodeTreeNode;
var var
NameNode: TCodeTreeNode; NameNode: TCodeTreeNode;
begin begin
NameNode:=FuncNode.FirstChild; NameNode:=GetFirstNameNode(FuncNode);
if (NameNode=nil) or (NameNode.Desc<>ccnName) then begin if (NameNode=nil) then begin
Result:=''; Result:='';
exit; exit;
end; end;
@ -1239,8 +1289,8 @@ function TCCodeParserTool.ExtractFunctionResultType(FuncNode: TCodeTreeNode;
var var
NameNode: TCodeTreeNode; NameNode: TCodeTreeNode;
begin begin
NameNode:=FuncNode.FirstChild; NameNode:=GetFirstNameNode(FuncNode);
if (NameNode=nil) or (NameNode.Desc<>ccnName) then begin if (NameNode=nil) then begin
Result:=''; Result:='';
exit; exit;
end; end;
@ -1262,7 +1312,7 @@ var
NameNode: TCodeTreeNode; NameNode: TCodeTreeNode;
begin begin
if (EnumBlockNode.FirstChild<>nil) if (EnumBlockNode.FirstChild<>nil)
and (EnumBlockNode.FirstChild.Desc=ccnEnumBlockName) then begin and (EnumBlockNode.FirstChild.Desc=ccnName) then begin
NameNode:=EnumBlockNode.FirstChild; NameNode:=EnumBlockNode.FirstChild;
Result:=copy(Src,NameNode.StartPos,NameNode.EndPos-NameNode.StartPos); Result:=copy(Src,NameNode.StartPos,NameNode.EndPos-NameNode.StartPos);
end else begin end else begin

View File

@ -25,6 +25,9 @@ enum {
TEST_ENUM3 TEST_ENUM3
}; };
enum e1{dark, light};
enum e2{a=3, b=9};
/* Byte order conversions */ /* Byte order conversions */
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
#define htobs(d) (d) #define htobs(d) (d)
@ -122,14 +125,12 @@ complex operator+(complex, complex);
int y = 7; int y = 7;
float f(int){}; float f(int){};
int dim2[][3];
bool b1 = a==b; bool b1 = a==b;
char c = 'a'; char c = 'a';
short signed int ssi_octal = 0123; short signed int ssi_octal = 0123;
long unsigned int lui = sizeof(char); long unsigned int lui = sizeof(char);
enum e1{dark, light};
enum e2{a=3, b=9};
int *pi; // pointer to int int *pi; // pointer to int
char ** ppc; // pointer to pointer to char char ** ppc; // pointer to pointer to char
int* ap[15]; // array of 15 pointers to ints int* ap[15]; // array of 15 pointers to ints

View File

@ -103,11 +103,17 @@ type
function GetSimplePascalTypeOfCVar(CVarNode: TCodeTreeNode): string; function GetSimplePascalTypeOfCVar(CVarNode: TCodeTreeNode): string;
function GetSimplePascalResultTypeOfCFunction(CFuncNode: TCodeTreeNode): string; function GetSimplePascalResultTypeOfCFunction(CFuncNode: TCodeTreeNode): string;
function ConvertSimpleCTypeToPascalType(CType: string): string; function ConvertSimpleCTypeToPascalType(CType: string;
UseSingleIdentifierAsDefault: boolean): string;
function CreateH2PNode(const PascalName, CName: string; CNode: TCodeTreeNode; function CreateH2PNode(const PascalName, CName: string; CNode: TCodeTreeNode;
PascalDesc: TCodeTreeNodeDesc; ParentNode: TH2PNode = nil; PascalDesc: TCodeTreeNodeDesc; ParentNode: TH2PNode = nil;
IsGlobal: boolean = true): TH2PNode; IsGlobal: boolean = true): TH2PNode;
function GetTypeForVarType(CVarNode: TCodeTreeNode;
CreateIfNotExists: boolean = true): TH2PNode;
function CreatePascalNameFromCCode(const CCode: string;
StartPos: integer = 1;
EndPos: integer = -1): string;
procedure WriteDebugReport; procedure WriteDebugReport;
procedure WriteH2PNodeReport; procedure WriteH2PNodeReport;
@ -217,6 +223,8 @@ begin
Add('double*','pcdouble'); Add('double*','pcdouble');
Add('long double','clongdouble'); Add('long double','clongdouble');
Add('long double*','pclongdouble'); Add('long double*','pclongdouble');
// void
Add('void*','pointer');
end; end;
end; end;
Result:=InternalPredefinedCTypes; Result:=InternalPredefinedCTypes;
@ -258,10 +266,13 @@ var
CurType: String; CurType: String;
SimpleType: String; SimpleType: String;
H2PNode: TH2PNode; H2PNode: TH2PNode;
NextCNode: TCodeTreeNode;
TypeH2PNode: TH2PNode;
begin begin
Tree.Clear; Tree.Clear;
CNode:=CTool.Tree.Root; CNode:=CTool.Tree.Root;
while CNode<>nil do begin while CNode<>nil do begin
NextCNode:=CNode.Next;
case CNode.Desc of case CNode.Desc of
ccnVariable: ccnVariable:
begin begin
@ -271,13 +282,16 @@ begin
DebugLn(['TH2PasTool.BuildH2PTree Variable Name="',CurName,'" Type="',CurType,'" SimpleType=',SimpleType]); DebugLn(['TH2PasTool.BuildH2PTree Variable Name="',CurName,'" Type="',CurType,'" SimpleType=',SimpleType]);
if SimpleType='' then begin if SimpleType='' then begin
// this variable has a complex type // this variable has a complex type
//SimpleType:=CreateTypeForVarType(CNode); TypeH2PNode:=GetTypeForVarType(CNode);
if TypeH2PNode<>nil then
SimpleType:=TypeH2PNode.PascalName;
end; end;
if SimpleType<>'' then begin if SimpleType<>'' then begin
H2PNode:=CreateH2PNode(CurName,CurName,CNode,ctnVarDefinition); H2PNode:=CreateH2PNode(CurName,CurName,CNode,ctnVarDefinition);
H2PNode.PascalCode:=SimpleType; H2PNode.PascalCode:=SimpleType;
//DebugLn(['TH2PasTool.BuildH2PTree CNode.Desc=',CCNodeDescAsString(CNode.Desc),' ',H2PNode.DescAsString]); //DebugLn(['TH2PasTool.BuildH2PTree CNode.Desc=',CCNodeDescAsString(CNode.Desc),' ',H2PNode.DescAsString]);
end; end;
NextCNode:=CNode.NextSkipChilds;
end; end;
ccnEnumBlock: ccnEnumBlock:
begin begin
@ -301,42 +315,27 @@ begin
end; end;
end; end;
end; end;
CNode:=CNode.Next; CNode:=NextCNode;
end; end;
end; end;
function TH2PasTool.GetSimplePascalTypeOfCVar(CVarNode: TCodeTreeNode): string; function TH2PasTool.GetSimplePascalTypeOfCVar(CVarNode: TCodeTreeNode): string;
var
SimpleType: String;
begin begin
Result:=CTool.ExtractVariableType(CVarNode); Result:=CTool.ExtractVariableType(CVarNode);
if Result='' then exit; if Result='' then exit;
SimpleType:=ConvertSimpleCTypeToPascalType(Result); Result:=ConvertSimpleCTypeToPascalType(Result,true);
if SimpleType<>'' then begin
Result:=SimpleType;
exit;
end;
if not IsValidIdent(Result) then
Result:='';
end; end;
function TH2PasTool.GetSimplePascalResultTypeOfCFunction( function TH2PasTool.GetSimplePascalResultTypeOfCFunction(
CFuncNode: TCodeTreeNode): string; CFuncNode: TCodeTreeNode): string;
var
SimpleType: String;
begin begin
Result:=CTool.ExtractFunctionResultType(CFuncNode); Result:=CTool.ExtractFunctionResultType(CFuncNode);
if Result='' then exit; if Result='' then exit;
SimpleType:=ConvertSimpleCTypeToPascalType(Result); Result:=ConvertSimpleCTypeToPascalType(Result,true);
if SimpleType<>'' then begin
Result:=SimpleType;
exit;
end;
if not IsValidIdent(Result) then
Result:='';
end; end;
function TH2PasTool.ConvertSimpleCTypeToPascalType(CType: string): string; function TH2PasTool.ConvertSimpleCTypeToPascalType(CType: string;
UseSingleIdentifierAsDefault: boolean): string;
// the type must be normalized. That means no directives, // the type must be normalized. That means no directives,
// no unneeded spaces, no tabs, no comments, no newlines. // no unneeded spaces, no tabs, no comments, no newlines.
var var
@ -375,6 +374,9 @@ begin
until false; until false;
// seach in predefined ctypes // seach in predefined ctypes
Result:=PredefinedCTypes[CType]; Result:=PredefinedCTypes[CType];
if (Result='') and (UseSingleIdentifierAsDefault) and IsValidIdent(CType) then
Result:=CType;
end; end;
function TH2PasTool.CreateH2PNode(const PascalName, CName: string; function TH2PasTool.CreateH2PNode(const PascalName, CName: string;
@ -393,6 +395,121 @@ begin
end; end;
end; end;
function TH2PasTool.GetTypeForVarType(CVarNode: TCodeTreeNode;
CreateIfNotExists: boolean): TH2PNode;
var
CCode: String;
PascalName: String;
AtomStart: integer;
p: Integer;
CurAtom: String;
BaseCType: String;
BasePascaltype: String;
begin
Result:=nil;
if (CVarNode.FirstChild<>nil)
and (CVarNode.FirstChild.Desc=ccnUnion) then begin
// ToDo: union
end else begin
CCode:=CTool.ExtractVariableType(CVarNode);
{ int[][3] -> array of array[0..2] of cint
char** -> PPchar
int *[15] -> array[0..14] of pcint
}
// read identifiers
p:=1;
BaseCType:='';
repeat
ReadRawNextCAtom(CCode,p,AtomStart);
if AtomStart>length(CCode) then break;
if IsIdentStartChar[CCode[AtomStart]] then begin
CurAtom:=copy(CCode,AtomStart,p-AtomStart);
if BaseCType<>'' then
BaseCType:=BaseCType+' ';
BaseCType:=BaseCType+CurAtom;
end;
until false;
if BaseCType='' then begin
DebugLn(['TH2PasTool.GetTypeForVarType no base type in c declaration: CCode="',dbgstr(CCode),'"']);
exit;
end;
BasePascaltype:=ConvertSimpleCTypeToPascalType(BaseCType,true);
if (BasePascaltype='') then begin
DebugLn(['TH2PasTool.GetTypeForVarType unknown c type: "',BaseCType,'"']);
exit;
end;
// read pointer
{while (AtomStart<=length(CCode)) do begin
CurAtom:=copy(CCode,AtomStart,p-AtomStart);
if (CurAtom='*') then begin
BaseCType:=BaseCType+'*';
NewBasePascaltype:=ConvertSimpleCTypeToPascalType(BaseCType,true);
end else if (CurAtom='const') then begin
// skip 'const'
end else begin
break;
end;
ReadRawNextCAtom(CCode,p,AtomStart);
end;}
PascalName:=CreatePascalNameFromCCode(CCode);
DebugLn(['TH2PasTool.GetTypeForVarType CCode="',dbgstr(CCode),'" PascalName="',PascalName,'"']);
end;
end;
function TH2PasTool.CreatePascalNameFromCCode(const CCode: string;
StartPos: integer; EndPos: integer): string;
const
MaxIdentLen = 70;
function Add(var PascalName: string; const Addition: string): boolean;
begin
if Addition='' then exit(true);
if length(PascalName)+length(Addition)>MaxIdentLen then
exit(false);
PascalName:=PascalName+Addition;
end;
var
p: Integer;
AtomStart: integer;
i: LongInt;
c: Char;
CurAtom: String;
begin
Result:='';
if EndPos<1 then
EndPos:=length(CCode)+1;
p:=StartPos;
if EndPos>length(CCode) then
EndPos:=length(CCode);
repeat
ReadRawNextCAtom(CCode,p,AtomStart);
if AtomStart>EndPos then exit;
if IsIdentStartChar[CCode[AtomStart]] then begin
CurAtom:=copy(CCode,AtomStart,p-AtomStart);
if (CurAtom<>'const')
and (CurAtom<>'struct')
and not Add(Result,CurAtom) then
exit;
end else begin
if CCode[AtomStart] in ['0'..'9'] then begin
CurAtom:=copy(CCode,AtomStart,p-AtomStart);
for i:=AtomStart to p-1 do begin
c:=CCode[i];
if not IsIdentChar[c] then
c:='_';
if not Add(Result,c) then exit;
end;
end;
end;
until false;
end;
procedure TH2PasTool.WriteDebugReport; procedure TH2PasTool.WriteDebugReport;
begin begin
DebugLn(['TH2PasTool.WriteDebugReport ']); DebugLn(['TH2PasTool.WriteDebugReport ']);