pretty.red 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. % This package prints list structures in an indented format that
  2. % is intended to make them legible. There are a number of special
  3. % cases recognized, but in general the intent of the algorithm
  4. % is that given a list (R1 R2 R3 ...), SUPERPRINT checks if
  5. % the list will fit directly on the current line and if so
  6. % prints it as:
  7. % (R1 R2 R3 ...)
  8. % if not it prints it as:
  9. % (R1
  10. % R2
  11. % R3
  12. % ... )
  13. % where each sublist is similarly treated.
  14. %
  15. % A. C. Norman. July 1978;
  16. % Functions:
  17. % SUPERPRINT(X) print expression X
  18. % SUPERPRINTM(X,M) print expression X with left margin M
  19. % PRETTYPRINT(X) = << SUPERPRINTM(X,POSN()), TERPRI() >>
  20. %
  21. % Flag:
  22. % !*SYMMETRIC If TRUE, print with escape characters,
  23. % otherwise do not (as PRIN1/PRIN2
  24. % distinction). defaults to TRUE;
  25. % !*QUOTES If TRUE, (QUOTE x) gets displayed as 'x.
  26. % default is TRUE;
  27. %
  28. % Variable:
  29. % THIN!* if THIN!* expressions can be fitted onto
  30. % a single line they will be printed that way.
  31. % this is a parameter used to control the
  32. % formatting of long thin lists. default
  33. % value is 5;
  34. SYMBOLIC;
  35. GLOBAL '(!*SYMMETRIC !*QUOTES THIN!*);
  36. !*SYMMETRIC:=T;
  37. !*QUOTES:=T;
  38. THIN!*:=5;
  39. SYMBOLIC PROCEDURE SUPERPRINT X;
  40. << SUPERPRINM(X,0); TERPRI(); X>>;
  41. SYMBOLIC PROCEDURE PRETTYPRINT X;
  42. << SUPERPRINM(X,POSN()); %WHAT REDUCE DOES NOW;
  43. TERPRI();
  44. TERPRI();
  45. NIL>>;
  46. SYMBOLIC PROCEDURE SUPERPRINTM(X,LMAR);
  47. << SUPERPRINM(X,LMAR); TERPRI(); X >>;
  48. % FROM HERE DOWN THE FUNCTIONS ARE NOT INTENDED FOR DIRECT USE;
  49. % THE FOLLOWING FUNCTIONS ARE DEFINED HERE IN CASE THIS PACKAGE
  50. % IS CALLED FROM LISP RATHER THAN REDUCE;
  51. SYMBOLIC PROCEDURE EQCAR(A,B);
  52. PAIRP A AND CAR A EQ B;
  53. SYMBOLIC PROCEDURE SPACES N;
  54. FOR I=1:N DO PRIN2 '! ;
  55. % END OF COMPATIBILITY SECTION;
  56. FLUID '(STACK BUFFERI BUFFERO BN LMAR RMAR INITIALBLANKS
  57. PENDINGRPARS INDENTLEVEL INDBLANKS RPARCOUNT);
  58. SYMBOLIC PROCEDURE SUPERPRINM(X,LMAR);
  59. BEGIN
  60. SCALAR STACK,BUFFERI,BUFFERO,BN,INITIALBLANKS,RMAR,
  61. PENDINGRPARS,INDENTLEVEL,INDBLANKS,RPARCOUNT,W;
  62. BUFFERI:=BUFFERO:=LIST NIL; %FIFO BUFFER;
  63. INITIALBLANKS:=0;
  64. RPARCOUNT:=0;
  65. INDBLANKS:=0;
  66. RMAR:=LINELENGTH(NIL)-3; %RIGHT MARGIN;
  67. IF RMAR<25 THEN ERROR(0,LIST(RMAR+3,
  68. "LINELENGTH TOO SHORT FOR SUPERPRINTING"));
  69. BN:=0; %CHARACTERS IN BUFFER;
  70. INDENTLEVEL:=0; %NO INDENTATION NEEDED, YET;
  71. IF LMAR+20>=RMAR THEN LMAR:=RMAR-21; %NO ROOM FOR SPECIFIED MARGIN;
  72. W:=POSN();
  73. IF W>LMAR THEN << TERPRI(); W:=0 >>;
  74. IF W<LMAR THEN INITIALBLANKS:=LMAR-W;
  75. PRINDENT(X,LMAR+3); %MAIN RECURSIVE PRINT ROUTINE;
  76. % TRAVERSE ROUTINE FINISHED - NOW TIDY UP BUFFERS;
  77. OVERFLOW 'NONE; %FLUSH OUT THE BUFFER;
  78. RETURN X
  79. END;
  80. % ACCESS FUNCTIONS FOR A STACK ENTRY;
  81. SMACRO PROCEDURE TOP; CAR STACK;
  82. SMACRO PROCEDURE DEPTH FRM; CAR FRM;
  83. SMACRO PROCEDURE INDENTING FRM; CADR FRM;
  84. SMACRO PROCEDURE BLANKCOUNT FRM; CADDR FRM;
  85. SMACRO PROCEDURE BLANKLIST FRM; CDDDR FRM;
  86. SMACRO PROCEDURE SETINDENTING(FRM,VAL); RPLACA(CDR FRM,VAL);
  87. SMACRO PROCEDURE SETBLANKCOUNT(FRM,VAL); RPLACA(CDDR FRM,VAL);
  88. SMACRO PROCEDURE SETBLANKLIST(FRM,VAL); RPLACD(CDDR FRM,VAL);
  89. SMACRO PROCEDURE NEWFRAME N; LIST(N,NIL,0);
  90. SMACRO PROCEDURE BLANKP CHAR; NUMBERP CAR CHAR;
  91. SYMBOLIC PROCEDURE PRINDENT(X,N);
  92. % PRINT LIST X WITH INDENTATION LEVEL N;
  93. IF ATOM X THEN IF VECTORP X THEN PRVECTOR(X,N)
  94. ELSE FOR EACH C IN
  95. (IF !*SYMMETRIC
  96. THEN IF STRINGP X THEN EXPLODES X ELSE EXPLODE X
  97. ELSE EXPLODEC X) DO PUTCH C
  98. ELSE IF QUOTEP X THEN <<
  99. PUTCH '!';
  100. PRINDENT(CADR X,N+1) >>
  101. ELSE BEGIN
  102. SCALAR CX;
  103. IF 4*N>3*RMAR THEN << %LIST IS TOO DEEP FOR SANITY;
  104. OVERFLOW 'ALL;
  105. N:=N/8;
  106. IF INITIALBLANKS>N THEN <<
  107. LMAR:=LMAR-INITIALBLANKS+N;
  108. INITIALBLANKS:=N >> >>;
  109. STACK := (NEWFRAME N) . STACK;
  110. PUTCH ('LPAR . TOP());
  111. CX:=CAR X;
  112. PRINDENT(CX,N+1);
  113. IF IDP CX AND NOT ATOM CDR X THEN
  114. CX:=GET(CX,'PPFORMAT) ELSE CX:=NIL;
  115. IF CX=2 AND ATOM CDDR X THEN CX:=NIL;
  116. IF CX='PROG THEN <<
  117. PUTCH '! ;
  118. PRINDENT(CAR (X:=CDR X),N+3) >>;
  119. % CX NOW CONTROLS THE FORMATTING OF WHAT FOLLOWS:
  120. % NIL DEFAULT ACTION
  121. % <NUMBER> FIRST FEW BLANKS ARE NON-INDENTING
  122. % PROG DISPLAY ATOMS AS LABELS;
  123. X:=CDR X;
  124. SCAN: IF ATOM X THEN GO TO OUT;
  125. FINISHPENDING(); %ABOUT TO PRINT A BLANK;
  126. IF CX='PROG THEN <<
  127. PUTBLANK();
  128. OVERFLOW BUFFERI; %FORCE FORMAT FOR PROG;
  129. IF ATOM CAR X THEN << % A LABEL;
  130. LMAR:=INITIALBLANKS:=MAX(LMAR-6,0);
  131. PRINDENT(CAR X,N-3); % PRINT THE LABEL;
  132. X:=CDR X;
  133. IF NOT ATOM X AND ATOM CAR X THEN GO TO SCAN;
  134. IF LMAR+BN>N THEN PUTBLANK()
  135. ELSE FOR I=LMAR+BN:N-1 DO PUTCH '! ;
  136. IF ATOM X THEN GO TO OUT >> >>
  137. ELSE IF NUMBERP CX THEN <<
  138. CX:=CX-1;
  139. IF CX=0 THEN CX:=NIL;
  140. PUTCH '! >>
  141. ELSE PUTBLANK();
  142. PRINDENT(CAR X,N+3);
  143. X:=CDR X;
  144. GO TO SCAN;
  145. OUT: IF NOT NULL X THEN <<
  146. FINISHPENDING();
  147. PUTBLANK();
  148. PUTCH '!.;
  149. PUTCH '! ;
  150. PRINDENT(X,N+5) >>;
  151. PUTCH ('RPAR . (N-3));
  152. IF INDENTING TOP()='INDENT AND NOT NULL BLANKLIST TOP() THEN
  153. OVERFLOW CAR BLANKLIST TOP()
  154. ELSE ENDLIST TOP();
  155. STACK:=CDR STACK
  156. END;
  157. SYMBOLIC PROCEDURE EXPLODES X;
  158. %dummy function just in case another format is needed;
  159. EXPLODE X;
  160. SYMBOLIC PROCEDURE PRVECTOR(X,N);
  161. BEGIN
  162. SCALAR BOUND;
  163. BOUND:=UPBV X; % LENGTH OF THE VECTOR;
  164. STACK:=(NEWFRAME N) . STACK;
  165. PUTCH ('LSQUARE . TOP());
  166. PRINDENT(GETV(X,0),N+3);
  167. FOR I=1:BOUND DO <<
  168. PUTCH '!,;
  169. PUTBLANK();
  170. PRINDENT(GETV(X,I),N+3) >>;
  171. PUTCH('RSQUARE . (N-3));
  172. ENDLIST TOP();
  173. STACK:=CDR STACK
  174. END;
  175. SYMBOLIC PROCEDURE PUTBLANK();
  176. BEGIN
  177. SCALAR B;
  178. PUTCH TOP(); %REPRESENTS A BLANK CHARACTER;
  179. SETBLANKCOUNT(TOP(),BLANKCOUNT TOP()+1);
  180. SETBLANKLIST(TOP(),BUFFERI . BLANKLIST TOP());
  181. %REMEMBER WHERE I WAS;
  182. INDBLANKS:=INDBLANKS+1
  183. END;
  184. SYMBOLIC PROCEDURE ENDLIST L;
  185. %FIX UP THE BLANKS IN A COMPLETE LIST SO THAT THEY
  186. %WILL NOT BE TURNED INTO INDENTATIONS;
  187. PENDINGRPARS:=L . PENDINGRPARS;
  188. % WHEN I HAVE PRINTED A ')' I WANT TO MARK ALL OF THE BLANKS
  189. % WITHIN THE PARENTHESES AS BEING UNINDENTED, ORDINARY BLANK
  190. % CHARACTERS. IT IS HOWEVER POSSIBLE THAT I MAY GET A BUFFER
  191. % OVERFLOW WHILE PRINTING A STRING OF )))))))))), AND SO THIS
  192. % MARKING SHOULD BE DELAYED UNTIL I GET ROUND TO PRINTING
  193. % A FURTHER BLANK (WHICH WILL BE A CANDIDATE FOR A PLACE TO
  194. % SPLIT LINES). THIS DELAY IS DEALT WITH BY THE LIST
  195. % PENDINGRPARS WHICH HOLDS A LIST OF LEVELS THAT, WHEN
  196. % CONVENIENT, CAN BE TIDIED UP AND CLOSED OUT;
  197. SYMBOLIC PROCEDURE FINISHPENDING();
  198. << FOR EACH STACKFRAME IN PENDINGRPARS DO <<
  199. IF INDENTING STACKFRAME NEQ 'INDENT THEN
  200. FOR EACH B IN BLANKLIST STACKFRAME DO
  201. << RPLACA(B,'! ); INDBLANKS:=INDBLANKS-1 >>;
  202. % BLANKLIST OF STACKFRAME MUST BE NON-NIL SO THAT OVERFLOW
  203. % WILL NOT TREAT THE '(' SPECIALLY;
  204. SETBLANKLIST(STACKFRAME,T) >>;
  205. PENDINGRPARS:=NIL >>;
  206. SYMBOLIC PROCEDURE QUOTEP X;
  207. !*QUOTES AND
  208. NOT ATOM X AND
  209. CAR X='QUOTE AND
  210. NOT ATOM CDR X AND
  211. NULL CDDR X;
  212. % PROPERTY PPFORMAT DRIVES THE PRETTYPRINTER -
  213. % PROG : SPECIAL FOR PROG ONLY
  214. % 1 : (FN A1
  215. % A2
  216. % ... )
  217. % 2 : (FN A1 A2
  218. % A3
  219. % ... ) ;
  220. PUT('PROG,'PPFORMAT,'PROG);
  221. PUT('LAMBDA,'PPFORMAT,1);
  222. PUT('LAMBDAQ,'PPFORMAT,1);
  223. PUT('SETQ,'PPFORMAT,1);
  224. PUT('SET,'PPFORMAT,1);
  225. PUT('WHILE,'PPFORMAT,1);
  226. PUT('T,'PPFORMAT,1);
  227. PUT('DE,'PPFORMAT,2);
  228. PUT('DF,'PPFORMAT,2);
  229. PUT('DM,'PPFORMAT,2);
  230. PUT('FOREACH,'PPFORMAT,4); % (FOREACH X IN Y DO ...) ETC;
  231. % NOW FOR THE ROUTINES THAT BUFFER THINGS ON A CHARACTER BY CHARACTER
  232. % BASIS, AND DEAL WITH BUFFER OVERFLOW;
  233. SYMBOLIC PROCEDURE PUTCH C;
  234. BEGIN
  235. IF ATOM C THEN RPARCOUNT:=0
  236. ELSE IF BLANKP C THEN << RPARCOUNT:=0; GO TO NOCHECK >>
  237. ELSE IF CAR C='RPAR THEN <<
  238. RPARCOUNT:=RPARCOUNT+1;
  239. % FORMAT FOR A LONG STRING OF RPARS IS:
  240. % )))) ))) ))) ))) ))) ;
  241. IF RPARCOUNT>4 THEN << PUTCH '! ; RPARCOUNT:=2 >> >>
  242. ELSE RPARCOUNT:=0;
  243. WHILE LMAR+BN>=RMAR DO OVERFLOW 'MORE;
  244. NOCHECK:
  245. BUFFERI:=CDR RPLACD(BUFFERI,LIST C);
  246. BN:=BN+1
  247. END;
  248. SYMBOLIC PROCEDURE OVERFLOW FLG;
  249. BEGIN
  250. SCALAR C,BLANKSTOSKIP;
  251. %THE CURRENT BUFFER HOLDS SO MUCH INFORMATION THAT IT WILL
  252. %NOT ALL FIT ON A LINE. TRY TO DO SOMETHING ABOUT IT;
  253. % FLG IS ONE OF:
  254. % 'NONE DO NOT FORCE MORE INDENTATION
  255. % 'MORE FORCE ONE LEVEL MORE INDENTATION
  256. % <A POINTER INTO THE BUFFER>
  257. % PRINTS UP TO AND INCLUDING THAT CHARACTER, WHICH
  258. % SHOULD BE A BLANK;
  259. IF INDBLANKS=0 AND INITIALBLANKS>3 AND FLG='MORE THEN <<
  260. INITIALBLANKS:=INITIALBLANKS-3;
  261. LMAR:=LMAR-3;
  262. RETURN 'MOVED!-LEFT >>;
  263. FBLANK:
  264. IF BN=0 THEN <<
  265. %NO BLANK FOUND - CAN DO NO MORE FOR NOW;
  266. % IF FLG='MORE I AM IN TROUBLE AND SO HAVE TO PRINT
  267. % A CONTINUATION MARK. IN THE OTHER CASES I CAN JUST EXIT;
  268. IF NOT(FLG = 'MORE) THEN RETURN 'EMPTY;
  269. IF ATOM CAR BUFFERO THEN
  270. % CONTINUATION MARK NOT NEEDED IF LAST CHAR PRINTED WAS
  271. % SPECIAL (E.G. LPAR OR RPAR);
  272. PRIN2 "%+"; %CONTINUATION MARKER;
  273. TERPRI();
  274. LMAR:=0;
  275. RETURN 'CONTINUED >>
  276. ELSE <<
  277. SPACES INITIALBLANKS;
  278. INITIALBLANKS:=0 >>;
  279. BUFFERO:=CDR BUFFERO;
  280. BN:=BN-1;
  281. LMAR:=LMAR+1;
  282. C:=CAR BUFFERO;
  283. IF ATOM C THEN << PRIN2 C; GO TO FBLANK >>
  284. ELSE IF BLANKP C THEN IF NOT ATOM BLANKSTOSKIP THEN <<
  285. PRIN2 '! ;
  286. INDBLANKS:=INDBLANKS-1;
  287. % BLANKSTOSKIP = (STACK-FRAME . SKIP-COUNT);
  288. IF C EQ CAR BLANKSTOSKIP THEN <<
  289. RPLACD(BLANKSTOSKIP,CDR BLANKSTOSKIP-1);
  290. IF CDR BLANKSTOSKIP=0 THEN BLANKSTOSKIP:=T >>;
  291. GO TO FBLANK >>
  292. ELSE GO TO BLANKFOUND
  293. ELSE IF CAR C='LPAR OR CAR C='LSQUARE THEN <<
  294. PRIN2 GET(CAR C,'PPCHAR);
  295. IF FLG='NONE THEN GO TO FBLANK;
  296. % NOW I WANT TO FLAG THIS LEVEL FOR INDENTATION;
  297. C:=CDR C; %THE STACK FRAME;
  298. IF NOT NULL BLANKLIST C THEN GO TO FBLANK;
  299. IF DEPTH C>INDENTLEVEL THEN << %NEW INDENTATION;
  300. % THIS LEVEL HAS NOT EMITTED ANY BLANKS YET;
  301. INDENTLEVEL:=DEPTH C;
  302. SETINDENTING(C,'INDENT) >>;
  303. GO TO FBLANK >>
  304. ELSE IF CAR C='RPAR OR CAR C='RSQUARE THEN <<
  305. IF CDR C<INDENTLEVEL THEN INDENTLEVEL:=CDR C;
  306. PRIN2 GET(CAR C,'PPCHAR);
  307. GO TO FBLANK >>
  308. ELSE ERROR(0,LIST(C,"UNKNOWN TAG IN OVERFLOW"));
  309. BLANKFOUND:
  310. IF EQCAR(BLANKLIST C,BUFFERO) THEN
  311. SETBLANKLIST(C,NIL);
  312. % AT LEAST ONE ENTRY ON BLANKLIST OUGHT TO BE VALID, SO IF I
  313. % PRINT THE LAST BLANK I MUST KILL BLANKLIST TOTALLY;
  314. INDBLANKS:=INDBLANKS-1;
  315. % CHECK IF NEXT LEVEL REPRESENTS NEW INDENTATION;
  316. IF DEPTH C>INDENTLEVEL THEN <<
  317. IF FLG='NONE THEN << %JUST PRINT AN ORDINARY BLANK;
  318. PRIN2 '! ;
  319. GO TO FBLANK >>;
  320. % HERE I INCREASE THE INDENTATION LEVEL BY ONE;
  321. IF BLANKSTOSKIP THEN BLANKSTOSKIP:=NIL
  322. ELSE <<
  323. INDENTLEVEL:=DEPTH C;
  324. SETINDENTING(C,'INDENT) >> >>;
  325. %OTHERWISE I WAS INDENTING AT THAT LEVEL ANYWAY;
  326. IF BLANKCOUNT C>(THIN!*-1) THEN << %LONG THIN LIST FIX-UP HERE;
  327. BLANKSTOSKIP:=C . ((BLANKCOUNT C) - 2);
  328. SETINDENTING(C,'THIN);
  329. SETBLANKCOUNT(C,1);
  330. INDENTLEVEL:=(DEPTH C)-1;
  331. PRIN2 '! ;
  332. GO TO FBLANK >>;
  333. SETBLANKCOUNT(C,(BLANKCOUNT C)-1);
  334. TERPRI();
  335. LMAR:=INITIALBLANKS:=DEPTH C;
  336. IF BUFFERO EQ FLG THEN RETURN 'TO!-FLG;
  337. IF BLANKSTOSKIP OR NOT (FLG='MORE) THEN GO TO FBLANK;
  338. % KEEP GOING UNLESS CALL WAS OF TYPE 'MORE';
  339. RETURN 'MORE; %TRY SOME MORE;
  340. END;
  341. PUT('LPAR,'PPCHAR,'!();
  342. PUT('LSQUARE,'PPCHAR,'![);
  343. PUT('RPAR,'PPCHAR,'!));
  344. PUT('RSQUARE,'PPCHAR,'!]);
  345. END;