home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol081 / pp.pas < prev    next >
Pascal/Delphi Source File  |  1984-04-29  |  20KB  |  791 lines

  1. { Pascal/Z pretty printer }
  2.  
  3. { Author:  Peter Grogono }
  4.  
  5. { This program is based on a Pascal pretty-printer written by Ledgard,
  6.   Hueras, and Singer.  See SIGPLAN Notices, Vol. 12, No. 7, July 1977,
  7.   pages 101-105.  }
  8.  
  9. { This version of PP must be compiled by Pascal/Z V4.0 or later.
  10.   It will run correctly under V3.0 only if 'byte' fields in records
  11.   are changed to 'integer'.  }
  12.  
  13. {$M- inhibit integer multiply/divide check }
  14. {$R- inhibit range/bound check - see procedure HASH }
  15. {$S- inhibit stack overflow check }
  16. {$U- inhibit range/bound check on parameters }
  17.  
  18. program pp;
  19.  
  20. const
  21.  
  22. {$ICONSTS.PAS }
  23. maxsymbolsize = 80;
  24. maxstacksize = 100;
  25. maxkeylength = 9;     { The longest keyword is PROCEDURE }
  26. maxlinesize = 90;     { Maximum length of output line }
  27. indent = 2;           { Indentation step size for structured statements }
  28. extin = '.PAS';
  29. extout = '.PPP';
  30. casediff = 32;        { ord('a') - ord('A') }
  31.  
  32. type
  33.  
  34. {$ITYPES.PAS }
  35.  
  36. keysymbol = 
  37. { keywords }
  38. (endsym,beginsym,ifsym,thensym,elsesym,procsym,varsym,ofsym,
  39. whilesym,dosym,casesym,withsym,forsym,repeatsym,untilsym,
  40. funcsym,labelsym,constsym,typesym,recordsym,stringsym,progsym,
  41. andsym,arrsym,divsym,downsym,filesym,gotosym,insym,modsym,
  42. notsym,nilsym,orsym,setsym,tosym,casevarsym,
  43. { other symbols }
  44. becomes,opencomment,closecomment,semicolon,colon,equals,
  45. openparen,closeparen,period,endoffile,othersym);
  46.  
  47. options = (crsupp,crbefore,blinbefore,
  48. dindonkey,dindent,spbef,
  49. spaft,gobsym,inbytab,crafter);
  50.  
  51. optionset = set of options;
  52. keysymset = set of keysymbol;
  53.  
  54. tableentry = record
  55. selected : optionset;
  56. dindsym : keysymset;
  57. terminators : keysymset
  58. end;
  59.  
  60. tableptr = ^ tableentry;
  61. optiontable = array [keysymbol] of tableptr;
  62. key = array [1..maxkeylength] of char;
  63. keywordtable = array [endsym..tosym] of key;
  64. specialchar = array [1..2] of char;
  65. dblcharset = set of endsym..othersym;
  66. dblchartable = array [becomes..opencomment] of specialchar;
  67. sglchartable = array [opencomment..period] of char;
  68. token = array [1..maxsymbolsize] of char;
  69.  
  70. symbol = record
  71. name : keysymbol;
  72. value : token;
  73. iskeyword : boolean;
  74. length, spacesbefore, crsbefore : byte
  75. end;
  76.  
  77. symbolinfo = ^ symbol;
  78. charname = (letter,digit,space,quote,endofline,
  79. filemark,otherchar);
  80.  
  81. charinfo = record
  82. name : charname;
  83. value : char
  84. end;
  85.  
  86. stackentry = record
  87. indentsymbol : keysymbol;
  88. prevmargin : byte
  89. end;
  90.  
  91. symbolstack = array [1..maxstacksize] of stackentry;
  92.  
  93. hashentry = record
  94. keyword : key;
  95. symtype : keysymbol
  96. end;
  97.  
  98. var
  99.  
  100. infilename,outfilename : string 20;
  101. infile,outfile : text;
  102. recordseen : boolean;
  103. currchar,nextchar : charinfo;
  104. currsym,nextsym : symbolinfo;
  105. crpending : boolean;
  106. option : optiontable;
  107. sets : tableptr;
  108. keyword : keywordtable;
  109. dblch : dblcharset;
  110. dblchar : dblchartable;
  111. sglchar : sglchartable;
  112. stack : symbolstack;
  113. top,startpos,currlinepos,currmargin,
  114. inlines,outlines : integer;
  115. hashtable : array [byte] of hashentry;
  116.  
  117. {$IPROCS.PAS }
  118. {$IGETFILES.PAS }
  119.  
  120. { Convert letters to upper case }
  121.  
  122. function upper (ch : char) : char;
  123.  
  124. begin
  125. if ch in ['a'..'z'] then upper := chr(ord(ch) - casediff)
  126. else upper := ch
  127. end; { upper }
  128.  
  129. { Read the next character and classify it }
  130.  
  131. procedure getchar;
  132.  
  133. var
  134. ch : char;
  135.  
  136. begin
  137. currchar := nextchar;
  138. with nextchar do
  139. if eof(infile) then
  140. begin name := filemark; value := blank end
  141. else
  142. if eoln(infile) then
  143. begin name := endofline; value := blank;
  144. inlines := inlines + 1; readln(infile) end
  145. else
  146. begin
  147. read(infile,ch);
  148. value := ch;
  149. if ch in ['a'..'z','A'..'Z','_'] then name := letter
  150. else
  151. if ch in ['0'..'9'] then name := digit
  152. else
  153. if ch = '''' then name := quote
  154. else
  155. if (ch = blank) or (ch = chr(tab)) then name := space
  156. else name := otherchar
  157. end
  158. end; { getchar }
  159.  
  160. { Store a character in the current symbol }
  161.  
  162. procedure storenextchar(var length : byte; var value : token);
  163.  
  164. begin
  165. getchar;
  166. if length < maxsymbolsize then
  167. begin length := length + 1; value[length] := currchar.value end;
  168. end; { storenextchar }
  169.  
  170. { Count the spaces between symbols }
  171.  
  172. procedure skipblanks (var spacesbefore,crsbefore : byte);
  173.  
  174. begin
  175. spacesbefore := 0;
  176. crsbefore := 0;
  177. while nextchar.name in [space,endofline] do
  178. begin
  179. getchar;
  180. case currchar.name of
  181. space : spacesbefore := spacesbefore + 1;
  182. endofline : begin
  183. crsbefore := crsbefore + 1;
  184. spacesbefore := 0
  185. end
  186. end
  187. end
  188. end; { skipspaces }
  189.  
  190. { Process comments using either brace or parenthesis notation }
  191.  
  192. procedure getcomment (sym : symbolinfo);
  193.  
  194. begin
  195. sym^.name := opencomment;
  196. while not (((currchar.value = '*') and (nextchar.value = ')'))
  197. or (currchar.value = '}')
  198. or (nextchar.name = endofline)
  199. or (nextchar.name = filemark)) do
  200. storenextchar(sym^.length,sym^.value);
  201. if (currchar.value = '*') and (nextchar.value = ')') 
  202. then
  203. begin
  204. storenextchar(sym^.length,sym^.value); sym^.name := closecomment
  205. end;
  206. if currchar.value = '}' 
  207. then sym^.name := closecomment
  208. end; { getcommment }
  209.  
  210. { Hashing function for identifiers.  The formula gives a unique value
  211.   in the range 0..255 for each Pascal/Z keyword.  Note that range and
  212.   overflow checking must be turned off for this function even if they
  213.   are enabled for the rest of the program.  }
  214.  
  215. function hash (symbol : key; length : byte) : byte;
  216.  
  217. begin
  218. hash := (ord(symbol[1]) * 5 + ord(symbol[length])) * 5 + length
  219. end; { hash }
  220.  
  221. { Classify an identifier.  We are only interested
  222.   in it if it is a keyword, so we use the hash table. }
  223.  
  224. procedure classid (value : token; length : byte;
  225. var idtype : keysymbol; var iskeyword : boolean);
  226.  
  227. var
  228. keyvalue : key;
  229. i, tabent : byte;
  230.  
  231. begin
  232. if length > maxkeylength then 
  233. begin idtype := othersym; iskeyword := false end
  234. else
  235. begin
  236. for i := 1 to length do keyvalue[i] := upper(value[i]);
  237. for i := length + 1 to maxkeylength do keyvalue[i] := blank;
  238. tabent := hash(keyvalue,length);
  239. if keyvalue = hashtable[tabent].keyword then
  240. begin idtype := hashtable[tabent].symtype; iskeyword := true end
  241. else
  242. begin idtype := othersym; iskeyword := false end
  243. end
  244. end; { classid }
  245.  
  246. { Read an identifier and classify it }
  247.  
  248. procedure getidentifier (sym : symbolinfo);
  249.  
  250. begin
  251. while nextchar.name in [letter,digit] do
  252. storenextchar(sym^.length,sym^.value);
  253. classid(sym^.value,sym^.length,sym^.name,sym^.iskeyword);
  254. if sym^.name in [recordsym,casesym,endsym]
  255. then case sym^.name of
  256. recordsym : recordseen := true;
  257. casesym : if recordseen then sym^.name := casevarsym;
  258. endsym : recordseen := false
  259. end
  260. end; { getidentifier }
  261.  
  262. { Read a number and store it as a string }
  263.  
  264. procedure getnumber (sym : symbolinfo);
  265.  
  266. begin
  267. while nextchar.name = digit do
  268. storenextchar(sym^.length,sym^.value);
  269. sym^.name := othersym
  270. end; { getnumber }
  271.  
  272. { Read a quoted string }
  273.  
  274. procedure getcharliteral (sym : symbolinfo);
  275.  
  276. begin
  277. while nextchar.name = quote do
  278. begin
  279. storenextchar(sym^.length,sym^.value);
  280. while not (nextchar.name in [quote,endofline,filemark]) do
  281. storenextchar(sym^.length,sym^.value);
  282. if nextchar.name = quote
  283. then storenextchar(sym^.length,sym^.value)
  284. end;
  285. sym^.name := othersym
  286. end; { getcharliteral }
  287.  
  288. { Classify a character pair }
  289.  
  290. function chartype : keysymbol;
  291.  
  292. var
  293. nexttwochars : specialchar;
  294. hit : boolean;
  295. thischar : keysymbol;
  296.  
  297. begin
  298. nexttwochars[1] := currchar.value;
  299. nexttwochars[2] := nextchar.value;
  300. thischar := becomes;
  301. hit := false;
  302. while not (hit or (thischar = closecomment)) do
  303. begin
  304. if nexttwochars = dblchar[thischar]
  305. then hit := true
  306. else thischar := succ(thischar)
  307. end;
  308. if not hit then
  309. begin
  310. thischar := opencomment;
  311. while not (hit or (pred(thischar) = period)) do
  312. begin
  313. if currchar.value = sglchar[thischar]
  314. then hit := true
  315. else thischar := succ(thischar) 
  316. end
  317. end;
  318. if hit then chartype := thischar
  319. else chartype := othersym;
  320. end; { chartype }
  321.  
  322. { Read special characters }
  323.  
  324. procedure getspecialchar (sym : symbolinfo);
  325.  
  326. begin
  327. storenextchar(sym^.length,sym^.value);
  328. sym^.name := chartype;
  329. if sym^.name in dblch then storenextchar(sym^.length,sym^.value)
  330. end; { getspecialchar }
  331.  
  332. { Read a symbol using the appropriate procedure }
  333.  
  334. procedure getnextsymbol (sym : symbolinfo);
  335.  
  336. begin
  337. case nextchar.name of
  338. letter : getidentifier(sym);
  339. digit : getnumber(sym);
  340. quote : getcharliteral(sym);
  341. otherchar : begin
  342. getspecialchar(sym);
  343. if sym^.name = opencomment then getcomment(sym)
  344. end;
  345. filemark : sym^.name := endoffile;
  346. else : writeln('Unknown character type: ',ord(nextchar.name))
  347. end
  348. end; { getnextsymbol }
  349.  
  350. { Store the next symbol in NEXTSYM }
  351.  
  352. procedure getsymbol;
  353.  
  354. var
  355. dummy : symbolinfo;
  356.  
  357. begin
  358. dummy := currsym;
  359. currsym := nextsym;
  360. nextsym := dummy;
  361. skipblanks(nextsym^.spacesbefore,nextsym^.crsbefore);
  362. nextsym^.length := 0;
  363. nextsym^.iskeyword := false;
  364. if currsym^.name = opencomment
  365. then getcomment(nextsym)
  366. else getnextsymbol(nextsym)
  367. end;
  368.  
  369. { Manage stack of indentation symbols and margins }
  370.  
  371. procedure popstack (var indentsymbol : keysymbol; var prevmargin : byte);
  372.  
  373. begin
  374. if top > 0 
  375. then
  376. begin
  377. indentsymbol := stack[top].indentsymbol;
  378. prevmargin := stack[top].prevmargin;
  379. top := top - 1
  380. end
  381. else 
  382. begin
  383. indentsymbol := othersym; 
  384. prevmargin := 0
  385. end
  386. end; { popstack }
  387.  
  388. procedure pushstack (indentsymbol : keysymbol; prevmargin : byte);
  389.  
  390. begin
  391. top := top + 1;
  392. stack[top].indentsymbol := indentsymbol;
  393. stack[top].prevmargin := prevmargin
  394. end; { pushstack }
  395.  
  396. procedure writecrs (numberofcrs : byte);
  397.  
  398. var
  399. i : byte;
  400.  
  401. begin
  402. if numberofcrs > 0 then
  403. begin
  404. for i := 1 to numberofcrs do writeln(outfile);
  405. outlines := outlines + numberofcrs;
  406. currlinepos := 0
  407. end
  408. end; { writecrs }
  409.  
  410. procedure insertcr;
  411.  
  412. begin
  413. if currsym^.crsbefore = 0
  414. then
  415. begin
  416. writecrs(1); currsym^.spacesbefore := 0
  417. end
  418. end; { insertcr }
  419.  
  420. procedure insertblankline;
  421.  
  422. begin
  423. if currsym^.crsbefore = 0
  424. then
  425. begin
  426. if currlinepos = 0
  427. then writecrs(1)
  428. else writecrs(2);
  429. currsym^.spacesbefore := 0
  430. end
  431. else
  432. if currsym^.crsbefore = 1 then
  433. if currlinepos > 0 then writecrs(1)
  434. end; { insertblankline }
  435.  
  436. { Move margin left according to stack configuration and current symbol }
  437.  
  438. procedure lshifton (dindsym : keysymset);
  439.  
  440. var
  441. indentsymbol : keysymbol;
  442. prevmargin : byte;
  443.  
  444. begin
  445. if top > 0 then
  446. begin
  447. repeat
  448. popstack(indentsymbol,prevmargin);
  449. if indentsymbol in dindsym
  450. then currmargin := prevmargin
  451. until not (indentsymbol in dindsym) or (top = 0);
  452. if not (indentsymbol in dindsym)
  453. then pushstack(indentsymbol,prevmargin)
  454. end
  455. end; { lshifton }
  456.  
  457. { Move margin left according to stack top }
  458.  
  459. procedure lshift;
  460.  
  461. var
  462. indentsymbol : keysymbol;
  463. prevmargin : byte;
  464.  
  465. begin
  466. if top > 0 then
  467. begin
  468. popstack(indentsymbol,prevmargin);
  469. currmargin := prevmargin
  470. end
  471. end; { lshift }
  472.  
  473. { Insert space if room on line }
  474.  
  475. procedure insertspace (var symbol : symbolinfo);
  476.  
  477. begin
  478. if currlinepos < maxlinesize
  479. then
  480. begin
  481. write(outfile,blank);
  482. currlinepos := currlinepos + 1;
  483. if (symbol^.crsbefore = 0) and (symbol^.spacesbefore > 0)
  484. then symbol^.spacesbefore := symbol^.spacesbefore - 1
  485. end
  486. end; { insertspace }
  487.  
  488. { Insert spaces until correct line position reached }
  489.  
  490. procedure movelinepos (newlinepos : byte);
  491.  
  492. var
  493. i : byte;
  494.  
  495. begin
  496. for i := currlinepos + 1 to newlinepos do write(outfile,blank);
  497. currlinepos := newlinepos
  498. end; { movelinepos }
  499.  
  500. { Print a symbol converting keywords to upper case }
  501.  
  502. procedure printsymbol;
  503.  
  504. var
  505. i : byte;
  506.  
  507. begin
  508. if currsym^.iskeyword then
  509. for i := 1 to currsym^.length do write(outfile,upper(currsym^.value[i]))
  510. else
  511. for i := 1 to currsym^.length do write(outfile,currsym^.value[i]);
  512. startpos := currlinepos;
  513. currlinepos := currlinepos + currsym^.length
  514. end; { printsymbol }
  515.  
  516. { Find position for symbol and then print it }
  517.  
  518. procedure ppsymbol;
  519.  
  520. var
  521. newlinepos : byte;
  522.  
  523. begin
  524. writecrs(currsym^.crsbefore);
  525. if (currlinepos + currsym^.spacesbefore > currmargin)
  526. or (currsym^.name in [opencomment,closecomment])
  527. then newlinepos := currlinepos + currsym^.spacesbefore
  528. else newlinepos := currmargin;
  529. if newlinepos + currsym^.length > maxlinesize
  530. then
  531. begin
  532. writecrs(1);
  533. if currmargin + currsym^.length <= maxlinesize
  534. then newlinepos := currmargin
  535. else
  536. if currsym^.length < maxlinesize
  537. then newlinepos := maxlinesize - currsym^.length
  538. else newlinepos := 0
  539. end;
  540. movelinepos(newlinepos);
  541. printsymbol
  542. end; { ppsymbol }
  543.  
  544. { Print symbols which follow a formatting symbol but which do not
  545.   affect layout }
  546.  
  547. procedure gobble (terminators : keysymset);
  548.  
  549. begin
  550. if top < maxstacksize 
  551. then pushstack(currsym^.name,currmargin);
  552. currmargin := currlinepos;
  553. while not ((nextsym^.name in terminators)
  554.            or (nextsym^.name = endoffile)) do
  555. begin
  556. getsymbol; ppsymbol
  557. end;
  558. lshift
  559. end; { gobble }
  560.  
  561. { Move right, stacking margin positions }
  562.  
  563. procedure rshift (currsym : keysymbol);
  564.  
  565. begin
  566. if top < maxstacksize
  567. then pushstack(currsym,currmargin);
  568. if startpos > currmargin
  569. then currmargin := startpos;
  570. currmargin := currmargin + indent
  571. end; { rshift }
  572.  
  573. { Initialize everything }
  574.  
  575. procedure initialize;
  576.  
  577. var
  578. sym : keysymbol;
  579. ch : char;
  580. pos, len : byte;
  581.  
  582. begin
  583.  
  584. { Get file name and open files }
  585.  
  586. getfilenames(extin,extout);
  587. writeln('Reading from ',infilename);
  588. writeln('Writing to   ',outfilename);
  589. reset(infilename,infile);
  590. rewrite(outfilename,outfile);
  591.  
  592. { Initialize variables and set up control tables }
  593.  
  594. top := 0;
  595. currlinepos := 0;
  596. currmargin := 0;
  597. inlines := 0;
  598. outlines := 0;
  599.  
  600. { Keywords used for formatting }
  601.  
  602. keyword[progsym]    := 'PROGRAM  ';
  603. keyword[funcsym]    := 'FUNCTION ';
  604. keyword[procsym]    := 'PROCEDURE';
  605. keyword[labelsym]   := 'LABEL    ';
  606. keyword[constsym]   := 'CONST    ';
  607. keyword[typesym]    := 'TYPE     ';
  608. keyword[varsym]     := 'VAR      ';
  609. keyword[beginsym]   := 'BEGIN    ';
  610. keyword[repeatsym]  := 'REPEAT   ';
  611. keyword[recordsym]  := 'RECORD   ';
  612. keyword[casesym]    := 'CASE     ';
  613. keyword[ofsym]      := 'OF       ';
  614. keyword[forsym]     := 'FOR      ';
  615. keyword[whilesym]   := 'WHILE    ';
  616. keyword[withsym]    := 'WITH     ';
  617. keyword[dosym]      := 'DO       ';
  618. keyword[ifsym]      := 'IF       ';
  619. keyword[thensym]    := 'THEN     ';
  620. keyword[elsesym]    := 'ELSE     ';
  621. keyword[endsym]     := 'END      ';
  622. keyword[untilsym]   := 'UNTIL    ';
  623.  
  624. { Keywords not used for formatting }
  625.  
  626. keyword[andsym]     := 'AND      ';
  627. keyword[arrsym]     := 'ARRAY    ';
  628. keyword[divsym]     := 'DIV      ';
  629. keyword[downsym]    := 'DOWNTO   ';
  630. keyword[filesym]    := 'FILE     ';
  631. keyword[gotosym]    := 'GOTO     ';
  632. keyword[insym]      := 'IN       ';
  633. keyword[modsym]     := 'MOD      ';
  634. keyword[notsym]     := 'NOT      ';
  635. keyword[nilsym]     := 'NIL      ';
  636. keyword[orsym]      := 'OR       ';
  637. keyword[setsym]     := 'SET      ';
  638. keyword[tosym]      := 'TO       ';
  639. keyword[stringsym]  := 'STRING   ';
  640.  
  641. { Create hash table }
  642.  
  643. for pos := 0 to maxbyte do
  644. begin
  645. hashtable[pos].keyword := '         ';
  646. hashtable[pos].symtype := othersym
  647. end; { for }
  648. for sym := endsym to tosym do
  649. begin
  650. len := maxkeylength;
  651. while keyword[sym,len] = blank do len := len - 1;
  652. pos := hash(keyword[sym],len);
  653. hashtable[pos].keyword := keyword[sym];
  654. hashtable[pos].symtype := sym
  655. end; { for }
  656.  
  657. { Set up other special symbols }
  658.  
  659. dblch := [becomes,opencomment];
  660.  
  661. dblchar[becomes] := ':=';
  662. dblchar[opencomment] := '(*';
  663.  
  664. sglchar[semicolon] := ';';
  665. sglchar[colon]     := ':';
  666. sglchar[equals]    := '=';
  667. sglchar[openparen] := '(';
  668. sglchar[closeparen] := ')';
  669. sglchar[period]    := '.';
  670. sglchar[opencomment] := '{';
  671. sglchar[closecomment] := '}';
  672.  
  673. { Set up the sets that control formatting.  If you want PP to insert a
  674.   line break before every statement, include CRBEFORE in the SELECTED
  675.   set of the appropriate keywords (WHILE, IF, REPEAT, etc.).  The
  676.   disadvantage of this is that PP will sometimes put line breaks 
  677.   where you don't want them, e.g. after ':' in CASE statements.  Note
  678.   also that PP does not understand the Pascal/Z use of ELSE as a
  679.   CASE label -- I wish they'd used OTHERWISE like everybody else.  }
  680.  
  681. for sym := endsym to othersym do
  682. begin
  683. new(option[sym]);
  684. option[sym]^.selected := [];
  685. option[sym]^.dindsym := [];
  686. option[sym]^.terminators := []
  687. end;
  688.  
  689. option[progsym]^.selected    := [blinbefore,spaft];
  690. option[funcsym]^.selected    := [blinbefore,dindonkey,spaft];
  691. option[funcsym]^.dindsym     := [labelsym,constsym,typesym,varsym]; 
  692. option[procsym]^.selected    := [blinbefore,dindonkey,spaft];
  693. option[procsym]^.dindsym     := [labelsym,constsym,typesym,varsym];
  694. option[labelsym]^.selected   := [blinbefore,spaft,inbytab];
  695. option[constsym]^.selected   := [blinbefore,dindonkey,spaft,inbytab];
  696. option[constsym]^.dindsym    := [labelsym];
  697. option[typesym]^.selected    := [blinbefore,dindonkey,spaft,inbytab];
  698. option[typesym]^.dindsym     := [labelsym,constsym];
  699. option[varsym]^.selected     := [blinbefore,dindonkey,spaft,inbytab];
  700. option[varsym]^.dindsym      := [labelsym,constsym,typesym];
  701. option[beginsym]^.selected   := [dindonkey,inbytab,crafter];
  702. option[beginsym]^.dindsym    := [labelsym,constsym,typesym,varsym];
  703. option[repeatsym]^.selected  := [inbytab,crafter];
  704. option[recordsym]^.selected  := [inbytab,crafter];
  705. option[casesym]^.selected    := [spaft,inbytab,gobsym,crafter];
  706. option[casesym]^.terminators := [ofsym];
  707. option[casevarsym]^.selected := [spaft,inbytab,gobsym,crafter];
  708. option[casevarsym]^.terminators := [ofsym]; 
  709. option[ofsym]^.selected      := [crsupp,spbef];
  710. option[forsym]^.selected     := [spaft,inbytab,gobsym,crafter];
  711. option[forsym]^.terminators  := [dosym];
  712. option[whilesym]^.selected   := [spaft,inbytab,gobsym,crafter];
  713. option[whilesym]^.terminators := [dosym];
  714. option[withsym]^.selected    := [spaft,inbytab,gobsym,crafter];
  715. option[withsym]^.terminators := [dosym];
  716. option[dosym]^.selected      := [crsupp,spbef];
  717. option[ifsym]^.selected      := [spaft,inbytab,gobsym,crafter];
  718. option[ifsym]^.terminators   := [thensym];
  719. option[thensym]^.selected    := [inbytab];
  720. option[elsesym]^.selected    := [crbefore,dindonkey,dindent,inbytab];
  721. option[elsesym]^.dindsym     := [ifsym,elsesym];
  722. option[endsym]^.selected     := [crbefore,dindonkey,dindent,crafter];
  723. option[endsym]^.dindsym      := [ifsym,thensym,elsesym,forsym,whilesym,
  724. withsym,casevarsym,colon,equals];
  725. option[untilsym]^.selected   := [crbefore,dindonkey,dindent,
  726. spaft,gobsym,crafter];
  727. option[untilsym]^.dindsym    := [ifsym,thensym,elsesym,forsym,whilesym,
  728. withsym,colon,equals];
  729. option[untilsym]^.terminators := [endsym,untilsym,elsesym,semicolon];
  730. option[becomes]^.selected    := [spbef,spaft,gobsym];
  731. option[becomes]^.terminators := [endsym,untilsym,elsesym,semicolon];
  732. option[opencomment]^.selected := [crsupp];
  733. option[closecomment]^.selected := [crsupp];
  734. option[semicolon]^.selected  := [crsupp,dindonkey,crafter];
  735. option[semicolon]^.dindsym   := [ifsym,thensym,elsesym,forsym,whilesym,
  736. withsym,colon,equals];
  737. option[colon]^.selected      := [inbytab];
  738. option[equals]^.selected     := [spbef,spaft,inbytab];
  739. option[openparen]^.selected  := [gobsym];
  740. option[openparen]^.terminators := [closeparen];
  741. option[period]^.selected     := [crsupp]; 
  742.  
  743. { Start i/o }
  744.  
  745. crpending := false;
  746. recordseen := false;
  747. getchar;
  748. new(currsym); new(nextsym);
  749. getsymbol;
  750.  
  751. end; { initialize }
  752.  
  753. { Main Program }
  754.  
  755. begin
  756. initialize;
  757. while nextsym^.name <> endoffile do
  758. begin
  759. getsymbol;
  760. sets := option[currsym^.name];
  761. if (crpending and not (crsupp in sets^.selected))
  762. or (crbefore in sets^.selected) then
  763. begin
  764. insertcr; crpending := false
  765. end;
  766. if blinbefore in sets^.selected then
  767. begin
  768. insertblankline; crpending := false
  769. end;
  770. if dindonkey in sets^.selected
  771. then lshifton(sets^.dindsym);
  772. if dindent in sets^.selected
  773. then lshift;
  774. if spbef in sets^.selected
  775. then insertspace(currsym);
  776. ppsymbol;
  777. if spaft in sets^.selected
  778. then insertspace(nextsym);
  779. if inbytab in sets^.selected
  780. then rshift(currsym^.name);
  781. if gobsym in sets^.selected
  782. then gobble(sets^.terminators);
  783. if crafter in sets^.selected
  784. then crpending := true
  785. end;
  786. if crpending then writecrs(1);
  787.  
  788. writeln(inlines:1,' lines read, ',outlines:1,' lines written.')
  789.  
  790. end.
  791.