diff --git a/components/codetools/ccodeparsertool.pas b/components/codetools/ccodeparsertool.pas index 3b848b6a8c..4b3116fe37 100644 --- a/components/codetools/ccodeparsertool.pas +++ b/components/codetools/ccodeparsertool.pas @@ -53,13 +53,13 @@ const ccnDirective = 2+ccnBase;// e.g. "#define a" ,can be multiple lines, without line end ccnExtern = 3+ccnBase;// e.g. extern "C" {} ccnEnumBlock = 4+ccnBase;// e.g. enum {}; - ccnEnumBlockName = 5+ccnBase;// e.g. enum {}; - ccnEnumID = 6+ccnBase;// e.g. name = value; - ccnConstant = 7+ccnBase;// e.g. 1 - ccnTypedef = 8+ccnBase;// e.g. typedef int TInt; - ccnStruct = 9+ccnBase;// e.g. struct{}; + ccnEnumID = 5+ccnBase;// e.g. name = value; + ccnConstant = 6+ccnBase;// e.g. 1 + ccnTypedef = 7+ccnBase;// e.g. typedef int TInt; + ccnStruct = 8+ccnBase;// e.g. struct{} + ccnUnion = 9+ccnBase;// e.g. union{} 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 ccnFuncParamList = 13+ccnBase;// e.g. () ccnStatementBlock = 14+ccnBase;// e.g. {} @@ -96,11 +96,12 @@ type procedure EndChildNode; procedure CloseNodes; + procedure ReadVariable; procedure ReadEnum; procedure ReadStruct; + procedure ReadUnion; procedure ReadConstant; - procedure ReadVariable; - + procedure RaiseException(const AMessage: string; ReportPos: integer = 0); procedure RaiseExpectedButAtomFound(const AToken: string; ReportPos: integer = 0); public @@ -170,6 +171,7 @@ type function ExtractCode(StartPos, EndPos: integer; WithDirectives: boolean = false): string;// extract code without comments + function GetFirstNameNode(Node: TCodeTreeNode): TCodeTreeNode; function ExtractVariableName(VarNode: TCodeTreeNode): string; function ExtractVariableType(VarNode: TCodeTreeNode; WithDirectives: boolean = false): string; @@ -210,11 +212,11 @@ begin ccnDirective : Result:='Directive'; ccnExtern : Result:='extern block'; ccnEnumBlock : Result:='enum block'; - ccnEnumBlockName : Result:='enum block name'; ccnEnumID : Result:='enum ID'; ccnConstant : Result:='constant'; ccnTypedef : Result:='typedef'; ccnStruct : Result:='struct'; + ccnUnion : Result:='union'; ccnVariable : Result:='variable'; ccnFunction : Result:='function'; ccnName : Result:='name'; @@ -339,7 +341,7 @@ begin ReadNextAtom; // read optional name if AtomIsIdentifier then begin - CreateChildNode(ccnEnumBlockName); + CreateChildNode(ccnName); EndChildNode; ReadNextAtom; end; @@ -378,7 +380,8 @@ begin end; procedure TCCodeParserTool.ReadStruct; -(* Example for NeedIdentifier=false: +(* Examples: + As typedef: typedef struct { uint8_t b[6]; // implicit type @@ -403,6 +406,8 @@ begin // read variable name if not AtomIsIdentifier then RaiseExpectedButAtomFound('identifier'); + CreateChildNode(ccnName); + EndChildNode; ReadNextAtom; end; @@ -444,6 +449,48 @@ begin EndChildNode; 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; { examples: typedef type name; @@ -607,10 +654,7 @@ begin // for example: struct structname varname ReadNextAtom; end else if AtomIs('union') then begin - ReadNextAtom; - if not AtomIsChar('{') then - RaiseExpectedButAtomFound('{'); - ReadTilBracketClose(true); + ReadUnion; end else if IsCCodeFunctionModifier.DoItCaseSensitive(Src,AtomStart,SrcPos-AtomStart) then begin // read function modifiers @@ -1163,12 +1207,18 @@ begin Result:=s; 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; var NameNode: TCodeTreeNode; begin - NameNode:=VarNode.FirstChild; - if (NameNode=nil) or (NameNode.Desc<>ccnName) then + NameNode:=GetFirstNameNode(VarNode); + if (NameNode=nil) then Result:='' else Result:=copy(Src,NameNode.StartPos,NameNode.EndPos-NameNode.StartPos); @@ -1180,8 +1230,8 @@ var NameNode: TCodeTreeNode; s: String; begin - NameNode:=VarNode.FirstChild; - if (NameNode=nil) or (NameNode.Desc<>ccnName) then + NameNode:=GetFirstNameNode(VarNode); + if (NameNode=nil) then Result:='' else begin Result:=ExtractCode(VarNode.StartPos,NameNode.StartPos,WithDirectives); @@ -1204,8 +1254,8 @@ function TCCodeParserTool.ExtractFunctionName(FuncNode: TCodeTreeNode): string; var NameNode: TCodeTreeNode; begin - NameNode:=FuncNode.FirstChild; - if (NameNode=nil) or (NameNode.Desc<>ccnName) then + NameNode:=GetFirstNameNode(FuncNode); + if (NameNode=nil) then Result:='' else Result:=copy(Src,NameNode.StartPos,NameNode.EndPos-NameNode.StartPos); @@ -1216,8 +1266,8 @@ function TCCodeParserTool.ExtractFunctionType(FuncNode: TCodeTreeNode; var NameNode: TCodeTreeNode; begin - NameNode:=FuncNode.FirstChild; - if (NameNode=nil) or (NameNode.Desc<>ccnName) then begin + NameNode:=GetFirstNameNode(FuncNode); + if (NameNode=nil) then begin Result:=''; exit; end; @@ -1239,8 +1289,8 @@ function TCCodeParserTool.ExtractFunctionResultType(FuncNode: TCodeTreeNode; var NameNode: TCodeTreeNode; begin - NameNode:=FuncNode.FirstChild; - if (NameNode=nil) or (NameNode.Desc<>ccnName) then begin + NameNode:=GetFirstNameNode(FuncNode); + if (NameNode=nil) then begin Result:=''; exit; end; @@ -1262,7 +1312,7 @@ var NameNode: TCodeTreeNode; begin if (EnumBlockNode.FirstChild<>nil) - and (EnumBlockNode.FirstChild.Desc=ccnEnumBlockName) then begin + and (EnumBlockNode.FirstChild.Desc=ccnName) then begin NameNode:=EnumBlockNode.FirstChild; Result:=copy(Src,NameNode.StartPos,NameNode.EndPos-NameNode.StartPos); end else begin diff --git a/components/codetools/examples/scanexamples/test.h b/components/codetools/examples/scanexamples/test.h index b981ff4b9f..8b7b367280 100644 --- a/components/codetools/examples/scanexamples/test.h +++ b/components/codetools/examples/scanexamples/test.h @@ -25,6 +25,9 @@ enum { TEST_ENUM3 }; +enum e1{dark, light}; +enum e2{a=3, b=9}; + /* Byte order conversions */ #if __BYTE_ORDER == __LITTLE_ENDIAN #define htobs(d) (d) @@ -122,14 +125,12 @@ complex operator+(complex, complex); int y = 7; float f(int){}; +int dim2[][3]; bool b1 = a==b; char c = 'a'; short signed int ssi_octal = 0123; long unsigned int lui = sizeof(char); -enum e1{dark, light}; -enum e2{a=3, b=9}; - int *pi; // pointer to int char ** ppc; // pointer to pointer to char int* ap[15]; // array of 15 pointers to ints diff --git a/components/codetools/h2pastool.pas b/components/codetools/h2pastool.pas index 68a47a3fb7..fc96c97745 100644 --- a/components/codetools/h2pastool.pas +++ b/components/codetools/h2pastool.pas @@ -103,11 +103,17 @@ type function GetSimplePascalTypeOfCVar(CVarNode: 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; PascalDesc: TCodeTreeNodeDesc; ParentNode: TH2PNode = nil; 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 WriteH2PNodeReport; @@ -217,6 +223,8 @@ begin Add('double*','pcdouble'); Add('long double','clongdouble'); Add('long double*','pclongdouble'); + // void + Add('void*','pointer'); end; end; Result:=InternalPredefinedCTypes; @@ -258,10 +266,13 @@ var CurType: String; SimpleType: String; H2PNode: TH2PNode; + NextCNode: TCodeTreeNode; + TypeH2PNode: TH2PNode; begin Tree.Clear; CNode:=CTool.Tree.Root; while CNode<>nil do begin + NextCNode:=CNode.Next; case CNode.Desc of ccnVariable: begin @@ -271,13 +282,16 @@ begin DebugLn(['TH2PasTool.BuildH2PTree Variable Name="',CurName,'" Type="',CurType,'" SimpleType=',SimpleType]); if SimpleType='' then begin // this variable has a complex type - //SimpleType:=CreateTypeForVarType(CNode); + TypeH2PNode:=GetTypeForVarType(CNode); + if TypeH2PNode<>nil then + SimpleType:=TypeH2PNode.PascalName; end; if SimpleType<>'' then begin H2PNode:=CreateH2PNode(CurName,CurName,CNode,ctnVarDefinition); H2PNode.PascalCode:=SimpleType; //DebugLn(['TH2PasTool.BuildH2PTree CNode.Desc=',CCNodeDescAsString(CNode.Desc),' ',H2PNode.DescAsString]); end; + NextCNode:=CNode.NextSkipChilds; end; ccnEnumBlock: begin @@ -301,42 +315,27 @@ begin end; end; end; - CNode:=CNode.Next; + CNode:=NextCNode; end; end; function TH2PasTool.GetSimplePascalTypeOfCVar(CVarNode: TCodeTreeNode): string; -var - SimpleType: String; begin Result:=CTool.ExtractVariableType(CVarNode); if Result='' then exit; - SimpleType:=ConvertSimpleCTypeToPascalType(Result); - if SimpleType<>'' then begin - Result:=SimpleType; - exit; - end; - if not IsValidIdent(Result) then - Result:=''; + Result:=ConvertSimpleCTypeToPascalType(Result,true); end; function TH2PasTool.GetSimplePascalResultTypeOfCFunction( CFuncNode: TCodeTreeNode): string; -var - SimpleType: String; begin Result:=CTool.ExtractFunctionResultType(CFuncNode); if Result='' then exit; - SimpleType:=ConvertSimpleCTypeToPascalType(Result); - if SimpleType<>'' then begin - Result:=SimpleType; - exit; - end; - if not IsValidIdent(Result) then - Result:=''; + Result:=ConvertSimpleCTypeToPascalType(Result,true); end; -function TH2PasTool.ConvertSimpleCTypeToPascalType(CType: string): string; +function TH2PasTool.ConvertSimpleCTypeToPascalType(CType: string; + UseSingleIdentifierAsDefault: boolean): string; // the type must be normalized. That means no directives, // no unneeded spaces, no tabs, no comments, no newlines. var @@ -375,6 +374,9 @@ begin until false; // seach in predefined ctypes Result:=PredefinedCTypes[CType]; + + if (Result='') and (UseSingleIdentifierAsDefault) and IsValidIdent(CType) then + Result:=CType; end; function TH2PasTool.CreateH2PNode(const PascalName, CName: string; @@ -393,6 +395,121 @@ begin 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; begin DebugLn(['TH2PasTool.WriteDebugReport ']);