unit UIsxclassesParser;
interface
uses
Classes;
type
TIsxclassesParserStoredString = (ssLine, ssType, ssEnumValue, ssConstant, ssMemberName, ssMember, ssProperty);
TIsxclassesParserStrings = array [TIsxclassesParserStoredString] of TStringList;
TIsxclassesParser = class
private
FStrings: TIsxclassesParserStrings;
public
constructor Create;
destructor Destroy; override;
procedure Parse(const FileName: String);
procedure SaveXML(const HeaderFileName, HeaderFileName2, FooterFileName, OutputFileName: String);
procedure SaveWordLists(const OutputFileName: String);
end;
implementation
uses
Windows, SysUtils,
PathFunc;
constructor TIsxclassesParser.Create;
begin
inherited;
for var I := Low(TIsxClassesParserStoredString) to High(TIsxClassesParserStoredString) do
FStrings[I] := TStringList.Create;
{ Sorted for speed of IndexOf used below }
FStrings[ssType].Duplicates := dupError;
FStrings[ssType].Sorted := True;
{ Sorted for sanity checking of duplicates }
FStrings[ssEnumValue].Duplicates := dupError;
FStrings[ssEnumValue].Sorted := True;
FStrings[ssConstant].Duplicates := dupError;
FStrings[ssConstant].Sorted := True;
{ Sorted for ignoring duplicates }
FStrings[ssMemberName].Duplicates := dupIgnore;
FStrings[ssMemberName].Sorted := True;
FStrings[ssMember].Duplicates := dupIgnore;
FStrings[ssMember].Sorted := True;
FStrings[ssProperty].Duplicates := dupIgnore;
FStrings[ssProperty].Sorted := True;
end;
destructor TIsxclassesParser.Destroy;
begin
for var I := Low(TIsxClassesParserStoredString) to High(TIsxClassesParserStoredString) do
FStrings[I].Free;
inherited;
end;
procedure TIsxclassesParser.Parse(const FileName: String);
{ Also presents in ScriptFunc.pas - changed from AnsiString to String + check for [ added }
function ExtractScriptFuncWithoutHeaderName(const ScriptFuncWithoutHeader: String): String;
begin
Result := ScriptFuncWithoutHeader;
const C0: String = '[';
const C1: String = '(';
const C2: String = ':';
const C3: String = ';';
var P := Pos(C0, Result);
if P = 0 then
P := Pos(C1, Result);
if P = 0 then
P := Pos(C2, Result);
if P = 0 then
P := Pos(C3, Result);
if P = 0 then
raise Exception.CreateFmt('Invalid ScriptFuncWithoutHeader: %s', [Result]);
Delete(Result, P, Maxint);
end;
begin
var F: TextFile;
AssignFile(F, FileName);
Reset(F);
try
while not Eof(F) do begin
var S: String;
ReadLn(F, S);
FStrings[ssLine].Add(S);
var P := Pos('=', S);
if P > 1 then begin
{ Remember type and if it's an enum also remember the enum values }
FStrings[ssType].Add(Trim(Copy(S, 1, P-1)));
Delete(S, 1, P+1);
var N := Length(S);
if (N > 3) and (S[1] = '(') and (S[N-1] = ')') and (S[N] = ';') then
FStrings[ssEnumValue].Add(Copy(S, 2, N-3));
Continue;
end;
P := Pos('{', S);
if P <> 0 then begin
{ Remember constants }
P := Pos(': ', S);
if P <> 0 then begin
Delete(S, 1, P+1);
var N := Length(S);
if (N > 2) and (S[N-1] = ' ') and (S[N] = '}') then
FStrings[ssConstant].Add(Copy(S, 1, N-2));
end;
Continue;
end;
var Typ := ssMemberName;
P := Pos('procedure ', S);
if P = 0 then
P := Pos('function ', S);
if P = 0 then
P := Pos('constructor ', S);
if P = 0 then begin
Typ := ssProperty;
P := Pos('property ', S);
end;
if P <> 0 then begin
if Typ = ssMemberName then
FStrings[ssMember].Add(StringReplace(S.TrimLeft, 'const ', '', [rfReplaceAll]));
Delete(S, 1, P-1);
P := Pos(' ', S);
Delete(S, 1, P);
FStrings[Typ].Add(ExtractScriptFuncWithoutHeaderName(S));
Continue;
end;
end;
finally
CloseFile(F);
end;
end;
procedure TIsxclassesParser.SaveXML(const HeaderFileName, HeaderFileName2, FooterFileName, OutputFileName: String);
procedure FCopyFile(const SourceFileName, DestFileName: String; AppendToDestFile: Boolean);
begin
var F1: TextFile;
AssignFile(F1, SourceFileName);
Reset(F1);
try
var F2: TextFile;
AssignFile(F2, DestFileName);
if AppendToDestFile then begin
if FileExists(DestFileName) then
Append(F2)
else
Reset(F2);
end else
Rewrite(F2);
try
while not Eof(F1) do begin
var S: String;
ReadLn(F1, S);
WriteLn(F2, S);
end;
finally
CloseFile(F2);
end;
finally
CloseFile(F1);
end;
end;
function FGetNextPart(var Text: PChar): String;
begin
case Text^ of
#0:
begin
Result := '';
end;
#1..#32:
begin
var P := Text;
Inc(Text);
while CharInSet(Text^ , [#1..#32]) do
Inc(Text);
SetString(Result, P, Text - P);
end;
'(', ')', ',', '=', ':', ';', '[', ']', '{', '}':
begin
Result := Text^;
Inc(Text);
end;
'0'..'9', 'A'..'Z', 'a'..'z', '_', '.':
begin
var P := Text;
Inc(Text);
while CharInSet(Text^ , ['0'..'9', 'A'..'Z', 'a'..'z', '_', '.']) do
Inc(Text);
SetString(Result, P, Text - P);
end;
else
raise Exception.CreateFmt('Invalid symbol ''%s'' found', [Text^]);
end;
end;
function FLinkTypes(const S: String): String;
begin
Result := '';
var Text := PChar(S);
var NextPart := FGetNextPart(Text);
while NextPart <> '' do begin
if FStrings[ssType].IndexOf(NextPart) >= 0 then begin
if Result = '' then //start of line = object definition
NextPart := '' + NextPart + ''
else
NextPart := '
');
for var Line in FStrings[ssLine] do begin
var S := FLinkTypes(Line);
S := FConvertLeadingSpacesToNbsp(S);
WriteLn(F, S, '
');
end;
WriteLn(F, '