codetools: added unit ppugraph to parse groups of ppu files

git-svn-id: trunk@15655 -
This commit is contained in:
mattias 2008-07-02 13:41:40 +00:00
parent 168bd041aa
commit bf2774ed3d
5 changed files with 369 additions and 33 deletions

1
.gitattributes vendored
View File

@ -185,6 +185,7 @@ components/codetools/multikeywordlisttool.pas svneol=native#text/pascal
components/codetools/nonpascalcodetools.pas svneol=native#text/plain components/codetools/nonpascalcodetools.pas svneol=native#text/plain
components/codetools/pascalparsertool.pas svneol=native#text/pascal components/codetools/pascalparsertool.pas svneol=native#text/pascal
components/codetools/pascalreadertool.pas svneol=native#text/pascal components/codetools/pascalreadertool.pas svneol=native#text/pascal
components/codetools/ppugraph.pas svneol=native#text/plain
components/codetools/ppuparser.pas svneol=native#text/plain components/codetools/ppuparser.pas svneol=native#text/plain
components/codetools/resourcecodetool.pas svneol=native#text/pascal components/codetools/resourcecodetool.pas svneol=native#text/pascal
components/codetools/sourcechanger.pas svneol=native#text/pascal components/codetools/sourcechanger.pas svneol=native#text/pascal

View File

@ -24,7 +24,7 @@ uses
CodeCache, KeywordFuncLists, SourceLog, ExprEval, DefineTemplates, FileProcs, CodeCache, KeywordFuncLists, SourceLog, ExprEval, DefineTemplates, FileProcs,
CodeToolsStrConsts, DirectoryCacher, CCodeParserTool, H2PasTool, CodeToolsStrConsts, DirectoryCacher, CCodeParserTool, H2PasTool,
MultiKeyWordListTool, ResourceCodeTool, CodeToolsStructs, CacheCodeTools, MultiKeyWordListTool, ResourceCodeTool, CodeToolsStructs, CacheCodeTools,
PPUParser, PPUParser, PPUGraph,
// fast xml units, changes not merged in current fpc // fast xml units, changes not merged in current fpc
Laz_DOM, Laz_XMLCfg, Laz_XMLRead, Laz_XMLWrite, Laz_XMLStreaming; Laz_DOM, Laz_XMLCfg, Laz_XMLRead, Laz_XMLWrite, Laz_XMLStreaming;

View File

