123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- unit pascodegen;
- {$mode objfpc}{$H+}
- interface
- uses
- Classes, SysUtils;
- Type
- TCodegenLogType = (cltInfo);
- TCodegenLogTypes = Set of TCodegenLogType;
- TCodeGeneratorLogEvent = Procedure (Sender : TObject; LogType : TCodegenLogType; Const Msg : String) of object;
- TCodesection = (csUnknown, csConst, csType, csVar, csResourcestring, csDeclaration);
- { TPascalCodeGenerator }
- TPascalCodeGenerator = Class(TComponent)
- Private
- FAddTimeStamp: Boolean;
- FExtraUnits: String;
- FKeywordPrefix: String;
- FKeywordSuffix: String;
- FLicenseText: TStrings;
- FOnLog: TCodeGeneratorLogEvent;
- FOutputUnitName: String;
- FSource : TStrings;
- Findent : String;
- FSections : Array of TCodeSection;
- FSectionCount : Integer;
- FSwitches: TStrings;
- function GetSection: TCodeSection;
- procedure SetLicenseText(AValue: TStrings);
- procedure SetSection(AValue: TCodeSection);
- procedure SetSwitches(AValue: TStrings);
- Protected
- // Source manipulation
- Procedure DoLog(Const Msg : String; AType : TCodegenLogType = cltInfo);
- Procedure DoLog(Const Fmt : String; Args : Array of const; AType : TCodegenLogType = cltInfo);
- Function BaseUnits : String; virtual;
- Public
- Public
- Constructor Create(AOwner : TComponent); override;
- Destructor Destroy; override;
- // Emit section type word
- Procedure EnsureSection(aSection : TCodeSection);
- Procedure PushSection(ASection : TCodeSection = csUnknown);
- Function PopSection : TCodeSection;
- Procedure CreateHeader; virtual;
- Procedure CreateUnitClause; virtual;
- Procedure Indent;
- Procedure Undent;
- Function IsKeyWord (Const S : String) : Boolean;
- Function EscapeKeyWord(Const S : String) : String;
- Function MakePascalString(S: String; AddQuotes: Boolean=False): String;
- Function PrettyPrint(Const S: string): String;
- Procedure AddLn(Const Aline: string);
- Procedure AddLn(Const Alines : array of string);
- Procedure AddLn(Const Alines : TStrings);
- Procedure AddLn(Const Fmt: string; Args : Array of const);
- Procedure Comment(Const AComment : String; Curly : Boolean = False);
- Procedure Comment(Const AComment : Array of String);
- Procedure Comment(Const AComment : TStrings);
- Procedure ClassHeader(Const AClassName: String); virtual;
- Procedure SimpleMethodBody(Lines: Array of string); virtual;
- procedure SaveToStream(const AStream: TStream);
- Procedure SaveToFile(Const AFileName : string);
- Property Source : TStrings Read FSource;
- Property CurrentSection : TCodeSection Read GetSection Write SetSection;
- Published
- Property OutputUnitName : String Read FOutputUnitName Write FOutputUnitName;
- Property ExtraUnits : String Read FExtraUnits Write FExtraUnits;
- Property LicenseText : TStrings Read FLicenseText Write SetLicenseText;
- Property Switches : TStrings Read FSwitches Write SetSwitches;
- Property OnLog : TCodeGeneratorLogEvent Read FOnLog Write FOnlog;
- Property AddTimeStamp : Boolean Read FAddTimeStamp Write FAddTimeStamp;
- Property KeywordSuffix : String Read FKeywordSuffix Write FKeywordSuffix;
- Property KeywordPrefix : String Read FKeywordPrefix Write FKeywordPrefix;
- end;
- implementation
- { TPascalCodeGenerator }
- procedure TPascalCodeGenerator.Indent;
- begin
- FIndent:=FIndent+StringOfChar(' ',2);
- end;
- procedure TPascalCodeGenerator.Undent;
- Var
- L : Integer;
- begin
- L:=Length(Findent);
- if L>0 then
- FIndent:=Copy(FIndent,1,L-2)
- end;
- function TPascalCodeGenerator.IsKeyWord(const S: String): Boolean;
- Const
- KW=';absolute;and;array;asm;begin;case;const;constructor;destructor;div;do;'+
- 'downto;else;end;file;for;function;goto;if;implementation;in;inherited;'+
- 'inline;interface;label;mod;nil;not;object;of;on;operator;or;packed;'+
- 'procedure;program;record;reintroduce;repeat;self;set;shl;shr;string;then;'+
- 'to;type;unit;until;uses;var;while;with;xor;dispose;exit;false;new;true;'+
- 'as;class;dispinterface;except;exports;finalization;finally;initialization;'+
- 'inline;is;library;on;out;packed;property;raise;resourcestring;threadvar;try;'+
- 'private;published;length;setlength;';
- begin
- Result:=Pos(';'+lowercase(S)+';',KW)<>0;
- end;
- function TPascalCodeGenerator.EscapeKeyWord(const S: String): String;
- begin
- Result:=S;
- if IsKeyWord(S) then
- Result:=KeywordPrefix+Result+KeywordSuffix
- end;
- procedure TPascalCodeGenerator.AddLn(const Aline: string);
- begin
- FSource.Add(FIndent+ALine);
- end;
- procedure TPascalCodeGenerator.AddLn(const Alines: array of string);
- Var
- S : String;
- begin
- For s in alines do
- Addln(S);
- end;
- procedure TPascalCodeGenerator.AddLn(const Alines: TStrings);
- Var
- S : String;
- begin
- For s in alines do
- Addln(S);
- end;
- procedure TPascalCodeGenerator.AddLn(const Fmt: string; Args: array of const);
- begin
- AddLn(Format(Fmt,Args));
- end;
- procedure TPascalCodeGenerator.Comment(const AComment: String; Curly: Boolean);
- begin
- if Curly then
- AddLn('{ '+AComment+' }')
- else
- AddLn('// '+AComment);
- end;
- procedure TPascalCodeGenerator.Comment(const AComment: array of String);
- begin
- AddLn('{');
- Indent;
- AddLn(AComment);
- Undent;
- AddLn('}');
- end;
- procedure TPascalCodeGenerator.Comment(const AComment: TStrings);
- begin
- AddLn('{');
- Indent;
- AddLn(AComment);
- Undent;
- AddLn('}');
- end;
- constructor TPascalCodeGenerator.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FSource:=TstringList.Create;
- FLicenseText:=TstringList.Create;
- FSwitches:=TstringList.Create;
- FSwitches.Add('MODE ObjFPC');
- FSwitches.Add('H+');
- SetLength(FSections,0);
- FSectionCount:=0;
- PushSection(csUnknown);
- FKeywordPrefix:='&';
- end;
- destructor TPascalCodeGenerator.Destroy;
- begin
- FreeAndNil(FSwitches);
- FreeAndNil(FLicenseText);
- FreeAndNil(FSource);
- inherited Destroy;
- end;
- procedure TPascalCodeGenerator.EnsureSection(aSection: TCodeSection);
- Const
- SectionKeyWords : Array[TCodesection] of string
- = ('', 'Const', 'Type', 'Var', 'Resourcestring', '');
- begin
- If CurrentSection<>aSection then
- begin
- CurrentSection:=aSection;
- AddLn(SectionKeyWords[CurrentSection]);
- end;
- end;
- procedure TPascalCodeGenerator.PushSection(ASection : TCodeSection = csUnknown);
- begin
- if FSectionCount=Length(FSections) then
- SetLength(FSections,FSectionCount+10);
- FSections[FSectionCount]:=ASection;
- Inc(FSectionCount);
- end;
- function TPascalCodeGenerator.PopSection: TCodeSection;
- begin
- if FSectionCount=0 then
- Result:=csUnknown
- else
- begin
- Dec(FSectionCount);
- Result:=FSections[FSectionCount];
- end;
- end;
- procedure TPascalCodeGenerator.SaveToStream(const AStream : TStream);
- begin
- FSource.SaveToStream(AStream)
- end;
- procedure TPascalCodeGenerator.SaveToFile(const AFileName: string);
- Var
- F : TFileStream;
- B : Boolean;
- begin
- B:=False;
- F:=Nil;
- try
- B:=(Source.Count=0) and (OutputUnitName='');
- if B then
- OutputUnitname:=ChangeFileExt(ExtractFileName(AFileName),'');
- F:=TFileStream.Create(aFilename,fmCreate);
- SaveToStream(F);
- finally
- F.Free;
- if B then
- OutputUnitName:='';
- end;
- end;
- procedure TPascalCodeGenerator.SetSection(AValue: TCodeSection);
- begin
- if GetSection=AValue then
- Exit;
- FSections[FSectionCount-1]:=AValue;
- end;
- procedure TPascalCodeGenerator.SetSwitches(AValue: TStrings);
- begin
- if FSwitches=AValue then Exit;
- FSwitches.Assign(AValue);
- end;
- function TPascalCodeGenerator.GetSection: TCodeSection;
- begin
- Result:=FSections[FSectionCount-1];
- end;
- procedure TPascalCodeGenerator.SetLicenseText(AValue: TStrings);
- begin
- if FLicenseText=AValue then Exit;
- FLicenseText.Assign(AValue);
- end;
- procedure TPascalCodeGenerator.DoLog(const Msg: String; AType: TCodegenLogType);
- begin
- If Assigned(FOnLog) then
- FOnLog(Self,Atype,Msg);
- end;
- procedure TPascalCodeGenerator.DoLog(const Fmt: String; Args: array of const;
- AType: TCodegenLogType);
- begin
- DoLog(Format(Fmt,Args),AType);
- end;
- procedure TPascalCodeGenerator.CreateHeader;
- Var
- B,S : String;
- begin
- if LicenseText.Count>0 then
- Comment(LicenseText);
- if AddTimeStamp then
- Comment('Generated on: '+DateTimeToStr(Now));
- For S in Switches do
- addln('{$%s}',[S]);
- addln('');
- addln('interface');
- addln('');
- S:=ExtraUnits;
- B:=BaseUnits;
- if (B<>'') then
- if (S<>'') then
- begin
- if (B[Length(B)]<>',') then
- B:=B+',';
- S:=B+S;
- end
- else
- S:=B;
- addln('uses %s;',[S]);
- addln('');
- end;
- procedure TPascalCodeGenerator.CreateUnitClause;
- begin
- AddLn('Unit %s;',[OutputUnitName]);
- AddLn('');
- end;
- procedure TPascalCodeGenerator.SimpleMethodBody(Lines: array of string);
- Var
- S : String;
- begin
- AddLn('');
- AddLn('begin');
- Indent;
- For S in Lines do
- AddLn(S);
- Undent;
- AddLn('end;');
- AddLn('');
- end;
- function TPascalCodeGenerator.BaseUnits: String;
- begin
- Result:='';
- end;
- function TPascalCodeGenerator.MakePascalString(S: String; AddQuotes: Boolean
- ): String;
- begin
- Result:=StringReplace(S,'''','''''',[rfReplaceAll]);
- if AddQuotes then
- Result:=''''+Result+'''';
- end;
- function TPascalCodeGenerator.PrettyPrint(const S: string): String;
- begin
- If (S='') then
- Result:=''
- else
- Result:=Upcase(S[1])+Copy(S,2,Length(S)-1);
- end;
- procedure TPascalCodeGenerator.ClassHeader(const AClassName: String);
- begin
- AddLn('');
- AddLn('{ '+StringOfChar('-',68));
- AddLn(' '+AClassName);
- AddLn(' '+StringOfChar('-',68)+'}');
- AddLn('');
- end;
- end.
- end.
|