util.red 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236
  1. module cedit; % REDUCE input string editor.
  2. % Author: Anthony C. Hearn;
  3. fluid '(!*mode);
  4. global '(!$eol!$
  5. !*blanknotok!*
  6. !*eagain
  7. !*full
  8. crbuf!*
  9. crbuf1!*
  10. crbuflis!*
  11. esc!*
  12. inputbuflis!*
  13. rprifn!*
  14. rterfn!*
  15. statcounter);
  16. %esc!* := intern ascii 125; %this is system dependent and defines
  17. %a terminator for strings.
  18. symbolic procedure rplacw(u,v);
  19. if atom u or atom v then errach list('rplacw,u,v)
  20. else rplacd(rplaca(u,car v),cdr v);
  21. symbolic procedure cedit n;
  22. begin scalar x,ochan;
  23. if null terminalp() then rederr "Edit must be from a terminal";
  24. ochan := wrs nil;
  25. if n eq 'fn then x := reversip crbuf!*
  26. else if null n
  27. then if null crbuflis!*
  28. then <<statcounter := statcounter-1;
  29. rederr "No previous entry">>
  30. else x := cdar crbuflis!*
  31. else if (x := assoc(car n,crbuflis!*))
  32. then x := cedit0(cdr x,car n)
  33. else <<statcounter := statcounter-1;
  34. rederr list("Entry",car n,"not found")>>;
  35. crbuf!* := nil;
  36. x := for each j in x collect j; %to make a copy.
  37. terpri();
  38. editp x;
  39. terpri();
  40. x := cedit1 x;
  41. wrs ochan;
  42. if x eq 'failed then nil else crbuf1!* := x
  43. end;
  44. symbolic procedure cedit0(u,n);
  45. % Returns input string augmented by appropriate mode.
  46. begin scalar x;
  47. if not(x := assoc(n,inputbuflis!*)) or ((x := cddr x) eq !*mode)
  48. then return u
  49. else return append(explode x,append(cdr explode '! ,u))
  50. end;
  51. symbolic procedure cedit1 u;
  52. begin scalar x,y,z;
  53. z := setpchar '!>;
  54. if not !*eagain
  55. then <<prin2t "For help, type ?"; !*eagain := t>>;
  56. while u and (car u eq !$eol!$) do u := cdr u;
  57. u := append(u,list '! ); %to avoid 'last char' problem.
  58. if !*full then editp u;
  59. top:
  60. x := u; %current pointer position.
  61. a:
  62. y := readch(); %current command.
  63. if y eq 'p or y eq '!p then editp x
  64. else if y eq 'i or y eq '!i then editi x
  65. else if y eq 'c or y eq '!c then editc x
  66. else if y eq 'd or y eq '!d then editd x
  67. else if y eq 'f or y eq '!f then x := editf(x,nil)
  68. else if y eq 'e or y eq '!e
  69. then <<terpri(); editp1 u; setpchar z; return u>>
  70. else if y eq 'q or y eq '!q then <<setpchar z; return 'failed>>
  71. else if y eq '!? then edith()
  72. else if y eq 'b or y eq '!b then go to top
  73. else if y eq 'k or y eq '!k then editf(x,t)
  74. else if y eq 's or y eq '!s then x := edits x
  75. else if y eq '! and not !*blanknotok!* or y eq 'x or y eq '!x
  76. then x := editn x
  77. else if y eq '! and !*blanknotok!* then go to a
  78. else if y eq !$eol!$ then go to a
  79. else lprim!* list(y,"Invalid editor character");
  80. go to a
  81. end;
  82. symbolic procedure editc x;
  83. if null cdr x then lprim!* "No more characters"
  84. else rplaca(x,readch());
  85. symbolic procedure editd x;
  86. if null cdr x then lprim!* "No more characters"
  87. else rplacw(x,cadr x . cddr x);
  88. symbolic procedure editf(x,bool);
  89. begin scalar y,z;
  90. y := cdr x;
  91. z := readch();
  92. if null y then return <<lprim!* list(z,"Not found"); x>>;
  93. while cdr y and not z eq car y do y := cdr y;
  94. return if null cdr y then <<lprim!* list(z,"Not found"); x>>
  95. else if bool then rplacw(x,car y . cdr y)
  96. else y
  97. end;
  98. symbolic procedure edith;
  99. <<prin2t "THE FOLLOWING COMMANDS ARE SUPPORTED:";
  100. prin2t " B move pointer to beginning";
  101. prin2t " C<character> replace next character by <character>";
  102. prin2t " D delete next character";
  103. prin2t " E end editing and reread text";
  104. prin2t
  105. " F<character> move pointer to next occurrence of <character>";
  106. prin2t
  107. " I<string><escape> insert <string> in front of pointer";
  108. prin2t " K<character> delete all chars until <character>";
  109. prin2t " P print string from current pointer";
  110. prin2t " Q give up with error exit";
  111. prin2t
  112. " S<string><escape> search for first occurrence of <string>";
  113. prin2t " positioning pointer just before it";
  114. prin2t " <space> or X move pointer right one character";
  115. terpri();
  116. prin2t
  117. "ALL COMMAND SEQUENCES SHOULD BE FOLLOWED BY A CARRIAGE RETURN";
  118. prin2t " TO BECOME EFFECTIVE">>;
  119. symbolic procedure editi x;
  120. begin scalar y,z;
  121. while (y := readch()) neq esc!* do z := y . z;
  122. rplacw(x,nconc(reversip z,car x . cdr x))
  123. end;
  124. symbolic procedure editn x;
  125. if null cdr x then lprim!* "NO MORE CHARACTERS"
  126. else cdr x;
  127. symbolic procedure editp u;
  128. <<editp1 u; terpri()>>;
  129. symbolic procedure editp1 u;
  130. for each x in u do if x eq !$eol!$ then terpri() else prin2 x;
  131. symbolic procedure edits u;
  132. begin scalar x,y,z;
  133. x := u;
  134. while (y := readch()) neq esc!* do z := y . z;
  135. z := reversip z;
  136. a: if null x then return <<lprim!* "not found"; u>>
  137. else if edmatch(z,x) then return x;
  138. x := cdr x;
  139. go to a
  140. end;
  141. symbolic procedure edmatch(u,v);
  142. % Matches list of characters U against V. Returns rest of V if
  143. % match occurs or NIL otherwise.
  144. if null u then v
  145. else if null v then nil
  146. else if car u=car v then edmatch(cdr u,cdr v)
  147. else nil;
  148. symbolic procedure lprim!* u; <<lprim u; terpri()>>;
  149. comment Editing Function Definitions;
  150. remprop('editdef,'stat);
  151. symbolic procedure editdef u; editdef1 car u;
  152. symbolic procedure editdef1 u;
  153. begin scalar type,x;
  154. if null(x := getd u) then return lprim list(u,"not defined")
  155. else if codep cdr x or not eqcar(cdr x,'lambda)
  156. then return lprim list(u,"cannot be edited");
  157. type := car x;
  158. x := cdr x;
  159. if type eq 'expr then x := 'de . u . cdr x
  160. else if type eq 'fexpr then x := 'df . u . cdr x
  161. else if type eq 'macro then x := 'dm . u . cdr x
  162. else rederr list("strange function type",type);
  163. rprifn!* := 'add2buf;
  164. rterfn!* := 'addter2buf;
  165. crbuf!* := nil;
  166. x := errorset(list('rprint,mkquote x),t,nil);
  167. rprifn!* := nil;
  168. rterfn!* := nil;
  169. if errorp x then return (crbuf!* := nil);
  170. crbuf!* := cedit 'fn;
  171. return nil
  172. end;
  173. symbolic procedure add2buf u; crbuf!* := u . crbuf!*;
  174. symbolic procedure addter2buf; crbuf!* := !$eol!$ . crbuf!*;
  175. put('editdef,'stat,'rlis);
  176. comment Displaying past input expressions;
  177. put('display,'stat,'rlis);
  178. symbolic procedure display u;
  179. % Displays input stack in reverse order.
  180. % Modification to reverse list added by F. Kako.
  181. begin scalar x,w;
  182. u := car u;
  183. x := crbuflis!*;
  184. terpri();
  185. if not numberp u then u := length x;
  186. while u>0 and x do
  187. <<w := car x . w; x := cdr x; u := u - 1>>;
  188. for each j in w do
  189. <<prin2 car j; prin2 ": "; editp cdr j; terpri()>>
  190. end;
  191. endmodule;
  192. module pretty; % Print list structures in an indented format.
  193. % Author: A. C. Norman, July 1978.
  194. fluid '(bn
  195. bufferi
  196. buffero
  197. indblanks
  198. indentlevel
  199. initialblanks
  200. lmar
  201. pendingrpars
  202. rmar
  203. rparcount
  204. stack);
  205. global '(!*quotes !*symmetric thin!*);
  206. !*symmetric := t;
  207. !*quotes := t;
  208. thin!* := 5;
  209. % This package prints list structures in an indented format that
  210. % is intended to make them legible. There are a number of special
  211. % cases recognized, but in general the intent of the algorithm
  212. % is that given a list (R1 R2 R3 ...), SUPERPRINT checks if
  213. % the list will fit directly on the current line and if so
  214. % prints it as:
  215. % (R1 R2 R3 ...)
  216. % if not it prints it as:
  217. % (R1
  218. % R2
  219. % R3
  220. % ... )
  221. % where each sublist is similarly treated.
  222. %
  223. % Functions:
  224. % SUPERPRINTM(X,M) print expression X with left margin M
  225. % PRETTYPRINT(X) = <<superprintm(x,posn()); terpri(); terpri()>>;
  226. %
  227. % Flag:
  228. % !*SYMMETRIC If TRUE, print with escape characters,
  229. % otherwise do not (as PRIN1/PRIN2
  230. % distinction). defaults to TRUE;
  231. % !*QUOTES If TRUE, (QUOTE x) gets displayed as 'x.
  232. % default is TRUE;
  233. %
  234. % Variable:
  235. % THIN!* if THIN!* expressions can be fitted onto
  236. % a single line they will be printed that way.
  237. % this is a parameter used to control the
  238. % formatting of long thin lists. default
  239. % value is 5;
  240. symbolic procedure prettyprint x;
  241. << superprinm(x,posn()); %WHAT REDUCE DOES NOW;
  242. terpri();
  243. terpri();
  244. nil>>;
  245. symbolic procedure superprintm(x,lmar);
  246. << superprinm(x,lmar); terpri(); x >>;
  247. % From here down the functions are not intended for direct use.
  248. % The following functions are defined here in case this package
  249. % is called from LISP rather than REDUCE.
  250. symbolic procedure eqcar(a,b);
  251. pairp a and car a eq b;
  252. symbolic procedure spaces n;
  253. for i:=1:n do prin2 '! ;
  254. % End of compatibility section.
  255. symbolic procedure superprinm(x,lmar);
  256. begin
  257. scalar stack,bufferi,buffero,bn,initialblanks,rmar,
  258. pendingrpars,indentlevel,indblanks,rparcount,w;
  259. bufferi:=buffero:=list nil; %fifo buffer.
  260. initialblanks:=0;
  261. rparcount:=0;
  262. indblanks:=0;
  263. rmar:=linelength(nil)-3; %right margin.
  264. if rmar<25 then error(0,list(rmar+3,
  265. "Linelength too short for superprinting"));
  266. bn:=0; %characters in buffer.
  267. indentlevel:=0; %no indentation needed, yet.
  268. if lmar+20>=rmar then lmar:=rmar-21; %no room for specified margin.
  269. w:=posn();
  270. if w>lmar then << terpri(); w:=0 >>;
  271. if w<lmar then initialblanks:=lmar-w;
  272. prindent(x,lmar+3); %main recursive print routine.
  273. % traverse routine finished - now tidy up buffers.
  274. overflow 'none; %flush out the buffer.
  275. return x
  276. end;
  277. % Access functions for a stack entry.
  278. smacro procedure top; car stack;
  279. smacro procedure depth frm; car frm;
  280. smacro procedure indenting frm; cadr frm;
  281. smacro procedure blankcount frm; caddr frm;
  282. smacro procedure blanklist frm; cdddr frm;
  283. smacro procedure setindenting(frm,val); rplaca(cdr frm,val);
  284. smacro procedure setblankcount(frm,val); rplaca(cddr frm,val);
  285. smacro procedure setblanklist(frm,val); rplacd(cddr frm,val);
  286. smacro procedure newframe n; list(n,nil,0);
  287. smacro procedure blankp char; numberp car char;
  288. symbolic procedure prindent(x,n);
  289. % Print list x with indentation level n.
  290. if atom x then if vectorp x then prvector(x,n)
  291. else for each c in
  292. (if !*symmetric
  293. then if stringp x then explodes x else explode x
  294. else explode2 x) do putch c
  295. else if quotep x then <<
  296. putch '!';
  297. prindent(cadr x,n+1) >>
  298. else begin
  299. scalar cx;
  300. if 4*n>3*rmar then << %list is too deep for sanity.
  301. overflow 'all;
  302. n:=n/8;
  303. if initialblanks>n then <<
  304. lmar:=lmar-initialblanks+n;
  305. initialblanks:=n >> >>;
  306. stack := (newframe n) . stack;
  307. putch ('lpar . top());
  308. cx:=car x;
  309. prindent(cx,n+1);
  310. if idp cx and not atom cdr x then
  311. cx:=get(cx,'ppformat) else cx:=nil;
  312. if cx=2 and atom cddr x then cx:=nil;
  313. if cx='prog then <<
  314. putch '! ;
  315. prindent(car (x:=cdr x),n+3) >>;
  316. % CX now controls the formatting of what follows:
  317. % nil default action
  318. % <number> first few blanks are non-indenting
  319. % prog display atoms as labels.
  320. x:=cdr x;
  321. scan: if atom x then go to outt;
  322. finishpending(); %about to print a blank.
  323. if cx='prog then <<
  324. putblank();
  325. overflow bufferi; %force format for prog.
  326. if atom car x then << % a label.
  327. lmar:=initialblanks:=max(lmar-6,0);
  328. prindent(car x,n-3); % print the label.
  329. x:=cdr x;
  330. if not atom x and atom car x then go to scan;
  331. if lmar+bn>n then putblank()
  332. else for i:=lmar+bn:n-1 do putch '! ;
  333. if atom x then go to outt>> >>
  334. else if numberp cx then <<
  335. cx:=cx-1;
  336. if cx=0 then cx:=nil;
  337. putch '! >>
  338. else putblank();
  339. prindent(car x,n+3);
  340. x:=cdr x;
  341. go to scan;
  342. outt: if not null x then <<
  343. finishpending();
  344. putblank();
  345. putch '!.;
  346. putch '! ;
  347. prindent(x,n+5) >>;
  348. putch ('rpar . (n-3));
  349. if indenting top()='indent and not null blanklist top() then
  350. overflow car blanklist top()
  351. else endlist top();
  352. stack:=cdr stack
  353. end;
  354. symbolic procedure explodes x;
  355. %dummy function just in case another format is needed.
  356. explode x;
  357. symbolic procedure prvector(x,n);
  358. begin
  359. scalar bound;
  360. bound:=upbv x; % length of the vector.
  361. stack:=(newframe n) . stack;
  362. putch ('lsquare . top());
  363. prindent(getv(x,0),n+3);
  364. for i:=1:bound do <<
  365. putch '!,;
  366. putblank();
  367. prindent(getv(x,i),n+3) >>;
  368. putch('rsquare . (n-3));
  369. endlist top();
  370. stack:=cdr stack
  371. end;
  372. symbolic procedure putblank();
  373. begin
  374. putch top(); %represents a blank character.
  375. setblankcount(top(),blankcount top()+1);
  376. setblanklist(top(),bufferi . blanklist top());
  377. %remember where I was.
  378. indblanks:=indblanks+1
  379. end;
  380. symbolic procedure endlist l;
  381. %Fix up the blanks in a complete list so that they
  382. %will not be turned into indentations.
  383. pendingrpars:=l . pendingrpars;
  384. % When I have printed a ')' I want to mark all of the blanks
  385. % within the parentheses as being unindented, ordinary blank
  386. % characters. It is however possible that I may get a buffer
  387. % overflow while printing a string of )))))))))), and so this
  388. % marking should be delayed until I get round to printing
  389. % a further blank (which will be a candidate for a place to
  390. % split lines). This delay is dealt with by the list
  391. % pendingrpars which holds a list of levels that, when
  392. % convenient, can be tidied up and closed out.
  393. symbolic procedure finishpending();
  394. << for each stackframe in pendingrpars do <<
  395. if indenting stackframe neq 'indent then
  396. for each b in blanklist stackframe do
  397. << rplaca(b,'! ); indblanks:=indblanks-1 >>;
  398. % blanklist of stackframe must be non-nil so that overflow
  399. % will not treat the '(' specially.
  400. setblanklist(stackframe,t) >>;
  401. pendingrpars:=nil >>;
  402. symbolic procedure quotep x;
  403. !*quotes and
  404. not atom x and
  405. car x='quote and
  406. not atom cdr x and
  407. null cddr x;
  408. % property ppformat drives the prettyprinter -
  409. % prog : special for prog only
  410. % 1 : (fn a1
  411. % a2
  412. % ... )
  413. % 2 : (fn a1 a2
  414. % a3
  415. % ... ) ;
  416. put('prog,'ppformat,'prog);
  417. put('lambda,'ppformat,1);
  418. put('lambdaq,'ppformat,1);
  419. put('setq,'ppformat,1);
  420. put('set,'ppformat,1);
  421. put('while,'ppformat,1);
  422. put('t,'ppformat,1);
  423. put('de,'ppformat,2);
  424. put('df,'ppformat,2);
  425. put('dm,'ppformat,2);
  426. put('foreach,'ppformat,4); % (foreach x in y do ...) etc.
  427. % Now for the routines that buffer things on a character by character
  428. % basis, and deal with buffer overflow.
  429. symbolic procedure putch c;
  430. begin
  431. if atom c then rparcount:=0
  432. else if blankp c then << rparcount:=0; go to nocheck >>
  433. else if car c='rpar then <<
  434. rparcount:=rparcount+1;
  435. % format for a long string of rpars is:
  436. % )))) ))) ))) ))) ))) ;
  437. if rparcount>4 then << putch '! ; rparcount:=2 >> >>
  438. else rparcount:=0;
  439. while lmar+bn>=rmar do overflow 'more;
  440. nocheck:
  441. bufferi:=cdr rplacd(bufferi,list c);
  442. bn:=bn+1
  443. end;
  444. symbolic procedure overflow flg;
  445. begin
  446. scalar c,blankstoskip;
  447. %the current buffer holds so much information that it will
  448. %not all fit on a line. try to do something about it.
  449. % flg is one of:
  450. % 'none do not force more indentation
  451. % 'more force one level more indentation
  452. % <a pointer into the buffer>
  453. % prints up to and including that character, which
  454. % should be a blank.
  455. if indblanks=0 and initialblanks>3 and flg='more then <<
  456. initialblanks:=initialblanks-3;
  457. lmar:=lmar-3;
  458. return 'moved!-left >>;
  459. fblank:
  460. if bn=0 then <<
  461. % No blank found - can do no more for now.
  462. % If flg='more I am in trouble and so have to print
  463. % a continuation mark. in the other cases I can just exit.
  464. if not(flg = 'more) then return 'empty;
  465. if atom car buffero then
  466. % continuation mark not needed if last char printed was
  467. % special (e.g. lpar or rpar).
  468. prin2 "%+"; %continuation marker.
  469. terpri();
  470. lmar:=0;
  471. return 'continued >>
  472. else <<
  473. spaces initialblanks;
  474. initialblanks:=0 >>;
  475. buffero:=cdr buffero;
  476. bn:=bn-1;
  477. lmar:=lmar+1;
  478. c:=car buffero;
  479. if atom c then << prin2 c; go to fblank >>
  480. else if blankp c then if not atom blankstoskip then <<
  481. prin2 '! ;
  482. indblanks:=indblanks-1;
  483. % blankstoskip = (stack-frame . skip-count).
  484. if c eq car blankstoskip then <<
  485. rplacd(blankstoskip,cdr blankstoskip-1);
  486. if cdr blankstoskip=0 then blankstoskip:=t >>;
  487. go to fblank >>
  488. else go to blankfound
  489. else if car c='lpar or car c='lsquare then <<
  490. prin2 get(car c,'ppchar);
  491. if flg='none then go to fblank;
  492. % now I want to flag this level for indentation.
  493. c:=cdr c; %the stack frame.
  494. if not null blanklist c then go to fblank;
  495. if depth c>indentlevel then << %new indentation.
  496. % this level has not emitted any blanks yet.
  497. indentlevel:=depth c;
  498. setindenting(c,'indent) >>;
  499. go to fblank >>
  500. else if car c='rpar or car c='rsquare then <<
  501. if cdr c<indentlevel then indentlevel:=cdr c;
  502. prin2 get(car c,'ppchar);
  503. go to fblank >>
  504. else error(0,list(c,"UNKNOWN TAG IN OVERFLOW"));
  505. blankfound:
  506. if eqcar(blanklist c,buffero) then
  507. setblanklist(c,nil);
  508. % at least one entry on blanklist ought to be valid, so if I
  509. % print the last blank I must kill blanklist totally.
  510. indblanks:=indblanks-1;
  511. % check if next level represents new indentation.
  512. if depth c>indentlevel then <<
  513. if flg='none then << %just print an ordinary blank.
  514. prin2 '! ;
  515. go to fblank >>;
  516. % here I increase the indentation level by one.
  517. if blankstoskip then blankstoskip:=nil
  518. else <<
  519. indentlevel:=depth c;
  520. setindenting(c,'indent) >> >>;
  521. %otherwise I was indenting at that level anyway.
  522. if blankcount c>(thin!*-1) then << %long thin list fix-up here.
  523. blankstoskip:=c . ((blankcount c) - 2);
  524. setindenting(c,'thin);
  525. setblankcount(c,1);
  526. indentlevel:=(depth c)-1;
  527. prin2 '! ;
  528. go to fblank >>;
  529. setblankcount(c,(blankcount c)-1);
  530. terpri();
  531. lmar:=initialblanks:=depth c;
  532. if buffero eq flg then return 'to!-flg;
  533. if blankstoskip or not (flg='more) then go to fblank;
  534. % keep going unless call was of type 'more'.
  535. return 'more; %try some more.
  536. end;
  537. put('lpar,'ppchar,'!();
  538. put('lsquare,'ppchar,'![);
  539. put('rpar,'ppchar,'!));
  540. put('rsquare,'ppchar,'!]);
  541. endmodule;
  542. module rprint; % The Standard LISP to REDUCE pretty-printer.
  543. % Author: Anthony C. Hearn.
  544. fluid '(!*n buffp combuff curmark curpos orig pretop pretoprinf rmar);
  545. global '(rprifn!* rterfn!*);
  546. comment RPRIFN!* allows output from RPRINT to be handled differently,
  547. RTERFN!* allows end of lines to be handled differently;
  548. pretop := 'op; pretoprinf := 'oprinf;
  549. symbolic procedure rprint u;
  550. begin integer !*n; scalar buff,buffp,curmark,rmar,x;
  551. curmark := 0;
  552. buff := buffp := list list(0,0);
  553. rmar := linelength nil;
  554. x := get('!*semicol!*,pretop);
  555. !*n := 0;
  556. mprino1(u,list(caar x,cadar x));
  557. prin2ox ";";
  558. omarko curmark;
  559. prinos buff
  560. end;
  561. symbolic procedure rprin1 u;
  562. begin scalar buff,buffp,curmark,x;
  563. curmark := 0;
  564. buff := buffp := list list(0,0);
  565. x := get('!*semicol!*,pretop);
  566. mprino1(u,list(caar x,cadar x));
  567. omarko curmark;
  568. prinos buff
  569. end;
  570. symbolic procedure mprino u; mprino1(u,list(0,0));
  571. symbolic procedure mprino1(u,v);
  572. begin scalar x;
  573. if x := atsoc(u,combuff)
  574. then <<for each y in cdr x do comprox y;
  575. combuff := delete(x,combuff)>>;
  576. if numberp u and u<0 and (x := get('difference,pretop))
  577. then return begin scalar p;
  578. x := car x;
  579. p := (not car x>cadr v) or (not cadr x>car v);
  580. if p then prin2ox "(";
  581. prinox u;
  582. if p then prinox ")"
  583. end
  584. else if atom u then return prinox u
  585. else if not atom car u
  586. then <<curmark := curmark+1;
  587. prin2ox "("; mprino car u; prin2ox ")";
  588. omark list(curmark,3); curmark := curmark-1>>
  589. else if x := get(car u,pretoprinf)
  590. then return begin scalar p;
  591. p := car v>0
  592. and not car u
  593. memq '(block procedure prog quote string);
  594. if p then prin2ox "(";
  595. apply(x,list cdr u);
  596. if p then prin2ox ")"
  597. end
  598. else if x := get(car u,pretop)
  599. then return if car x then inprinox(u,car x,v)
  600. else if cddr u then rederr "Syntax error"
  601. else if null cadr x then inprinox(u,list(100,1),v)
  602. else inprinox(u,list(100,cadr x),v)
  603. else prinox car u;
  604. if rlistatp car u then return rlpri cdr u;
  605. u := cdr u;
  606. if null u then prin2ox "()"
  607. else mprargs(u,v)
  608. end;
  609. symbolic procedure mprargs(u,v);
  610. if null cdr u then <<prin2ox " "; mprino1(car u,list(100,100))>>
  611. else inprinox('!*comma!* . u,list(0,0),v);
  612. symbolic procedure inprinox(u,x,v);
  613. begin scalar p;
  614. p := (not car x>cadr v) or (not cadr x>car v);
  615. if p then prin2ox "("; omark '(m u);
  616. inprino(car u,x,cdr u);
  617. if p then prin2ox ")"; omark '(m d)
  618. end;
  619. symbolic procedure inprino(opr,v,l);
  620. begin scalar flg,x;
  621. curmark := curmark+2;
  622. x := get(opr,pretop);
  623. if x and car x
  624. then <<mprino1(car l,list(car v,0)); l := cdr l; flg := t>>;
  625. while l do
  626. <<if opr eq '!*comma!* then <<prin2ox ","; omarko curmark>>
  627. else if opr eq 'setq
  628. then <<prin2ox " := "; omark list(curmark,1)>>
  629. else if atom car l or not opr eq get!*(caar l,'alt)
  630. then <<omark list(curmark,1); oprino(opr,flg); flg := t>>;
  631. mprino1(car l,list(if null cdr l then 0 else car v,
  632. if null flg then 0 else cadr v));
  633. l := cdr l>>;
  634. curmark := curmark-2
  635. end;
  636. symbolic procedure oprino(opr,b);
  637. (lambda x; if null x
  638. then <<if b then prin2ox " "; prinox opr; prin2ox " ">>
  639. else prin2ox x)
  640. get(opr,'prtch);
  641. symbolic procedure prin2ox u;
  642. <<rplacd(buffp,explode2 u);
  643. while cdr buffp do buffp := cdr buffp>>;
  644. symbolic procedure explode2 u;
  645. % "explodes" atom U without including escape characters;
  646. if numberp u then explode u
  647. else if stringp u then reversip cdr reversip cdr explode u
  648. else explode21 explode u;
  649. symbolic procedure explode21 u;
  650. if null u then nil
  651. else if car u eq '!! then cadr u . explode21 cddr u
  652. else car u . explode21 cdr u;
  653. symbolic procedure prinox u;
  654. <<rplacd(buffp,explode u);
  655. while cdr buffp do buffp := cdr buffp>>;
  656. symbolic procedure omark u;
  657. <<rplacd(buffp,list u); buffp := cdr buffp>>;
  658. symbolic procedure omarko u; omark list(u,0);
  659. symbolic procedure comprox u;
  660. begin scalar x;
  661. if car buffp = '(0 0)
  662. then return <<for each j in u do prin2ox j;
  663. omark '(0 0)>>;
  664. x := car buffp;
  665. rplaca(buffp,list(curmark+1,3));
  666. for each j in u do prin2ox j;
  667. omark x
  668. end;
  669. symbolic procedure rlistatp u;
  670. get(u,'stat) member '(endstat rlis);
  671. symbolic procedure rlpri u;
  672. if null u then nil
  673. else begin
  674. prin2ox " ";
  675. omark '(m u);
  676. inprino('!*comma!*,list(0,0),u);
  677. omark '(m d)
  678. end;
  679. symbolic procedure condox u;
  680. begin scalar x;
  681. omark '(m u);
  682. curmark := curmark+2;
  683. while u do
  684. <<prin2ox "IF "; mprino caar u; omark list(curmark,1);
  685. prin2ox " THEN ";
  686. if cdr u and eqcar(cadar u,'cond)
  687. and not eqcar(car reverse cadar u,'t)
  688. then <<x := t; prin2ox "(">>;
  689. mprino cadar u;
  690. if x then prin2ox ")";
  691. u := cdr u;
  692. if u then <<omarko(curmark-1); prin2ox " ELSE ">>;
  693. if u and null cdr u and caar u eq 't
  694. then <<mprino cadar u; u := nil>>>>;
  695. curmark := curmark-2;
  696. omark '(m d)
  697. end;
  698. put('cond,pretoprinf,'condox);
  699. symbolic procedure blockox u;
  700. begin
  701. omark '(m u);
  702. curmark := curmark+2;
  703. prin2ox "BEGIN ";
  704. if car u then varprx car u;
  705. u := labchk cdr u;
  706. omark list(curmark,if eqcar(car u,'!*label) then 1 else 3);
  707. while u do
  708. <<mprino car u;
  709. if not eqcar(car u,'!*label) and cdr u then prin2ox "; ";
  710. u := cdr u;
  711. if u
  712. then omark list(curmark,
  713. if eqcar(car u,'!*label) then 1 else 3)>>;
  714. omark list(curmark-1,-1);
  715. prin2ox " END";
  716. curmark := curmark-2;
  717. omark '(m d)
  718. end;
  719. symbolic procedure retox u;
  720. begin
  721. omark '(m u);
  722. curmark := curmark+2;
  723. prin2ox "RETURN ";
  724. omark '(m u);
  725. mprino car u;
  726. curmark := curmark-2;
  727. omark '(m d);
  728. omark '(m d)
  729. end;
  730. put('return,pretoprinf,'retox);
  731. % symbolic procedure varprx u;
  732. % mapc(cdr u,function (lambda j;
  733. % <<prin2ox car j;
  734. % prin2ox " ";
  735. % inprino('!*comma!*,list(0,0),cdr j);
  736. % prin2ox "; ";
  737. % omark list(curmark,6)>>));
  738. comment a version for the old parser;
  739. symbolic procedure varprx u;
  740. begin scalar typ;
  741. u := reverse u;
  742. while u do
  743. <<if cdar u eq typ
  744. then <<prin2ox ","; omarko(curmark+1); prinox caar u>>
  745. else <<if typ then <<prin2ox "; "; omark '(m d)>>;
  746. prinox (typ := cdar u);
  747. prin2ox " "; omark '(m u); prinox caar u>>;
  748. u := cdr u>>;
  749. prin2ox "; ";
  750. omark '(m d)
  751. end;
  752. put('block,pretoprinf,'blockox);
  753. symbolic procedure progox u;
  754. blockox(mapcar(reverse car u,function (lambda j; j . 'scalar))
  755. . cdr u);
  756. symbolic procedure labchk u;
  757. begin scalar x;
  758. for each z in u do if atom z
  759. then x := list('!*label,z) . x else x := z . x;
  760. return reversip x
  761. end;
  762. put('prog,pretoprinf,'progox);
  763. symbolic procedure gox u;
  764. <<prin2ox "GO TO "; prinox car u>>;
  765. put('go,pretoprinf,'gox);
  766. symbolic procedure labox u;
  767. <<prinox car u; prin2ox ": ">>;
  768. put('!*label,pretoprinf,'labox);
  769. symbolic procedure quotox u;
  770. if stringp u then prinox u else <<prin2ox "'"; prinsox car u>>;
  771. symbolic procedure prinsox u;
  772. if atom u then prinox u
  773. else <<prin2ox "(";
  774. omark '(m u);
  775. curmark := curmark+1;
  776. while u do <<prinsox car u;
  777. u := cdr u;
  778. if u then <<omark list(curmark,-1);
  779. if atom u
  780. then <<prin2ox " . "; prinsox u; u := nil>>
  781. else prin2ox " ">>>>;
  782. curmark := curmark-1;
  783. omark '(m d);
  784. prin2ox ")">>;
  785. put('quote,pretoprinf,'quotox);
  786. symbolic procedure prognox u;
  787. begin
  788. curmark := curmark+1;
  789. prin2ox "<<";
  790. omark '(m u);
  791. while u do <<mprino car u; u := cdr u;
  792. if u then <<prin2ox "; "; omarko curmark>>>>;
  793. omark '(m d);
  794. prin2ox ">>";
  795. curmark := curmark-1
  796. end;
  797. put('prog2,pretoprinf,'prognox);
  798. put('progn,pretoprinf,'prognox);
  799. symbolic procedure repeatox u;
  800. begin
  801. curmark := curmark+1;
  802. omark '(m u);
  803. prin2ox "REPEAT ";
  804. mprino car u;
  805. prin2ox " UNTIL ";
  806. omark list(curmark,3);
  807. mprino cadr u;
  808. omark '(m d);
  809. curmark := curmark-1
  810. end;
  811. put('repeat,pretoprinf,'repeatox);
  812. symbolic procedure whileox u;
  813. begin
  814. curmark := curmark+1;
  815. omark '(m u);
  816. prin2ox "WHILE ";
  817. mprino car u;
  818. prin2ox " DO ";
  819. omark list(curmark,3);
  820. mprino cadr u;
  821. omark '(m d);
  822. curmark := curmark-1
  823. end;
  824. put('while,pretoprinf,'whileox);
  825. symbolic procedure procox u;
  826. begin
  827. omark '(m u);
  828. curmark := curmark+1;
  829. if cadddr cdr u then <<mprino cadddr cdr u; prin2ox " ">>;
  830. prin2ox "PROCEDURE ";
  831. procox1(car u,cadr u,caddr u)
  832. end;
  833. symbolic procedure procox1(u,v,w);
  834. begin
  835. prinox u;
  836. if v then mprargs(v,list(0,0));
  837. prin2ox "; ";
  838. omark list(curmark,3);
  839. mprino w;
  840. curmark := curmark-1;
  841. omark '(m d)
  842. end;
  843. put('proc,pretoprinf,'procox);
  844. symbolic procedure proceox u;
  845. begin
  846. omark '(m u);
  847. curmark := curmark+1;
  848. if cadr u then <<mprino cadr u; prin2ox " ">>;
  849. if not caddr u eq 'expr then <<mprino caddr u; prin2ox " ">>;
  850. prin2ox "PROCEDURE ";
  851. proceox1(car u,cadddr u,car cddddr u)
  852. end;
  853. symbolic procedure proceox1(u,v,w);
  854. begin
  855. prinox u;
  856. if v
  857. then <<if not atom car v then v:= for each j in v collect car j;
  858. %allows for typing to be included with proc arguments;
  859. mprargs(v,list(0,0))>>;
  860. prin2ox "; ";
  861. omark list(curmark,3);
  862. mprino w;
  863. curmark := curmark -1;
  864. omark '(m d)
  865. end;
  866. put('procedure,pretoprinf,'proceox);
  867. symbolic procedure proceox0(u,v,w,x);
  868. proceox list(u,'symbolic,v,
  869. mapcar(w,function (lambda j; j . 'symbolic)),x);
  870. symbolic procedure deox u;
  871. proceox0(car u,'expr,cadr u,caddr u);
  872. put('de,pretoprinf,'deox);
  873. symbolic procedure dfox u;
  874. proceox0(car u,'fexpr,cadr u,caddr u);
  875. %put('df,pretoprinf,'dfox); %commented out because of confusion with
  876. %differentiation;
  877. symbolic procedure stringox u;
  878. <<prin2ox '!"; prin2ox car u; prin2ox '!">>;
  879. put('string,pretoprinf,'stringox);
  880. symbolic procedure lambdox u;
  881. begin
  882. omark '(m u);
  883. curmark := curmark+1;
  884. procox1('lambda,car u,cadr u)
  885. end;
  886. put('lambda,pretoprinf,'lambdox);
  887. symbolic procedure eachox u;
  888. <<prin2ox "FOR EACH ";
  889. while cdr u do <<mprino car u; prin2ox " "; u := cdr u>>;
  890. mprino car u>>;
  891. put('foreach,pretoprinf,'eachox);
  892. symbolic procedure forox u;
  893. begin
  894. curmark := curmark+1;
  895. omark '(m u);
  896. prin2ox "FOR ";
  897. mprino car u;
  898. prin2ox " := ";
  899. mprino caadr u;
  900. if cadr cadr u neq 1
  901. then <<prin2ox " STEP "; mprino cadr cadr u; prin2ox " UNTIL ">>
  902. else prin2ox ":";
  903. mprino caddr cadr u;
  904. prin2ox " ";
  905. mprino caddr u;
  906. prin2ox " ";
  907. omark list(curmark,3);
  908. mprino cadddr u;
  909. omark '(m d);
  910. curmark := curmark-1
  911. end;
  912. put('for,pretoprinf,'forox);
  913. symbolic procedure forallox u;
  914. begin
  915. curmark := curmark+1;
  916. omark '(m u);
  917. prin2ox "FOR ALL ";
  918. inprino('!*comma!*,list(0,0),car u);
  919. if cadr u
  920. then <<omark list(curmark,3);
  921. prin2ox " SUCH THAT ";
  922. mprino cadr u>>;
  923. prin2ox " ";
  924. omark list(curmark,3);
  925. mprino caddr u;
  926. omark '(m d);
  927. curmark := curmark-1
  928. end;
  929. put('forall,pretoprinf,'forallox);
  930. comment Declarations needed by old parser;
  931. if null get('!*semicol!*,'op)
  932. then <<put('!*semicol!*,'op,'((-1 0)));
  933. put('!*comma!*,'op,'((5 6)))>>;
  934. comment RPRINT MODULE, Part 2;
  935. fluid '(orig curpos);
  936. symbolic procedure prinos u;
  937. begin integer curpos;
  938. scalar orig;
  939. orig := list posn();
  940. curpos := car orig;
  941. prinoy(u,0);
  942. terpri0x()
  943. end;
  944. symbolic procedure prinoy(u,n);
  945. begin scalar x;
  946. if car(x := spaceleft(u,n)) then return prinom(u,n)
  947. else if null cdr x then return if car orig<10 then prinom(u,n)
  948. else <<orig := 9 . cdr orig;
  949. terpri0x();
  950. spaces20x(curpos := 9+cadar u);
  951. prinoy(u,n)>>
  952. else begin
  953. a: u := prinoy(u,n+1);
  954. if null cdr u or caar u<=n then return;
  955. terpri0x();
  956. spaces20x(curpos := car orig+cadar u);
  957. go to a end;
  958. return u
  959. end;
  960. symbolic procedure spaceleft(u,mark);
  961. %U is an expanded buffer of characters delimited by non-atom marks
  962. %of the form: '(M ...) or '(INT INT))
  963. %MARK is an integer;
  964. begin integer n; scalar flg,mflg;
  965. n := rmar - curpos;
  966. u := cdr u; %move over the first mark;
  967. while u and not flg and n>=0 do
  968. <<if atom car u then n := n-1
  969. else if caar u eq 'm then nil
  970. else if mark>=caar u then <<flg := t; u := nil . u>>
  971. else mflg := t;
  972. u := cdr u>>;
  973. return ((n>=0) . mflg)
  974. end;
  975. symbolic procedure prinom(u,mark);
  976. begin integer n; scalar flg,x;
  977. n := curpos;
  978. u := cdr u;
  979. while u and not flg do
  980. <<if atom car u then <<x := prin20x car u; n := n+1>>
  981. else if caar u eq 'm
  982. then if cadar u eq 'u then orig := n . orig
  983. else orig := cdr orig
  984. else if mark>=caar u
  985. and not(x='!, and rmar-n-6>charspace(u,x,mark))
  986. then <<flg := t; u := nil . u>>;
  987. u := cdr u>>;
  988. curpos := n;
  989. if mark=0 and cdr u
  990. then <<terpri0x();
  991. terpri0x();
  992. orig := list 0; curpos := 0; prinoy(u,mark)>>;
  993. %must be a top level constant;
  994. return u
  995. end;
  996. symbolic procedure charspace(u,char,mark);
  997. %determines if there is space until the next character CHAR;
  998. begin integer n;
  999. n := 0;
  1000. while u do
  1001. <<if car u = char then u := list nil
  1002. else if atom car u then n := n+1
  1003. else if car u='(m u) then <<n := 1000; u := list nil>>
  1004. else if numberp caar u and caar u<mark then u := list nil;
  1005. u := cdr u>>;
  1006. return n
  1007. end;
  1008. symbolic procedure spaces20x n;
  1009. %for i := 1:n do prin20x '! ;
  1010. while n>0 do <<prin20x '! ; n := n-1>>;
  1011. symbolic procedure prin2rox u;
  1012. begin integer m,n; scalar x,y;
  1013. m := rmar-12;
  1014. n := rmar-1;
  1015. while u do
  1016. if car u eq '!"
  1017. then <<if not stringspace(cdr u,n-!*n)
  1018. then <<terpri0x(); !*n := 0>>
  1019. else nil;
  1020. prin20x '!";
  1021. u := cdr u;
  1022. while not car u eq '!" do
  1023. <<prin20x car u; u := cdr u; !*n := !*n+1>>;
  1024. prin20x '!";
  1025. u := cdr u;
  1026. !*n := !*n+2;
  1027. x := y := nil>>
  1028. else if atom car u and not(car u eq '! and (!*n=0 or null x
  1029. or cdr u and breakp cadr u or breakp x and not y eq '!!))
  1030. then <<y := x; prin20x(x := car u); !*n := !*n+1;
  1031. u := cdr u;
  1032. if !*n=n or !*n>m and not breakp car u and nospace(u,n-!*n)
  1033. then <<terpri0x(); x := y := nil>> else nil>>
  1034. else u := cdr u
  1035. end;
  1036. symbolic procedure nospace(u,n);
  1037. if n<1 then t
  1038. else if null u then nil
  1039. else if not atom car u then nospace(cdr u,n)
  1040. else if not car u eq '!! and (cadr u eq '! or breakp cadr u)
  1041. then nil
  1042. else nospace(cdr u,n-1);
  1043. symbolic procedure breakp u;
  1044. u member '(!< !> !; !: != !) !+ !- !, !' !");
  1045. symbolic procedure stringspace(u,n);
  1046. if n<1 then nil else if car u eq '!" then t
  1047. else stringspace(cdr u,n-1);
  1048. comment Some interfaces needed;
  1049. symbolic procedure prin20x u;
  1050. if rprifn!* then apply(rprifn!*,list u) else prin2 u;
  1051. symbolic procedure terpri0x;
  1052. if rterfn!* then apply(rterfn!*,nil) else terpri();
  1053. endmodule;
  1054. end;