@ -123,12 +123,12 @@ type
end; end;
function CompareGraphNodeByNode(GraphNode1, GraphNode2: Pointer): integer; function CompareGraphNodeByNode(GraphNode1, GraphNode2: Pointer): integer;
function ComparePointerWithGraphNodeNode(p, GraphNode: Pointer): integer; function CompareNodeWithGraphNodeNode(p, GraphNode: Pointer): integer;
function CompareGraphEdgeByFromNode(GraphEdge1, GraphEdge2: Pointer): integer; function CompareGraphEdgeByFromNode(GraphEdge1, GraphEdge2: Pointer): integer;
function ComparePointerWithGraphEdgeFromNode(p, GraphEdge: Pointer): integer; function CompareNodeWithGraphEdgeFromNode(p, GraphEdge: Pointer): integer;
function CompareGraphEdgeByToNode(GraphEdge1, GraphEdge2: Pointer): integer; function CompareGraphEdgeByToNode(GraphEdge1, GraphEdge2: Pointer): integer;
function ComparePointerWithGraphEdgeToNode(p, GraphEdge: Pointer): integer; function CompareNodeWithGraphEdgeToNode(p, GraphEdge: Pointer): integer;
function CompareGraphEdgeByNodes(GraphEdge1, GraphEdge2: Pointer): integer; function CompareGraphEdgeByNodes(GraphEdge1, GraphEdge2: Pointer): integer;
function CompareEdgeKeyWithGraphEdge(EdgeKey, GraphEdge: Pointer): integer; function CompareEdgeKeyWithGraphEdge(EdgeKey, GraphEdge: Pointer): integer;
@ -151,7 +151,7 @@ begin
//DebugLn(['CompareGraphNodeByNode ',Node1.DescAsString,' ',Node2.DescAsString,' ',Result]); //DebugLn(['CompareGraphNodeByNode ',Node1.DescAsString,' ',Node2.DescAsString,' ',Result]);
end; end;
function ComparePointerWithGraphNodeNode(p, GraphNode: Pointer): integer; function CompareNodeWithGraphNodeNode(p, GraphNode: Pointer): integer;
var var
Node: TCodeTreeNode; Node: TCodeTreeNode;
begin begin
@ -180,7 +180,7 @@ begin
Result:=0; Result:=0;
end; end;
function ComparePointerWithGraphEdgeFromNode(p, GraphEdge: Pointer): integer; function CompareNodeWithGraphEdgeFromNode(p, GraphEdge: Pointer): integer;
var var
Node: TCodeTreeNode; Node: TCodeTreeNode;
begin begin
@ -208,7 +208,7 @@ begin
Result:=0; Result:=0;
end; end;
function ComparePointerWithGraphEdgeToNode(p, GraphEdge: Pointer): integer; function CompareNodeWithGraphEdgeToNode(p, GraphEdge: Pointer): integer;
var var
Node: TCodeTreeNode; Node: TCodeTreeNode;
begin begin
@ -382,6 +382,8 @@ var
begin begin
if Source=Self then exit; if Source=Self then exit;
Clear; Clear;
FNodeClass:=Source.FNodeClass;
FEdgeClass:=Source.FEdgeClass;
// copy nodes // copy nodes
AVLNode:=Source.Nodes.FindLowest; AVLNode:=Source.Nodes.FindLowest;
while AVLNode<>nil do begin while AVLNode<>nil do begin
@ -841,14 +843,14 @@ end;
function TCodeGraph.FindAVLNodeOfNode(Node: TCodeTreeNode): TAVLTreeNode; function TCodeGraph.FindAVLNodeOfNode(Node: TCodeTreeNode): TAVLTreeNode;
begin begin
Result:=Nodes.FindKey(Node,@ComparePointerWithGraphNodeNode); Result:=Nodes.FindKey(Node,@CompareNodeWithGraphNodeNode);
end; end;
function TCodeGraph.FindAVLNodeOfToNode(InTree: TAVLTree; ToNode: TCodeTreeNode function TCodeGraph.FindAVLNodeOfToNode(InTree: TAVLTree; ToNode: TCodeTreeNode
): TAVLTreeNode; ): TAVLTreeNode;
begin begin
if InTree<>nil then if InTree<>nil then
Result:=InTree.FindKey(ToNode,@ComparePointerWithGraphEdgeToNode) Result:=InTree.FindKey(ToNode,@CompareNodeWithGraphEdgeToNode)
else else
Result:=nil; Result:=nil;
end; end;
@ -857,7 +859,7 @@ function TCodeGraph.FindAVLNodeOfFromNode(OutTree: TAVLTree;
FromNode: TCodeTreeNode): TAVLTreeNode; FromNode: TCodeTreeNode): TAVLTreeNode;
begin begin
if OutTree<>nil then if OutTree<>nil then
Result:=OutTree.FindKey(FromNode,@ComparePointerWithGraphEdgeFromNode) Result:=OutTree.FindKey(FromNode,@CompareNodeWithGraphEdgeFromNode)
else else
Result:=nil; Result:=nil;
end; end;

View File

@ -28,39 +28,34 @@ program PPUDependencies;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
uses uses
Classes, SysUtils, PPUParser, FileProcs; Classes, SysUtils, PPUParser, FileProcs, PPUGraph;
var var
PPU: TPPU;
Filename: String; Filename: String;
UsedUnits: TStringList; Groups: TPPUGroups;
Group: TPPUGroup;
i: Integer;
Member: TPPUMember;
begin begin
if (Paramcount<1) then begin if (Paramcount<1) then begin
writeln('Usage:'); writeln('Usage:');
writeln(' ',ParamStr(0),' <ppu filename>'); writeln(' ',ParamStr(0),' <ppu filename1> ...');
Halt; Halt;
end; end;
Filename:=ParamStr(1); Groups:=TPPUGroups.Create;
PPU:=TPPU.Create;
UsedUnits:=TStringList.Create;
try try
PPU.LoadFromFile(Filename); Group:=Groups.AddGroup('Default');
debugln('================================================================'); for i:=1 to Paramcount do begin
PPU.Dump(''); Filename:=ParamStr(i);
debugln('================================================================'); debugln(Filename);
UsedUnits.Clear; Member:=Group.AddMember(ExtractFileNameOnly(Filename));
PPU.GetMainUsesSectionNames(UsedUnits); Member.PPUFilename:=Filename;
debugln('Main used units: ',UsedUnits.DelimitedText); end;
UsedUnits.Clear;
PPU.GetImplementationUsesSectionNames(UsedUnits); Groups.UpdateDependencies;
debugln('Implementation used units: ',UsedUnits.DelimitedText);
debugln('Intialization proc: ',PPU.GetInitProcName);
debugln('Finalization proc: ',PPU.GetFinalProcName);
finally finally
PPU.Free; Groups.Free;
UsedUnits.Free;
end; end;
end. end.

View File

