rrprint.red 81 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329
  1. module rrprint; % Output interface for Run-REDUCE (a JavaFX GUI for REDUCE)
  2. % This file is a version of "tmprint.red" modified by Francis Wright.
  3. % It outputs algebraic-mode mathematics using LaTeX-like markup.
  4. % I (FJW) think the history of this file is as follows, but please see
  5. % "fmprint.red" and "tmprint.red" for further details. It began life
  6. % as "fmprint.red" by Herbert Melenk, using ideas from "maprin.red"
  7. % (by Anthony Hearn and Arthur Norman), which produced TeX-like output
  8. % to drive a REDUCE GUI for an early version of Microsoft Windows and
  9. % made some direct references to characters in the Microsoft Windows
  10. % Symbol font.
  11. % It was then developed into "tmprint.red" by Andrey Grozin and
  12. % several other authors (see below) to drive the TeXmacs GUI and
  13. % developed further by Arthur Norman to drive the CSL REDUCE GUI. I
  14. % now propose to use it to drive my own GUI, so I will remove the code
  15. % specific to TeXmacs and CSL whilst aiming not to break the LaTeX
  16. % output!
  17. % The code at the end of this file is based on code from
  18. % "redfront.red" and supports colouring of non-typeset algebraic-mode
  19. % mathematical output.
  20. % Francis Wright, initiated September 2020.
  21. % ----------------------------------------------------------------------
  22. % $Id: tmprint.red 5408 2020-09-25 12:22:46Z eschruefer $
  23. % ----------------------------------------------------------------------
  24. % Copyright (c) 1993-1994, 1999, 2003-2005 A. Dolzmann, T. Hearn, A.
  25. % Grozin, H. Melenk, W. Neun, A. Norman, A. Seidl, and T. Sturm
  26. %
  27. % Permission is hereby granted, free of charge, to any person
  28. % obtaining a copy of this software and associated documentation files
  29. % (the "Software"), to deal in the Software without restriction,
  30. % including without limitation the rights to use, copy, modify, merge,
  31. % publish, distribute, sublicense, and/or sell copies of the Software,
  32. % and to permit persons to whom the Software is furnished to do so,
  33. % subject to the following conditions:
  34. %
  35. % The above copyright notice and this permission notice shall be
  36. % included in all copies or substantial portions of the Software.
  37. %
  38. % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  39. % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  40. % MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  41. % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  42. % BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  43. % ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  44. % CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  45. % SOFTWARE.
  46. % ----------------------------------------------------------------------
  47. % Switches:
  48. %
  49. % on fancy enable algebraic output processing.
  50. % (Defaults to on when the package is loaded.)
  51. %
  52. % Properties:
  53. %
  54. % fancy!-prifn print function for an operator.
  55. %
  56. % fancy!-pprifn print function for an operator including current
  57. % operator precedence for infix printing.
  58. %
  59. % fancy!-flatprifn print function for objects which require
  60. % special printing if prefix operator form
  61. % would have been used, e.g. matrix, list.
  62. %
  63. % fancy!-prtch string for infix printing of an operator
  64. %
  65. % fancy!-special!-symbol print expression for a non-indexed item
  66. % string with TeX expression e.g. "\alpha " or a
  67. % number referring to ASCII symbol code (deprecated).
  68. %
  69. % fancy!-infix!-symbol special symbol for an infix operator.
  70. %
  71. % fancy!-functionsymbol special symbol for a (prefix) function.
  72. %
  73. % fancy!-symbol!-length the number of horizontal units needed for
  74. % a special symbol. A standard character has
  75. % 2 units, which is the default.
  76. % To enable typeset algebraic-mode output execute
  77. % rrprint 'fancy!-output;
  78. create!-package('(rrprint), nil);
  79. fluid '(
  80. !*list
  81. !*nat
  82. !*nosplit
  83. !*ratpri
  84. !*revpri
  85. curline!*
  86. overflowed!*
  87. p!*!*
  88. testing!-width!*
  89. tablevel!*
  90. sumlevel!*
  91. outputhandler!*
  92. outputhandler!-stack!*
  93. posn!*
  94. long!*
  95. obrkp!* % outside-brackets-p
  96. );
  97. global '(ofl!*);
  98. %
  99. % The interaction between the code here and a variety of other REDUCE flags
  100. % that set output options is possibly delicate and probably often broken.
  101. % As well as "list" the code here needs review with regard to options
  102. % such as "fort" for generating other formats of output.
  103. %
  104. switch list,ratpri,revpri,nosplit;
  105. % Temp experiment while investigating a possible fix for an interaction with
  106. % "on list". Well in fact "on/off acn" can provide a general guard for
  107. % some incremental changes being made here. But evenually this switch
  108. % will be retired. ACN March 2011
  109. switch acn;
  110. on acn; % FJW Seems better!
  111. % Global variables initialized in this section.
  112. fluid '(
  113. fancy!-switch!-on!*
  114. fancy!-switch!-off!*
  115. !*fancy!-mode
  116. fancy!-pos!*
  117. fancy!-line!*
  118. fancy!-page!*
  119. fancy!-bstack!*
  120. !*fancy!-lower % control of conversion to lower case
  121. );
  122. fluid '(fancy!-texpos); %FJW not really used?
  123. fancy!-switch!-on!* := int2id 16$
  124. fancy!-switch!-off!* := int2id 17$
  125. !*fancy!-lower := nil;
  126. % global '(fancy_lower_digits); % not currently used
  127. % share fancy_lower_digits; % T, NIL or ALL.
  128. % if null fancy_lower_digits then fancy_lower_digits:=t;
  129. global '(fancy_print_df);
  130. share fancy_print_df; % PARTIAL, TOTAL, INDEXED.
  131. if null fancy_print_df then fancy_print_df := 'partial;
  132. switch fancy;
  133. % put('fancy,'simpfg,
  134. % '((t (fmp!-switch t))
  135. % (nil (fmp!-switch nil)) ));
  136. % symbolic procedure fmp!-switch mode;
  137. % if mode then
  138. % <<if outputhandler!* neq 'fancy!-output then
  139. % <<outputhandler!-stack!* :=
  140. % outputhandler!* . outputhandler!-stack!*;
  141. % outputhandler!* := 'fancy!-output;
  142. % >>;
  143. % % !*fancy := t %FJW Handled by switch module
  144. % >>
  145. % else
  146. % <<if outputhandler!* = 'fancy!-output then
  147. % <<outputhandler!* := car outputhandler!-stack!*;
  148. % outputhandler!-stack!* := cdr outputhandler!-stack!*;
  149. % % !*fancy := nil %FJW Handled by switch module
  150. % >>
  151. % else
  152. % << % !*fancy := nil; %FJW Handled by switch module
  153. % rederr "FANCY is not current output handler" >>
  154. % % ACN feels that raising an error on an attempt to switch off an option
  155. % % in the case that the option is already disabled is a bit harsh.
  156. % >>;
  157. % fluid '(lispsystem!*);
  158. symbolic procedure fancy!-out!-item(it);
  159. % Called by fancy!-flush only.
  160. if atom it then prin2 it else
  161. if eqcar(it,'ascii) then prin2 int2id cadr it else
  162. if eqcar(it,'tab) then
  163. for i:=1:cdr it do prin2 " "
  164. else
  165. if eqcar(it,'bkt) then
  166. % begin scalar m,b,l; integer n;
  167. % m:=cadr it; b:=caddr it; n:=cadddr it;
  168. begin scalar b, l;
  169. b := caddr it;
  170. l := b member '( !( !{ );
  171. % if m then prin2 if l then "\left" else "\right"
  172. % else
  173. % if n> 0 then
  174. % <<prin2 if n=1 then "\big" else if n=2 then "\Big" else
  175. % if n=3 then "\bigg" else "\Bigg";
  176. % prin2 if l then "l" else "r";
  177. % >>;
  178. if l then prin2 "\left" else prin2 "\right";
  179. if b member '(!{ !}) then prin2 "\";
  180. prin2 b;
  181. end
  182. else <<
  183. % Finish processing as fancy!-flush() would have done to avoid
  184. % hanging the GUI:
  185. fancy!-out!-trailer();
  186. set!-fancymode nil;
  187. rederr {"unknown print item", it};
  188. >>;
  189. symbolic procedure set!-fancymode bool;
  190. if bool neq !*fancy!-mode then
  191. <<!*fancy!-mode:=bool;
  192. fancy!-pos!* :=0;
  193. fancy!-page!*:=nil;
  194. fancy!-line!*:=nil;
  195. overflowed!* := nil;
  196. % new: with tab
  197. fancy!-line!*:= '((tab . 1));
  198. fancy!-pos!* := 10;
  199. sumlevel!* := tablevel!* := 1;
  200. >>;
  201. symbolic procedure fancy!-output(mode,l);
  202. % Interface routine.
  203. %
  204. % ACN does not understand the "posn!*>2" filter here. To avoid some
  205. % bad consequences it was having for my new screen/log-file stuff it now only
  206. % applies in maprin mode not terpri mode, but it would be nice if somebody
  207. % could explain to me just why it was needed in the first case at all. I can
  208. % imagine that if "on fancy" is acticated when there is still some partly-
  209. % printed expression (in non-fancy mode) buffered up the terpri!* to flush it
  210. % may need special care. But if that is what it is about I would suggest that
  211. % treatment be applied in fmp!-switch not here...
  212. %
  213. if ofl!* or (mode='maprin and posn!*>2) or not !*nat then <<
  214. % not terminal handler or current output line non-empty.
  215. if mode = 'maprin then maprin l
  216. else terpri!*(l) >> where outputhandler!* = nil
  217. else
  218. <<set!-fancymode t;
  219. if mode = 'maprin then
  220. fancy!-maprin0 l
  221. else if mode = 'assgnpri then <<
  222. fancy!-assgnpri l;
  223. fancy!-flush() >>
  224. else
  225. fancy!-flush() >>;
  226. % fancy!-assgnpri checks whether a special printing function is defined
  227. % and calls it
  228. symbolic procedure fancy!-assgnpri u;
  229. % E.g. a := b := c := mat(()) -> u = ((mat (0)) (a b c) only)
  230. % FJW But this seems to be called when there is no assignment! Why?
  231. begin scalar x,y;
  232. x := getrtype car u; % e.g. matrix; tag = mat
  233. y := get(get(x,'tag),'fancy!-assgnpri);
  234. return if y then apply1(y,u) else fancy!-maprin0 car u
  235. end;
  236. symbolic procedure fancy!-assgnpri!-matrix u; % FJW
  237. % E.g. a := b := c := mat(()) -> u = ((mat (0)) (a b c) only)
  238. % Plain printing displays this as "a := [0]", ignoring b and c!
  239. begin scalar lhvars := cadr u;
  240. if lhvars then <<
  241. % if cdr lhvars then
  242. % fancy!-inprint('setq, get('setq,'infix), lhvars)
  243. % else
  244. fancy!-maprin0 car lhvars;
  245. fancy!-oprin 'setq;
  246. >>;
  247. return fancy!-maprin0 car u
  248. end;
  249. put('mat, 'fancy!-assgnpri, 'fancy!-assgnpri!-matrix); % FJW
  250. symbolic procedure fancy!-out!-header();
  251. <<
  252. if posn()>0 then terpri();
  253. prin2 fancy!-switch!-on!*;
  254. >>;
  255. symbolic procedure fancy!-out!-trailer();
  256. prin2 fancy!-switch!-off!*;
  257. symbolic procedure fancy!-flush();
  258. %FJW Modified to avoid leading spaces and precede a leading + or -
  259. % on a follow-on line with an invisible term using an empty text
  260. % box (see the LaTeX book, page 48, but KaTeX does not support \mbox).
  261. (begin scalar not_first_line;
  262. fancy!-terpri!* t;
  263. for each line in reverse fancy!-page!* do
  264. if line and not eqcar(car line,'tab) then <<
  265. fancy!-out!-header();
  266. % for each it in reverse line do fancy!-out!-item it;
  267. line := reverse line;
  268. while eqcar(car line, 'tab) do line := cdr line;
  269. if not_first_line and car line memq '(!+ !-) then fancy!-out!-item "\mathrm{}";
  270. for each it in line do fancy!-out!-item it;
  271. fancy!-out!-trailer();
  272. not_first_line := t
  273. >>;
  274. set!-fancymode nil;
  275. end) where !*lower = nil;
  276. %---------------- primitives -----------------------------------
  277. symbolic procedure fancy!-special!-symbol(u,n);
  278. if numberp u then
  279. <<fancy!-prin2!*("\symb{",n);
  280. fancy!-prin2!*(u,0);
  281. fancy!-prin2!*("}",0);
  282. >>
  283. else fancy!-prin2!*(u,n);
  284. symbolic procedure fancy!-prin2 u;
  285. fancy!-prin2!*(u,nil);
  286. % fancy!-prin2!* maintains a variable fancy!-pos!* which is compared
  287. % against (multiples of) linelength. This is not incremented when a
  288. % TeX keyword is inserted. That is probably reasonable for some
  289. % words such as "\mathrm", but seems odd for "\alpha".
  290. % It is incremented for "{" and "}" and also for "^" and "_". That also
  291. % seems deeply wrong. And to the extent that it is used to estimate the
  292. % width of the current part-line it is certainly oblivious to the
  293. % different metrics that "\,", "i", "m", and "\ldots" might have, where
  294. % those are rather more than minor.
  295. %
  296. % So even if one assumes that the units in which linelength() returns
  297. % its value are relevant in TeX output (they probably are at least
  298. % roughly, except that the idea of users altering linelength and getting
  299. % different behaviour seems pretty scary to me, and the potential confusion
  300. % between desired width of mathematical display and the number of character
  301. % positions that the TeX material should fit with seems messy) the calculation
  302. % done here is a bit of a mess.
  303. % for each x in '(
  304. % !\sqrt !\equiv !\alpha !\beta
  305. % !\gamma !\delta !\varepsilon !\zeta
  306. % !\eta !\theta !\iota !\varkappa
  307. % !\lambda !\mu !\nu !\xi
  308. % !\pi !\rho !\sigma !\tau
  309. % !\upsilon !\phi !\chi !\psi
  310. % !\omega !\mathit!{a!} !\mathit!{b!} !\chi! % Trailing space
  311. % !\delta! !\mathit!{e!} !\phi! !\gamma! %
  312. % !\mathit!{h!} !\mathit!{i!} !\vartheta !\kappa! %
  313. % !\lambda! !\mathit!{m!} !\mathit!{n!} !\mathit!{o!}
  314. % !\pi! !\theta! !\mathit!{r!} !\sigma! %
  315. % !\tau! !\upsilon! !\omega! !\xi! %
  316. % !\psi! !\mathit!{z!} !\varphi! !\pound\ )
  317. % do put(x, 'fancy!-symbol!-length, 1);
  318. put('!\not, 'fancy!-symbol!-length, 0);
  319. % FJW fancy!-prin2!* should do *all* (virtual) output and record
  320. % position on the (virtual) line. It should not do much else!
  321. symbolic procedure fancy!-prin2!*(u,n);
  322. % Print (internally) u. If n is a number then it is the width (in characters) of u.
  323. if numberp n then << % width provided
  324. fancy!-pos!* := fancy!-pos!* + n;
  325. if fancy!-pos!* > 2*(linelength nil + 1) then overflowed!* := t; % FJW Why +1?
  326. fancy!-line!* := u . fancy!-line!* >>
  327. else % look up the width
  328. if atom u and eqcar(explode2 u,'!\) then <<
  329. n := (idp u and get(u, 'fancy!-symbol!-length)) or
  330. (stringp u and get(intern u, 'fancy!-symbol!-length)) or 2;
  331. fancy!-pos!* := fancy!-pos!* + n;
  332. if fancy!-pos!* > 2*(linelength nil + 1) then overflowed!* := t;
  333. fancy!-line!* := u . fancy!-line!* >>
  334. else if numberp u then
  335. if testing!-width!* then <<
  336. %FJW This is a version of the block below specialised for numbers
  337. %FJW and intended to avoid specifying the font style.
  338. u := explode u;
  339. for each x in u do fancy!-line!* := x . fancy!-line!*;
  340. fancy!-pos!* := fancy!-pos!* + if numberp n then n else 2*length u;
  341. if fancy!-pos!* > 2*(linelength nil + 1) then overflowed!* := t;
  342. >>
  343. else fancy!-prin2number u
  344. else
  345. (begin scalar str,id; integer l;
  346. str := stringp u; id := idp u and not digit u; long!*:=nil;
  347. u:= if atom u then <<
  348. if !*fancy!-lower then explode2lc u
  349. else explode2 u >>
  350. else {u};
  351. if cdr u then long!*:=t; %FJW identifier longer than 1 character
  352. if car u = '!\ then long!*:=nil;
  353. l := if numberp n then n else 2*length u;
  354. % if id and not numberp n then
  355. % % Process implicit subscripts: digits within an identifier or
  356. % % digits or a single letter after an underscore:
  357. % u:=fancy!-lower!-digits(fancy!-esc u); % SHOULD NO LONGER BE USED!
  358. if long!* then
  359. fancy!-line!* := '!\mathit!{ . fancy!-line!*; %FJW '!\mathrm!{ . fancy!-line!*;
  360. for each x in u do
  361. <<if str and (x = blank or x = '!_)
  362. then fancy!-line!* := '!\ . fancy!-line!*;
  363. fancy!-line!* :=
  364. (if id and !*fancy!-lower
  365. then red!-char!-downcase x else x) . fancy!-line!*;
  366. >>;
  367. if long!* then fancy!-line!* := '!} . fancy!-line!*;
  368. fancy!-pos!* := fancy!-pos!* + l;
  369. if fancy!-pos!* > 2 * (linelength nil +1 ) then overflowed!*:=t;
  370. end) where !*lower = !*lower;
  371. symbolic procedure fancy!-last!-symbol();
  372. if fancy!-line!* then car fancy!-line!*;
  373. symbolic procedure fancy!-prin2number u;
  374. % we print a number eventually causing a line break
  375. % for very big numbers.
  376. if testing!-width!* then fancy!-prin2!*(u,t) else
  377. fancy!-prin2number1 (if atom u then explode2 u else u);
  378. symbolic procedure fancy!-prin2number1 u;
  379. begin integer c,ll;
  380. ll := 2 * (linelength nil +1 );
  381. while u do
  382. <<c:=c+1;
  383. if c>10 and fancy!-pos!* > ll then fancy!-terpri!*(t);
  384. fancy!-prin2!*(car u,2); u:=cdr u;
  385. >>;
  386. end;
  387. symbolic procedure fancy!-terpri!* u;
  388. <<
  389. if fancy!-line!* then
  390. fancy!-page!* := fancy!-line!* . fancy!-page!*;
  391. fancy!-pos!* := tablevel!* * 10;
  392. fancy!-line!*:= {'tab . tablevel!*};
  393. overflowed!* := nil
  394. >>;
  395. % Moved to alg/general.red so that other modules could use it when
  396. % implementing their own custom printing.
  397. %
  398. %symbolic macro procedure fancy!-level u;
  399. % % unwind-protect for special output functions.
  400. % {'prog,'(pos tpos fl w),
  401. % '(setq pos fancy!-pos!*),
  402. % '(setq tpos fancy!-texpos),
  403. % '(setq fl fancy!-line!*),
  404. % {'setq,'w,cadr u},
  405. % '(cond ((eq w 'failed)
  406. % (setq fancy!-line!* fl)
  407. % (setq fancy!-texpos tpos)
  408. % (setq fancy!-pos!* pos))),
  409. % '(return w)};
  410. % symbolic procedure fancy!-begin();
  411. % % collect current status of fancy output. Return as a list
  412. % % for later recovery.
  413. % {fancy!-pos!*,fancy!-line!*};
  414. % symbolic procedure fancy!-end(r,s);
  415. % % terminates a fancy print sequence. Eventually resets
  416. % % the output status from status record <s> if the result <r>
  417. % % signals an overflow.
  418. % <<if r='failed then
  419. % <<fancy!-line!*:=car s; fancy!-pos!*:=cadr s>>;
  420. % r>>;
  421. symbolic procedure fancy!-mode u;
  422. % Get the value of the shared variable fancy_print_df or
  423. % fancy_lower_digits.
  424. begin scalar m;
  425. m:= lispeval u;
  426. if eqcar(m,'!*sq) then m:=reval m;
  427. return m;
  428. end;
  429. %---------------- central formula converter --------------------
  430. symbolic procedure fancy!-maprin0 u;
  431. %% if not overflowed!* then
  432. fancy!-maprint(u,0) where !*lower=nil;
  433. symbolic procedure fancy!-maprint(l,p!*!*);
  434. % Print expression l at bracket level p!*!* without terminating
  435. % print line. Special cases are handled by:
  436. % pprifn: a print function that includes bracket level as 2nd arg.
  437. % prifn: a print function with one argument.
  438. (begin scalar p,x,w,pos,fl;
  439. p := p!*!*; % p!*!* needed for (expt a (quotient ...)) case.
  440. if null l then return nil;
  441. if atom l then return fancy!-maprint!-atom(l,p);
  442. pos := fancy!-pos!*; fl := fancy!-line!*;
  443. if not atom car l then return fancy!-maprint(car l,p);
  444. l := fancy!-convert(l,nil); % Convert e^x to exp(x) if x is long.
  445. if (x:=get(car l,'fancy!-reform)) then
  446. return fancy!-maprint(apply1(x,l),p);
  447. if ((x := get(car l,'fancy!-pprifn)) and
  448. not(apply2(x,l,p) eq 'failed))
  449. or ((x := get(car l,'fancy!-prifn)) and
  450. not(apply1(x,l) eq 'failed))
  451. or (get(car l,'print!-format)
  452. and fancy!-print!-format(l,p) neq 'failed)
  453. then return nil;
  454. if testing!-width!* and overflowed!*
  455. or w='failed then return fancy!-fail(pos,fl);
  456. % eventually convert expression to a different form
  457. % for printing.
  458. l := fancy!-convert(l,'infix); % Convert e^x to exp(x).
  459. % printing operators with integer argument in index form.
  460. if flagp(car l,'print!-indexed) then
  461. << fancy!-prefix!-operator l;
  462. w := fancy!-print!-indexlist cdr l
  463. >>
  464. else if x := get(car l,'infix) then
  465. << p := not(x>p);
  466. w:= if p then fancy!-in!-brackets(
  467. {'fancy!-inprint,mkquote car l,x,mkquote cdr l},
  468. '!(,'!))
  469. else
  470. fancy!-inprint(car l,x,cdr l);
  471. >>
  472. else if x:= get(car l,'fancy!-flatprifn) then
  473. w:=apply(x,{l})
  474. else
  475. <<
  476. fancy!-prefix!-operator l;
  477. obrkp!* := nil;
  478. if w neq 'failed then
  479. w:=fancy!-print!-function!-arguments cdr l;
  480. >>;
  481. return if testing!-width!* and overflowed!*
  482. or w='failed then fancy!-fail(pos,fl) else nil;
  483. end ) where obrkp!*=obrkp!*;
  484. symbolic procedure fancy!-convert(l,m);
  485. % Convert e^x to exp(x) if appropriate.
  486. if eqcar(l,'expt) and cadr l= 'e and
  487. ( m='infix or treesizep(l,20) )
  488. then {'exp,caddr l}
  489. else l;
  490. symbolic procedure fancy!-print!-function!-arguments u;
  491. % u is a function argument list.
  492. fancy!-in!-brackets(
  493. u and {'fancy!-inprint, mkquote '!*comma!*, 0, mkquote u},
  494. '!(,'!));
  495. symbolic procedure fancy!-maprint!-atom(l,p);
  496. % This should be where any atomic entity provided by the user gets
  497. % treated. The "ordinarily special" cases are
  498. % (a) Things like the names "alpha", "beta", "geq", "partial-df" and
  499. % a whole bunch more that have a fancy!-special!-symbol property
  500. % indicating that they stand for some special character.
  501. % (b) vectors, which get displayed as eg [1,2,3,4]
  502. % (c) negative numbers in cases where they should be rendered in
  503. % parentheses to avoid ambiguity in the output.
  504. % In the original code here all other cases where merely delegated to
  505. % fancy!-prin2!*.
  506. %
  507. % There are however some "less ordinary" special cases that arise when
  508. % material from the user clashes with TeX. I am at present aware of
  509. % five cases of oddity:
  510. % (1) Strings: If the user puts a string in the input it ought to end
  511. % up rendered literally come what may. At present it tends
  512. % to get transcribed to the TeX stream unaltered, and if the
  513. % string has TeX special characters in it the result can be
  514. % odd!
  515. % (2) Names with special characters within. For instance "abc!%def" leads
  516. % to TeX that says "\mathrm{abc%def}" and the "%" there is
  517. % treated as a comment marker, leading to disaster.
  518. % (3) Names that alias a TeX directive. Eg "on revpri; (1+!\big)^3;". This
  519. % case can include explicit cases that could be held to
  520. % be deliberate such as !\alpha, but the fancy!-special!-symbol
  521. % scheme ought to make that unnecessary.
  522. % (4) Names (or strings) containing characters outside the LaTeX fonts that
  523. % are used by default. Mostly these will be special LaTeX
  524. % control characters, but e.g. if a user could get a "pounds
  525. % sterling" character into a name...
  526. % (5) All the follow-on joys that go beyond just (4) and correspond to
  527. % "Internationalisation"!
  528. %
  529. fancy!-level
  530. begin scalar x;
  531. if (x:=get(l,'fancy!-special!-symbol)) then
  532. fancy!-special!-symbol(x, get(l,'fancy!-symbol!-length) or 2)
  533. else if vectorp l then <<
  534. fancy!-prin2!*("[",0);
  535. l:=for i:=0:upbv l collect getv(l,i);
  536. x:=fancy!-inprint(",",0,l);
  537. fancy!-prin2!*("]",0);
  538. return x >>
  539. %FJW Output strings as text rather than maths:
  540. %FJW The result looks OK!
  541. %FJW fancy!-tex!-character adds a character, escaped or replaced
  542. % as necessary, to fancy!-line!*.
  543. else if stringp l then <<
  544. fancy!-line!* := '!\text!{ . fancy!-line!*;
  545. for each c in explode2 l do fancy!-tex!-character c;
  546. fancy!-line!* := '!} . fancy!-line!* >>
  547. else if idp l then fancy!-maprint!-identifier l
  548. else if not numberp l or (not (l<0) or p<=get('minus,'infix))
  549. then fancy!-prin2!*(l,'index)
  550. else fancy!-in!-brackets({'fancy!-prin2!*,mkquote l,t}, '!(,'!));
  551. return (if testing!-width!* and overflowed!* then 'failed else nil);
  552. end;
  553. symbolic procedure fancy!-maprint!-identifier ident;
  554. %FJW New procedure, 09/10/2020
  555. % ident -> ident, body123 -> body_{123}, body_123 -> body_{123},
  556. % body_k -> body_k, body_alpha -> body_{\alpha}.
  557. % Only the last _ introduces a subscript, and only if it is, or
  558. % translates to, a digit sequence or a single character.
  559. % Both body and subscript in body_subscript are processed for
  560. % special symbols, e.g. beta -> \beta, and TeX special characters
  561. % (#$%&~_\{}}) are escaped, e.g. # -> \#.
  562. % Special case: body_bar -> \bar{body} for a single-character body
  563. % or \overline{body} for a multi-character body. This form can be
  564. % followed by digits or _k, which is displayed as a subscript.
  565. begin scalar chars, subscript, body, subscript_symbol, body_symbol, digits, bar;
  566. ident := explode2 ident;
  567. if null cdr ident then <<
  568. % A single-character identifier:
  569. ident := car ident;
  570. if liter ident then fancy!-prin2!*(ident, 1)
  571. else <<
  572. fancy!-prin2!*('!\mathit!{, 0);
  573. fancy!-tex!-character ident;
  574. fancy!-prin2!*('!}, 0)
  575. >>;
  576. return
  577. >>;
  578. % Search ident backwards for digits:
  579. chars := reverse ident;
  580. % Collect trailing digits, which take precedence over _:
  581. while chars and digit car chars do <<
  582. digits := car chars . digits;
  583. chars := cdr chars
  584. >>;
  585. if null digits then
  586. % Search ident backwards for _:
  587. while chars and not (car chars eq '!_) do <<
  588. subscript := car chars . subscript;
  589. chars := cdr chars
  590. >>;
  591. % Skip next char if it is _:
  592. if eqcar(chars, '!_) then chars := cdr chars;
  593. if subscript then
  594. if (bar := subscript = '(b a r)) or
  595. not((subscript_symbol := get(intern compress subscript, 'fancy!-special!-symbol))
  596. or null cdr subscript) then subscript := nil;
  597. % Look again for _bar:
  598. if (digits or subscript) and length chars > 4 and
  599. car chars eq 'r and cadr chars eq 'a and caddr chars eq 'b and cadddr chars eq '!_ then <<
  600. bar := t;
  601. chars := cddddr chars
  602. >>;
  603. % Retrieve identifier body:
  604. body := reversip chars;
  605. if body and (digits or subscript or bar) then <<
  606. % If subscript is bar then output \bar{body} after processing.
  607. % Otherwise, if digits then output body_{digits} after processing,
  608. % else subscript is, or translates to, a single character,
  609. % so output body_{subscript} after processing.
  610. body_symbol := get(intern compress body, 'fancy!-special!-symbol);
  611. if bar then <<
  612. if body_symbol or null cdr body then
  613. fancy!-prin2!*('!\bar!{, 0)
  614. else
  615. fancy!-prin2!*('!\overline!{, 0)
  616. >>;
  617. if body_symbol then
  618. fancy!-prin2!*(body_symbol, 1)
  619. else <<
  620. fancy!-prin2!*('!\mathit!{, 0);
  621. for each c in body do fancy!-tex!-character c;
  622. fancy!-prin2!*('!}, 0)
  623. >>;
  624. if bar then fancy!-prin2!*('!}, 0);
  625. if digits then <<
  626. fancy!-prin2!*('!_!{, 0);
  627. for each c in digits do fancy!-prin2!*(c, 1);
  628. fancy!-prin2!*('!}, 0)
  629. >> else if subscript then <<
  630. fancy!-prin2!*('!_, 0);
  631. if subscript_symbol then
  632. fancy!-prin2!*(subscript_symbol, 1)
  633. else
  634. fancy!-tex!-character car subscript
  635. >>;
  636. return
  637. >>;
  638. % No subscript:
  639. fancy!-prin2!*('!\mathit!{, 0);
  640. for each c in ident do fancy!-tex!-character c;
  641. fancy!-prin2!*('!}, 0);
  642. end;
  643. fluid '(pound1!* pound2!*);
  644. % Pounds signs are HORRID! Well all sorts of characters that are not
  645. % in the original 96-char ASCII set are horrid, but pounds signs are
  646. % present on an UK keyboard and that make things hurt for me! I think
  647. % that pound1!* is WRONG now if one gets input in utf-8 and it being
  648. % here would mess up on a unicode system. But I will still leave it for
  649. % at least a while!
  650. pound1!* := int2id 0x9c; % In code page 850 (ie DOS style)
  651. pound2!* := int2id 0xa3; % Unicode
  652. % I will force blank and tab to be declared and set here since there
  653. % are signs that in PSL they might not be!
  654. global '(blank tab);
  655. blank := '! ;
  656. tab := '! ;
  657. symbolic procedure fancy!-tex!-character c;
  658. % FJW Output a single (inert) character to the (virtual) line,
  659. % handling special (active) TeX characters appropriately.
  660. <<
  661. fancy!-pos!* := fancy!-pos!* #+ 2;
  662. fancy!-line!* :=
  663. if c memq '(!# !$ !% !& !_ !{ !}) then c . '!\ . fancy!-line!*
  664. else if c eq '!~ then '!\text!{!\textasciitilde!} . fancy!-line!*
  665. else if c eq '!^ then '!\text!{!\textasciicircum!} . fancy!-line!*
  666. else if c eq '!\ then '!\text!{!\textbackslash!} . fancy!-line!*
  667. else if c eq blank then '!~ . fancy!-line!*
  668. else if c eq tab then <<
  669. fancy!-pos!* := fancy!-pos!* #+ 2;
  670. '!~ . '!~ . fancy!-line!* >>
  671. else if c eq !$eol!$ then '!\!$eol!\!$ . fancy!-line!*
  672. else if c eq pound1!* or c eq pound2!* then '!{!\pound!} . fancy!-line!*
  673. else c . fancy!-line!*;
  674. >>;
  675. symbolic procedure fancy!-print!-indexlist l;
  676. fancy!-print!-indexlist1(l, '!_, '!,);
  677. symbolic procedure fancy!-print!-indexlist1(l,op,sep);
  678. % print index or exponent lists, with or without separator.
  679. fancy!-level
  680. begin scalar w,testing!-width!*,obrkp!*;
  681. testing!-width!* :=t;
  682. fancy!-prin2!*(op,0);
  683. fancy!-prin2!*('!{,0);
  684. if null l then w:=nil
  685. else w:=fancy!-inprint(sep or 'times,0,l);
  686. fancy!-prin2!*("}",0);
  687. return w;
  688. end;
  689. symbolic procedure fancy!-print!-one!-index i;
  690. fancy!-level
  691. begin scalar w,testing!-width!*,obrkp!*;
  692. testing!-width!* :=t;
  693. fancy!-prin2!*('!_,0);
  694. fancy!-prin2!*('!{,0);
  695. w:=fancy!-inprint('times,0,{i});
  696. fancy!-prin2!*("}",0);
  697. return w;
  698. end;
  699. symbolic procedure fancy!-in!-brackets(u,l,r);
  700. % put form into brackets (round, curly, ...).
  701. % u: form to be evaluated,
  702. % l,r: left and right brackets to be inserted.
  703. fancy!-level
  704. (begin scalar fp,w,r1,r2,rec;
  705. rec := {0};
  706. fancy!-bstack!* := rec . fancy!-bstack!*;
  707. fancy!-adjust!-bkt!-levels fancy!-bstack!*;
  708. fp := length fancy!-page!*;
  709. fancy!-prin2!*(r1 := 'bkt.nil.l.rec, 2);
  710. % E.g. r1 = (bkt nil !( 0)
  711. w := eval u;
  712. fancy!-prin2!*(r2 := 'bkt.nil.r.rec, 2);
  713. % E.g. r2 = (bkt nil !) 0)
  714. % no line break: use \left( .. \right) pair.
  715. if fp = length fancy!-page!* then
  716. <<car cdr r1 := t; car cdr r2 := t>>;
  717. return w;
  718. end)
  719. where fancy!-bstack!* = fancy!-bstack!*;
  720. symbolic procedure fancy!-adjust!-bkt!-levels u;
  721. if null u or null cdr u then nil
  722. else if caar u >= caadr u then
  723. <<car cadr u := car cadr u +1;
  724. fancy!-adjust!-bkt!-levels cdr u; >>;
  725. symbolic procedure fancy!-exptpri(l,p);
  726. % Prints expression in an exponent notation.
  727. (begin scalar !*list,pp,w,w1,w2,pos,fl;
  728. pos:=fancy!-pos!*; fl:=fancy!-line!*;
  729. w1 := cadr l; w2 := caddr l;
  730. pp := eqcar(w1, 'quotient) or
  731. eqcar(w1, 'expt) or
  732. (eqcar(w1, '!*hold) and not atom cadr w1);
  733. testing!-width!* := t;
  734. if eqcar(w2,'quotient) and cadr w2 = 1
  735. and (fixp caddr w2 or liter caddr w2) then
  736. return fancy!-sqrtpri!*(w1,caddr w2);
  737. if eqcar(w2,'quotient) and eqcar(cadr w2,'minus)
  738. then w2 := list('minus,list(car w2,cadadr w2,caddr w2))
  739. else w2 := negnumberchk w2;
  740. if pp then <<
  741. if fancy!-in!-brackets({'fancy!-maprint,
  742. mkquote w1,
  743. get('expt,'infix)},
  744. '!(, '!))='failed
  745. then return fancy!-fail(pos,fl) >>
  746. else if fancy!-maprint(w1,get('expt,'infix))='failed
  747. then return fancy!-fail(pos,fl);
  748. fancy!-prin2!*("^",0);
  749. if eqcar(w2,'quotient) and fixp cadr w2 and fixp caddr w2 then
  750. <<fancy!-prin2!*("{",0); w:=fancy!-inprint('!/,0,cdr w2);
  751. fancy!-prin2!*("}",0)>>
  752. else w:=fancy!-maprint!-tex!-bkt(w2,0,nil);
  753. if w='failed then return fancy!-fail(pos,fl) ;
  754. end) where !*ratpri=!*ratpri,
  755. testing!-width!*=testing!-width!*;
  756. put('expt,'fancy!-pprifn,'fancy!-exptpri);
  757. symbolic procedure fancy!-inprint(op,p,l);
  758. % Print (internally) an infix expression.
  759. % op = infix operator, p = op infix precedence,
  760. % E.g. l = ((times a (plus x y z)) (times b (plus x y z)))
  761. (begin scalar x,y,w, pos,fl;
  762. pos:=fancy!-pos!*;
  763. fl:=fancy!-line!*;
  764. % print product of quotients using *.
  765. if op = 'times and eqcar(car l,'quotient) and
  766. cdr l and eqcar(cadr l,'quotient) then
  767. op:='!*;
  768. if op eq 'plus and !*revpri then l := reverse l;
  769. if not get(op,'alt) then
  770. <<
  771. if op eq 'not then
  772. << fancy!-oprin op;
  773. return fancy!-maprint(car l,get('not,'infix));
  774. >>;
  775. if op eq 'setq and not atom (x := car reverse l)
  776. and idp car x and (y := getrtype x)
  777. and (y := get(get(y,'tag),'fancy!-setprifn))
  778. then return apply2(y,car l,x);
  779. if not atom car l and idp caar l
  780. and
  781. ((x := get(caar l,'fancy!-prifn))
  782. or (x := get(caar l,'fancy!-pprifn)))
  783. and (get(x,op) eq 'inbrackets)
  784. % to avoid mix up of indices and exponents.
  785. then<<
  786. fancy!-in!-brackets(
  787. {'fancy!-maprint,mkquote car l,p}, '!(,'!));
  788. >>
  789. else if !*nosplit and not testing!-width!* then
  790. fancy!-prinfit(car l, p, nil)
  791. else w:=fancy!-maprint(car l, p);
  792. l := cdr l
  793. >>;
  794. if testing!-width!* and (overflowed!* or w='failed)
  795. then return fancy!-fail(pos,fl);
  796. if !*list and obrkp!* and memq(op,'(plus minus)) then
  797. % sumlevel!* is the recursion depth of fancy!-inprint applied
  798. % to a sum and is used only in fancy!-oprin.
  799. <<sumlevel!* := sumlevel!* + 1;
  800. tablevel!* := tablevel!* + 1>>;
  801. if !*nosplit and not testing!-width!* then
  802. % main line:
  803. fancy!-inprint1(op,p,l)
  804. else w:=fancy!-inprint2(op,p,l);
  805. if testing!-width!* and w='failed then return fancy!-fail(pos,fl);
  806. end
  807. ) where tablevel!*=tablevel!*, sumlevel!*=sumlevel!*;
  808. symbolic procedure fancy!-inprint1(op,p,l);
  809. % main line (top level) infix printing, allow line break;
  810. begin scalar lop;
  811. for each v in l do
  812. <<lop := op;
  813. if op='plus and eqcar(v,'minus) then
  814. <<lop := 'minus; v:= cadr v; p:=get('minus,'infix)>>;
  815. if 'failed = fancy!-oprin lop then
  816. <<fancy!-terpri!* nil; fancy!-oprin lop>>;
  817. fancy!-prinfit(negnumberchk v, p, nil)
  818. >>;
  819. end;
  820. symbolic procedure fancy!-inprint2(op,p,l);
  821. % second line
  822. begin scalar lop,w;
  823. for each v in l do
  824. if not testing!-width!* or w neq 'failed then
  825. <<lop:=op;
  826. if op='plus and eqcar(v,'minus) then
  827. <<lop := 'minus; v:= cadr v; p:=get('minus,'infix)>>;
  828. fancy!-oprin lop;
  829. if w neq 'failed then w:=fancy!-maprint(negnumberchk v,p)
  830. >>;
  831. return w;
  832. end;
  833. symbolic procedure fancy!-inprintlist(op,p,l);
  834. % Print (internally) contents of an algebraic list or matrix row.
  835. % op is the operator, e.g. !*comma!*.
  836. % p is ignored
  837. % l is the list to print
  838. fancy!-level
  839. begin scalar fst, w, v;
  840. loop:
  841. if null l then return w;
  842. v := car l; l:= cdr l;
  843. if fst then w := fancy!-oprin op;
  844. if w eq 'failed and testing!-width!* then return w;
  845. w := if w eq 'failed then fancy!-prinfit(v,0,op)
  846. else fancy!-prinfit(v,0,nil);
  847. if w eq 'failed and testing!-width!* then return w;
  848. fst := t;
  849. goto loop;
  850. end;
  851. put('times, 'fancy!-prtch, "\*");
  852. %FJW TeX discretionary times (\*) is not defined in LaTeX and not
  853. %FJW supported by KaTeX, so I handle it in Run-REDUCE.
  854. put('setq, 'fancy!-infix!-symbol, "\coloneqq "); %FJW otherwise uses prtch prop !:!=
  855. symbolic procedure fancy!-oprin op;
  856. fancy!-level
  857. begin scalar x;
  858. if (x:=get(op,'fancy!-prtch)) then fancy!-prin2!*(x,1)
  859. else
  860. if (x:=get(op,'fancy!-infix!-symbol))
  861. then fancy!-special!-symbol(x,get(op,'fancy!-symbol!-length)
  862. or 4)
  863. else
  864. if null(x:=get(op,'prtch)) then fancy!-prin2!*(op,t)
  865. else
  866. << if !*list and obrkp!* and op memq '(plus minus)
  867. and (sumlevel!* = 2 or sumlevel!* = 3) % FJW hack
  868. % to improve `on list', but probably not right!
  869. % The right fix may be to change how or where sumlevel!* is
  870. % incremented in fancy!-inprint, but I can't see how to do it.
  871. then
  872. if testing!-width!* and not (!*acn and !*list) then return 'failed
  873. else fancy!-terpri!* t;
  874. fancy!-prin2!*(x,t);
  875. >>;
  876. if overflowed!* then return 'failed
  877. end;
  878. %FJW The next two lists are based on https://katex.org/docs/supported.html#letters-and-unicode:
  879. deflist('(
  880. (!Alpha "\Alpha ") (!Beta "\Beta ") (!Gamma "\Gamma ") (!Delta "\Delta ")
  881. (!Epsilon "\Epsilon ") (!Zeta "\Zeta ") (!Eta "\Eta ") (!Theta "\Theta ")
  882. (!Iota "\Iota ") (!Kappa "\Kappa ") (!Lambda "\Lambda ") (!Mu "\Mu ")
  883. (!Nu "\Nu ") (!Xi "\Xi ") (!Omicron "\Omicron ") (!Pi "\Pi ")
  884. (!Rho "\Rho ") (!Sigma "\Sigma ") (!Tau "\Tau ") (!Upsilon "\Upsilon ")
  885. (!Phi "\Phi ") (!Chi "\Chi ") (!Psi "\Psi ") (!Omega "\Omega ")
  886. ),'fancy!-special!-symbol);
  887. deflist('(
  888. (!alpha "\alpha ") (!beta "\beta ") (!gamma "\gamma ") (!delta "\delta ")
  889. (!epsilon "\epsilon ") (!zeta "\zeta ") (!eta "\eta ") (!theta "\theta ")
  890. (!iota "\iota ") (!kappa "\kappa ") (!lambda "\lambda ") (!mu "\mu ")
  891. (!nu "\nu ") (!xi "\xi ") (!omicron "\omicron ") (!pi "\pi ")
  892. (!rho "\rho ") (!sigma "\sigma ") (!tau "\tau ") (!upsilon "\upsilon ")
  893. (!phi "\phi ") (!chi "\chi ") (!psi "\psi ") (!omega "\omega ")
  894. ),'fancy!-special!-symbol);
  895. put('infinity,'fancy!-special!-symbol,"\infty ");
  896. put('partial!-df,'fancy!-special!-symbol,"\partial ");
  897. %put('partial!-df,'fancy!-symbol!-length,8);
  898. put('empty!-set,'fancy!-special!-symbol,"\emptyset ");
  899. put('not,'fancy!-special!-symbol,"\neg ");
  900. put('not,'fancy!-infix!-symbol,"\neg ");
  901. put('leq,'fancy!-infix!-symbol,"\leq ");
  902. put('geq,'fancy!-infix!-symbol,"\geq ");
  903. put('neq,'fancy!-infix!-symbol,"\neq ");
  904. put('intersection,'fancy!-infix!-symbol,"\cap ");
  905. put('union,'fancy!-infix!-symbol,"\cup ");
  906. put('member,'fancy!-infix!-symbol,"\in ");
  907. put('and,'fancy!-infix!-symbol,"\wedge ");
  908. put('or,'fancy!-infix!-symbol,"\vee ");
  909. put('when,'fancy!-infix!-symbol,"|");
  910. % put('!*wcomma!*,'fancy!-infix!-symbol,",\,");
  911. put('replaceby,'fancy!-infix!-symbol,"\Rightarrow ");
  912. %put('replaceby,'fancy!-symbol!-length,8);
  913. put('!~,'fancy!-functionsymbol,"\forall "); % forall
  914. %put('!~,'fancy!-symbol!-length,8);
  915. % arbint, arbcomplex.
  916. %put('arbcomplex,'fancy!-functionsymbol,227);
  917. %put('arbint,'fancy!-functionsymbol,226);
  918. %flag('(arbcomplex arbint),'print!-indexed);
  919. % flag('(delta),'print!-indexed); % Dirac delta symbol.
  920. % David Hartley voted against..
  921. % The following definitions allow for more natural printing of
  922. % conditional expressions within rule lists.
  923. symbolic procedure fancy!-condpri0 u;
  924. fancy!-condpri(u,0);
  925. symbolic procedure fancy!-condpri(u,p);
  926. fancy!-level
  927. begin scalar w;
  928. if p>0 then fancy!-prin2 "\left(";
  929. while (u := cdr u) and w neq 'failed do
  930. <<if not(caar u eq 't)
  931. then <<fancy!-prin2 'if; fancy!-prin2 " ";
  932. w:=fancy!-maprin0 caar u;
  933. fancy!-prin2 "\,"; fancy!-prin2 'then;
  934. fancy!-prin2 "\,">>;
  935. if w neq 'failed then w := fancy!-maprin0 cadar u;
  936. if cdr u then <<fancy!-prin2 "\,";
  937. fancy!-prin2 'else; fancy!-prin2 "\,">>>>;
  938. if p>0 then fancy!-prin2 "\right)";
  939. if overflowed!* or w='failed then return 'failed;
  940. end;
  941. put('cond,'fancy!-pprifn,'fancy!-condpri);
  942. put('cond,'fancy!-flatprifn,'fancy!-condpri0);
  943. symbolic procedure fancy!-revalpri u;
  944. fancy!-maprin0 fancy!-unquote cadr u;
  945. symbolic procedure fancy!-unquote u;
  946. if eqcar(u,'list) then for each x in cdr u collect
  947. fancy!-unquote x
  948. else if eqcar(u,'quote) then cadr u else u;
  949. put('aeval,'fancy!-prifn,'fancy!-revalpri);
  950. put('aeval!*,'fancy!-prifn,'fancy!-revalpri);
  951. put('reval,'fancy!-prifn,'fancy!-revalpri);
  952. put('reval!*,'fancy!-prifn,'fancy!-revalpri);
  953. put('aminusp!:,'fancy!-prifn,'fancy!-patpri);
  954. put('aminusp!:,'fancy!-pat,'(lessp !&1 0));
  955. symbolic procedure fancy!-holdpri u;
  956. if atom cadr u then fancy!-maprin0 cadr u
  957. else fancy!-in!-brackets({'fancy!-maprin0, mkquote cadr u}, '!(, '!));
  958. put('!*hold, 'fancy!-prifn, 'fancy!-holdpri);
  959. symbolic procedure fancy!-patpri u;
  960. begin scalar p;
  961. p:=subst(fancy!-unquote cadr u,'!&1,
  962. get(car u,'fancy!-pat));
  963. return fancy!-maprin0 p;
  964. end;
  965. symbolic procedure fancy!-boolvalpri u;
  966. fancy!-maprin0 cadr u;
  967. put('boolvalue!*,'fancy!-prifn,'fancy!-boolvalpri);
  968. symbolic procedure fancy!-quotpri u;
  969. begin scalar n1,n2,fl,w,pos,testing!-width!*,!*list;
  970. if overflowed!* or (!*acn and !*list) then return 'failed;
  971. testing!-width!*:=t;
  972. pos:=fancy!-pos!*;
  973. fl:=fancy!-line!*;
  974. fancy!-prin2!*("\frac",0);
  975. w:=fancy!-maprint!-tex!-bkt(cadr u,0,t);
  976. n1 := fancy!-pos!*;
  977. if w='failed
  978. then return fancy!-fail(pos,fl);
  979. fancy!-pos!* := pos;
  980. w := fancy!-maprint!-tex!-bkt(caddr u,0,t);
  981. n2 := fancy!-pos!*;
  982. if w='failed
  983. then return fancy!-fail(pos,fl);
  984. fancy!-pos!* := max(n1,n2);
  985. return t;
  986. end;
  987. symbolic procedure fancy!-maprint!-tex!-bkt(u,p,m);
  988. % Produce expression with tex brackets {...} if
  989. % necessary. Ensure that {} unit is in same formula.
  990. % If m=t brackets will be inserted in any case.
  991. begin scalar w,pos,fl,testing!-width!*;
  992. testing!-width!*:=t;
  993. pos:=fancy!-pos!*;
  994. fl:=fancy!-line!*;
  995. if not m and (numberp u and 0<=u and u <=9 or liter u) then
  996. << fancy!-prin2!*(u,t);
  997. return if overflowed!* then fancy!-fail(pos,fl);
  998. >>;
  999. fancy!-prin2!*("{",0);
  1000. w := fancy!-maprint(u,p);
  1001. fancy!-prin2!*("}",0);
  1002. if w='failed then return fancy!-fail(pos,fl);
  1003. end;
  1004. symbolic procedure fancy!-fail(pos,fl);
  1005. <<
  1006. overflowed!* := nil;
  1007. fancy!-pos!* := pos;
  1008. fancy!-line!* := fl;
  1009. 'failed
  1010. >>;
  1011. put('quotient,'fancy!-prifn,'fancy!-quotpri);
  1012. symbolic procedure fancy!-prinfit(u, p, op);
  1013. % Display u (as with maprint) with op in front of it, but starting
  1014. % a new line before it if there would be overflow otherwise.
  1015. begin scalar pos,fl,w,ll,f;
  1016. if pairp u and (f:=get(car u,'fancy!-prinfit)) then
  1017. return apply(f,{u,p,op});
  1018. pos:=fancy!-pos!*;
  1019. fl:=fancy!-line!*;
  1020. begin scalar testing!-width!*;
  1021. testing!-width!*:=t;
  1022. if op then w:=fancy!-oprin op;
  1023. if w neq 'failed then w := fancy!-maprint(u,p);
  1024. end;
  1025. if w neq 'failed then return t;
  1026. fancy!-line!*:=fl; fancy!-pos!*:=pos;
  1027. if testing!-width!* and w eq 'failed then return w;
  1028. if op='plus and eqcar(u,'minus) then <<op := 'minus; u:=cadr u>>;
  1029. w:=if op then fancy!-oprin op;
  1030. % if the operator causes the overflow, we break the line now.
  1031. if w eq 'failed then
  1032. <<fancy!-terpri!* nil;
  1033. if op then fancy!-oprin op;
  1034. return fancy!-maprint(u, p);>>;
  1035. % if at least half the line is still free and the
  1036. % object causing the overflow has been a number,
  1037. % let it break.
  1038. if fancy!-pos!* < (ll:=linelength(nil)) then
  1039. if numberp u then return fancy!-prin2number u else
  1040. if eqcar(u,'!:rd!:) then return fancy!-rdprin u;
  1041. % generate a line break if we are not just behind an
  1042. % opening bracket at the beginning of a line.
  1043. if fancy!-pos!* > linelength nil / 2 or
  1044. not eqcar(fancy!-last!-symbol(),'bkt) then
  1045. fancy!-terpri!* nil;
  1046. return fancy!-maprint(u, p);
  1047. end;
  1048. %-----------------------------------------------------------
  1049. %
  1050. % support for print format property
  1051. %
  1052. %-----------------------------------------------------------
  1053. symbolic procedure print_format(f,pat);
  1054. % Assign a print pattern p to the operator form f.
  1055. put(car f, 'print!-format, (cdr f . pat) . get(car f, 'print!-format));
  1056. symbolic operator print_format;
  1057. symbolic procedure fancy!-print!-format(u,p);
  1058. fancy!-level
  1059. begin scalar fmt,fmtl,a;
  1060. fmtl:=get(car u,'print!-format);
  1061. l:
  1062. if null fmtl then return 'failed;
  1063. fmt := car fmtl; fmtl := cdr fmtl;
  1064. if length(car fmt) neq length cdr u then goto l;
  1065. a:=pair(car fmt,cdr u);
  1066. return fancy!-print!-format1(cdr fmt,p,a);
  1067. end;
  1068. symbolic procedure fancy!-print!-format1(u,p,a);
  1069. begin scalar w,x,pl,bkt,obkt,q;
  1070. if eqcar(u,'list) then u:= cdr u;
  1071. while u and w neq 'failed do
  1072. <<x:=car u; u:=cdr u;
  1073. if eqcar(x,'list) then x:=cdr x;
  1074. obkt := bkt; bkt:=nil;
  1075. if obkt then fancy!-prin2!*('!{,0);
  1076. w:=if pairp x then fancy!-print!-format1(x,p,a) else
  1077. if memq(x,'(!( !) !, !. !|)) then
  1078. <<if x eq '!( then <<pl:=p.pl; p:=0>> else
  1079. if x eq '!) then <<p:=car pl; pl:=cdr pl>>;
  1080. fancy!-prin2!*(x,1)>> else
  1081. if x eq '!_ or x eq '!^ then <<bkt:=t;fancy!-prin2!*(x,0)>> else
  1082. if q:=assoc(x,a) then fancy!-maprint(cdr q,p) else
  1083. fancy!-maprint(x,p);
  1084. if obkt then fancy!-prin2!*('!},0);
  1085. >>;
  1086. return w;
  1087. end;
  1088. %-----------------------------------------------------------
  1089. %
  1090. % some operator-specific print functions
  1091. %
  1092. %-----------------------------------------------------------
  1093. symbolic procedure fancy!-prefix!-operator(u);
  1094. % FJW Display an operator identifier, possibly as a special symbol
  1095. % that may depend on the arity.
  1096. begin scalar sy;
  1097. if atom u then <<
  1098. % u is the operator identifier, for backward compatibility
  1099. if not((sy := get(u, 'fancy!-functionsymbol))
  1100. and (atom sy or car sy eq 'ascii)) then
  1101. sy := get(u, 'fancy!-special!-symbol)
  1102. >> else <<
  1103. % u is the full sexpr (fn arg1 arg2 ...) for arity checking.
  1104. % fancy!-functionsymbol may be a symbol or an alist of
  1105. % (arity . symbol) pairs.
  1106. if sy := get(car u, 'fancy!-functionsymbol) then
  1107. if pairp sy then
  1108. sy := (sy := assoc(length cdr u, sy)) and cdr sy;
  1109. u := car u;
  1110. if not sy then sy := get(u, 'fancy!-special!-symbol);
  1111. >>;
  1112. if sy then
  1113. % This needs more work. Currently, fancy!-symbol!-length is
  1114. % not used, but it could and probably should be!
  1115. fancy!-special!-symbol(sy, get(u, 'fancy!-symbol!-length) or 2)
  1116. else if stringp u then fancy!-prin2!*(u, t) % FJW new
  1117. else fancy!-maprint!-identifier u; %FJW was fancy!-prin2!*(u,t);
  1118. end;
  1119. put('sqrt,'fancy!-prifn,'fancy!-sqrtpri);
  1120. inline procedure fancy!-sqrtpri(u);
  1121. % FJW Display the square root of u.
  1122. fancy!-sqrtpri!*(cadr u, 2);
  1123. symbolic procedure fancy!-sqrtpri!*(u, n);
  1124. % FJW Display the n'th root of u, where n must be a number or a
  1125. % single character.
  1126. fancy!-level
  1127. begin
  1128. if not numberp n and not liter n then return 'failed;
  1129. fancy!-prin2!*("\sqrt", 3); % should the width be larger?
  1130. if n neq 2 then
  1131. <<fancy!-prin2!*("[", 0);
  1132. % fancy!-prin2!*("\,",1);
  1133. fancy!-prin2!*(n, 0); % nth root no wider than square root
  1134. fancy!-prin2!*("]", 0);
  1135. >>;
  1136. return fancy!-maprint!-tex!-bkt(u, 0, t);
  1137. end;
  1138. symbolic procedure fancy!-sub(l,p);
  1139. % Prints expression in an exponent notation.
  1140. if get('expt,'infix)<=p then
  1141. fancy!-in!-brackets({'fancy!-sub,mkquote l,0},'!(,'!))
  1142. else
  1143. fancy!-level
  1144. begin scalar eqs,w;
  1145. l:=cdr l;
  1146. while cdr l do <<eqs:=append(eqs,{car l}); l:=cdr l>>;
  1147. l:=car l;
  1148. testing!-width!* := t;
  1149. w := fancy!-maprint(l,get('expt,'infix));
  1150. if w='failed then return w;
  1151. % fancy!-prin2!*("\bigl",0);
  1152. fancy!-prin2!*("|",1);
  1153. fancy!-prin2!*('!_,0);
  1154. fancy!-prin2!*("{",0);
  1155. w:=fancy!-inprint('!*comma!*,0,eqs);
  1156. fancy!-prin2!*("}",0);
  1157. return w;
  1158. end;
  1159. put('sub,'fancy!-pprifn,'fancy!-sub);
  1160. put('factorial,'fancy!-pprifn,'fancy!-factorial);
  1161. symbolic procedure fancy!-factorial(u,n);
  1162. fancy!-level
  1163. begin scalar w;
  1164. w := (if atom cadr u then fancy!-maprint(cadr u,9999)
  1165. else
  1166. fancy!-in!-brackets({'fancy!-maprint,mkquote cadr u,0},
  1167. '!(,'!))
  1168. );
  1169. fancy!-prin2!*("!",2);
  1170. return w;
  1171. end;
  1172. put('binomial,'fancy!-prifn,'fancy!-binomial);
  1173. symbolic procedure fancy!-binomial u;
  1174. fancy!-level
  1175. begin scalar w1,w2,!*list;
  1176. fancy!-prin2!*("\left(\begin{matrix}",2);
  1177. w1 := fancy!-maprint(cadr u,0);
  1178. fancy!-prin2!*("\\",0);
  1179. w2 := fancy!-maprint(caddr u,0);
  1180. fancy!-prin2!*("\end{matrix}\right)",2);
  1181. if w1='failed or w2='failed then return 'failed;
  1182. end;
  1183. symbolic procedure fancy!-intpri(u,p);
  1184. % Fancy integral print.
  1185. if p>get('times,'infix) then
  1186. fancy!-in!-brackets({'fancy!-intpri,mkquote u,0},'!(,'!))
  1187. else
  1188. fancy!-level
  1189. begin scalar w0,w1,w2,hi,lo;
  1190. if cdddr u then lo:=cadddr u;
  1191. if lo and cddddr u then hi := car cddddr u;
  1192. if fancy!-height(cadr u,1.0) > 3 then
  1193. fancy!-prin2!*("\int ",0) % big integral wanted
  1194. else
  1195. fancy!-prin2!*("\int ",0);
  1196. if lo then <<
  1197. fancy!-prin2!*('!_,0);
  1198. fancy!-prin2!*('!{,0);
  1199. w0 := fancy!-maprint(lo,0) where !*list=nil;
  1200. fancy!-prin2!*('!},0);
  1201. >>;
  1202. if hi then <<
  1203. fancy!-prin2!*('!^,0);
  1204. fancy!-maprint!-tex!-bkt(hi,0,t) where !*list=nil;
  1205. >>;
  1206. w1:=fancy!-maprint(cadr u,0);
  1207. fancy!-prin2!*("\,d\,",2);
  1208. w2:=fancy!-maprint(caddr u,0);
  1209. if w1='failed or w2='failed or w0='failed then return 'failed;
  1210. end;
  1211. symbolic procedure fancy!-height(u,h);
  1212. % Fancy height. Estimate the height of an expression, this is a
  1213. % subroutine of fancy!-intpri.
  1214. if atom u then h
  1215. else if car u = 'minus then fancy!-height(cadr u,h)
  1216. else if car u = 'plus or car u = 'times then
  1217. eval('max. for each w in cdr u collect fancy!-height(w,h))
  1218. else if car u = 'expt then
  1219. fancy!-height(cadr u,h) + fancy!-height(caddr u,h*0.8)
  1220. else if car u = 'quotient then
  1221. fancy!-height(cadr u,h) + fancy!-height(caddr u,h)
  1222. else if get(car u,'simpfn) then fancy!-height(cadr u,h)
  1223. else h;
  1224. put('int,'fancy!-pprifn,'fancy!-intpri);
  1225. symbolic procedure fancy!-sumpri!*(u,p,mode);
  1226. if p>get('minus,'infix) then
  1227. fancy!-in!-brackets({'fancy!-sumpri!*,mkquote u,0,mkquote mode},
  1228. '!(,'!))
  1229. else
  1230. fancy!-level
  1231. begin scalar w,w0,w1,lo,hi,var;
  1232. var := caddr u;
  1233. if cdddr u then lo:=cadddr u;
  1234. if lo and cddddr u then hi := car cddddr u;
  1235. w:=if lo then {'equal,var,lo} else var;
  1236. if mode = 'sum then
  1237. fancy!-prin2!*("\sum",0) % big SIGMA
  1238. else if mode = 'prod then
  1239. fancy!-prin2!*("\prod",0); % big PI
  1240. fancy!-prin2!*('!_,0);
  1241. fancy!-prin2!*('!{,0);
  1242. if w then w0:=fancy!-maprint(w,0) where !*list=nil;
  1243. fancy!-prin2!*('!},0);
  1244. if hi then <<fancy!-prin2!*('!^,0);
  1245. fancy!-maprint!-tex!-bkt(hi,0,nil) where !*list=nil;
  1246. >>;
  1247. fancy!-prin2!*('!\!, ,1);
  1248. w1:=fancy!-maprint(cadr u,0);
  1249. if w0='failed or w1='failed then return 'failed;
  1250. end;
  1251. symbolic procedure fancy!-sumpri(u,p); fancy!-sumpri!*(u,p,'sum);
  1252. put('sum,'fancy!-pprifn,'fancy!-sumpri);
  1253. put('infsum,'fancy!-pprifn,'fancy!-sumpri);
  1254. symbolic procedure fancy!-prodpri(u,p); fancy!-sumpri!*(u,p,'prod);
  1255. put('prod,'fancy!-pprifn,'fancy!-prodpri);
  1256. symbolic procedure fancy!-limpri(u,p);
  1257. if p>get('minus,'infix) then
  1258. fancy!-in!-brackets({'fancy!-sumpri,mkquote u,0},'!(,'!))
  1259. else
  1260. fancy!-level
  1261. begin scalar w,lo,var;
  1262. var := caddr u;
  1263. if cdddr u then lo:=cadddr u;
  1264. fancy!-prin2!*("\lim",6);
  1265. fancy!-prin2!*('!_,0);
  1266. fancy!-prin2!*('!{,0);
  1267. fancy!-maprint(var,0);
  1268. fancy!-prin2!*("\rightarrow ",0);
  1269. fancy!-prin2!*('! ,0); % make sure there is space before the following symbol
  1270. fancy!-maprint(lo,0) where !*list=nil;
  1271. fancy!-prin2!*('!},0);
  1272. w:=fancy!-maprint(cadr u,0);
  1273. return w;
  1274. end;
  1275. put('limit,'fancy!-pprifn,'fancy!-limpri);
  1276. symbolic procedure fancy!-listpri(u);
  1277. % Print (internally) an algebraic list.
  1278. % u = (list ...)
  1279. fancy!-level
  1280. if null cdr u then fancy!-maprint('empty!-set, 0)
  1281. else
  1282. fancy!-in!-brackets(
  1283. {'fancy!-inprintlist, mkquote '!*comma!*, 0, mkquote cdr u},
  1284. '!{,'!});
  1285. put('list,'fancy!-prifn,'fancy!-listpri);
  1286. put('list,'fancy!-flatprifn,'fancy!-listpri);
  1287. put('!*sq,'fancy!-reform,'fancy!-sqreform);
  1288. symbolic procedure fancy!-sqreform u;
  1289. << u := cadr u;
  1290. if !*pri or wtl!* then prepreform prepsq!* sqhorner!* u
  1291. else if denr u = 1 then fancy!-sfreform numr u
  1292. else {'quotient,fancy!-sfreform numr u,fancy!-sfreform denr u} >>;
  1293. symbolic procedure fancy!-sfreform u;
  1294. begin scalar z;
  1295. while not domainp u do <<z := fancy!-termreform lt u . z; u := red u >>;
  1296. if not null u then z := prepd u . z;
  1297. return replus reversip z;
  1298. end;
  1299. symbolic procedure fancy!-termreform u;
  1300. begin scalar v,w,z,sgn;
  1301. v := tc u;
  1302. u := tpow u;
  1303. if (w := kernlp v) and not !:onep w
  1304. then <<v := quotf(v,w);
  1305. if minusf w then <<sgn := t; w := !:minus w>>>>;
  1306. if w and not !:onep w
  1307. then z := (if domainp w then prepd w else w) . z;
  1308. z := fancy!-powerreform u . z;
  1309. if not(domainp v and !:onep v) then z := fancy!-sfreform v . z;
  1310. z := retimes reversip z;
  1311. if sgn then z := {'minus,z};
  1312. return z;
  1313. end;
  1314. symbolic procedure fancy!-powerreform u;
  1315. begin scalar b;
  1316. % Process main variable.
  1317. if atom car u then b := car u
  1318. else if not atom caar u then b := fancy!-sfreform car u
  1319. else if caar u eq '!*sq then b := fancy!-sqreform cadar u
  1320. else b := car u;
  1321. % Process degree.
  1322. if (u := pdeg u)=1 then return b
  1323. else return {'expt,b,u}
  1324. end;
  1325. put('df,'fancy!-pprifn,'fancy!-dfpri);
  1326. global '(!*dfprint);
  1327. symbolic procedure fancy!-dfpri(u,l);
  1328. % E.g. u = (df f x y) or (df (g x y) x y)
  1329. if !*dfprint then
  1330. fancy!-dfpriindexed(
  1331. if atom cadr u then u else car u . caadr u . cddr u, l)
  1332. else
  1333. (if flagp(cadr u,'print!-indexed) or
  1334. pairp cadr u and flagp(caadr u,'print!-indexed)
  1335. then fancy!-dfpriindexed(u,l)
  1336. else if m = 'partial then fancy!-dfpri0(u,l,'partial!-df)
  1337. else if m = 'total then fancy!-dfpri0(u,l,'!d)
  1338. else if m = 'indexed then fancy!-dfpriindexed(u,l)
  1339. else rederr "unknown print mode for DF")
  1340. where m=fancy!-mode('fancy_print_df);
  1341. symbolic procedure fancy!-partialdfpri(u,l);
  1342. fancy!-dfpri0(u,l,'partial!-df);
  1343. symbolic procedure fancy!-dfpri0(u,l,symb);
  1344. if null cddr u then fancy!-maprin0{'times,symb,cadr u} else
  1345. if l >= get('expt,'infix) then % brackets if exponented
  1346. fancy!-in!-brackets({'fancy!-dfpri0,mkquote u,0,mkquote symb},
  1347. '!(,'!))
  1348. else
  1349. fancy!-level
  1350. begin scalar x,d,q; integer n,m;
  1351. u:=cdr u;
  1352. q:=car u;
  1353. u:=cdr u;
  1354. while u do
  1355. <<x:=car u; u:=cdr u;
  1356. if u and numberp car u then
  1357. <<m:=car u; u := cdr u>> else m:=1;
  1358. n:=n+m;
  1359. d:= append(d,{symb,if m=1 then x else {'expt,x,m}});
  1360. >>;
  1361. return fancy!-maprin0
  1362. {'quotient, {'times,if n=1 then symb else
  1363. {'expt,symb,n},q},
  1364. 'times. d};
  1365. end;
  1366. symbolic procedure fancy!-dfpriindexed(u,l);
  1367. if null cddr u then fancy!-maprin0{'times,'partial!-df,cadr u} else
  1368. begin scalar w;
  1369. w:=fancy!-maprin0 cadr u;
  1370. if testing!-width!* and w='failed then return w;
  1371. w :=fancy!-print!-indexlist fancy!-dfpriindexedx(cddr u,nil);
  1372. return w;
  1373. end;
  1374. symbolic procedure fancy!-dfpriindexedx(u,p);
  1375. if null u then nil else
  1376. if numberp car u then
  1377. append(for i:=2:car u collect p,fancy!-dfpriindexedx(cdr u,p))
  1378. else
  1379. car u . fancy!-dfpriindexedx(cdr u,car u);
  1380. put('!:rd!:,'fancy!-prifn,'fancy!-rdprin);
  1381. put('!:rd!:,'fancy!-flatprifn,'fancy!-rdprin);
  1382. symbolic procedure fancy!-rdprin u;
  1383. fancy!-level
  1384. begin scalar digits; integer dotpos,xp;
  1385. u:=rd!:explode u;
  1386. digits := car u; xp := cadr u; dotpos := caddr u;
  1387. return fancy!-rdprin1(digits,xp,dotpos);
  1388. end;
  1389. symbolic procedure fancy!-rdprin1(digits,xp,dotpos);
  1390. begin scalar str;
  1391. if xp>0 and dotpos+xp<length digits-1 then
  1392. <<dotpos := dotpos+xp; xp:=0>>;
  1393. % build character string from number.
  1394. for i:=1:dotpos do
  1395. <<str := car digits . str;
  1396. digits := cdr digits; if null digits then digits:='(!0);
  1397. >>;
  1398. str := '!. . str;
  1399. for each c in digits do str :=c.str;
  1400. if not(xp=0) then
  1401. <<str:='!e.str;
  1402. for each c in explode2 xp do str:=c.str>>;
  1403. if testing!-width!* and
  1404. fancy!-pos!* + 2*length str > 2 * linelength nil then
  1405. return 'failed;
  1406. fancy!-prin2number1 reversip str;
  1407. end;
  1408. put('!:cr!:,'fancy!-pprifn,'fancy!-cmpxprin);
  1409. put('!:cr!:,'fancy!-pprifn,'fancy!-cmpxprin);
  1410. symbolic procedure fancy!-cmpxprin(u,l);
  1411. begin scalar rp,ip;
  1412. rp:=reval {'repart,u}; ip:=reval {'impart,u};
  1413. return fancy!-maprint(
  1414. if ip=0 then rp else
  1415. if rp=0 then {'times,ip,'!i} else
  1416. {'plus,rp,{'times,ip,'!i}},l);
  1417. end;
  1418. symbolic procedure fancy!-dn!:prin u;
  1419. begin scalar lst; integer dotpos,ex;
  1420. lst := bfexplode0x (cadr u, cddr u);
  1421. ex := cadr lst;
  1422. dotpos := caddr lst;
  1423. lst := car lst;
  1424. return fancy!-rdprin1 (lst,ex,dotpos)
  1425. end;
  1426. put ('!:dn!:, 'fancy!-prifn, 'fancy!-dn!:prin);
  1427. % on fancy; %FJW fmp!-switch t;
  1428. endmodule;
  1429. %-------------------------------------------------------
  1430. module f; % Matrix printing routines.
  1431. fluid '(!*nat);
  1432. fluid '(obrkp!*);
  1433. symbolic procedure fancy!-setmatpri(u,v);
  1434. fancy!-matpri1(cdr v,u);
  1435. put('mat,'fancy!-setprifn,'fancy!-setmatpri);
  1436. symbolic procedure fancy!-matpri u;
  1437. fancy!-matpri1(cdr u,nil);
  1438. put('mat,'fancy!-prifn,'fancy!-matpri);
  1439. symbolic procedure fancy!-matpri1(u,x);
  1440. % Prints a matrix canonical form U with name X.
  1441. % Tries to do fancy display if nat flag is on.
  1442. begin scalar w;
  1443. w := fancy!-matpri2(u,x,nil);
  1444. if w neq 'failed or testing!-width!* then return w;
  1445. fancy!-matpri3(u,x);
  1446. end;
  1447. symbolic procedure fancy!-matpri2(u,x,bkt);
  1448. % Tries to print matrix as compact block.
  1449. fancy!-level
  1450. begin scalar w,testing!-width!*,fl,fp,fmat,row,elt,fail;
  1451. integer cols,rows,rw,maxpos;
  1452. testing!-width!*:=t;
  1453. rows := length u;
  1454. cols := length car u;
  1455. if cols*rows>400 then return 'failed;
  1456. if x then
  1457. << fancy!-maprint(x,0); fancy!-prin2!*(":=",4) >>;
  1458. fl := fancy!-line!*; fp := fancy!-pos!*;
  1459. % remaining room for the columns.
  1460. rw := linelength(nil)-2 -(fancy!-pos!*+2);
  1461. rw := rw/cols;
  1462. fmat := for each row in u collect
  1463. for each elt in row collect
  1464. if not fail then
  1465. <<fancy!-line!*:=nil; fancy!-pos!*:=0;
  1466. w:=fancy!-maprint(elt,0);
  1467. if fancy!-pos!*>maxpos then maxpos:=fancy!-pos!*;
  1468. if w='failed or fancy!-pos!*>rw
  1469. then fail:=t else
  1470. (fancy!-line!*.fancy!-pos!*)
  1471. >>;
  1472. if fail then return 'failed;
  1473. testing!-width!* := nil;
  1474. % restore output line.
  1475. fancy!-pos!* := fp; fancy!-line!* := fl;
  1476. % TEX header
  1477. fancy!-prin2!*(bldmsg("\left%w\begin{matrix}",
  1478. if bkt then car bkt else "("),0);
  1479. % join elements.
  1480. while fmat do
  1481. <<row := car fmat; fmat:=cdr fmat;
  1482. while row do
  1483. <<elt:=car row; row:=cdr row;
  1484. fancy!-line!* := "\displaystyle " . fancy!-line!*; %FJW
  1485. fancy!-line!* := append(car elt,fancy!-line!*);
  1486. if row then fancy!-line!* :='!& . fancy!-line!*
  1487. else if fmat then
  1488. fancy!-line!* := "\\[1.5em]" . fancy!-line!*; %FJW
  1489. >>;
  1490. >>;
  1491. fancy!-prin2!*(bldmsg("\end{matrix}\right%w",
  1492. if bkt then cdr bkt else ")"),0);
  1493. % compute total horizontal extent of matrix
  1494. fancy!-pos!* := fp + maxpos*(cols+1);
  1495. return t;
  1496. end;
  1497. symbolic procedure fancy!-matpri3(u,x);
  1498. if null x then fancy!-matpriflat('mat.u) else
  1499. begin scalar obrkp!*,!*list;
  1500. integer r,c;
  1501. obrkp!* := nil;
  1502. if null x then x:='mat;
  1503. % fancy!-terpri!*; % missing arg!!!
  1504. for each row in u do
  1505. <<r:=r+1; c:=0;
  1506. for each elt in row do
  1507. << c:=c+1;
  1508. if not !*nero then
  1509. << fancy!-prin2!*(x,t);
  1510. fancy!-print!-indexlist {r,c};
  1511. fancy!-prin2!*(":=",t);
  1512. fancy!-maprint(elt,0);
  1513. fancy!-terpri!* t;
  1514. >>;
  1515. >>;
  1516. >>;
  1517. end;
  1518. symbolic procedure fancy!-matpriflat(u);
  1519. begin
  1520. fancy!-oprin 'mat;
  1521. fancy!-in!-brackets(
  1522. {'fancy!-matpriflat1,mkquote '!*comma!*,0,mkquote cdr u},
  1523. '!(,'!));
  1524. end;
  1525. symbolic procedure fancy!-matpriflat1(op,p,l);
  1526. % Print (internally) the rows of a matrix.
  1527. begin scalar fst, w;
  1528. for each v in l do <<
  1529. if fst then <<
  1530. fancy!-oprin op;
  1531. % If the next row does not fit on the current print line
  1532. % then move it completely to a new line:
  1533. w := fancy!-level
  1534. fancy!-in!-brackets(
  1535. {'fancy!-inprintlist, mkquote '!*comma!*, 0, mkquote v},
  1536. '!(,'!)) where testing!-width!* = t;
  1537. >>;
  1538. if w eq 'failed then fancy!-terpri!* t;
  1539. if not fst or w eq 'failed then
  1540. fancy!-in!-brackets(
  1541. {'fancy!-inprintlist, mkquote '!*comma!*, 0, mkquote v},
  1542. '!(,'!));
  1543. fst := t;
  1544. >>;
  1545. end;
  1546. put('mat,'fancy!-flatprifn,'fancy!-matpriflat);
  1547. symbolic procedure fancy!-matfit(u,p,op);
  1548. % Prinfit routine for matrix.
  1549. % a new line before it if there would be overflow otherwise.
  1550. fancy!-level
  1551. begin scalar pos,fl,fp,w,ll;
  1552. pos:=fancy!-pos!*;
  1553. fl:=fancy!-line!*;
  1554. begin scalar testing!-width!*;
  1555. testing!-width!*:=t;
  1556. if op then w:=fancy!-oprin op;
  1557. if w neq 'failed then w := fancy!-matpri(u);
  1558. end;
  1559. if w neq 'failed or
  1560. (w eq 'failed and testing!-width!*) then return w;
  1561. fancy!-line!*:=fl; fancy!-pos!*:=pos; w:=nil;
  1562. fp := fancy!-page!*;
  1563. % matrix: give us a second chance with a fresh line
  1564. begin scalar testing!-width!*;
  1565. testing!-width!*:=t;
  1566. if op then w:=fancy!-oprin op;
  1567. fancy!-terpri!* nil;
  1568. if w neq 'failed then w := fancy!-matpri u;
  1569. end;
  1570. if w neq 'failed then return t;
  1571. fancy!-line!*:=fl; fancy!-pos!*:=pos; fancy!-page!*:=fp;
  1572. ll:=linelength nil;
  1573. if op then fancy!-oprin op;
  1574. if atom u or fancy!-pos!* > ll / 2 then fancy!-terpri!* nil;
  1575. return fancy!-matpriflat(u);
  1576. end;
  1577. put('mat,'fancy!-prinfit,'fancy!-matfit);
  1578. put('taylor!*,'fancy!-reform,'taylor!*print1);
  1579. endmodule;
  1580. module fancy_standard_functions;
  1581. % Display transcendental functions following the NIST Digital Library
  1582. % of Mathematical Functions, http://dlmf.nist.gov/.
  1583. % Elementary transcendental functions
  1584. put('sin, 'fancy!-functionsymbol, "\sin");
  1585. put('cos, 'fancy!-functionsymbol, "\cos");
  1586. put('tan, 'fancy!-functionsymbol, "\tan");
  1587. put('cot, 'fancy!-functionsymbol, "\cot");
  1588. put('sec, 'fancy!-functionsymbol, "\sec");
  1589. put('csc, 'fancy!-functionsymbol, "\csc");
  1590. put('sinh, 'fancy!-functionsymbol, "\sinh");
  1591. put('cosh, 'fancy!-functionsymbol, "\cosh");
  1592. put('tanh, 'fancy!-functionsymbol, "\tanh");
  1593. put('coth, 'fancy!-functionsymbol, "\coth");
  1594. put('sech, 'fancy!-functionsymbol, "\mathrm{sech}");
  1595. put('csch, 'fancy!-functionsymbol, "\mathrm{csch}");
  1596. % The inverse of the trigonometric or hyperbolic function fn is named
  1597. % arcfn and is written in normal (roman) font style.
  1598. put('asin, 'fancy!-functionsymbol, "\arcsin");
  1599. put('acos, 'fancy!-functionsymbol, "\arccos");
  1600. put('atan, 'fancy!-functionsymbol, "\arctan");
  1601. put('acot, 'fancy!-functionsymbol, "\mathrm{arccot}");
  1602. put('asec, 'fancy!-functionsymbol, "\mathrm{arcsec}");
  1603. put('acsc, 'fancy!-functionsymbol, "\mathrm{arccsc}");
  1604. put('asinh, 'fancy!-functionsymbol, "\mathrm{arcsinh}");
  1605. put('acosh, 'fancy!-functionsymbol, "\mathrm{arccosh}");
  1606. put('atanh, 'fancy!-functionsymbol, "\mathrm{arctanh}");
  1607. put('acoth, 'fancy!-functionsymbol, "\mathrm{arccoth}");
  1608. put('asech, 'fancy!-functionsymbol, "\mathrm{arcsech}");
  1609. put('acsch, 'fancy!-functionsymbol, "\mathrm{arccsch}");
  1610. put('exp, 'fancy!-functionsymbol, "\exp"); % Used in special cases, e.g. complicated argument.
  1611. put('log, 'fancy!-functionsymbol, "\log");
  1612. put('logb, 'fancy!-prifn, 'fancy!-logb);
  1613. put('log10, 'fancy!-prifn, 'fancy!-log10);
  1614. inline procedure fancy!-logb(u);
  1615. % u = (logb(x, b) -> \log_{b}(x)
  1616. fancy!-indexed!-fn {"\log", caddr u, cadr u};
  1617. inline procedure fancy!-log10(u);
  1618. % u = (log10 x) -> \log_{10}(x)
  1619. fancy!-indexed!-fn {"\log", 10, cadr u};
  1620. put('atan2, 'fancy!-functionsymbol, "\arctan_2");
  1621. symbolic procedure fancy!-indexed!-fn u;
  1622. fancy!-level
  1623. begin scalar w;
  1624. fancy!-prefix!-operator car u;
  1625. w := fancy!-print!-one!-index cadr u;
  1626. if testing!-width!* and w eq 'failed then return w;
  1627. return fancy!-print!-function!-arguments cddr u;
  1628. end;
  1629. put('ln, 'fancy!-functionsymbol, "\ln");
  1630. put('max, 'fancy!-functionsymbol, "\max");
  1631. put('min, 'fancy!-functionsymbol, "\min");
  1632. put('repart, 'fancy!-functionsymbol, "\Re");
  1633. put('impart, 'fancy!-functionsymbol, "\Im");
  1634. put('repart, 'fancy!-symbol!-length, 4); % wide symbols
  1635. put('impart, 'fancy!-symbol!-length, 4);
  1636. for each x in '(
  1637. sin cos tan cot sec csc
  1638. sinh cosh tanh coth sech csch
  1639. exp log ln max min
  1640. ) do put(x, 'fancy!-symbol!-length, 2*length explode2 x);
  1641. for each x in '(
  1642. arcsin arccos arctan arccot arcsec arccsc
  1643. arcsinh arccosh arctanh arccoth arcsech arccsch
  1644. ) do put(x, 'fancy!-symbol!-length, 2*(length explode2 x + 2));
  1645. put('abs, 'fancy!-prifn, 'fancy!-abs);
  1646. symbolic procedure fancy!-abs u;
  1647. fancy!-level
  1648. begin scalar w;
  1649. fancy!-prin2!*("\left|", 1);
  1650. w := fancy!-maprin0 cadr u;
  1651. fancy!-prin2!*("\right|", 1);
  1652. return w
  1653. end;
  1654. % Gamma, Beta and Related Functions
  1655. put('Euler_gamma, 'fancy!-special!-symbol, "\gamma ");
  1656. put('Gamma, 'fancy!-functionsymbol, '((1 . "\Gamma "))); % unary only
  1657. put('polygamma, 'fancy!-prifn, 'fancy!-polygamma);
  1658. symbolic procedure fancy!-polygamma(u);
  1659. % u = (polygamma n z) -> \psi^{(n)}(z)
  1660. fancy!-level
  1661. begin scalar w;
  1662. fancy!-prefix!-operator "\psi";
  1663. fancy!-prin2!*('!^, 0); fancy!-prin2!*('!{, 0);
  1664. w := fancy!-in!-brackets({'fancy!-maprin0, mkquote cadr u}, '!(, '!));
  1665. if testing!-width!* and w eq 'failed then return w;
  1666. fancy!-prin2!*('!}, 0);
  1667. return fancy!-in!-brackets({'fancy!-maprin0, mkquote caddr u}, '!(, '!));
  1668. end;
  1669. put('iGamma, 'fancy!-functionsymbol, '!P); % P(a,z)
  1670. put('m_Gamma, 'fancy!-functionsymbol, "\gamma"); % gamma(a,z)
  1671. put('iBeta, 'fancy!-prifn, 'fancy!-iBeta);
  1672. put('iBeta, 'fancy!-functionsymbol, '!I);
  1673. symbolic procedure fancy!-iBeta(u);
  1674. % u = (iBeta a b x) -> I_{x}(a,b)
  1675. fancy!-indexed!-fn({car u, cadddr u, cadr u, caddr u});
  1676. put('dilog, 'fancy!-functionsymbol, "\mathrm{Li}_2"); % roman Li_2(z)
  1677. put('dilog, 'fancy!-symbol!-length, 5);
  1678. put('Pochhammer, 'fancy!-prifn, 'fancy!-Pochhammer); % (a)_{n}
  1679. symbolic procedure fancy!-Pochhammer(u);
  1680. % u = (Pochhammer a n) -> (a)_{n}
  1681. fancy!-level
  1682. begin scalar w;
  1683. w := fancy!-in!-brackets({'fancy!-maprin0, mkquote cadr u}, '!(, '!));
  1684. if testing!-width!* and w eq 'failed then return w;
  1685. fancy!-prin2!*('!_, 0); fancy!-prin2!*('!{, 0);
  1686. fancy!-maprin0 caddr u;
  1687. fancy!-prin2!*('!}, 0);
  1688. end;
  1689. % Integral Functions
  1690. put('Ei, 'fancy!-functionsymbol, "\mathrm{Ei}");
  1691. put('Si, 'fancy!-functionsymbol, "\mathrm{Si}");
  1692. put('Ci, 'fancy!-functionsymbol, "\mathrm{Ci}");
  1693. put('Shi, 'fancy!-functionsymbol, "\mathrm{Shi}");
  1694. put('Chi, 'fancy!-functionsymbol, "\mathrm{Chi}");
  1695. put('erf, 'fancy!-functionsymbol, "\mathrm{erf}");
  1696. % erfc(x) -> 1 - erf(x) for all x.
  1697. put('Fresnel_S, 'fancy!-functionsymbol, "\mathrm{S}");
  1698. put('Fresnel_C, 'fancy!-functionsymbol, "\mathrm{C}");
  1699. for each x in '(Ei Si Ci Shi Chi erf) do
  1700. put(x, 'fancy!-symbol!-length, 2*length explode2 x);
  1701. % Airy, Bessel and Related Functions
  1702. put('Airy_Ai, 'fancy!-functionsymbol, "\mathrm{Ai}");
  1703. put('Airy_Bi, 'fancy!-functionsymbol, "\mathrm{Bi}");
  1704. put('Airy_Ai, 'fancy!-symbol!-length, 4);
  1705. put('Airy_Bi, 'fancy!-symbol!-length, 4);
  1706. put('Airy_AiPrime, 'fancy!-functionsymbol, "\mathrm{Ai}'");
  1707. put('Airy_BiPrime, 'fancy!-functionsymbol, "\mathrm{Bi}'");
  1708. put('Airy_AiPrime, 'fancy!-symbol!-length, 5);
  1709. put('Airy_BiPrime, 'fancy!-symbol!-length, 5);
  1710. put('BesselI, 'fancy!-prifn, 'fancy!-indexed!-fn);
  1711. put('BesselJ, 'fancy!-prifn, 'fancy!-indexed!-fn);
  1712. put('BesselY, 'fancy!-prifn, 'fancy!-indexed!-fn);
  1713. put('BesselK, 'fancy!-prifn, 'fancy!-indexed!-fn);
  1714. put('BesselI, 'fancy!-functionsymbol, '!I);
  1715. put('BesselJ, 'fancy!-functionsymbol, '!J);
  1716. put('BesselY, 'fancy!-functionsymbol, '!Y);
  1717. put('BesselK, 'fancy!-functionsymbol, '!K);
  1718. put('Hankel1, 'fancy!-prifn, 'fancy!-Hankel); % H_{nu}^{(1)}(z)
  1719. put('Hankel2, 'fancy!-prifn, 'fancy!-Hankel); % H_{nu}^{(2)}(z)
  1720. symbolic procedure fancy!-Hankel(u);
  1721. % u = (Hankel1/2 nu z)
  1722. fancy!-level
  1723. begin scalar w;
  1724. fancy!-prefix!-operator '!H;
  1725. w:=fancy!-print!-one!-index cadr u;
  1726. if testing!-width!* and w eq 'failed then return w;
  1727. fancy!-prin2!*('!^, 0);
  1728. fancy!-prin2!*('!{, 0); fancy!-prin2!*('!(, 0);
  1729. fancy!-prin2!*(if car u eq 'Hankel1 then 1 else 2, 0);
  1730. fancy!-prin2!*('!), 0); fancy!-prin2!*('!}, 0);
  1731. return fancy!-print!-function!-arguments cddr u;
  1732. end;
  1733. % Struve, Lommel, Kummer, Whittaker and Spherical Harmonic Functions
  1734. put('StruveH, 'fancy!-prifn, 'fancy!-indexed!-fn); % bold H_{nu}(z)
  1735. put('StruveH, 'fancy!-functionsymbol, "\mathbf{H}");
  1736. put('StruveL, 'fancy!-prifn, 'fancy!-indexed!-fn); % bold L_{nu}(z)
  1737. put('StruveL, 'fancy!-functionsymbol, "\mathbf{L}");
  1738. put('Lommel1, 'fancy!-prifn, 'fancy!-Lommel); % s_{mu,nu}(z)
  1739. put('Lommel2, 'fancy!-prifn, 'fancy!-Lommel); % S_{mu,nu}(z)
  1740. symbolic procedure fancy!-Lommel(u);
  1741. % u = (Lommel1/2 mu nu z)
  1742. fancy!-level
  1743. begin scalar w;
  1744. fancy!-prefix!-operator(if car u eq 'Lommel1 then '!s else '!S);
  1745. w := fancy!-print!-indexlist1({cadr u, caddr u}, '!_, '!*comma!*);
  1746. if testing!-width!* and w eq 'failed then return w;
  1747. return fancy!-print!-function!-arguments cdddr u;
  1748. end;
  1749. put('KummerM, 'fancy!-functionsymbol, '!M); % M(a, b, z)
  1750. put('KummerU, 'fancy!-functionsymbol, '!U); % U(a, b, z)
  1751. % Note the Whittaker M & W functions are simplified to expressions
  1752. % involving the Kummer M & U functions respectively.
  1753. put('Lambert_W, 'fancy!-functionsymbol, "\omega");
  1754. % Classical Orthogonal Polynomials
  1755. put('JacobiP, 'fancy!-prifn,'fancy!-JacobiP); % P_n^{(alpha, beta)}(x)
  1756. symbolic procedure fancy!-JacobiP(u);
  1757. % u = (JacobiP n alpha beta x)
  1758. fancy!-level
  1759. begin scalar w;
  1760. fancy!-prefix!-operator '!P;
  1761. w := fancy!-print!-one!-index cadr u;
  1762. if testing!-width!* and w eq 'failed then return w;
  1763. fancy!-prin2!*('!^, 0);
  1764. fancy!-prin2!*('!{, 0);
  1765. w := fancy!-print!-function!-arguments {caddr u, cadddr u};
  1766. if testing!-width!* and w eq 'failed then return w;
  1767. fancy!-prin2!*('!}, 0);
  1768. return fancy!-print!-function!-arguments cddddr u;
  1769. end;
  1770. put('GegenbauerP, 'fancy!-prifn, 'fancy!-Gegenbauer!-style); % C_n^{(lamda)}(x)
  1771. put('GegenbauerP, 'fancy!-functionsymbol, '!C);
  1772. symbolic procedure fancy!-Gegenbauer!-style(u);
  1773. % u = (GegenbauerP n lamda x)
  1774. fancy!-level
  1775. begin scalar w;
  1776. fancy!-prefix!-operator car u;
  1777. w := fancy!-print!-one!-index cadr u;
  1778. if testing!-width!* and w eq 'failed then return w;
  1779. fancy!-prin2!*('!^, 0);
  1780. fancy!-prin2!*('!{, 0); fancy!-prin2!*('!(, 0);
  1781. fancy!-maprint(caddr u, 0);
  1782. fancy!-prin2!*('!), 0); fancy!-prin2!*('!}, 0);
  1783. return fancy!-print!-function!-arguments cdddr u;
  1784. end;
  1785. put('ChebyshevT, 'fancy!-prifn, 'fancy!-indexed!-fn); % T_n(x)
  1786. put('ChebyshevT, 'fancy!-functionsymbol, '!T);
  1787. put('ChebyshevU, 'fancy!-prifn, 'fancy!-indexed!-fn); % U_n(x)
  1788. put('ChebyshevU, 'fancy!-functionsymbol, '!U);
  1789. put('LegendreP, 'fancy!-prifn, 'fancy!-Legendre!-style);
  1790. put('LegendreP, 'fancy!-functionsymbol, '!P);
  1791. symbolic procedure fancy!-Legendre!-style(u);
  1792. % u = (LegendreP n x) -> P_n(x)
  1793. % u = (LegendreP n m x) -> P_n^{(m)}(x)
  1794. if length u = 3 then fancy!-indexed!-fn(u)
  1795. else fancy!-Gegenbauer!-style(u);
  1796. put('LaguerreP, 'fancy!-prifn, 'fancy!-Legendre!-style);
  1797. put('LaguerreP, 'fancy!-functionsymbol, '!L);
  1798. put('HermiteP, 'fancy!-prifn, 'fancy!-indexed!-fn); % H_n(x)
  1799. put('HermiteP, 'fancy!-functionsymbol, '!H);
  1800. % Other Polynomials and Numbers
  1801. put('BernoulliP, 'fancy!-prifn, 'fancy!-indexed!-fn); % B_n(x)
  1802. put('BernoulliP, 'fancy!-functionsymbol, '!B);
  1803. put('EulerP, 'fancy!-prifn, 'fancy!-indexed!-fn); % E_n(x)
  1804. put('EulerP, 'fancy!-functionsymbol, '!E);
  1805. put('FibonacciP, 'fancy!-prifn, 'fancy!-indexed!-fn); % F_n(x)
  1806. put('FibonacciP, 'fancy!-functionsymbol, '!F);
  1807. put('Bernoulli, 'fancy!-prifn, 'fancy!-indexed!-symbol); % B_n
  1808. put('Bernoulli, 'fancy!-special!-symbol, '!B);
  1809. put('Euler, 'fancy!-prifn, 'fancy!-indexed!-symbol); % E_n
  1810. put('Euler, 'fancy!-special!-symbol, '!E);
  1811. put('Fibonacci, 'fancy!-prifn, 'fancy!-indexed!-symbol); % F_n
  1812. put('Fibonacci, 'fancy!-special!-symbol, '!F);
  1813. put('Motzkin, 'fancy!-prifn, 'fancy!-indexed!-symbol); % M_n
  1814. put('Motzkin, 'fancy!-special!-symbol, '!M);
  1815. symbolic procedure fancy!-indexed!-symbol(u);
  1816. % e.g. u = (Motzkin n)
  1817. fancy!-level
  1818. <<
  1819. fancy!-prefix!-operator car u;
  1820. fancy!-print!-one!-index cadr u
  1821. >>;
  1822. put('Stirling1, 'fancy!-prifn, 'fancy!-Stirling); % s_n^m
  1823. put('Stirling2, 'fancy!-prifn, 'fancy!-Stirling); % S_n^m
  1824. symbolic procedure fancy!-Stirling(u);
  1825. % u = (Stirling1/2 mu nu)
  1826. fancy!-level
  1827. begin scalar w;
  1828. fancy!-prefix!-operator(if car u eq 'Stirling1 then "\mathrm{s}"
  1829. else "\mathrm{S}");
  1830. w := fancy!-print!-indexlist1({cadr u}, '!_, '!*comma!*);
  1831. if testing!-width!* and w eq 'failed then return w;
  1832. w := fancy!-print!-indexlist1({caddr u}, '!^, '!*comma!*);
  1833. return w;
  1834. end;
  1835. % Other Special Functions
  1836. put('polylog, 'fancy!-prifn, 'fancy!-indexed!-fn);
  1837. put('polylog, 'fancy!-functionsymbol, "Li");
  1838. put('polylog, 'fancy!-symbolic!-length, 4);
  1839. % Hypergeometric Functions
  1840. put('hypergeometric,'fancy!-prifn,'fancy!-hypergeometric);
  1841. symbolic procedure fancy!-hypergeometric u;
  1842. fancy!-level
  1843. begin scalar w,a1,a2,a3;
  1844. a1 :=cdr cadr u;
  1845. a2 := cdr caddr u;
  1846. a3 := cadddr u;
  1847. fancy!-prin2!*("{}", 0);
  1848. w:=fancy!-print!-one!-index length a1;
  1849. if testing!-width!* and w eq 'failed then return w;
  1850. fancy!-prin2!*("F", 2);
  1851. w:=fancy!-print!-one!-index length a2;
  1852. if testing!-width!* and w eq 'failed then return w;
  1853. fancy!-prin2!*("\left(\left.", 1);
  1854. fancy!-prin2!*("{}", 0);
  1855. if null a1 then a1 := list '!-;
  1856. if null a2 then a2 := list '!-;
  1857. w := w eq 'failed or fancy!-print!-indexlist1(a1, '!^, '!*comma!*);
  1858. w := w eq 'failed or fancy!-print!-indexlist1(a2, '!_, '!*comma!*);
  1859. fancy!-prin2!*("\,", 1);
  1860. %w := w eq 'failed or fancy!-special!-symbol(124,1); % vertical bar
  1861. fancy!-prin2!*("\right|\,", 2);
  1862. w := w eq 'failed or fancy!-prinfit(a3, 0, nil);
  1863. fancy!-prin2!*("\right)", 1);
  1864. return w;
  1865. end;
  1866. % hypergeometric({1,2,u/w,v},{5,6},sqrt x);
  1867. put('MeijerG,'fancy!-prifn,'fancy!-meijerg);
  1868. symbolic procedure fancy!-meijerg u;
  1869. fancy!-level
  1870. begin scalar w,a1,a2,a3;
  1871. integer n,m,p,q;
  1872. a1 :=cdr cadr u;
  1873. a2 := cdr caddr u;
  1874. a3 := cadddr u;
  1875. m:=length cdar a2;
  1876. n:=length cdar a1;
  1877. a1 := append(cdar a1 , cdr a1);
  1878. a2 := append(cdar a2 , cdr a2);
  1879. p:=length a1; q:=length a2;
  1880. fancy!-prin2!*("G", 2);
  1881. w := w eq 'failed or
  1882. fancy!-print!-indexlist1({m,n},'!^,nil);
  1883. w := w eq 'failed or
  1884. fancy!-print!-indexlist1({p,q},'!_,nil);
  1885. fancy!-prin2!*("\left(", 1);
  1886. w := w eq 'failed or fancy!-prinfit(a3,0,nil);
  1887. fancy!-prin2!*("\,", 1);
  1888. %w := w eq 'failed or fancy!-special!-symbol(124,1); % vertical bar
  1889. fancy!-prin2!*("\left|\,{}", 2);
  1890. if null a1 then a1 := list '!-;
  1891. if null a2 then a2 := list '!-;
  1892. w := w eq 'failed or fancy!-print!-indexlist1(a1, '!^, '!*comma!*);
  1893. w := w eq 'failed or fancy!-print!-indexlist1(a2, '!_, '!*comma!*);
  1894. fancy!-prin2!*("\right.\right)", 1);
  1895. return w;
  1896. end;
  1897. % meijerg({{},1},{{0}},x);
  1898. %ACN Now a few things that can be useful for testing this code...
  1899. symbolic <<
  1900. % Arrange that if this file is loaded twice you do not get silly messages
  1901. % to do with redefinition of these.
  1902. if not get('texsym, 'simpfn) then
  1903. algebraic operator texsym, texbox, texfbox, texstring >>;
  1904. % texsym(!Longleftarrow) should generate \Longleftarrow (etc). This
  1905. % might plausibly be useful while checking that the interface can render
  1906. % all TeX built-in keywords properly. Furthermore I allow extra args, so
  1907. % that eg texsym(stackrel,f,texsym(longrightarrow)) turns into
  1908. % \stackrel{f}{\longrightarrow}
  1909. put('texsym,'fancy!-prifn,'fancy!-texsym);
  1910. symbolic procedure fancy!-texsym u;
  1911. fancy!-level
  1912. begin
  1913. if null u then return;
  1914. fancy!-prin2 list2string ('!\ . explode2 cadr u);
  1915. u := cddr u;
  1916. while u do <<
  1917. fancy!-line!* := "{" . fancy!-line!*;
  1918. fancy!-maprint(car u, 0);
  1919. fancy!-line!* := "}" . fancy!-line!*;
  1920. u := cdr u >>
  1921. end;
  1922. % texstring("arbitrary tex stuff",...)
  1923. % where atoms (eg strings and words) are just passed to tex but
  1924. % more complicated items go through fancy!-maprint.
  1925. put('texstring,'fancy!-prifn,'fancy!-texstring);
  1926. symbolic procedure fancy!-texstring u;
  1927. fancy!-level
  1928. for each s in cdr u do <<
  1929. if not atom s then fancy!-maprint(s, 0)
  1930. else <<
  1931. if not stringp s then s := list2string explode2 s;
  1932. fancy!-line!* := s . fancy!-line!* >> >>;
  1933. % texbox(h) is a box of given height (in points)
  1934. % texbox(h, d) is a box of given height and depth
  1935. % height is amount above the reference line, depth is amount
  1936. % below.
  1937. % textbox(h, d, c) is a box of given size with some specified content
  1938. % All these draw a frame around the space used so you can see what is
  1939. % goin on.
  1940. % The idea that this may be useful when checking how layouts cope with
  1941. % various sizes of content, eg big delimiters, square root signs etc. So I
  1942. % can test with "for i := 10:40 do write sqrt(texbox(i))" etc.
  1943. % to test sqrt with arguments of height 10, 11, ... to 40 points. Note that
  1944. % certainly with the CSL version the concept of a "point" is a bit vauge!
  1945. % However if I were to imagine that my screen was at 75 pixels per inch I
  1946. % could with SOME reason interpret point as meaning pixel, and that is
  1947. % what I will do. At present what I might do about hard-copy output is
  1948. % pretty uncertain. If height and depth are given as 0 and there is a
  1949. % content them the content will define the box size.
  1950. put('texbox,'fancy!-prifn,'fancy!-texbox);
  1951. symbolic procedure fancy!-texbox u;
  1952. fancy!-level
  1953. begin
  1954. scalar height, depth, contents;
  1955. contents := nil;
  1956. u := cdr u;
  1957. height := car u;
  1958. u := cdr u;
  1959. if u then <<
  1960. depth := car u;
  1961. u := cdr u;
  1962. if u then contents := car u >>;
  1963. if not numberp height then height:=0;
  1964. if not numberp depth then depth:=0;
  1965. if height=0 and depth=0 and null contents then height:=10;
  1966. fancy!-prin2 "\fbox{";
  1967. if height neq 0 or depth neq 0 then << % insert a rule
  1968. fancy!-line!* := "\rule" . fancy!-line!*;
  1969. if depth neq 0 then <<
  1970. fancy!-line!* := "[-" . fancy!-line!*;
  1971. fancy!-line!* := depth . fancy!-line!*;
  1972. fancy!-line!* := "pt]" . fancy!-line!* >>;
  1973. fancy!-line!* := "{0pt}{" . fancy!-line!*;
  1974. fancy!-line!* := (height+depth) . fancy!-line!*;
  1975. fancy!-line!* := "pt}" . fancy!-line!* >>;
  1976. if contents then contents := fancy!-maprint(contents, 0)
  1977. else fancy!-line!* := "\rule{10pt}{0pt}" . fancy!-line!*;
  1978. fancy!-prin2 "}";
  1979. return contents
  1980. end;
  1981. % texfbox is a simplified version of texbox, and just draws a box around the
  1982. % expression it is given.
  1983. put('texfbox,'fancy!-prifn,'fancy!-texfbox);
  1984. symbolic procedure fancy!-texfbox u;
  1985. fancy!-level
  1986. begin
  1987. fancy!-prin2 "\fbox{";
  1988. u := fancy!-maprint(cadr u, 0);
  1989. fancy!-prin2 "}";
  1990. return u
  1991. end;
  1992. endmodule;
  1993. module rrprint_redfront;
  1994. % Code based on the redfront package to support font colouring for
  1995. % non-typeset algebraic-mode output. To enable it, execute
  1996. % rrprint 'coloured!-output;
  1997. fluid '(orig!*);
  1998. procedure coloured!-output(mode,l);
  1999. begin scalar outputhandler!*;
  2000. if mode eq 'maprin then
  2001. if ofl!* or posn!* neq orig!* then
  2002. maprin l
  2003. else <<
  2004. coloured!-output!-on();
  2005. assgnpri(l,nil,nil);
  2006. coloured!-output!-off()
  2007. >>
  2008. else if mode eq 'prin2!* then
  2009. prin2!* l
  2010. else if mode eq 'terpri then
  2011. terpri!* l
  2012. else if mode eq 'assgnpri then <<
  2013. coloured!-output!-on();
  2014. % All args needed for matrix assignments:
  2015. assgnpri(car l, cadr l, caddr l);
  2016. coloured!-output!-off()
  2017. >> else
  2018. rederr {"unknown method ", mode, " in coloured!-output"}
  2019. end;
  2020. procedure coloured!-output!-on();
  2021. <<
  2022. terpri!* nil;
  2023. prin2 int2id 3;
  2024. terpri!* nil
  2025. >>;
  2026. procedure coloured!-output!-off();
  2027. <<
  2028. terpri!* nil;
  2029. prin2 int2id 4
  2030. >>;
  2031. procedure coloured!-output!-formwrite(u,vars,mode);
  2032. % Workaround to avoid linebreaks between elements output by write.
  2033. begin scalar z;
  2034. z := formwrite(u,vars,mode);
  2035. if z then return {'cond,
  2036. {{'and,{'eq,'outputhandler!*,'(quote coloured!-output)},'(not ofl!*)},
  2037. {'prog,'(outputhandler!*),'(coloured!-output!-on),z,'(coloured!-output!-off)}},
  2038. {t,z}}
  2039. end;
  2040. procedure rrprint outputhandler;
  2041. % Select an output handler or none.
  2042. % outputhandler = 'fancy!-output, 'coloured!-output or nil.
  2043. put('write, 'formfn,
  2044. if (outputhandler!* := outputhandler) eq 'coloured!-output
  2045. then 'coloured!-output!-formwrite else 'formwrite);
  2046. endmodule;
  2047. end;