ptopu.pp 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255
  1. Unit PtoPu;
  2. {
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Michael Van Canneyt, member of
  5. the Free Pascal development team
  6. Pascal Pretty-Printer object implementation
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. {
  14. This unit is based heavily on the code by
  15. Author: Peter Grogono
  16. This program is based on a Pascal pretty-printer written by Ledgard,
  17. Hueras, and Singer. See SIGPLAN Notices, Vol. 12, No. 7, July 1977,
  18. pages 101-105, and PP.DOC/HLP.
  19. This version of PP developed under Pascal/Z V4.0 or later.
  20. Very minor modifications for Turbo Pascal made by Willett Kempton
  21. March 1984 and Oct 84. Runs under 8-bit Turbo or 16-bit Turbo.
  22. Toad Hall tweak, rewrite for TP 5, 28 Nov 89
  23. The following was changed :
  24. - Object oriented
  25. - Uses streams
  26. - Run-time customizable.
  27. }
  28. Interface
  29. Uses objects;
  30. Const
  31. MAXSYMBOLSIZE = 65500;
  32. MAXSHOWSIZE = 40;
  33. MAXSTACKSIZE = 100;
  34. MAXKEYLENGTH = 15; { The longest keywords are IMPLEMENTATION INITIALIZATION }
  35. MAXLINESIZE = 90; { Maximum length of output line }
  36. TYPE
  37. {Token = String[MAXSYMBOLSIZE];}
  38. Token = AnsiString;
  39. {XXX this is not used String0 = STRING[1];} {Pascal/z had 0}
  40. FileName = STRING;
  41. { Keysymbols }
  42. { If you add keysyms, adjust the definition of lastkey }
  43. keysymbol = { keywords }
  44. (endsym,beginsym,ifsym,thensym,elsesym,procsym,varsym,ofsym,
  45. whilesym,dosym,casesym,withsym,forsym,repeatsym,untilsym,
  46. funcsym,labelsym,constsym,typesym,recordsym,stringsym,progsym,
  47. { TP and Delphi keywords}
  48. asmsym, trysym, finallysym,exceptsym,raisesym,classsym,objectsym,
  49. constructorsym,destructorsym,inheritedsym,propertysym,
  50. privatesym,publicsym,protectedsym,publishedsym,
  51. initializationsym,finalizationsym,
  52. inlinesym,librarysym,interfacesym,implementationsym,
  53. readsym,writesym,unitsym,
  54. { Not used for formatting }
  55. andsym,arrsym,divsym,downsym,filesym,gotosym,insym,modsym,
  56. notsym,nilsym,orsym,setsym,tosym,virtualsym,usessym,
  57. casevarsym,
  58. { other symbols }
  59. becomes,delphicomment,dopencomment,dclosecomment,opencomment,closecomment,semicolon,colon,equals,
  60. openparen,closeparen,period,endoffile,othersym);
  61. { Formatting options }
  62. { If you add options, adjust the definition of lastopt }
  63. options = (crsupp,crbefore,blinbefore,
  64. dindonkey,dindent,spbef,
  65. spaft,gobsym,inbytab,crafter,upper,lower,capital);
  66. optionset = SET OF options;
  67. keysymset = SET OF keysymbol;
  68. tableentry = RECORD
  69. selected : optionset;
  70. dindsym : keysymset;
  71. terminators : keysymset
  72. END;
  73. { Character identification }
  74. charname = (letter,digit,space,quote,endofline,
  75. filemark,otherchar);
  76. charinfo = RECORD
  77. name : charname;
  78. Value : CHAR
  79. END;
  80. symbol = RECORD
  81. name : keysymbol;
  82. Value : Token;
  83. IsKeyWord : BOOLEAN;
  84. length, spacesbefore, crsbefore : INTEGER;
  85. END;
  86. symbolinfo = ^ symbol;
  87. stackentry = RECORD
  88. indentsymbol : keysymbol;
  89. prevmargin : INTEGER
  90. END;
  91. symbolstack = ARRAY [1..MAXSTACKSIZE] OF stackentry;
  92. Const FirstOpt = crsupp;
  93. LastOpt = capital; { Adjust this if you add options }
  94. FirstKey = endsym;
  95. LastKey = othersym; { Adjust this if you add options }
  96. LastFormatsym = usessym;
  97. Type
  98. tableptr = ^tableentry;
  99. optiontable = ARRAY [keysymbol] OF tableptr;
  100. OEntriesTable = Array [keysymbol] OF String[15];
  101. ONamesTable = Array [Options] of String[15];
  102. KeywordTable = ARRAY [endsym..lastFormatsym] OF String[MAXKEYLENGTH];
  103. SpecialChar = ARRAY [1..2] OF CHAR;
  104. dblcharset = SET OF endsym..othersym;
  105. DblCharTable = ARRAY [becomes..dclosecomment] OF SpecialChar;
  106. SglCharTable = ARRAY [opencomment..period] OF CHAR;
  107. TPrettyPrinter=Object(TObject)
  108. Private
  109. RecordSeen,
  110. CRPending : BOOLEAN;
  111. currchar,nextchar : charinfo;
  112. currsym,nextsym : symbolinfo;
  113. inlines,outlines : INTEGER;
  114. stack : symbolstack;
  115. top,startpos,currlinepos,currmargin : Integer;
  116. option : OptionTable;
  117. Procedure Verbose (Const Msg : String);
  118. Procedure GetChar;
  119. Procedure StoreNextChar(VAR lngth: INTEGER;
  120. VAR Value: Token);
  121. Procedure SkipBlanks(VAR spacesbefore, crsbefore: INTEGER);
  122. Procedure GetComment(sym: symbolinfo);
  123. Procedure GetDoubleComment(sym: symbolinfo);
  124. Procedure GetDelphiComment(sym: symbolinfo);
  125. Procedure GetNumber(sym: symbolinfo);
  126. Procedure GetCharLiteral(sym: symbolinfo);
  127. Function char_Type: keysymbol;
  128. Procedure GetSpecialChar(sym: symbolinfo);
  129. Procedure GetNextSymbol(sym: symbolinfo);
  130. Procedure GetIdentifier(sym: symbolinfo);
  131. Procedure GetSymbol;
  132. Procedure PopStack(VAR indentsymbol: keysymbol;
  133. VAR prevmargin: INTEGER);
  134. Procedure PushStack(indentsymbol: keysymbol;
  135. prevmargin: INTEGER );
  136. Procedure WriteCRs(numberofcrs: INTEGER);
  137. Procedure InsertCR;
  138. Procedure InsertBlankLine;
  139. Procedure LShiftOn(dindsym: keysymset);
  140. Procedure LShift;
  141. Procedure InsertSpace(VAR symbol: symbolinfo);
  142. Procedure MoveLinePos(newlinepos: INTEGER);
  143. Procedure PrintSymbol;
  144. Procedure PPSymbol;
  145. Procedure Gobble(terminators: keysymset);
  146. Procedure RShift(currmsym: keysymbol);
  147. Function ReadConfigFile: Boolean;
  148. Public
  149. LineSize : longint;
  150. Indent : Integer; { How many characters to indent ? }
  151. InS,
  152. OutS,
  153. DiagS,cfgS : PStream;
  154. Constructor Create;
  155. Function PrettyPrint : Boolean;
  156. end;
  157. Procedure GenerateCfgFile(S: PStream);
  158. Implementation
  159. CONST
  160. version = '20 February 2005'; {was '11 October 1984','28 November 1989'; ..ancient stuff!}
  161. NUL = 0; { ASCII null character }
  162. TAB = 9; { ASCII tab character }
  163. FF = 12; { ASCII formfeed character }
  164. CR = 13; { ASCII carriage return }
  165. ESC = 27; { ASCII escape character }
  166. Blank = ' ';
  167. MAXBYTE = 255;{ Largest value of 1 byte variable }
  168. Type
  169. hashentry = RECORD
  170. Keyword : String[MAXKEYLENGTH];
  171. symtype : keysymbol
  172. END;
  173. VAR
  174. sets : tableptr;
  175. dblch : dblcharset;
  176. hashtable : ARRAY [Byte] OF hashentry;
  177. CONST
  178. Keyword : KeywordTable =
  179. ('END', 'BEGIN', 'IF', 'THEN',
  180. 'ELSE', 'PROCEDURE', 'VAR', 'OF',
  181. 'WHILE', 'DO', 'CASE', 'WITH',
  182. 'FOR', 'REPEAT', 'UNTIL', 'FUNCTION',
  183. 'LABEL', 'CONST', 'TYPE', 'RECORD',
  184. 'STRING', 'PROGRAM',
  185. 'ASM','TRY','FINALLY','EXCEPT','RAISE','CLASS','OBJECT',
  186. 'CONSTRUCTOR','DESCTRUCTOR','INHERITED','PROPERTY',
  187. 'PRIVATE','PUBLIC','PROTECTED','PUBLISHED',
  188. 'INITIALIZATION','FINALIZATION',
  189. 'INLINE','LIBRARY','INTERFACE','IMPLEMENTATION',
  190. 'READ','WRITE','UNIT',
  191. {keywords not used for formatting }
  192. 'AND', 'ARRAY', 'DIV', 'DOWNTO',
  193. 'FILE', 'GOTO', 'IN', 'MOD',
  194. 'NOT', 'NIL', 'OR', 'SET','TO','VIRTUAL','USES'
  195. );
  196. EntryNames : OEntriesTable =
  197. ('end','begin','if','then','else','proc','var',
  198. 'of','while','do','case','with','for','repeat','until',
  199. 'func','label','const','type','record','string',
  200. 'prog',
  201. 'asm','try','finally','except','raise','class','object',
  202. 'constructor','destructor','inherited','property',
  203. 'private','public','protected','published',
  204. 'initialization','finalization',
  205. 'inline','library','interface','implementation',
  206. 'read','write','unit',
  207. 'and','arr','div','down','file','goto',
  208. 'in','mod','not','nil','or','set','to','virtual','uses',
  209. 'casevar',
  210. 'becomes','delphicomment','dopencomment','dclosecomment',
  211. 'opencomment','closecomment','semicolon',
  212. 'colon','equals',
  213. 'openparen','closeparen','period','endoffile','other');
  214. OptionNames : ONamesTable =
  215. ('crsupp','crbefore','blinbefore',
  216. 'dindonkey','dindent','spbef','spaft',
  217. 'gobsym','inbytab','crafter','upper',
  218. 'lower','capital');
  219. DblChar : DblCharTable =
  220. ( ':=', '//','(*','*)' );
  221. SglChar : SglCharTable =
  222. ('{', '}', ';', ':', '=', '(', ')', '.' );
  223. { ---------------------------------------------------------------------
  224. General functions, not part of the object.
  225. ---------------------------------------------------------------------}
  226. function upperStr(const s : string) : string;
  227. var
  228. i : longint;
  229. begin
  230. setLength(upperStr,length(s));
  231. for i:=1 to length(s) do
  232. if s[i] in ['a'..'z'] then
  233. upperStr[i]:=char(byte(s[i])-32)
  234. else
  235. upperStr[i]:=s[i];
  236. end;
  237. function LowerStr(const s : string) : string;
  238. var
  239. i : longint;
  240. begin
  241. setLength(LowerStr,length(s));
  242. for i:=1 to length(s) do
  243. if s[i] in ['A'..'Z'] then
  244. LowerStr[i]:=char(byte(s[i])+32)
  245. else
  246. LowerStr[i]:=s[i];
  247. end;
  248. Function IntToStr(I : LongInt) : String;
  249. var
  250. s : string;
  251. begin
  252. str(I,s);
  253. IntToStr := s;
  254. end;
  255. Function StrToInt(Const S : String) : Integer;
  256. Var Code : integer;
  257. Res : Integer;
  258. begin
  259. Val(S, Res, Code);
  260. StrToInt := Res;
  261. If Code<>0 then StrToInt:=0;
  262. end;
  263. Procedure Strip (Var S : String);
  264. Const WhiteSpace = [#32,#9,#10,#13];
  265. Var I,J : Longint;
  266. begin
  267. If length(s)=0 then exit;
  268. I:=1;
  269. While (S[I] in whitespace) and (I<Length(S)) do inc(i);
  270. J:=length(S);
  271. While (S[J] in whitespace) and (J>1) do dec(j);
  272. If I<=J then
  273. S:=Copy(S,i,j-i+1)
  274. else
  275. S:='';
  276. end;
  277. { ---------------------------------------------------------------------
  278. Hash table related functions
  279. ---------------------------------------------------------------------}
  280. Function hash(Symbol: String): Byte;
  281. { Hashing function for identifiers. The formula gives a unique value
  282. in the range 0..255 for each Pascal/Z keyword. Note that range and
  283. overflow checking must be turned off for this function even if they
  284. are enabled for the rest of the program. }
  285. BEGIN
  286. {$R-}
  287. hash := (ORD(Symbol[1]) * 5 + ORD(Symbol[length(Symbol)])) * 5 + length(Symbol);
  288. {$R+}
  289. END; { of hash }
  290. Procedure CreateHash;
  291. Var psn : Byte;
  292. sym : keysymbol;
  293. begin
  294. FOR psn := 0 TO MAXBYTE DO BEGIN
  295. hashtable[psn].Keyword := ' ';
  296. hashtable[psn].symtype := othersym
  297. END;
  298. FOR sym := endsym TO lastformatsym DO BEGIN
  299. psn := hash(Keyword[sym]);
  300. hashtable[psn].Keyword := Keyword[sym];
  301. hashtable[psn].symtype := sym
  302. END; { for }
  303. end;
  304. Procedure ClassID(Value: Token;
  305. lngth: INTEGER;
  306. VAR idtype: keysymbol;
  307. VAR IsKeyWord: BOOLEAN);
  308. { Classify an identifier. We are only interested
  309. in it if it is a keyword, so we use the hash table. }
  310. VAR
  311. Keyvalue: String[MAXKEYLENGTH];
  312. tabent: INTEGER;
  313. BEGIN
  314. IF lngth > MAXKEYLENGTH THEN BEGIN
  315. idtype := othersym;
  316. IsKeyWord := FALSE
  317. END
  318. ELSE BEGIN
  319. KeyValue:= UpperStr(Value);
  320. tabent := hash(Keyvalue);
  321. IF Keyvalue = hashtable[tabent].Keyword THEN BEGIN
  322. idtype := hashtable[tabent].symtype;
  323. IsKeyWord := TRUE;
  324. END
  325. ELSE BEGIN
  326. idtype := othersym;
  327. IsKeyWord := FALSE;
  328. END
  329. END
  330. END; { of ClassID }
  331. { ---------------------------------------------------------------------
  332. Functions to create options and set defaults.
  333. ---------------------------------------------------------------------}
  334. Procedure CreateOptions (Var Option : OptionTable);
  335. Var Sym : KeySymbol;
  336. begin
  337. FOR sym := endsym TO othersym DO BEGIN
  338. NEW(option[sym]);
  339. option[sym]^.selected := [];
  340. option[sym]^.dindsym := [];
  341. option[sym]^.terminators := []
  342. END;
  343. end;
  344. Procedure SetTerminators(Var Option : OptionTable);
  345. begin
  346. option[casesym]^.terminators := [ofsym];
  347. option[casevarsym]^.terminators := [ofsym];
  348. option[forsym]^.terminators := [dosym];
  349. option[whilesym]^.terminators := [dosym];
  350. option[withsym]^.terminators := [dosym];
  351. option[ifsym]^.terminators := [thensym];
  352. option[untilsym]^.terminators := [endsym, untilsym, elsesym, semicolon];
  353. option[becomes]^.terminators := [endsym, untilsym, elsesym, semicolon];
  354. option[openparen]^.terminators := [closeparen];
  355. option[usessym]^.terminators := [semicolon];
  356. end;
  357. Procedure SetDefaultIndents (Var Option : OptionTable);
  358. begin
  359. option[recordsym]^.dindsym := [endsym];
  360. option[funcsym]^.dindsym := [labelsym, constsym, typesym, varsym];
  361. option[procsym]^.dindsym := [labelsym, constsym, typesym, varsym];
  362. option[constsym]^.dindsym := [labelsym, constsym, typesym, varsym];
  363. option[typesym]^.dindsym := [labelsym, constsym, typesym, varsym];
  364. option[varsym]^.dindsym := [labelsym, constsym, typesym, varsym];
  365. option[beginsym]^.dindsym := [labelsym, constsym, typesym, varsym];
  366. option[publicsym]^.dindsym := [protectedsym,privatesym,publicsym,publishedsym];
  367. option[privatesym]^.dindsym := [protectedsym,privatesym,publicsym,publishedsym];
  368. option[protectedsym]^.dindsym := [protectedsym,privatesym,publicsym,publishedsym];
  369. option[publishedsym]^.dindsym := [protectedsym,privatesym,publicsym,publishedsym];
  370. option[finallysym]^.dindsym := [trysym];
  371. option[exceptsym]^.dindsym := [trysym];
  372. option[elsesym]^.dindsym := [ifsym, thensym, elsesym];
  373. option[untilsym]^.dindsym := [ifsym, thensym, elsesym, forsym, whilesym,
  374. withsym, colon, equals];
  375. option[endsym]^.dindsym := [ifsym, thensym, elsesym, forsym, whilesym,
  376. withsym, casevarsym, colon, equals, recordsym,
  377. classsym,objectsym];
  378. option[semicolon]^.dindsym := [ifsym, thensym, elsesym, forsym,
  379. whilesym, withsym, colon, equals];
  380. end;
  381. Procedure SetDefaults (Var Option : OptionTable);
  382. { Sets default values for the formatting rules. }
  383. begin
  384. option[progsym]^.selected := [capital,blinbefore, spaft];
  385. option[unitsym]^.selected := [capital,blinbefore, spaft];
  386. option[librarysym]^.selected := [capital,blinbefore, spaft];
  387. option[funcsym]^.selected := [capital,blinbefore, dindonkey, spaft];
  388. option[procsym]^.selected := [capital,blinbefore, dindonkey, spaft];
  389. option[labelsym]^.selected := [capital,blinbefore, spaft, inbytab];
  390. option[constsym]^.selected := [capital,blinbefore, dindonkey, spaft, inbytab];
  391. option[typesym]^.selected := [capital,blinbefore, dindonkey, spaft, inbytab];
  392. option[varsym]^.selected := [capital,blinbefore, dindonkey, spaft, inbytab];
  393. option[beginsym]^.selected := [capital,dindonkey, crbefore, crafter, inbytab];
  394. option[repeatsym]^.selected := [capital,inbytab, crafter];
  395. option[recordsym]^.selected := [capital,inbytab, crafter];
  396. option[objectsym]^.selected := [capital,inbytab, crafter];
  397. option[classsym]^.selected := [capital,inbytab, crafter];
  398. option[publicsym]^.selected := [capital,crbefore, dindonkey, spaft, inbytab];
  399. option[publishedsym]^.selected := [capital,crbefore, dindonkey, spaft, inbytab];
  400. option[protectedsym]^.selected := [capital,crbefore, dindonkey, spaft, inbytab];
  401. option[privatesym]^.selected := [capital,crbefore, dindonkey, spaft, inbytab];
  402. option[trysym]^.Selected := [capital,crbefore,crafter,inbytab];
  403. option[finallysym]^.selected := [capital,crbefore,dindonkey,crafter,inbytab];
  404. option[exceptsym]^.selected := [capital,crbefore,dindonkey,crafter,inbytab];
  405. option[casesym]^.selected := [capital,spaft, inbytab, gobsym, crafter];
  406. option[casevarsym]^.selected := [capital,spaft, inbytab, gobsym, crafter];
  407. option[ofsym]^.selected := [capital,crsupp, spbef];
  408. option[forsym]^.selected := [capital,spaft, inbytab, gobsym, crafter];
  409. option[whilesym]^.selected := [capital,spaft, inbytab, gobsym, crafter];
  410. option[withsym]^.selected := [capital,spaft, inbytab, gobsym, crafter];
  411. option[dosym]^.selected := [capital,crsupp, spbef];
  412. option[ifsym]^.selected := [capital,spaft, inbytab, gobsym];
  413. option[thensym]^.selected := [capital];
  414. option[elsesym]^.selected := [capital,crbefore, dindonkey, inbytab];
  415. option[endsym]^.selected := [capital,crbefore, crafter,dindonkey,dindent];
  416. option[untilsym]^.selected := [capital,crbefore, dindonkey, dindent, spaft,
  417. gobsym, crafter];
  418. option[becomes]^.selected := [capital,spbef, spaft, gobsym];
  419. option[Delphicomment]^.Selected := [crafter];
  420. option[opencomment]^.selected := [capital,crsupp];
  421. option[closecomment]^.selected := [capital,crsupp];
  422. option[semicolon]^.selected := [capital,crsupp, dindonkey, crafter];
  423. option[colon]^.selected := [capital,inbytab];
  424. option[equals]^.selected := [capital,spbef, spaft, inbytab];
  425. option[openparen]^.selected := [capital,gobsym];
  426. option[period]^.selected := [capital,crsupp];
  427. end;
  428. { ---------------------------------------------------------------------
  429. Stream handling routines
  430. ---------------------------------------------------------------------}
  431. Function ReadChar (S : PStream) : Char;
  432. Var C : Char;
  433. begin
  434. repeat
  435. if S^.GetPos = S^.GetSize then
  436. C:=#0
  437. else
  438. S^.Read(C,1);
  439. Until C<>#13;
  440. ReadChar:=C;
  441. end;
  442. Function EoSLn (S : PStream) : Char;
  443. Const WhiteSpace = [' ', #9, #13 ];
  444. Var C : Char;
  445. begin
  446. Repeat
  447. if S^.GetPos = S^.GetSize then
  448. C:=#0
  449. else
  450. S^.Read(C,1);
  451. Until (Not (C in WhiteSpace)) or ((C=#10));
  452. EoSln:=C;
  453. end;
  454. Function ReadString (S: PStream): String;
  455. Var Buffer : String;
  456. I : Byte;
  457. begin
  458. Buffer:='';
  459. I:=0;
  460. Repeat
  461. S^.Read(Buffer[I+1],1);
  462. Inc(I);
  463. until (I=255) or (Buffer[I]=#10) Or (S^.Status=StReadError);
  464. If S^.Status=stReadError then Dec(I);
  465. If Buffer[i]=#10 Then Dec(I);
  466. If Buffer[I]=#13 then Dec(I);
  467. Buffer[0] := chr(I);
  468. ReadString:=Buffer;
  469. end;
  470. Procedure WriteString (S : PStream; ST : String);
  471. begin
  472. S^.Write(St[1],length(St));
  473. end;
  474. Procedure WriteAnsiString (S : PStream; ST : AnsiString);
  475. begin
  476. S^.Write(St[1],length(St));
  477. end;
  478. Procedure WriteCR (S: PStream);
  479. Const
  480. Newline = System.LineEnding;
  481. begin
  482. WriteString(S,Newline);
  483. end;
  484. Procedure WriteLnString (S : PStream; ST : String);
  485. begin
  486. WriteString(S,ST);
  487. WriteCR(S);
  488. end;
  489. { ---------------------------------------------------------------------
  490. TPrettyPrinter object
  491. ---------------------------------------------------------------------}
  492. Procedure TPrettyPrinter.Verbose (Const Msg : String);
  493. begin
  494. If Assigned (DiagS) then
  495. WriteLnString (DiagS,Msg);
  496. end;
  497. Procedure TPrettyPrinter.GetChar;
  498. { Read the next character and classify it }
  499. VAR Ch: CHAR;
  500. BEGIN
  501. currchar := nextchar;
  502. WITH nextchar DO
  503. begin
  504. Ch:=ReadCHar(Ins);
  505. If Ch=#0 then
  506. BEGIN
  507. name := filemark;
  508. Value := Blank
  509. END
  510. ELSE If (Ch=#10) THEN
  511. BEGIN
  512. name := endofline;
  513. Value := Ch;
  514. Inc(inlines);
  515. END
  516. ELSE
  517. BEGIN
  518. Value := Ch;
  519. IF Ch IN ['a'..'z', 'A'..'Z', '_'] THEN name := letter
  520. ELSE IF Ch IN ['0'..'9'] THEN name := digit
  521. ELSE IF Ch = '''' THEN name := quote
  522. ELSE IF Ch in [#13,' ',#9] THEN name := space
  523. ELSE name := otherchar
  524. END
  525. end;
  526. END; { of GetChar }
  527. Procedure TPrettyPrinter.StoreNextChar(VAR lngth: INTEGER;
  528. VAR Value: Token);
  529. { Store a character in the current symbol }
  530. BEGIN
  531. GetChar;
  532. IF lngth < MAXSYMBOLSIZE THEN BEGIN {XXX - should there be a limit at all?}
  533. Inc(lngth);
  534. setlength(Value,lngth);
  535. Value[lngth] := currchar.Value;
  536. END;
  537. END; { of StoreNextChar }
  538. Procedure TPrettyPrinter.SkipBlanks(VAR spacesbefore, crsbefore: INTEGER);
  539. { Count the spaces between symbols }
  540. BEGIN
  541. spacesbefore := 0;
  542. crsbefore := 0;
  543. WHILE nextchar.name IN [space, endofline] DO BEGIN
  544. GetChar;
  545. CASE currchar.name OF
  546. space: Inc(spacesbefore);
  547. endofline: BEGIN
  548. Inc(crsbefore);
  549. spacesbefore := 0;
  550. END;
  551. END; {case}
  552. END;
  553. END; { of SkipBlanks }
  554. Procedure TPrettyPrinter.GetComment(sym: symbolinfo);
  555. { Process comments using brace notation }
  556. BEGIN
  557. sym^.name := opencomment;
  558. WHILE NOT ((currchar.Value = '}')
  559. OR (nextchar.name = filemark)) DO
  560. StoreNextChar(sym^.length, sym^.Value);
  561. IF currchar.Value = '}' THEN sym^.name := closecomment;
  562. END; { of GetCommment }
  563. Procedure TPrettyPrinter.GetDoubleComment(sym: symbolinfo);
  564. { Process comments using parenthesis notation }
  565. BEGIN
  566. sym^.name := dopencomment;
  567. WHILE NOT (((currchar.Value = '*') AND (nextchar.Value = ')'))
  568. OR (nextchar.name = filemark)) DO
  569. StoreNextChar(sym^.length, sym^.Value);
  570. IF (currchar.Value = '*') AND (nextchar.Value = ')') THEN BEGIN
  571. StoreNextChar(sym^.length, sym^.Value);
  572. sym^.name := dclosecomment;
  573. END;
  574. END; { of GetDoubleCommment }
  575. Procedure TPrettyPrinter.GetDelphiComment(sym: symbolinfo);
  576. { Process comments using either brace or parenthesis notation }
  577. BEGIN
  578. sym^.name := Delphicomment;
  579. WHILE NOT ((nextchar.name = endofline) OR (nextchar.name = filemark)) DO
  580. StoreNextChar(sym^.length, sym^.Value);
  581. END; { of GetDelphiCommment }
  582. Procedure TPrettyPrinter.GetIdentifier(sym: symbolinfo);
  583. { Read an identifier and classify it }
  584. BEGIN
  585. WHILE nextchar.name IN [letter, digit] DO
  586. StoreNextChar(sym^.length, sym^.Value);
  587. ClassID(sym^.Value, sym^.length, sym^.name, sym^.IsKeyWord);
  588. IF sym^.name IN [recordsym, casesym, endsym] THEN
  589. CASE sym^.name OF
  590. recordsym : RecordSeen := TRUE;
  591. casesym : IF RecordSeen THEN sym^.name := casevarsym;
  592. endsym : RecordSeen := FALSE;
  593. END; {case}
  594. END; { of GetIdentifier }
  595. { Read a number and store it as a string }
  596. Procedure TPrettyPrinter.GetNumber(sym: symbolinfo);
  597. BEGIN
  598. WHILE nextchar.name = digit DO StoreNextChar(sym^.length, sym^.Value);
  599. sym^.name := othersym;
  600. END; { of GetNumber }
  601. PROCEDURE TPrettyPrinter.GetCharLiteral(sym: symbolinfo);
  602. { Read a quoted string }
  603. BEGIN
  604. WHILE nextchar.name = quote DO BEGIN
  605. StoreNextChar(sym^.length, sym^.Value);
  606. WHILE NOT (nextchar.name IN [quote, endofline, filemark]) DO
  607. StoreNextChar(sym^.length, sym^.Value);
  608. IF nextchar.name = quote THEN StoreNextChar(sym^.length, sym^.Value);
  609. END;
  610. sym^.name := othersym;
  611. END; { of GetCharLiteral }
  612. FUNCTION TPrettyPrinter.char_Type: keysymbol;
  613. { Classify a character pair }
  614. VAR
  615. NextTwoChars: SpecialChar;
  616. Hit: BOOLEAN;
  617. thischar: keysymbol;
  618. BEGIN
  619. NextTwoChars[1] := currchar.Value;
  620. NextTwoChars[2] := nextchar.Value;
  621. thischar := becomes;
  622. Hit := FALSE;
  623. WHILE NOT (Hit OR (thischar = opencomment)) DO BEGIN
  624. IF NextTwoChars = DblChar[thischar] THEN Hit := TRUE
  625. ELSE Inc(thischar);
  626. END;
  627. IF NOT Hit THEN BEGIN
  628. thischar := opencomment;
  629. WHILE NOT (Hit OR (PRED(thischar) = period)) DO BEGIN
  630. IF currchar.Value = SglChar[thischar] THEN Hit := TRUE
  631. ELSE Inc(thischar);
  632. END;
  633. END;
  634. IF Hit THEN char_Type := thischar
  635. ELSE char_Type := othersym;
  636. END; { of char_Type }
  637. Procedure TPrettyPrinter.GetSpecialChar(sym: symbolinfo);
  638. { Read special characters }
  639. BEGIN
  640. StoreNextChar(sym^.length, sym^.Value);
  641. sym^.name := char_Type;
  642. IF sym^.name IN dblch THEN StoreNextChar(sym^.length, sym^.Value)
  643. END; { of GetSpecialChar }
  644. Procedure TPrettyPrinter.GetNextSymbol(sym: symbolinfo);
  645. { Read a symbol using the appropriate procedure }
  646. BEGIN
  647. CASE nextchar.name OF
  648. letter: GetIdentifier(sym);
  649. digit: GetNumber(sym);
  650. quote: GetCharLiteral(sym);
  651. otherchar: BEGIN
  652. GetSpecialChar(sym);
  653. IF sym^.name = opencomment THEN GetComment(sym)
  654. else IF sym^.name = dopencomment THEN GetDoubleComment(sym)
  655. else IF sym^.name= DelphiComment then GetDelphiComment(Sym)
  656. END;
  657. filemark: sym^.name := endoffile;
  658. ELSE {:} {Turbo}
  659. WRITELN('Unknown character type: ', ORD(nextchar.name));
  660. END; {case}
  661. END; { of GetNextSymbol }
  662. Procedure TprettyPrinter.GetSymbol;
  663. { Store the next symbol in NEXTSYM }
  664. VAR
  665. dummy: symbolinfo;
  666. BEGIN
  667. dummy := currsym;
  668. currsym := nextsym;
  669. nextsym := dummy;
  670. SkipBlanks(nextsym^.spacesbefore, nextsym^.crsbefore);
  671. nextsym^.length := 0;
  672. nextsym^.IsKeyWord := FALSE;
  673. IF currsym^.name = opencomment THEN GetComment(nextsym)
  674. ELSE IF currsym^.name = dopencomment THEN GetDoubleComment(nextsym)
  675. ELSE GetNextSymbol(nextsym);
  676. END; {of GetSymbol}
  677. Procedure TprettyPrinter.PopStack(VAR indentsymbol: keysymbol;
  678. VAR prevmargin: INTEGER);
  679. { Manage stack of indentation symbols and margins }
  680. BEGIN
  681. IF top > 0 THEN BEGIN
  682. indentsymbol := stack[top].indentsymbol;
  683. prevmargin := stack[top].prevmargin;
  684. Dec(top);
  685. END
  686. ELSE BEGIN
  687. indentsymbol := othersym;
  688. prevmargin := 0;
  689. END;
  690. END; { of PopStack }
  691. Procedure TPrettyPrinter.PushStack(indentsymbol: keysymbol;
  692. prevmargin: INTEGER );
  693. BEGIN
  694. Inc(top);
  695. stack[top].indentsymbol := indentsymbol;
  696. stack[top].prevmargin := prevmargin;
  697. END; { of PushStack }
  698. Procedure TPrettyPrinter.WriteCRs(numberofcrs: INTEGER);
  699. VAR
  700. i: INTEGER;
  701. BEGIN
  702. IF numberofcrs > 0 THEN BEGIN
  703. FOR i := 1 TO numberofcrs DO
  704. WriteCr(OutS);
  705. Inc(outlines,numberofcrs);
  706. currlinepos := 0;
  707. END;
  708. END; { of WriteCRs }
  709. Procedure TPrettyPrinter.InsertCR;
  710. BEGIN
  711. IF currsym^.crsbefore = 0 THEN BEGIN
  712. WriteCRs(1);
  713. currsym^.spacesbefore := 0;
  714. END;
  715. END; { of InsertCR }
  716. Procedure TPrettyPrinter.InsertBlankLine;
  717. BEGIN
  718. IF currsym^.crsbefore = 0 THEN BEGIN
  719. IF currlinepos = 0 THEN WriteCRs(1)
  720. ELSE WriteCRs(2);
  721. currsym^.spacesbefore := 0;
  722. END
  723. ELSE IF currsym^.crsbefore = 1 THEN
  724. IF currlinepos > 0 THEN WriteCRs(1);
  725. END; { of InsertBlankLine }
  726. Procedure TPrettyPrinter.LShiftOn(dindsym: keysymset);
  727. { Move margin left according to stack configuration and current symbol }
  728. VAR
  729. indentsymbol: keysymbol;
  730. prevmargin: INTEGER;
  731. BEGIN
  732. IF top > 0 THEN BEGIN
  733. REPEAT
  734. PopStack(indentsymbol, prevmargin);
  735. IF indentsymbol IN dindsym THEN currmargin := prevmargin;
  736. UNTIL NOT (indentsymbol IN dindsym) OR (top = 0);
  737. IF NOT (indentsymbol IN dindsym) THEN
  738. PushStack(indentsymbol, prevmargin);
  739. END;
  740. END; { of LShiftOn }
  741. Procedure TprettyPrinter.LShift;
  742. { Move margin left according to stack top }
  743. VAR
  744. indentsymbol: keysymbol;
  745. prevmargin: INTEGER;
  746. BEGIN
  747. IF top > 0 THEN BEGIN
  748. PopStack(indentsymbol, prevmargin);
  749. currmargin := prevmargin;
  750. (* maybe PopStack(indentsymbol,currmargin); *)
  751. END;
  752. END; { of LShift }
  753. Procedure TPrettyPrinter.InsertSpace(VAR symbol: symbolinfo);
  754. { Insert space if room on line }
  755. BEGIN
  756. IF currlinepos < LineSize THEN BEGIN
  757. WriteString(OutS, Blank);
  758. Inc(currlinepos);
  759. IF (symbol^.crsbefore = 0) AND (symbol^.spacesbefore > 0)
  760. THEN Dec(symbol^.spacesbefore);
  761. END;
  762. END; { of InsertSpace }
  763. Procedure TPrettyPrinter.MoveLinePos(newlinepos: INTEGER);
  764. { Insert spaces until correct line position reached }
  765. VAR i: INTEGER;
  766. BEGIN
  767. FOR i := SUCC(currlinepos) TO newlinepos DO
  768. WriteString(OutS, Blank);
  769. currlinepos := newlinepos;
  770. END; { of MoveLinePos }
  771. Procedure TPrettyPrinter.PrintSymbol;
  772. BEGIN
  773. IF (currsym^.IsKeyWord) then
  774. begin
  775. If upper in sets^.selected Then
  776. WriteString (OutS,UpperStr(currsym^.value))
  777. else if lower in sets^.selected then
  778. WriteString (OutS,LowerStr(currsym^.value))
  779. else if capital in sets^.selected then
  780. begin
  781. WriteString(OutS,UpCase(CurrSym^.Value[1]));
  782. WriteString(OutS,LowerStr(Copy(CurrSym^.Value,2,MAXSYMBOLSIZE)));{XXX - ?should it be length?}
  783. end
  784. else
  785. WriteString(OutS,Currsym^.Value);
  786. end
  787. ELSE
  788. WriteAnsiString(OutS, currsym^.Value);
  789. startpos := currlinepos;
  790. Inc(currlinepos,currsym^.length);
  791. END; { of PrintSymbol }
  792. Procedure TPrettyPrinter.PPSymbol;
  793. { Find position for symbol and then print it }
  794. VAR newlinepos: INTEGER;
  795. BEGIN
  796. WriteCRs(currsym^.crsbefore);
  797. IF (currlinepos + currsym^.spacesbefore > currmargin)
  798. OR (currsym^.name IN [opencomment, closecomment,dopencomment, dclosecomment])
  799. THEN newlinepos := currlinepos + currsym^.spacesbefore
  800. ELSE newlinepos := currmargin;
  801. IF newlinepos + currsym^.length > LINESIZE THEN BEGIN {XXX - this needs to be cleaned for case of long symbol values}
  802. WriteCRs(1);
  803. IF currmargin + currsym^.length <= LINESIZE
  804. THEN newlinepos := currmargin
  805. ELSE IF currsym^.length < LINESIZE
  806. THEN newlinepos := LINESIZE - currsym^.length
  807. ELSE newlinepos := 0;
  808. END;
  809. MoveLinePos(newlinepos);
  810. PrintSymbol;
  811. END; { of PPSymbol }
  812. Procedure TPrettyPrinter.Gobble(terminators: keysymset);
  813. { Print symbols which follow a formatting symbol but which do not
  814. affect layout }
  815. BEGIN
  816. IF top < MAXSTACKSIZE THEN PushStack(currsym^.name, currmargin);
  817. currmargin := currlinepos;
  818. WHILE NOT ((nextsym^.name IN terminators)
  819. OR (nextsym^.name = endoffile)) DO BEGIN
  820. GetSymbol;
  821. PPSymbol;
  822. END;
  823. LShift;
  824. END; { of Gobble }
  825. Procedure TprettyPrinter.RShift(currmsym: keysymbol);
  826. { Move right, stacking margin positions }
  827. BEGIN
  828. IF top < MAXSTACKSIZE THEN PushStack(currmsym, currmargin);
  829. IF startpos > currmargin THEN currmargin := startpos;
  830. Inc(currmargin,INDENT);
  831. END; { of RShift }
  832. Function TPrettyPrinter.ReadConfigFile : Boolean;
  833. Var I,J : Longint;
  834. Procedure SetOption(TheKey : KeySymbol;Var OptionList : String);
  835. Var TheOpt : Options;
  836. Found : Boolean;
  837. K : longint;
  838. opt : string;
  839. begin
  840. Repeat
  841. K:=pos(',',optionlist);
  842. If k>0 then
  843. begin
  844. opt:=Copy(OptionList,1,k-1);
  845. strip(opt);
  846. Delete(OptionList,1,k);
  847. end
  848. else
  849. opt:=OptionList;
  850. If Length(Opt)>0 then
  851. begin
  852. Found:=False;
  853. for TheOpt :=firstopt to lastopt do
  854. begin
  855. found:=opt=OptionNames[Theopt];
  856. If found then break;
  857. end;
  858. If not found then
  859. Verbose ('Unknown option on line '+inttostr(i)+': '+Opt)
  860. else
  861. Option[TheKey]^.Selected:=Option[TheKey]^.Selected+[TheOpt];
  862. end;
  863. until k=0;
  864. end;
  865. Procedure SetIndent(TheKey : KeySymbol; Var OptionList : String);
  866. Var
  867. TheIndent : Keysymbol;
  868. Found : Boolean;
  869. K : longint;
  870. opt : string;
  871. begin
  872. Repeat
  873. K:=pos(',',optionlist);
  874. If k>0 then
  875. begin
  876. opt:=Copy(OptionList,1,k-1);
  877. strip(opt);
  878. Delete(OptionList,1,k);
  879. end
  880. else
  881. opt:=OptionList;
  882. If Length(Opt)>0 then
  883. begin
  884. Found:=False;
  885. for TheIndent :=firstKey to lastKey do
  886. begin
  887. found:=opt=EntryNames[Theindent];
  888. If found then break;
  889. end;
  890. If not found then
  891. begin
  892. Verbose ('Unknown indent keysym on line '+inttostr(i)+': '+Opt);
  893. exit;
  894. end;
  895. Option[TheKey]^.dindsym:=Option[TheKey]^.dindsym+[Theindent];
  896. end;
  897. until k=0;
  898. end;
  899. Var TheKey : KeySymbol;
  900. Found,DoIndent : Boolean;
  901. Line, Name : String;
  902. begin
  903. ReadConfigFile:=false;
  904. I:=0;
  905. while not (CfgS^.Status=stReadError) do
  906. begin
  907. inc(i);
  908. Line:='';
  909. Line:=ReadString(cfgS);
  910. { Strip comment }
  911. If pos('#',Line)<>0 then
  912. Line:=Copy(Line,1,Pos('#',Line)-1);
  913. If length(Line)<>0 then
  914. begin
  915. J:=Pos('=',Line);
  916. If J>0 then
  917. begin
  918. Line:=LowerStr(Line);
  919. Name:=Copy(Line,1,j-1);
  920. Delete(Line,1,J);
  921. { indents or options ? }
  922. If (Name[1]='[') and
  923. (Name[Length(Name)]=']') then
  924. begin
  925. Name:=Copy(Name,2,Length(Name)-2);
  926. Doindent:=True;
  927. end
  928. else
  929. DoIndent:=False;
  930. Strip(Name);
  931. found:=false;
  932. for thekey:=firstkey to lastkey do
  933. begin
  934. found:=Name=EntryNames[thekey];
  935. If Found then break;
  936. end;
  937. If not found then
  938. Verbose ('Unknown keyword on line '+inttostr(i)+': '+Name)
  939. else
  940. If DoIndent then
  941. SetIndent(TheKey,Line)
  942. else
  943. SetOption(TheKey,Line)
  944. end
  945. else
  946. verbose ('Error in config file on line '+IntToStr(i));
  947. end;
  948. end;
  949. Verbose ('Processed configfile: read '+IntToStr(I)+' lines');
  950. ReadConfigFile:=true;
  951. end;
  952. Procedure GenerateCfgFile(S : PStream);
  953. Var TheKey,TheIndent : KeySymbol;
  954. TheOpt : Options;
  955. Written : Boolean;
  956. Option : OptionTable;
  957. begin
  958. CreateOptions(option);
  959. SetDefaults(option);
  960. SetDefaultIndents(option);
  961. For TheKey:=Firstkey to lastkey do
  962. begin
  963. { Write options }
  964. WriteString (S,EntryNames[TheKey]+'=');
  965. Written:=False;
  966. for TheOpt:=FirstOpt to LastOpt do
  967. If TheOpt in Option[TheKey]^.Selected then
  968. begin
  969. if written then
  970. WriteString (S,',')
  971. else
  972. Written:=True;
  973. writeString (S,OptionNames[TheOpt]);
  974. end;
  975. WriteCr (S);
  976. { Write de-indent keysyms, if any }
  977. If Option[TheKey]^.dindsym<>[] then
  978. begin
  979. WriteString (S,'['+EntryNames[TheKey]+']=');
  980. Written:=False;
  981. For TheIndent:=FirstKey to lastkey do
  982. If TheIndent in Option[TheKey]^.dindsym then
  983. begin
  984. if written then
  985. WriteString (S,',')
  986. else
  987. Written:=True;
  988. WriteString (S,EntryNames[Theindent]);
  989. end;
  990. WriteCr (S);
  991. end;
  992. end;
  993. end;
  994. Function trimMiddle ( a:ansistring; lnght: integer; size: integer):string;
  995. var
  996. half:Integer;
  997. begin
  998. if lnght > size
  999. then
  1000. begin
  1001. half := (size - 3) div 2;
  1002. trimMiddle := copy(a,1,half) + '...' + copy(a,lnght-half+1,half);
  1003. end
  1004. else
  1005. trimMiddle := a;
  1006. end;
  1007. Function TPrettyPrinter.PrettyPrint : Boolean;
  1008. Begin
  1009. PrettyPrint:=False;
  1010. If Not Assigned(Ins) or Not Assigned(OutS) then
  1011. exit;
  1012. If Not Assigned(CfgS) then
  1013. begin
  1014. SetDefaults(Option);
  1015. SetDefaultIndents(Option);
  1016. end
  1017. else
  1018. ReadConfigFile;
  1019. { Initialize variables }
  1020. top := 0;
  1021. currlinepos := 0;
  1022. currmargin := 0;
  1023. inlines := 0;
  1024. outlines := 0;
  1025. CrPending := FALSE;
  1026. RecordSeen := FALSE;
  1027. GetChar;
  1028. NEW(currsym);
  1029. NEW(nextsym);
  1030. GetSymbol;
  1031. WHILE nextsym^.name <> endoffile DO BEGIN
  1032. GetSymbol;
  1033. Verbose('line in-'+IntToStr(inlines)+' out-'+IntToStr(outlines)+
  1034. ' symbol "'+EntryNames[currsym^.name]+'" = "'+
  1035. trimMiddle(currsym^.value,length(currsym^.value),MAXSHOWSIZE)+'"');
  1036. sets := option[currsym^.name];
  1037. IF (CrPending AND NOT (crsupp IN sets^.selected))
  1038. OR (crbefore IN sets^.selected) THEN BEGIN
  1039. InsertCR;
  1040. CrPending := FALSE
  1041. END;
  1042. IF blinbefore IN sets^.selected THEN BEGIN
  1043. InsertBlankLine;
  1044. CrPending := FALSE
  1045. END;
  1046. IF dindonkey IN sets^.selected THEN LShiftOn(sets^.dindsym);
  1047. IF dindent IN sets^.selected THEN LShift;
  1048. IF spbef IN sets^.selected THEN InsertSpace(currsym);
  1049. PPSymbol;
  1050. IF spaft IN sets^.selected THEN InsertSpace(nextsym);
  1051. IF inbytab IN sets^.selected THEN RShift(currsym^.name);
  1052. IF gobsym IN sets^.selected THEN Gobble(sets^.terminators);
  1053. IF crafter IN sets^.selected THEN CrPending := TRUE
  1054. END;
  1055. IF CrPending THEN WriteCRs(1);
  1056. Verbose(IntToStr(inlines)+' lines read, '+IntToStr(outlines)+' lines written.');
  1057. PrettyPrint:=True;
  1058. end;
  1059. Constructor TPrettyPrinter.Create;
  1060. Begin
  1061. LineSize:=MaxLineSize;
  1062. CreateOptions (Option);
  1063. SetTerminators(Option);
  1064. DiagS:=Nil;
  1065. InS:=Nil;
  1066. OutS:=Nil;
  1067. CfgS:=Nil;
  1068. End;
  1069. { ---------------------------------------------------------------------
  1070. Unit initialization
  1071. ---------------------------------------------------------------------}
  1072. Begin
  1073. CreateHash;
  1074. dblch := [becomes, opencomment];
  1075. end.