diff --git a/components/codetools/ccodeparsertool.pas b/components/codetools/ccodeparsertool.pas
index 5ee0df9d01..7c5e8058a6 100644
--- a/components/codetools/ccodeparsertool.pas
+++ b/components/codetools/ccodeparsertool.pas
@@ -104,7 +104,7 @@ interface
{$I codetools.inc}
{$DEFINE VerboseCCodeParser}
-{off $DEFINE VerboseCDirectives}
+{$DEFINE VerboseCDirectives}
uses
{$IFDEF MEM_CHECK}
@@ -128,17 +128,17 @@ const
ccnEnumBlock = 4+ccnBase;// e.g. enum {};
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{}
- ccnStructAlias = 9+ccnBase;// e.g. struct alias name;
+ ccnTypedef = 7+ccnBase;// e.g. typedef int TInt; last child is ccnName
+ ccnStruct = 8+ccnBase;// e.g. struct{}, child is ccnTypeName or ccnTypeName+ccnSubDefs or ccnSubDefs
ccnUnion = 10+ccnBase;// e.g. union{}
- ccnUnionAlias = 11+ccnBase;// e.g. union alias name;
- ccnVariable = 12+ccnBase;// e.g. int i
+ ccnDefinition = 12+ccnBase;// e.g. variable: int i, type: struct typename {} or both: union typename {} varname
ccnFunction = 13+ccnBase;// e.g. int i()
ccnName = 14+ccnBase;// e.g. i
- ccnFuncParamList = 15+ccnBase;// e.g. ()
- ccnFuncParameter = 16+ccnBase;// e.g. ()
- ccnStatementBlock = 17+ccnBase;// e.g. {}
+ ccnTypeName = 15+ccnBase;// e.g. i
+ ccnSubDefs = 16+ccnBase;// e.g. the {} of a struct
+ ccnFuncParamList = 17+ccnBase;// e.g. ()
+ ccnFuncParameter = 18+ccnBase;// e.g. ()
+ ccnStatementBlock = 19+ccnBase;// e.g. {}
// values for Node.SubDesc
ccnsNone = 0;
@@ -188,6 +188,7 @@ type
function CurlyBracketCloseToken: boolean;
function TypedefToken: boolean;
function StructToken: boolean;
+ function UnionToken: boolean;
procedure InitKeyWordList;
procedure InitParser;
@@ -198,8 +199,7 @@ type
procedure ReadVariable(AsParameter: boolean);
procedure ReadParameterList;
procedure ReadEnum;
- procedure ReadStruct;
- procedure ReadUnion;
+ procedure ReadUnionStruct(IsStruct: boolean);
procedure ReadConstant;
procedure Read__attribute__;
@@ -279,9 +279,9 @@ type
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;
+ function ExtractDefinitionName(VarNode: TCodeTreeNode): string;
+ function ExtractDefinitionType(VarNode: TCodeTreeNode;
+ WithDirectives: boolean = false): string;
function ExtractFunctionName(FuncNode: TCodeTreeNode): string;
function GetFunctionParamListNode(Node: TCodeTreeNode): TCodeTreeNode;
function ExtractFunctionParamList(FuncNode: TCodeTreeNode): string;
@@ -405,11 +405,11 @@ begin
ccnConstant : Result:='constant';
ccnTypedef : Result:='typedef';
ccnStruct : Result:='struct';
- ccnStructAlias : Result:='struct-alias';
ccnUnion : Result:='union';
- ccnVariable : Result:='variable';
+ ccnDefinition : Result:='definition(var/type/const)';
ccnFunction : Result:='function';
ccnName : Result:='name';
+ ccnTypeName : Result:='type-name';
ccnFuncParamList : Result:='function-param-list';
ccnFuncParameter : Result:='function-parameter';
ccnStatementBlock: Result:='statement-block';
@@ -787,7 +787,10 @@ function TCCodeParserTool.DirectiveToken: boolean;
begin
BracketLevel:=0;
repeat
- ReadRawNextCAtom(Src,SrcPos,AtomStart);
+ ReadRawNextAtom;
+ {$IFDEF VerboseCCodeParser}
+ debugln(['ReadExpression Atom ',GetAtom]);
+ {$ENDIF}
if AtomStart>SrcLen then
RaiseException('missing expression');
if Src[AtomStart] in [#10,#13] then begin
@@ -811,17 +814,17 @@ function TCCodeParserTool.DirectiveToken: boolean;
if AtomIs('defined') then begin
// read defined(macro)
// or read defined macro
- ReadRawNextCAtom(Src,SrcPos,AtomStart);
+ ReadRawNextAtom;
if AtomIsChar('(') then begin
NeedBracket:=true;
- ReadRawNextCAtom(Src,SrcPos,AtomStart);
+ ReadRawNextAtom;
end else begin
NeedBracket:=false;
end;
if not AtomIsIdentifier then
RaiseExpectedButAtomFound('macro');
if NeedBracket then begin
- ReadRawNextCAtom(Src,SrcPos,AtomStart);
+ ReadRawNextAtom;
if not AtomIsChar(')') then
RaiseExpectedButAtomFound(')');
end;
@@ -937,8 +940,8 @@ begin
end;
end;
// read til end of line
- ReadTilCLineEnd(Src,SrcPos);
- AtomStart:=SrcPos;
+ ReadTilCLineEnd(Src,AtomStart);
+ SrcPos:=AtomStart;
//DebugLn(['TCCodeParserTool.DirectiveToken ',copy(Src,CurNode.StartPos,AtomStart-CurNode.Startpos)]);
EndChildNode;
end;
@@ -1029,7 +1032,7 @@ begin
EndChildNode;
end;
-procedure TCCodeParserTool.ReadStruct;
+procedure TCCodeParserTool.ReadUnionStruct(IsStruct: boolean);
(* Examples:
union sign /* A definition and a declaration */
@@ -1061,15 +1064,18 @@ procedure TCCodeParserTool.ReadStruct;
// typeof(*(ptr)) __v;
// } *__p = (void *) (ptr);
//
+var
+ InTypeDef: Boolean;
begin
- CreateChildNode(ccnStruct);
+ InTypeDef:=CurNode.Desc=ccnTypedef;
+ if IsStruct then
+ CreateChildNode(ccnStruct)
+ else
+ CreateChildNode(ccnUnion);
ReadNextAtom;
- if CurNode.Parent.Desc<>ccnTypedef then begin
- // read variable name
- if not AtomIsIdentifier then
- RaiseExpectedButAtomFound('identifier');
- CreateChildNode(ccnName);
+ if AtomIsIdentifier then begin
+ CreateChildNode(ccnTypeName);
EndChildNode;
ReadNextAtom;
end;
@@ -1081,6 +1087,7 @@ begin
end;
if AtomIsChar('{') then begin
// read block {}
+ CreateChildNode(ccnSubDefs);
repeat
ReadNextAtom;
// read variables
@@ -1098,6 +1105,7 @@ begin
else
RaiseExpectedButAtomFound('identifier');
until false;
+ EndChildNode;
// read after attributes
ReadNextAtom;
if AtomIs('__attribute__') then begin
@@ -1105,12 +1113,12 @@ begin
end else begin
UndoReadNextAtom;
end;
- end else if AtomIsIdentifier then begin
+ end else if InTypeDef and AtomIsIdentifier then begin
// using another struct
- CreateChildNode(ccnStructAlias);
- EndChildNode;
+ UndoReadNextAtom;
end else if AtomIsChar(';') then begin
// struct without content
+ UndoReadNextAtom;
end else
RaiseExpectedButAtomFound('{');
@@ -1118,74 +1126,6 @@ begin
EndChildNode;
end;
-procedure TCCodeParserTool.ReadUnion;
-(* Example
- union {
- uint16_t uuid16;
- uint32_t uuid32;
- uint128_t uuid128;
- } value;
-
- union _GFloatIEEE754
- {
- gfloat v_float;
- struct {
- guint mantissa : 23;
- guint biased_exponent : 8;
- guint sign : 1;
- } mpn;
- };
-
- typedef union _GDoubleIEEE754 GDoubleIEEE754;
-*)
-begin
- CreateChildNode(ccnUnion);
-
- ReadNextAtom;
-
- debugln(['TCCodeParserTool.ReadUnion AAA1 ',GetAtom]);
- if AtomIsIdentifier then begin
- // read type name
- CreateChildNode(ccnName);
- EndChildNode;
- ReadNextAtom;
- debugln(['TCCodeParserTool.ReadUnion AAA2 ',GetAtom]);
- end;
-
- if AtomIsChar('{') then begin
- // read block {}
- repeat
- ReadNextAtom;
- // read variables
- if AtomIsIdentifier then begin
- ReadVariable(false);
- 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
- // for example: typedef union _GDoubleIEEE754 GDoubleIEEE754;
- CreateChildNode(ccnUnionAlias);
- EndChildNode;
- end else if AtomIsChar(';') then begin
- // union without content
- end else
- RaiseExpectedButAtomFound('{');
- debugln(['TCCodeParserTool.ReadUnion AAA3 ',GetAtom]);
-
- // close node
- EndChildNode;
-end;
-
function TCCodeParserTool.TypedefToken: boolean;
{ examples:
typedef type name;
@@ -1197,8 +1137,8 @@ begin
ReadNextAtom;
if AtomIs('typedef') then
RaiseExpectedButAtomFound('declaration')
- else if AtomIs('struct') then begin
- ReadStruct;
+ else if AtomIs('struct') or AtomIs('union') then begin
+ ReadUnionStruct(AtomIs('struct'));
ReadNextAtom;
if not AtomIsIdentifier then
RaiseExpectedButAtomFound('identifier');
@@ -1225,7 +1165,13 @@ end;
function TCCodeParserTool.StructToken: boolean;
begin
Result:=true;
- ReadStruct;
+ ReadUnionStruct(true);
+end;
+
+function TCCodeParserTool.UnionToken: boolean;
+begin
+ Result:=true;
+ ReadUnionStruct(false);
end;
procedure TCCodeParserTool.InitKeyWordList;
@@ -1239,6 +1185,7 @@ begin
Add('enum',{$ifdef FPC}@{$endif}EnumToken);
Add('typedef',{$ifdef FPC}@{$endif}TypedefToken);
Add('struct',{$ifdef FPC}@{$endif}StructToken);
+ Add('union',{$ifdef FPC}@{$endif}UnionToken);
DefaultKeyWordFunction:={$ifdef FPC}@{$endif}OtherToken;
end;
end;
@@ -1379,17 +1326,15 @@ begin
exit;
end;
end else
- CreateChildNode(ccnVariable);
+ CreateChildNode(ccnDefinition);
MainNode:=CurNode;
IsFunction:=false;
if AtomIs('const') then ReadNextAtom;
if AtomIs('struct') then begin
- // for example: struct structname varname
- ReadNextAtom;
- end
- else if AtomIs('union') then begin
- ReadUnion;
+ ReadUnionStruct(true);
+ end else if AtomIs('union') then begin
+ ReadUnionStruct(false);
end else begin
if IsCCodeFunctionModifier.DoItCaseSensitive(Src,AtomStart,SrcPos-AtomStart)
then begin
@@ -1834,6 +1779,9 @@ begin
end else begin
SrcPos:=AtomStart;
end;
+ {$IFDEF VerboseCCodeParser}
+ DebugLn(['TCCodeParserTool.UndoReadNextAtom END ',AtomStart,'-',SrcPos,' "',copy(Src,AtomStart,SrcPos-AtomStart),'"']);
+ {$ENDIF}
end;
function TCCodeParserTool.ReadTilBracketClose(
@@ -2024,7 +1972,7 @@ begin
while (Result<>nil) and (Result.Desc<>ccnName) do Result:=Result.NextBrother;
end;
-function TCCodeParserTool.ExtractVariableName(VarNode: TCodeTreeNode): string;
+function TCCodeParserTool.ExtractDefinitionName(VarNode: TCodeTreeNode): string;
var
NameNode: TCodeTreeNode;
begin
@@ -2035,7 +1983,7 @@ begin
Result:=copy(Src,NameNode.StartPos,NameNode.EndPos-NameNode.StartPos);
end;
-function TCCodeParserTool.ExtractVariableType(VarNode: TCodeTreeNode;
+function TCCodeParserTool.ExtractDefinitionType(VarNode: TCodeTreeNode;
WithDirectives: boolean): string;
var
NameNode: TCodeTreeNode;
diff --git a/components/codetools/examples/h2pastest.lpi b/components/codetools/examples/h2pastest.lpi
index a09b0cd76a..c255f7680e 100644
--- a/components/codetools/examples/h2pastest.lpi
+++ b/components/codetools/examples/h2pastest.lpi
@@ -33,7 +33,7 @@
-
+
@@ -47,6 +47,10 @@
+
+
+
+
diff --git a/components/codetools/h2pastool.pas b/components/codetools/h2pastool.pas
index 25c5290eb7..8499671de9 100644
--- a/components/codetools/h2pastool.pas
+++ b/components/codetools/h2pastool.pas
@@ -546,7 +546,7 @@ var
begin
if (CNode.FirstChild<>nil) and (CNode.FirstChild.Desc=ccnUnion)
then begin
- CurName:=CTool.ExtractVariableName(CNode);
+ CurName:=CTool.ExtractDefinitionName(CNode);
if (ParentNode<>nil) and (ParentNode.PascalDesc=ctnRecordType)
then begin
// create a pascal 'record case'
@@ -578,8 +578,8 @@ begin
DebugLn(['TH2PasTool.ConvertVariable SKIPPING union variable at ',CTool.CleanPosToStr(CNode.StartPos)]);
end;
end else begin
- CurName:=CTool.ExtractVariableName(CNode);
- CurType:=CTool.ExtractVariableType(CNode);
+ CurName:=CTool.ExtractDefinitionName(CNode);
+ CurType:=CTool.ExtractDefinitionType(CNode);
SimpleType:=GetSimplePascalTypeOfCVar(CNode);
if SimpleType='' then begin
// this variable has a complex type
@@ -751,6 +751,8 @@ var
CurCName: String;
CurValue: String;
SubChildNode: TCodeTreeNode;
+ TypeNode: TCodeTreeNode;
+ SubTypeName: String;
begin
if CNode.FirstChild=nil then begin
exit;
@@ -760,10 +762,10 @@ begin
ChildNode:=CNode.FirstChild;
case ChildNode.Desc of
- ccnVariable: // typedef variable
+ ccnDefinition: // typedef name
begin
- CurName:=CTool.ExtractVariableName(ChildNode);
- CurType:=CTool.ExtractVariableType(ChildNode);
+ CurName:=CTool.ExtractDefinitionName(ChildNode);
+ CurType:=CTool.ExtractDefinitionType(ChildNode);
SimpleType:=GetSimplePascalTypeOfCVar(ChildNode);
if SimpleType='' then begin
// this variable has a complex type
@@ -783,22 +785,49 @@ begin
ccnStruct: // typedef struct
begin
- ChildNode:=CNode.FirstChild.FirstChild;
- if (ChildNode<>nil)
- and (ChildNode.Desc=ccnStructAlias) then begin
- // this is a struct alias
- CurType:=GetIdentifier(@CTool.Src[ChildNode.StartPos]);
- CurCName:=CurName;
- TypeH2PNode:=CreateH2PNode(CurName,CurCName,CNode,
- ctnTypeDefinition,CurType);
- end else begin
- // this is a new struct
- CurCName:=CurName;
- TypeH2PNode:=CreateH2PNode(CurName,CurCName,CNode,ctnRecordType,'');
+ (* typedef struct a b; => alias b = a
+ typedef struct a {} b; => a = record + alias b = a
+ typedef struct {} b; => b = record
+ *)
+ if (ChildNode.FirstChild.Desc=ccnTypeName)
+ and (ChildNode.LastChild.Desc=ccnSubDefs) then begin
+ // for example: typedef struct a {} b;
+ // => create a new record type a and an alias b = a
+ TypeNode:=ChildNode.FirstChild;
+ SubChildNode:=ChildNode.LastChild;
+ // create a new record
+ CurCName:=GetIdentifier(@CTool.Src[TypeNode.StartPos]);
+ SubTypeName:=CurCName;
+ TypeH2PNode:=CreateH2PNode(SubTypeName,CurCName,TypeNode,ctnRecordType,'');
DebugLn(['TH2PasTool.ConvertTypedef added record: ',TypeH2PNode.DescAsString(CTool)]);
// build recursively
- if ChildNode<>nil then
- BuildH2PTree(TypeH2PNode,ChildNode);
+ BuildH2PTree(TypeH2PNode,SubChildNode.FirstChild);
+ // create an alias b=a
+ CurCName:=CurName;
+ TypeH2PNode:=CreateH2PNode(CurName,CurCName,CNode,
+ ctnTypeDefinition,SubTypeName);
+ DebugLn(['TH2PasTool.ConvertTypedef added type alias: ',TypeH2PNode.DescAsString(CTool)]);
+ end else if ChildNode.FirstChild.Desc=ccnSubDefs then begin
+ // for example: typedef struct {} b; => b = record
+ // => create a new record type b
+ SubChildNode:=ChildNode.LastChild;
+ CurCName:=CurName;
+ TypeH2PNode:=CreateH2PNode(CurName,CurCName,ChildNode,ctnRecordType,'');
+ DebugLn(['TH2PasTool.ConvertTypedef added record: ',TypeH2PNode.DescAsString(CTool)]);
+ // build recursively
+ BuildH2PTree(TypeH2PNode,SubChildNode.FirstChild);
+ end else if (ChildNode.FirstChild.Desc=ccnTypeName)
+ and (ChildNode.FirstChild.NextBrother=nil) then begin
+ // for example: typedef struct a b;
+ // => create a type alias b = a
+ TypeNode:=ChildNode.FirstChild;
+ SubTypeName:=GetIdentifier(@CTool.Src[TypeNode.StartPos]);
+ CurCName:=CurName;
+ TypeH2PNode:=CreateH2PNode(CurName,CurCName,CNode,
+ ctnTypeDefinition,SubTypeName);
+ DebugLn(['TH2PasTool.ConvertTypedef added type alias: ',TypeH2PNode.DescAsString(CTool)]);
+ end else begin
+ raise Exception.Create('TH2PasTool.ConvertTypedef inconsistency: unknown format of typedef struct');
end;
end;
@@ -2008,7 +2037,7 @@ begin
ccnTypedef:
ConvertTypedef(CNode,ParentNode);
- ccnVariable:
+ ccnDefinition:
ConvertVariable(CNode,ParentNode);
ccnFunction:
@@ -2222,7 +2251,7 @@ end;
function TH2PasTool.GetSimplePascalTypeOfCVar(CVarNode: TCodeTreeNode): string;
begin
- Result:=CTool.ExtractVariableType(CVarNode);
+ Result:=CTool.ExtractDefinitionType(CVarNode);
if Result='' then exit;
Result:=ConvertSimpleCTypeToPascalType(Result,true);
end;
@@ -2379,14 +2408,14 @@ var
NeedH2PNode: Boolean;
begin
Result:=nil;
- if (CNode.Desc=ccnVariable)
+ if (CNode.Desc=ccnDefinition)
and (CNode.FirstChild<>nil)
and (CNode.FirstChild.Desc=ccnUnion) then begin
// ToDo: union
end else begin
SubH2PNode:=nil;
- if CNode.Desc=ccnVariable then
- CCode:=CTool.ExtractVariableType(CNode)
+ if CNode.Desc=ccnDefinition then
+ CCode:=CTool.ExtractDefinitionType(CNode)
else if CNode.Desc=ccnFunction then
CCode:=CTool.ExtractFunctionResultType(CNode)
else if CNode.Desc=ccnFuncParameter then
diff --git a/components/codetools/nonpascalcodetools.pas b/components/codetools/nonpascalcodetools.pas
index f1650b9faa..233bb3e5ae 100644
--- a/components/codetools/nonpascalcodetools.pas
+++ b/components/codetools/nonpascalcodetools.pas
@@ -200,14 +200,14 @@ begin
begin
inc(Position);
end;
- #$EF:
- if (Source[Position+1]=#$BB)
- and (Source[Position+2]=#$BF) then begin
- // skip UTF BOM
- inc(Position,3);
- end else begin
- break;
- end;
+ #$EF:
+ if (Source[Position+1]=#$BB)
+ and (Source[Position+2]=#$BF) then begin
+ // skip UTF BOM
+ inc(Position,3);
+ end else begin
+ break;
+ end;
'\': // backslash
if (Positionc1) then
+ inc(Position);
+ end;
'A'..'Z','a'..'z','_':
begin
// identifier
@@ -352,8 +359,7 @@ begin
if Position<=Len then begin
c2:=Source[Position];
// test for double char operators
- if ((c1=#13) and (c2=#10))
- or ((c2='=') and (c1 in ['=','!','<','>','+','-','*','/','&','|']))
+ if ((c2='=') and (c1 in ['=','!','<','>','+','-','*','/','&','|']))
or ((c1=':') and (c2=':'))
or ((c1='|') and (c2='|'))
or ((c1='&') and (c2='&'))