pascodegen.pp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. unit pascodegen;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils;
  6. Type
  7. TCodegenLogType = (cltInfo);
  8. TCodegenLogTypes = Set of TCodegenLogType;
  9. TCodeGeneratorLogEvent = Procedure (Sender : TObject; LogType : TCodegenLogType; Const Msg : String) of object;
  10. TCodesection = (csUnknown, csConst, csType, csVar, csResourcestring, csDeclaration);
  11. { TPascalCodeGenerator }
  12. TPascalCodeGenerator = Class(TComponent)
  13. Private
  14. FAddTimeStamp: Boolean;
  15. FExtraUnits: String;
  16. FKeywordPrefix: String;
  17. FKeywordSuffix: String;
  18. FLicenseText: TStrings;
  19. FOnLog: TCodeGeneratorLogEvent;
  20. FOutputUnitName: String;
  21. FSource : TStrings;
  22. Findent : String;
  23. FSections : Array of TCodeSection;
  24. FSectionCount : Integer;
  25. FSwitches: TStrings;
  26. function GetSection: TCodeSection;
  27. procedure SetLicenseText(AValue: TStrings);
  28. procedure SetSection(AValue: TCodeSection);
  29. procedure SetSwitches(AValue: TStrings);
  30. Protected
  31. // Source manipulation
  32. Procedure DoLog(Const Msg : String; AType : TCodegenLogType = cltInfo);
  33. Procedure DoLog(Const Fmt : String; Args : Array of const; AType : TCodegenLogType = cltInfo);
  34. Function BaseUnits : String; virtual;
  35. Public
  36. Public
  37. Constructor Create(AOwner : TComponent); override;
  38. Destructor Destroy; override;
  39. // Emit section type word
  40. Procedure EnsureSection(aSection : TCodeSection);
  41. Procedure PushSection(ASection : TCodeSection = csUnknown);
  42. Function PopSection : TCodeSection;
  43. Procedure CreateHeader; virtual;
  44. Procedure CreateUnitClause; virtual;
  45. Procedure Indent;
  46. Procedure Undent;
  47. Function IsKeyWord (Const S : String) : Boolean;
  48. Function EscapeKeyWord(Const S : String; ForceAmpersand : Boolean = false) : String;
  49. Function MakePascalString(S: String; AddQuotes: Boolean=False): String;
  50. Function PrettyPrint(Const S: string): String;
  51. Procedure AddLn(Const Aline: string);
  52. Procedure AddLn(Const Alines : array of string);
  53. Procedure AddLn(Const Alines : TStrings);
  54. Procedure AddLn(Const Fmt: string; Args : Array of const);
  55. Procedure Comment(Const AComment : String; Curly : Boolean = False);
  56. Procedure Comment(Const AComment : Array of String);
  57. Procedure Comment(Const AComment : TStrings);
  58. Procedure ClassHeader(Const AClassName: String); virtual;
  59. Procedure SimpleMethodBody(Lines: Array of string); virtual;
  60. Property Source : TStrings Read FSource;
  61. Property CurrentSection : TCodeSection Read GetSection Write SetSection;
  62. Published
  63. Property OutputUnitName : String Read FOutputUnitName Write FOutputUnitName;
  64. Property ExtraUnits : String Read FExtraUnits Write FExtraUnits;
  65. Property LicenseText : TStrings Read FLicenseText Write SetLicenseText;
  66. Property Switches : TStrings Read FSwitches Write SetSwitches;
  67. Property OnLog : TCodeGeneratorLogEvent Read FOnLog Write FOnlog;
  68. Property AddTimeStamp : Boolean Read FAddTimeStamp Write FAddTimeStamp;
  69. Property KeywordSuffix : String Read FKeywordSuffix Write FKeywordSuffix;
  70. Property KeywordPrefix : String Read FKeywordPrefix Write FKeywordPrefix;
  71. end;
  72. implementation
  73. { TPascalCodeGenerator }
  74. procedure TPascalCodeGenerator.Indent;
  75. begin
  76. FIndent:=FIndent+StringOfChar(' ',2);
  77. end;
  78. procedure TPascalCodeGenerator.Undent;
  79. Var
  80. L : Integer;
  81. begin
  82. L:=Length(Findent);
  83. if L>0 then
  84. FIndent:=Copy(FIndent,1,L-2)
  85. end;
  86. function TPascalCodeGenerator.IsKeyWord(const S: String): Boolean;
  87. Const
  88. KW=';absolute;and;array;asm;begin;case;const;constructor;destructor;div;do;'+
  89. 'downto;else;end;file;for;function;goto;if;implementation;in;inherited;'+
  90. 'inline;interface;label;mod;nil;not;object;of;on;operator;or;packed;'+
  91. 'procedure;program;record;reintroduce;repeat;self;set;shl;shr;string;then;'+
  92. 'to;type;unit;until;uses;var;while;with;xor;dispose;exit;false;new;true;'+
  93. 'as;class;dispinterface;except;exports;finalization;finally;initialization;'+
  94. 'inline;is;library;on;out;packed;property;raise;resourcestring;threadvar;try;'+
  95. 'private;published;length;setlength;';
  96. begin
  97. Result:=Pos(';'+lowercase(S)+';',KW)<>0;
  98. end;
  99. function TPascalCodeGenerator.EscapeKeyWord(const S: String; ForceAmpersand : Boolean = false): String;
  100. begin
  101. Result:=S;
  102. if IsKeyWord(S) then
  103. if ForceAmpersand then
  104. Result:='&'+Result
  105. else
  106. Result:=KeywordPrefix+Result+KeywordSuffix
  107. end;
  108. procedure TPascalCodeGenerator.AddLn(const Aline: string);
  109. begin
  110. FSource.Add(FIndent+ALine);
  111. end;
  112. procedure TPascalCodeGenerator.AddLn(const Alines: array of string);
  113. Var
  114. S : String;
  115. begin
  116. For s in alines do
  117. Addln(S);
  118. end;
  119. procedure TPascalCodeGenerator.AddLn(const Alines: TStrings);
  120. Var
  121. S : String;
  122. begin
  123. For s in alines do
  124. Addln(S);
  125. end;
  126. procedure TPascalCodeGenerator.AddLn(const Fmt: string; Args: array of const);
  127. begin
  128. AddLn(Format(Fmt,Args));
  129. end;
  130. procedure TPascalCodeGenerator.Comment(const AComment: String; Curly: Boolean);
  131. begin
  132. if Curly then
  133. AddLn('{ '+AComment+' }')
  134. else
  135. AddLn('// '+AComment);
  136. end;
  137. procedure TPascalCodeGenerator.Comment(const AComment: array of String);
  138. begin
  139. AddLn('{');
  140. Indent;
  141. AddLn(AComment);
  142. Undent;
  143. AddLn('}');
  144. end;
  145. procedure TPascalCodeGenerator.Comment(const AComment: TStrings);
  146. begin
  147. AddLn('{');
  148. Indent;
  149. AddLn(AComment);
  150. Undent;
  151. AddLn('}');
  152. end;
  153. constructor TPascalCodeGenerator.Create(AOwner: TComponent);
  154. begin
  155. inherited Create(AOwner);
  156. FSource:=TstringList.Create;
  157. FLicenseText:=TstringList.Create;
  158. FSwitches:=TstringList.Create;
  159. FSwitches.Add('MODE ObjFPC');
  160. FSwitches.Add('H+');
  161. SetLength(FSections,0);
  162. FSectionCount:=0;
  163. PushSection(csUnknown);
  164. FKeywordPrefix:='&';
  165. end;
  166. destructor TPascalCodeGenerator.Destroy;
  167. begin
  168. FreeAndNil(FSwitches);
  169. FreeAndNil(FLicenseText);
  170. FreeAndNil(FSource);
  171. inherited Destroy;
  172. end;
  173. procedure TPascalCodeGenerator.EnsureSection(aSection: TCodeSection);
  174. Const
  175. SectionKeyWords : Array[TCodesection] of string
  176. = ('', 'Const', 'Type', 'Var', 'Resourcestring', '');
  177. begin
  178. If CurrentSection<>aSection then
  179. begin
  180. CurrentSection:=aSection;
  181. AddLn(SectionKeyWords[CurrentSection]);
  182. end;
  183. end;
  184. procedure TPascalCodeGenerator.PushSection(ASection : TCodeSection = csUnknown);
  185. begin
  186. if FSectionCount=Length(FSections) then
  187. SetLength(FSections,FSectionCount+10);
  188. FSections[FSectionCount]:=ASection;
  189. Inc(FSectionCount);
  190. end;
  191. function TPascalCodeGenerator.PopSection: TCodeSection;
  192. begin
  193. if FSectionCount=0 then
  194. Result:=csUnknown
  195. else
  196. begin
  197. Dec(FSectionCount);
  198. Result:=FSections[FSectionCount];
  199. end;
  200. end;
  201. procedure TPascalCodeGenerator.SetSection(AValue: TCodeSection);
  202. begin
  203. if GetSection=AValue then
  204. Exit;
  205. FSections[FSectionCount-1]:=AValue;
  206. end;
  207. procedure TPascalCodeGenerator.SetSwitches(AValue: TStrings);
  208. begin
  209. if FSwitches=AValue then Exit;
  210. FSwitches.Assign(AValue);
  211. end;
  212. function TPascalCodeGenerator.GetSection: TCodeSection;
  213. begin
  214. Result:=FSections[FSectionCount-1];
  215. end;
  216. procedure TPascalCodeGenerator.SetLicenseText(AValue: TStrings);
  217. begin
  218. if FLicenseText=AValue then Exit;
  219. FLicenseText.Assign(AValue);
  220. end;
  221. procedure TPascalCodeGenerator.DoLog(const Msg: String; AType: TCodegenLogType);
  222. begin
  223. If Assigned(FOnLog) then
  224. FOnLog(Self,Atype,Msg);
  225. end;
  226. procedure TPascalCodeGenerator.DoLog(const Fmt: String; Args: array of const;
  227. AType: TCodegenLogType);
  228. begin
  229. DoLog(Format(Fmt,Args),AType);
  230. end;
  231. procedure TPascalCodeGenerator.CreateHeader;
  232. Var
  233. B,S : String;
  234. begin
  235. if LicenseText.Count>0 then
  236. Comment(LicenseText);
  237. if AddTimeStamp then
  238. Comment('Generated on: '+DateTimeToStr(Now));
  239. For S in Switches do
  240. addln('{$%s}',[S]);
  241. addln('');
  242. addln('interface');
  243. addln('');
  244. S:=ExtraUnits;
  245. B:=BaseUnits;
  246. if (B<>'') then
  247. if (S<>'') then
  248. begin
  249. if (B[Length(B)]<>',') then
  250. B:=B+',';
  251. S:=B+S;
  252. end
  253. else
  254. S:=B;
  255. addln('uses %s;',[S]);
  256. addln('');
  257. end;
  258. procedure TPascalCodeGenerator.CreateUnitClause;
  259. begin
  260. AddLn('Unit %s;',[OutputUnitName]);
  261. AddLn('');
  262. end;
  263. procedure TPascalCodeGenerator.SimpleMethodBody(Lines: array of string);
  264. Var
  265. S : String;
  266. begin
  267. AddLn('');
  268. AddLn('begin');
  269. Indent;
  270. For S in Lines do
  271. AddLn(S);
  272. Undent;
  273. AddLn('end;');
  274. AddLn('');
  275. end;
  276. function TPascalCodeGenerator.BaseUnits: String;
  277. begin
  278. Result:='';
  279. end;
  280. function TPascalCodeGenerator.MakePascalString(S: String; AddQuotes: Boolean
  281. ): String;
  282. begin
  283. Result:=StringReplace(S,'''','''''',[rfReplaceAll]);
  284. if AddQuotes then
  285. Result:=''''+Result+'''';
  286. end;
  287. function TPascalCodeGenerator.PrettyPrint(const S: string): String;
  288. begin
  289. If (S='') then
  290. Result:=''
  291. else
  292. Result:=Upcase(S[1])+Copy(S,2,Length(S)-1);
  293. end;
  294. procedure TPascalCodeGenerator.ClassHeader(const AClassName: String);
  295. begin
  296. AddLn('');
  297. AddLn('{ '+StringOfChar('-',68));
  298. AddLn(' '+AClassName);
  299. AddLn(' '+StringOfChar('-',68)+'}');
  300. AddLn('');
  301. end;
  302. end.
  303. end.