@ -0,0 +1,338 @@
{
***************************************************************************
* *
* This source is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This code is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License for more details. *
* *
* A copy of the GNU General Public License is available on the World *
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
* obtain it by writing to the Free Software Foundation, *
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
***************************************************************************
Author: Mattias Gaertner
Abstract:
Functions and classes to build dependency graphs for ppu files.
}
unit PPUGraph;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, PPUParser, CodeTree, AVL_Tree, FileProcs, BasicCodeTools;
type
TPPUGroup = class;
{ TPPUMember }
TPPUMember = class
public
Unitname: string;
PPUFilename: string;
KeyNode: TCodeTreeNode;
InitializationMangledName: string;
FinalizationMangledName: string;
Group: TPPUGroup;
constructor Create;
destructor Destroy; override;
function UpdateDependencies: boolean;
end;
TPPUGroups = class;
{ TPPUGroup }
TPPUGroup = class
private
FMembers: TAVLTree;// tree of TPPUMember sorted for unitname
function FindAVLNodeOfMemberWithUnitName(const AName: string): TAVLTreeNode;
procedure InternalRemoveMember(AMember: TPPUMember);
public
Name: string;
KeyNode: TCodeTreeNode;
Groups: TPPUGroups;
constructor Create;
destructor Destroy; override;
procedure Clear;
function AddMember(const NewUnitName: string): TPPUMember;
function FindMemberWithUnitName(const AName: string): TPPUMember;
function UpdateDependencies: boolean;
end;
{ TPPUGroups }
TPPUGroups = class
private
FGroups: TAVLTree;// tree of TPPUGroup sorted for name
FMembers: TAVLTree;// tree of TPPUMember sorted for unitname
function FindAVLNodeOfGroupWithName(const AName: string): TAVLTreeNode;
function FindAVLNodeOfMemberWithName(const AName: string): TAVLTreeNode;
procedure InternalRemoveMember(AMember: TPPUMember);
procedure InternalRemoveGroup(AGroup: TPPUGroup);
public
Name: string;
constructor Create;
destructor Destroy; override;
procedure Clear;
function AddGroup(const NewName: string): TPPUGroup;
function FindGroupWithName(const AName: string): TPPUGroup;
function FindMemberWithUnitName(const AName: string): TPPUMember;
function UpdateDependencies: boolean;
end;
function ComparePPUMembersByUnitName(Member1, Member2: Pointer): integer;
function CompareNameWithPPUMemberName(NamePChar, Member: Pointer): integer;
function ComparePPUGroupsByName(Group1, Group2: Pointer): integer;
function CompareNameWithPPUGroupName(NamePChar, Group: Pointer): integer;
implementation
function ComparePPUMembersByUnitName(Member1, Member2: Pointer): integer;
begin
Result:=CompareIdentifierPtrs(Pointer(TPPUMember(Member1).Unitname),
Pointer(TPPUMember(Member2).Unitname));
end;
function CompareNameWithPPUMemberName(NamePChar, Member: Pointer): integer;
begin
Result:=CompareIdentifierPtrs(NamePChar,Pointer(TPPUMember(Member).Unitname));
end;
function ComparePPUGroupsByName(Group1, Group2: Pointer): integer;
begin
Result:=CompareIdentifierPtrs(Pointer(TPPUGroup(Group1).Name),
Pointer(TPPUGroup(Group2).Name));
end;
function CompareNameWithPPUGroupName(NamePChar, Group: Pointer): integer;
begin
Result:=CompareIdentifierPtrs(NamePChar,Pointer(TPPUGroup(Group).Name));
end;
{ TPPUMember }
constructor TPPUMember.Create;
begin
KeyNode:=NodeMemManager.NewNode;
end;
destructor TPPUMember.Destroy;
begin
if KeyNode<>nil then
NodeMemManager.DisposeNode(KeyNode);
KeyNode:=nil;
if Group<>nil then
Group.InternalRemoveMember(Self);
inherited Destroy;
end;
function TPPUMember.UpdateDependencies: boolean;
var
PPU: TPPU;
UsedUnits: TStringList;
begin
Result:=false;
PPU:=TPPU.Create;
UsedUnits:=TStringList.Create;
try
PPU.LoadFromFile(PPUFilename);
debugln('================================================================');
DebugLn(['TPPUMember.UpdateDependencies UnitName=',Unitname,' Filename=',PPUFilename]);
PPU.Dump('');
debugln('================================================================');
UsedUnits.Clear;
PPU.GetMainUsesSectionNames(UsedUnits);
debugln('Main used units: ',UsedUnits.DelimitedText);
UsedUnits.Clear;
PPU.GetImplementationUsesSectionNames(UsedUnits);
debugln('Implementation used units: ',UsedUnits.DelimitedText);
InitializationMangledName:=PPU.GetInitProcName;
debugln('Initialization proc: ',InitializationMangledName);
FinalizationMangledName:=PPU.GetFinalProcName;
debugln('Finalization proc: ',FinalizationMangledName);
finally
PPU.Free;
UsedUnits.Free;
end;
Result:=true;
end;
{ TPPUGroup }
function TPPUGroup.FindAVLNodeOfMemberWithUnitName(const AName: string
): TAVLTreeNode;
begin
Result:=FMembers.FindKey(PChar(AName),@CompareNameWithPPUMemberName);
end;
procedure TPPUGroup.InternalRemoveMember(AMember: TPPUMember);
begin
FMembers.RemovePointer(AMember);
if Groups<>nil then
Groups.InternalRemoveMember(AMember);
end;
constructor TPPUGroup.Create;
begin
FMembers:=TAVLTree.Create(@ComparePPUMembersByUnitName);
KeyNode:=NodeMemManager.NewNode;
end;
destructor TPPUGroup.Destroy;
begin
Clear;
FreeAndNil(FMembers);
if KeyNode<>nil then
NodeMemManager.DisposeNode(KeyNode);
KeyNode:=nil;
if Groups<>nil then
Groups.InternalRemoveGroup(Self);
inherited Destroy;
end;
procedure TPPUGroup.Clear;
begin
while FMembers.Count>0 do
TPPUMember(FMembers.Root.Data).Free;
end;
function TPPUGroup.AddMember(const NewUnitName: string): TPPUMember;
begin
Result:=FindMemberWithUnitName(NewUnitName);
if Result<>nil then exit;
Result:=TPPUMember.Create;
Result.Unitname:=NewUnitName;
FMembers.Add(Result);
Result.Group:=Self;
Groups.FMembers.Add(Result);
end;
function TPPUGroup.FindMemberWithUnitName(const AName: string): TPPUMember;
var
AVLNode: TAVLTreeNode;
begin
AVLNode:=FindAVLNodeOfMemberWithUnitName(AName);
if AVLNode<>nil then
Result:=TPPUMember(AVLNode.Data)
else
Result:=nil;
end;
function TPPUGroup.UpdateDependencies: boolean;
var
AVLNode: TAVLTreeNode;
begin
Result:=false;
AVLNode:=FMembers.FindLowest;
while AVLNode<>nil do begin
if not TPPUMember(AVLNode.Data).UpdateDependencies then exit;
AVLNode:=FMembers.FindSuccessor(AVLNode);
end;
Result:=true;
end;
{ TPPUGroups }
function TPPUGroups.FindAVLNodeOfGroupWithName(const AName: string
): TAVLTreeNode;
begin
Result:=FGroups.FindKey(PChar(AName),@CompareNameWithPPUGroupName);
end;
function TPPUGroups.FindAVLNodeOfMemberWithName(const AName: string
): TAVLTreeNode;
begin
Result:=FMembers.FindKey(PChar(AName),@CompareNameWithPPUMemberName);
end;
procedure TPPUGroups.InternalRemoveMember(AMember: TPPUMember);
begin
FMembers.RemovePointer(AMember);
end;
procedure TPPUGroups.InternalRemoveGroup(AGroup: TPPUGroup);
begin
FGroups.RemovePointer(AGroup);
end;
constructor TPPUGroups.Create;
begin
FGroups:=TAVLTree.Create(@ComparePPUGroupsByName);
FMembers:=TAVLTree.Create(@ComparePPUMembersByUnitName);
end;
destructor TPPUGroups.Destroy;
begin
Clear;
FreeAndNil(FGroups);
FreeAndNil(FMembers);
inherited Destroy;
end;
procedure TPPUGroups.Clear;
begin
while FGroups.Count>0 do
TPPUGroup(FGroups.Root.Data).Free;
end;
function TPPUGroups.AddGroup(const NewName: string): TPPUGroup;
begin
Result:=FindGroupWithName(NewName);
if Result<>nil then exit;
Result:=TPPUGroup.Create;
Result.Name:=NewName;
FGroups.Add(Result);
Result.Groups:=Self;
end;
function TPPUGroups.FindGroupWithName(const AName: string): TPPUGroup;
var
AVLNode: TAVLTreeNode;
begin
AVLNode:=FindAVLNodeOfGroupWithName(AName);
if AVLNode<>nil then
Result:=TPPUGroup(AVLNode.Data)
else
Result:=nil;
end;
function TPPUGroups.FindMemberWithUnitName(const AName: string): TPPUMember;
var
AVLNode: TAVLTreeNode;
begin
AVLNode:=FindAVLNodeOfMemberWithName(AName);
if AVLNode<>nil then
Result:=TPPUMember(AVLNode.Data)
else
Result:=nil;
end;
function TPPUGroups.UpdateDependencies: boolean;
var
AVLNode: TAVLTreeNode;
begin
Result:=false;
AVLNode:=FGroups.FindLowest;
while AVLNode<>nil do begin
if not TPPUGroup(AVLNode.Data).UpdateDependencies then exit;
AVLNode:=FGroups.FindSuccessor(AVLNode);
end;
Result:=true;
end;
end.