tri.red 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691
  1. % TeX-REDUCE-Interface 0.70
  2. % set GREEK asserted
  3. % set LOWERCASE asserted
  4. % \tolerance 10
  5. % \hsize=150mm
  6. module tri;
  7. % ======================================================================
  8. % T h e T e X - R e d u c e - I n t e r f a c e
  9. % ======================================================================
  10. % (C) 1987/1988 by Rechenzentrum der Universitaet zu Koeln
  11. % (University of Cologne Computer Center)
  12. % Abt. Anwendungssoftware
  13. % (Application Software Department)
  14. % ATTN: Werner Antweiler
  15. % Robert-Koch-Str. 10
  16. % 5000 Koeln 41
  17. % Federal Republic of Germany
  18. % E-Mail: reduce@rrz.Uni-Koeln.DE
  19. % All rights reserved. Permission to copy without fee all or part of
  20. % this software product is hereby granted provided that the copies are
  21. % not made or distributed for direct commercial advantage, this copy-
  22. % right notice and its date appear, and notice is given that copying is
  23. % by permission of the authors. To copy otherwise requires a fee and/or
  24. % specific permission. This software product has been developed by
  25. % WERNER ANTWEILER at the University of Cologne Computer Center, West
  26. % Germany. The TeX-Reduce-Interface has been totally written in REDUCE-
  27. % LISP.
  28. % ======================================================================
  29. % Authors: Werner Antweiler, Andreas Strotmann, Volker Winkelmann.
  30. % Modifications: David Hartley.
  31. %
  32. % Last Update: 14-Jul-96 Version 0.70
  33. % ======================================================================
  34. %
  35. % Section Survey
  36. % ----------------------------------------------------------------------
  37. % Section Contents Page
  38. % ----------------------------------------------------------------------
  39. % 0 Main Procedure (and Interfacing) 2
  40. % 1 Creating a TeX item list 5
  41. % 1.1 Operator Administration Routines 5
  42. % 1.2 Prefix to Infix Conversion 6
  43. % 1.3 Making a TeX item 9
  44. % 2 Inserting Glue Items 16
  45. % 3 Line Breaking 18
  46. % 3.1 Resolving Fraction Expressions 20
  47. % 3.2 Creating a Break List 21
  48. % 3.3 Major Line Breaking Routine 23
  49. % 4 TeX-Output Routines 28
  50. % 5 User Interface 30
  51. % ----------------------------------------------------------------------
  52. % Note: page breaks (form feeds) are indicated by "%ff" lines
  53. %ff
  54. % ----------------------------------------------------------------------
  55. % Section 0: Global Variables, Main Procedure and Interfacing
  56. % ----------------------------------------------------------------------
  57. % IMPORTANT NOTICE FOR REDUCE 3.2 USERS:
  58. % This code was written to run under REDUCE 3.3. Users of REDUCE 3.2
  59. % therefore have to change two lines of this code before compiling it:
  60. % 1) the line `switch ...;` must be deleted
  61. % 2) the construct `FOR EACH ... IN ... JOIN ...` must be changed
  62. % to `FOR EACH ... IN ... CONC ...` because only the latter is
  63. % accepted by REDUCE 3.2.
  64. % Furthermore, the TRI supports features of REDUCE that are new in ver-
  65. % sion 3.3. You cannot take advantage of them under version 3.2. In
  66. % particular, some of the examples in the accompanying test file may
  67. % fail.
  68. create!-package('(tri),'(contrib misc));
  69. fluid '(
  70. % -----------------+---------------------------------------------------+
  71. % FLUID VARIABLES | EXPLANATION |
  72. % -----------------+---------------------------------------------------+
  73. !*tex % flag to be switched ON and OFF (TeX Output Mode)
  74. !*texbreak % flag to be switched ON and OFF (Break Facility)
  75. !*texindent % flag to be switched ON and OFF (Indentation Mode)
  76. texstack!* % stack to save expressions for an unfilled line
  77. hsize!* % total page width in scaled points (sp)
  78. % note: 65536sp = 1pt = 1/72.27 inch
  79. hss!* % total line stretchability/shrinkability (in sp)
  80. hww!* % optimum page fit width (= 3/4 hsize) (in sp)
  81. tolerance!* % value within break points are considered to be
  82. % feasible (range: 0..10000)
  83. !*lower % used in REDUCE 3.5 to make everything lower case
  84. % -----------------+---------------------------------------------------+
  85. );
  86. global '(
  87. % ------------------+---------------------------------------------------+
  88. % GLOBAL VARIABLES | EXPLANATION |
  89. % ------------------+---------------------------------------------------+
  90. metricu!* % EXCALC
  91. indxl!* % EXCALC
  92. % ------------------+---------------------------------------------------+
  93. );
  94. % declare switches:
  95. switch tex,texbreak,texindent;
  96. % declare switch dependencies:
  97. put('texindent,'simpfg,'((t (progn (setq !*tex t)
  98. (setq !*texbreak t))) ));
  99. put('texbreak,'simpfg,'((t (setq !*tex t)) ));
  100. put('tex,'simpfg,'((nil (progn (setq !*texbreak nil)
  101. (setq !*texindent nil))) ));
  102. symbolic procedure tri!-error(strlst,errclass);
  103. << for each x in strlst do prin2 x; terpri();
  104. if errclass='fatal then
  105. rederr "Aborting."
  106. >>;
  107. % Code called by ASSGNPRI.
  108. symbolic procedure texpri(u,v,w);
  109. (if x and get(x,'texprifn) then apply3(get(x,'texprifn),u,v,w)
  110. else texvarpri(u,v,w)) where x = getrtype u;
  111. symbolic procedure texvarpri(u,v,w); % same parameters as above
  112. begin scalar !*lower;
  113. if w memq '(first only) then texstack!*:=nil;
  114. if v then for each x in reverse v do u:=list('setq,x,u);
  115. texstack!* := nconc(texstack!*,mktag(u,0,nil));
  116. if (w=t) or (w='only) or (w='last) then
  117. << if !*texbreak then
  118. << texstack!* := insertglue(texstack!*);
  119. texstack!* := trybreak(texstack!*,breaklist(texstack!*))
  120. >>;
  121. texout(texstack!*,!*texbreak); texstack!*:=nil
  122. >>;
  123. %if (null w) or (w eq 'first) then
  124. % texstack!* := nconc(texstack!*,list '!\!q!u!a!d! );
  125. nil
  126. end;
  127. %ff
  128. % The following procedure interfaces to E. Schruefer's EXCALC package.
  129. % Courtesy: E. Schruefer.
  130. put('form!-with!-free!-indices,'texprifn,'texindxpri);
  131. symbolic procedure texindxpri(u,v,w);
  132. begin scalar metricu,il,dnlist,uplist,r,x,y,z;
  133. if v then go to a;
  134. metricu := metricu!*;
  135. metricu!* := nil;
  136. il := allind !*t2f lt numr simp0 u;
  137. for each j in il do
  138. if atom revalind j
  139. then uplist := j . uplist
  140. else dnlist := cadr j . dnlist;
  141. for each j in intersection(uplist,dnlist) do
  142. il := delete(j,delete(revalind
  143. lowerind j,il));
  144. metricu!* := metricu;
  145. y := flatindxl il;
  146. r := simp!* u;
  147. for each j in mkaindxc(y,nil) do
  148. <<x := pair(y,j);
  149. z := exc!-mk!*sq2 multsq(subfindices(numr r,x),1 ./ denr r);
  150. if null(!*nero and (z = 0))
  151. then texvarpri(z,list subla(x,'ns . il),'only)>>;
  152. return u;
  153. a: v := car v;
  154. y := flatindxl allindk v;
  155. for each j in if flagp(car v,'antisymmetric) and
  156. coposp cdr v then comb(indxl!*,length y)
  157. else mkaindxc(y,nil) do
  158. <<x := pair(y,j);
  159. z := aeval subla(x,v);
  160. if null(!*nero and (z = 0))
  161. then texvarpri(z,list subla(x,v),'only)>>;
  162. return u
  163. end;
  164. %ff
  165. % ----------------------------------------------------------------------
  166. % Section 1: Creating a TeX item list
  167. % ----------------------------------------------------------------------
  168. %
  169. % Linearization is performed by expanding REDUCE prefix expressions into
  170. % a so called "TeX item list". Any TeX item is a readable TeX primitive
  171. % or macro (i.e. a LISP atom), with properties 'CLASS, 'TEXTAG, 'TEXNAME
  172. % and eventually 'TEXPREC, 'TEXPATT and 'TEXUBY bound to them, depending
  173. % on what kind of TeX item it actually is. (See Section 1.3 for further
  174. % information.)
  175. % A REDUCE expression is expanded using the two functions "mktag"
  176. % and "makefunc". Function "mktag" identifies the operator and is able
  177. % to put some brackets around the expression if necessary. "makefunc" is
  178. % a pattern oriented 'unification' function, which matches the arguments
  179. % of a REDUCE expression in order of appearance with so called 'unifica-
  180. % tion tags', as explained below. "mktag" and "makefunc" are highly
  181. % recursive functions.
  182. % The patterns mentioned above are lists (consisting of 'tags') asso-
  183. % ciated with each REDUCE operator. A tag is defined as either an atom
  184. % declared as a TeX item or one of the following 'unification tags':
  185. % (F) ............ insert operator
  186. % (X) ............ insert non-associative argument
  187. % (Y) ............ insert (left/right-) associative argument
  188. % (Z) ............ insert superscript/subscript argument
  189. % (R) ............ use tail recursion to unify remaining arguments
  190. % (associativity depends on previous (X) or (Y) )
  191. % (L) ............ insert a list of arguments (eat up all arguments)
  192. % (M) ............ insert a matrix (and eat up all arguments)
  193. % (APPLY <fun>) ... apply function <fun> to remaining argument list
  194. % ----------------------------------------------------------------------
  195. % ----------------------------------------------------------------------
  196. % Section 1.1: Operator Administration Routines
  197. % ----------------------------------------------------------------------
  198. symbolic procedure makeop(op,prec,patt,uby);
  199. << put(op,'texprec,prec); put(op,'texpatt,patt);
  200. put(op,'texuby,if uby then (car uby).(cadr uby) else nil.nil)
  201. >>;
  202. symbolic procedure makeops(l);
  203. for each w in l do makeop(car w,cadr w,caddr w,cadddr w);
  204. %ff
  205. makeops('(
  206. %-----------+----------+---------------------+-------------------------+
  207. % Name |Precedence|Expansion List |Unary/Binary Interchange |
  208. %-----------+----------+---------------------+-------------------------+
  209. (setq 1 ((x) (f) !\![ (x) !\!]) nil)
  210. (or 30 ((x) (f) (r)) nil)
  211. (and 40 ((x) (f) (r)) nil)
  212. (equal 50 ((x) (f) !\![ (x) !\!]) nil)
  213. (replaceby 50 ((x) (f) !\![ (x) !\!]) nil)
  214. (greaterp 50 ((x) (f) !\![ (x) !\!]) nil)
  215. (lessp 50 ((x) (f) !\![ (x) !\!]) nil)
  216. (geq 50 ((x) (f) !\![ (x) !\!]) nil)
  217. (leq 50 ((x) (f) !\![ (x) !\!]) nil)
  218. (neq 50 ((x) (f) !\![ (x) !\!]) nil)
  219. (member 50 ((x) (f) (x)) nil)
  220. (when 50 ((x) (f) (x)) nil)
  221. (plus 100 ((x) (f) (r)) (minus difference))
  222. (minus 100 ((f) (y)) nil)
  223. (difference 100 ((x) (f) (y)) nil)
  224. (union 100 ((x) (f) (r)) nil)
  225. (setdiff 100 ((x) (f) (y)) nil)
  226. (taylor!* 100 ((apply maketaylor)) nil) % precedence like plus
  227. (times 200 ((x) (f) (r)) (recip quotient))
  228. (wedge 200 ((x) (f) (r)) nil) % EXCALC
  229. (quotient 200 ((f) (z) !}!{ (z) !}) nil)
  230. (intersection 200 ((x) (f) (r)) nil)
  231. (!*sq 200 ((apply make!*sq)) nil) % precedence like quotient
  232. (recip 700 ((f) !1 !}!{ (z) !}) nil)
  233. (expt 850 ((x) !^!{ (z) !}) nil)
  234. (sqrt 800 ((f) ! ! ! (z) !}) nil)
  235. (!:rd!: 999 ((apply make!:rd!:)) nil)
  236. (!:cr!: 999 ((apply makedomain)) nil)
  237. (!:gi!: 999 ((apply makedomain)) nil)
  238. (!:rn!: 999 ((apply makedomain)) nil)
  239. (!:crn!: 999 ((apply makedomain)) nil)
  240. (!:mod!: 999 ((apply makedomain)) nil)
  241. (!:dn!: 999 ((apply makedomain)) nil)
  242. (!:int!: 999 ((apply makedomain)) nil)
  243. (not 999 ((f) (y)) nil)
  244. (mat 999 ((f) (m !\!c!r! !&) !}) nil)
  245. (list 999 (!\!{ (l !\co! ) !\!}) nil)
  246. (df 999 ((apply makedf)) nil)
  247. (int 999 ((apply makeint)) nil)
  248. (limit 999 ((apply makelimit)) nil)
  249. (limit!+ 999 ((apply makelimit)) nil)
  250. (limit!- 999 ((apply makelimit)) nil)
  251. (sum 999 ((apply makelimit)) nil)
  252. (prod 999 ((apply makelimit)) nil)
  253. (!~ 999 ((f) (y)) nil)
  254. (!*interval!* 999 ((x) !. !. (x)) nil)
  255. (innerprod 999 (!{ !\!r!m! !i !}
  256. !_!{ (z) !} (x)) nil) % EXCALC
  257. (liedf 999 (!\!h!b!o!x! !{ !\!i!t! !\!$ !}
  258. !_!{ (z) !} (x)) nil) % EXCALC
  259. (hodge 999 ((f) (y)) nil) % EXCALC
  260. (partdf 999 ((f) (apply makepartdf)) nil) % EXCALC
  261. (d 999 (!\!d! (x)) nil) % EXCALC
  262. (!:ps!: 999 ((apply make!:ps!:)) nil) % TPS
  263. (rest!_order 999 (!{ !\!r!m! !O !} (x)) nil) % TPS
  264. %-----------+----------+----------------------+------------------------+
  265. ));
  266. % ----------------------------------------------------------------------
  267. % Section 1.2 : Prefix to Infix Conversion
  268. % ----------------------------------------------------------------------
  269. symbolic procedure mktag(tag,prec,assf);
  270. % analyze an operator and decide what to do
  271. % parameters: tag ....... the term itself
  272. % prec ...... outer precedence
  273. % assf ...... outer associativity flag
  274. if null tag then nil else
  275. if atom tag then texexplode(tag) else
  276. begin
  277. scalar tagprec,term;
  278. tagprec:=get(car tag,'texprec) or 999; % get the operator's precedence
  279. term:=makefunc(car tag,cdr tag,tagprec); % expand expression and if it
  280. % is necessary, put a left and a right bracket around the expression.
  281. if (assf and (prec = tagprec)) or (tagprec < prec)
  282. then term:=nconc('!\!( . term , '!\!) . nil);
  283. return(term)
  284. end;
  285. symbolic procedure makearg(l,s);
  286. % collect arguments from a list <l> and put seperators <s> between them
  287. if null l then nil
  288. else if null cdr l then mktag(car l,0,nil)
  289. else nconc(mktag(car l,0,nil), s . makearg(cdr l,s));
  290. symbolic procedure makemat(m,v,h);
  291. % make a matrix <m> and use <h> as a horizontal seperator and <v> as
  292. % a vertical terminator.
  293. if null m then nil else nconc(makearg(car m,h), v . makemat(cdr m,v,h));
  294. %ff
  295. smacro procedure istag(v,w); car v=w;
  296. smacro procedure unary(uby); car uby;
  297. smacro procedure binary(uby); cdr uby;
  298. smacro procedure lcopy(a); for each x in a collect x;
  299. symbolic procedure makefunc(op,arg,prec);
  300. begin
  301. scalar term,tag,a,pattern,uby;
  302. term:=nil;
  303. pattern:=get(op,'texpatt)
  304. or ( if flagp(op,'indexvar) then '((apply makeexcinx))
  305. else '( (f) !\!( (l !,) !\!) ));
  306. uby:=get(op,'texuby);
  307. while pattern do
  308. << tag:=car pattern; pattern:=cdr pattern;
  309. if (atom tag) then a:=tag.nil
  310. else if (not atom car tag) then a:=nil
  311. else if istag(tag,'f) then
  312. % test for unary to binary operator interchange
  313. if arg and (not atom car arg) and uby and (caar arg=unary(uby))
  314. then << a:=texexplode(binary(uby)); arg:=cadar arg.cdr arg >>
  315. else a:=texexplode(op)
  316. else if istag(tag,'apply)
  317. then << a:=apply3(cadr tag,op,arg,prec); arg:=nil >>
  318. else if null arg then a:=nil
  319. else if istag(tag,'x)
  320. then << a:=mktag(car arg,prec,nil); arg:=cdr arg >>
  321. else if istag(tag,'y)
  322. then << a:=mktag(car arg,prec,t); arg:=cdr arg >>
  323. else if istag(tag,'z)
  324. then << a:=mktag(car arg,0,nil); arg:=cdr arg >>
  325. else if istag(tag,'r) then
  326. if cdr arg % more than one argument ?
  327. then << pattern:=get(op,'texpatt); a:=nil >>
  328. else << a:=mktag(car arg,prec,nil); arg:=cdr arg >>
  329. else if istag(tag,'l)
  330. then << a:=makearg(arg,cadr tag); arg:=nil >>
  331. else if istag(tag,'m)
  332. then << a:=makemat(arg,cadr tag,caddr tag); arg:=nil >>
  333. else a:=nil;
  334. if a then term:=nconc(term,a)
  335. >>;
  336. return(term)
  337. end;
  338. %ff
  339. symbolic procedure make!*sq(op,arg,prec);
  340. % Convert !*sq's to true prefix form
  341. mktag(prepreform prepsq!* sqhorner!* car arg,0,nil);
  342. symbolic procedure makedf(op,arg,prec); % DF operators are tricky
  343. begin
  344. scalar dfx,f,vvv; integer degree;
  345. dfx:=lcopy(f:=texexplode op); degree:=0;
  346. nconc(dfx,mktag(car arg,prec,nil)); dfx:=nconc(dfx,list '!}!{);
  347. for each item in cdr arg do
  348. if numberp(item) then
  349. << dfx:= nconc(dfx,'!^!{ .texexplode(item));
  350. dfx:= nconc(dfx,list '!});
  351. degree:=degree+item-1;
  352. >>
  353. else
  354. << dfx:= nconc(dfx,append(f,mktag(item,prec,nil))); degree:=degree+1
  355. >>;
  356. if degree>1 then
  357. << vvv:=nconc(texexplode(degree), '!} . cdr dfx);
  358. rplacd(dfx,'!^!{ . vvv)
  359. >>;
  360. return ('!\!f!r!a!c!{ . nconc(dfx, list '!}))
  361. end;
  362. symbolic procedure makepartdf(op,arg,prec); % EXCALC extension
  363. if cdr arg then
  364. ('!_!{ . nconc(makearg(cdr arg,'!,), '!} . mktag(car arg,prec,nil)))
  365. else ('!_!{ . nconc(mktag(car arg,prec,nil), list '!}));
  366. smacro procedure inxextend(item,ld,rd);
  367. nconc(result,ld.nconc(texexplode(item),list rd));
  368. symbolic procedure makeexcinx(op,arg,prec); % EXCALC extension
  369. begin scalar result;
  370. result:=nconc('!{.nil,texexplode(op));
  371. for each item in arg do
  372. if numberp item then
  373. if minusp item then inxextend(-item,'!{!}!_!{,'!})
  374. else inxextend(item ,'!{!}!^!{,'!}) else
  375. if atom item then inxextend(item ,'!{!}!^!{,'!}) else
  376. if car item='minus then inxextend(cadr item ,'!{!}!_!{,'!})
  377. else inxextend('! ,'!{!}!_!{,'!});
  378. return nconc(result,'!}.nil)
  379. end;
  380. symbolic procedure make!:rd!:(op,arg,prec);
  381. begin scalar digits,str; integer dotpos,xp;
  382. op := rd!:explode(op . arg);
  383. digits := car op; xp := cadr op; dotpos := caddr op;
  384. for i:=1:dotpos do
  385. << str := car digits . str;
  386. digits := cdr digits; if null digits then digits := '(!0) >>;
  387. str := '!. . str;
  388. for each c in digits do str := c . str;
  389. if not(xp=0) then
  390. << for each c in '(!\!, !1 !0 !^!{) do str := c . str;
  391. for each c in explode2 xp do str := c . str;
  392. str := '!} . str >>;
  393. return reverse str;
  394. end;
  395. symbolic procedure makedomain(op,arg,prec);
  396. if get(op,'prepfn) then
  397. mktag(apply1(get(op,'prepfn),op . arg),prec,nil)
  398. else if get(op,'prepfn2) then
  399. mktag(apply1(get(op,'prepfn2),op . arg),prec,nil)
  400. else if get(op,'simpfn) then
  401. mktag(apply1(get(op,'simpfn),op . arg),prec,nil)
  402. else rerror(tri,000,
  403. {"Don't know how to print domain",get(op,'dname) or op});
  404. symbolic procedure makelimit(op,arg,prec);
  405. % for operators like limit, sum and prod which may have limit scripts
  406. begin scalar a,term,limits;
  407. if arg then limits := cdr arg;
  408. term := texexplode(op);
  409. if limits then
  410. << a := '!_!{ . mktag(car limits,0,nil);
  411. limits := cdr limits;
  412. term := nconc(term,a) >>;
  413. if limits then
  414. << a :=
  415. if op = 'limit then '!\!t!o! % spaces critical
  416. else if op = 'limit!+ then '!\!u!p!a!r!r!o!w! %
  417. else if op = 'limit!- then '!\!d!o!w!n!a!r!r!o!w! %
  418. else '!=;
  419. a := a . mktag(car limits,0,nil);
  420. limits := cdr limits;
  421. term := nconc(term,a) >>;
  422. if limits then
  423. << a := '!} . '!^!{ . mktag(car limits,0,nil);
  424. term := nconc(term,a) >>;
  425. a := '!{ . if arg then mktag(car arg,prec,nil) else nil;
  426. if arg and cdr arg then a := '!} . a;
  427. term := nconc(term,a);
  428. term := nconc(term,'!} . nil);
  429. return term;
  430. end;
  431. symbolic procedure texgroup u;
  432. % surround u by TeX {}
  433. % NB Destructive!!
  434. nconc('!{ . if null u or listp u then u else {u},'!} . nil);
  435. symbolic procedure makeint(op,arg,prec);
  436. % for operators like int which may have limit scripts
  437. begin scalar a,term,limits;
  438. if arg and cdr arg then limits := cddr arg;
  439. term := texexplode(op);
  440. if limits then
  441. << a := '!_!{ . cdr texgroup mktag(car limits,0,nil);
  442. limits := cdr limits;
  443. term := nconc(term,a) >>;
  444. if limits then
  445. << a := '!^!{ . cdr texgroup mktag(car limits,0,nil);
  446. limits := cdr limits;
  447. term := nconc(term,a) >>;
  448. a := if arg then mktag(car arg,0,nil);
  449. a := nconc(a,if arg and cdr arg then '!\!, . '!d . mktag(cadr arg,0,nil));
  450. term := nconc(term,texgroup a);
  451. return term;
  452. end;
  453. symbolic procedure maketaylor(op,arg,prec);
  454. mktag(apply1(get(op,'fancy!-reform),op . arg),prec,nil);
  455. % The following is part of the interface to TPS.
  456. % Andreas Strotmann, 19 Mar 93
  457. % ps:numberp smacro required for compilation; copied over from tps.red
  458. symbolic smacro procedure ps!:numberp u;
  459. numberp u or (car u neq '!:ps!: and get(car u,'dname));
  460. % fluid declaration to avoid compiler warnings
  461. fluid '(ps!:exp!-lim);
  462. % symbolic procedure ps!:prin!: p;
  463. symbolic procedure make!:ps!:(op, arg, prec); % TPS interface,
  464. % (lambda (first,u,delta,symbolic!-exp!-pt,about,atinf);
  465. (lambda (first,u,delta,symbolic!-exp!-pt,about,atinf,texps,p);
  466. << % if !*nat and posn!*<20 then orig!*:=posn!*;
  467. atinf:=(about='ps!:inf);
  468. ps!:find!-order p;
  469. delta:=prepf((ps!:depvar p) .** 1 .*1 .+
  470. (negf if atinf then nil
  471. % expansion about infinity
  472. else if idp about then !*k2f about
  473. else if ps!:numberp about then !*n2f about
  474. else if (u:=!*pre2dp about) then !*n2f u
  475. else !*k2f(symbolic!-exp!-pt:= compress
  476. append(explode ps!:depvar p, explode '0))));
  477. % if symbolic!-exp!-pt then prin2!* "[";
  478. % prin2!* "{";
  479. texps := nconc(texps, list '!\!{ );
  480. %
  481. for i:=(ps!:order p): ps!:exp!-lim do
  482. << u:=ps!:term(p,i);
  483. if not null numr u then
  484. <<if minusf numr u then <<u:=negsq u; % prin2!* " - ">>
  485. texps := nconc(texps, list '!-)
  486. >>
  487. else if not first then % prin2!* " + ";
  488. texps := nconc(texps, list '!+);
  489. first := nil;
  490. % if posn!*>55 then <<terpri!* nil;prin2!* " ">>;
  491. if denr u neq 1 then % prin2!* "(";
  492. texps := nconc(texps, list '!\!( );
  493. if u neq '(1 . 1) then
  494. % maprint(prepsq u,get('times,'infix))
  495. texps := nconc(texps,
  496. mktag(prepsq u,
  497. get('times, 'texprec),
  498. nil))
  499. else if i=0 then % prin2!* 1;
  500. texps := nconc(texps, list '!1);
  501. if denr u neq 1 then % prin2!* ")";
  502. texps := nconc(texps, list '!\!) );
  503. if i neq 0 and u neq '(1 . 1) then % prin2!* "*";
  504. texps := nconc(texps,list get('times,'texname));
  505. if i neq 0 then
  506. % xprinf(!*p2f mksp(delta,
  507. % if atinf then -i else i),nil,nil)
  508. texps := (lambda i;
  509. nconc(texps,
  510. mktag (if (i = 1) then delta
  511. else list('expt, delta, i),
  512. get('times, 'texprec),
  513. nil)))
  514. (if atinf then -i else i);
  515. >>
  516. >>;
  517. if first then % prin2!* "0";
  518. texps := nconc(texps, list '!0 );
  519. % if posn!*>55 then terpri!* nil;
  520. u:=ps!:exp!-lim +1;
  521. texps := (lambda u;
  522. nconc(texps,
  523. '!+ . mktag(list('rest!_order,
  524. if (u = 1) then delta
  525. else list('expt, delta, u)),
  526. get('plus, 'texprec),
  527. nil)))
  528. (if atinf then -u else u);
  529. %if (u=1) and not atinf and (about neq 0) then
  530. % prin2!* " + O"
  531. %else prin2!* " + O(";
  532. %xprinf(!*p2f mksp(delta,if atinf then -u else u),nil,nil);
  533. %if (u=1) and not atinf and (about neq 0) then
  534. % prin2!* "}"
  535. % else prin2!* ")}";
  536. texps := nconc(texps, list '!\!} );
  537. if symbolic!-exp!-pt then
  538. << %if posn!*>45 then terpri!* nil;
  539. %prin2!* " where ";
  540. texps := nconc(texps, list '!_!{ );
  541. %prin2!* symbolic!-exp!-pt;
  542. texps := nconc(texps, texexplode symbolic!-exp!-pt);
  543. %prin2!* " = ";
  544. texps := nconc(texps, list '!= );
  545. %maprin about;
  546. texps := nconc(texps, mktag(makeprefix about,
  547. get('equal, 'texprec), nil));
  548. texps := nconc(texps, list '!} );
  549. %prin2!* "]"
  550. >>;
  551. texps
  552. >>)
  553. % (t,nil,nil,nil,ps!:expansion!-point p,nil);
  554. (t,nil,nil,nil,ps!:expansion!-point(op . arg),nil,nil,op . arg);
  555. %ff
  556. % ----------------------------------------------------------------------
  557. % Section 1.3 : Making a TeX Item
  558. % ----------------------------------------------------------------------
  559. % Properties of TeX items:
  560. % 'CLASS ..... one of the following class specifiers
  561. % 'ORD .... ordinary symbols
  562. % 'LOP .... large operators
  563. % 'BIN .... binary operators
  564. % 'REL .... relational operators
  565. % 'OPN .... opening symbols (left parenthesis)
  566. % 'CLO .... closing symbols (right parenthesis)
  567. % 'PCT .... punctuation symbols
  568. % 'INN .... inner TeX group delimiters
  569. % 'TEXTAG ..... one of the following lists or atoms
  570. % <kind> .. an atom describing an 'INN class group delimiter
  571. % (<w1> <w2> <w3>) ... where is
  572. % <w1> ..... width for text style (cmmi10)
  573. % <w2> ..... width for scriptstyle (cmmi8)
  574. % <w3> ..... width for scriptscriptstyle (cmmi5)
  575. % The parital lists of the list which is passed to makeitems have the
  576. % following general structure:
  577. % (<TeX-item> <class> <TeX-tag> <v1> <v2> ... )
  578. % where is
  579. % <TeX-item> .... the atom which actually is the TeX code
  580. % <class> ....... the 'CLASS property as explained above
  581. % <TeX-tag> ..... the 'TEXTAG property as explained above
  582. % <v1> etc. ..... atoms which will be bound to specific TeX items
  583. % by its property 'TEXNAME
  584. % ----------------------------------------------------------------------
  585. smacro procedure triassert(name,item); put(name,'texname,item);
  586. smacro procedure assertl(l); for each v in l do triassert(car v,cadr v);
  587. smacro procedure retract(name); put(name,'texname,nil);
  588. smacro procedure retractl(l); for each v in l do retract(car v);
  589. smacro procedure gettexitem(a); get(a,'texname) or (get(a,'class)and a);
  590. put ('texitem,'stat,'rlis); % handle argument passing for func. TeXitem
  591. symbolic procedure texitem(arglist);
  592. begin scalar x,ok,item,class,tag;
  593. if length arglist neq 3
  594. then rederr "Usage: TeXitem(item,class,width-list);";
  595. item:=car arglist; class:= cadr arglist; tag:= caddr arglist;
  596. ok:=memq(class,'(ord bin rel pct opn clo lop));
  597. if not ok then << prin2 "% illegal item class "; print class >>;
  598. if atom tag then ok:=nil else
  599. << if car(tag)='list then tag:=cdr tag; % accept algebraic lists
  600. for each x in tag do if not numberp x then ok:=nil
  601. >>;
  602. if not ok then << prin2 "% illegal width tag "; print tag >>;
  603. if ok then
  604. << item:=intern(item); put(item,'class,class); put(item,'textag,tag)
  605. >>;
  606. prin2 "% Item "; prin2 item;
  607. if not ok then prin2 "not "; prin2 " added"; terpri();
  608. return nil
  609. end;
  610. %ff
  611. symbolic procedure makeitems(l);
  612. for each w in l do
  613. begin scalar iw;
  614. iw:=intern(car w);
  615. put(iw,'class,cadr w); put(iw,'textag,caddr w);
  616. for each v in cdddr w do triassert(v,iw);
  617. end;
  618. fluid '(texunknowncounter!*);
  619. texunknowncounter!*:= 0;
  620. symbolic procedure unknownitem(a);
  621. << texunknowncounter!* := texunknowncounter!* +1;
  622. prin2 "% non-fatal error: unknown atom "; prin2 a;
  623. prin2 " replaced by ?_{"; prin2 texunknowncounter!*;
  624. prin2 "}"; terpri();
  625. '!? . '!_!{ . nconc(explode texunknowncounter!*, list '!})
  626. >>;
  627. symbolic procedure texexplode(a);
  628. begin scalar b;
  629. b:=if a and (atom a) then
  630. (gettexitem(a)
  631. or if numberp(a) then texcollect(explode(a))
  632. else if stringp(a) then strcollect(explode2(a))
  633. else texexplist(texcollect(explode2(a))));
  634. b:=if null b then list '! else if not atom b then b else list b;
  635. return b
  636. end;
  637. symbolic procedure texcollect(l);
  638. for each el in l join
  639. if null gettexitem(el) then unknownitem(el)
  640. else gettexitem(el).nil;
  641. smacro procedure strtexitem(e);
  642. if e='! then list '!\! % space after ! is necessary
  643. else if e='! then list '!\! % there is a tab before the "then"
  644. else if liter(e) then {e}
  645. else if gettexitem(e) then {gettexitem(e)}
  646. else unknownitem(e); % or '! ;
  647. symbolic procedure strcollect(l);
  648. for each el in l join strtexitem el;
  649. symbolic procedure texexplist(r);
  650. begin scalar r,v;
  651. v:=nil;
  652. for each rl on r do
  653. if digit(car rl) and not v then v:=rl
  654. else if v and not digit(car rl) then v:=nil;
  655. if v then
  656. << rplacd(v,car v.cdr v); rplaca(v,'!_!{); nconc(r,'!}.nil) >>;
  657. return r
  658. end;
  659. %ff
  660. makeitems('(
  661. (! inn dmy) % no nonsense dummy item
  662. (!{ inn beg) % begin of a TeX inner group
  663. (!^!{ inn sup) % superscript
  664. (!_!{ inn sub) % subscript nolimits
  665. (!{!}!^!{ inn sup) % spread superscript
  666. (!{!}!_!{ inn sub) % spread subscript
  667. (!}!{ inn sep) % general group seperator
  668. (!}!^!{ inn esp) % end of group and superscript
  669. (!}!_!{ inn esb) % end of group and subscript
  670. (!} inn end) % end of TeX inner group
  671. (!\!f!r!a!c!{ inn frc recip quotient) % fraction group
  672. (!\!s!q!r!t!{ inn frc sqrt) % square root
  673. (!\!p!m!a!t!r!i!x!{ inn mat mat) % matrix group
  674. (!& inn tab) % horizontal tabulation
  675. (!\!c!r! inn cr ) % vertical tabulation
  676. (!\!n!l! inn cr ) % vertical tabulation (special)
  677. (!\!( opn (327680 276707 241208)) % test value
  678. (!\!) clo (327680 276707 241208)) % ...
  679. (!\!{ opn (327680 276707 241208)) % ...
  680. (!\!} clo (327680 276707 241208)) % ...
  681. (!\![ opn (0))
  682. (!\!] clo (0))
  683. (!\!< opn (254863 212082 195700))
  684. (!\!> clo (254863 212082 195700))
  685. (!\!, ord (80960))
  686. (!\!q!u!a!d! rel (655360))
  687. (! ord (0)) % dummy item
  688. (!\!r!m! ord (0)) % dummy def of font change
  689. (!\!i!t! ord (0)) % dummy def of font change
  690. (!\!b!f! ord (0)) % dummy def of font change
  691. (!\!h!b!o!x! ord (0)) % dummy def of box opening
  692. (!! ord (182045 148367 131984))
  693. (!? ord (309476 247127 211630))
  694. (!\!l!b!r!a!c!e! ord (327681 268516 241211) !{)
  695. (!\!r!b!r!a!c!e! ord (327681 268516 241211) !})
  696. (!\!l!b!r!a!c!k! ord (182045 148367 131984) ![)
  697. (!\!r!b!r!a!c!k! ord (182045 148367 131984) !])
  698. (!\!b!a!c!k!s!l!a!s!h! ord (327681 268516 241211) !\)
  699. (!\!% ord (546135 430537 359544) !%)
  700. (!\!# ord (546135 430537 359544) !#)
  701. (!\!& ord (509726 402320 336788) !&)
  702. (!@ ord (509726 402320 336788))
  703. (!\!_ ord (235930) !_)
  704. (!\!$ ord (327681 261235 223008) !$)
  705. (!; ord (182045 148367 131984))
  706. (!: ord (182045 148367 131984))
  707. (!. ord (182045 148367 131984))
  708. (!, ord (182045 148367 131984))
  709. (!| ord (182045 148367 131984))
  710. (!' ord (183865 177267))
  711. (!` ord (182045 148367 131984))
  712. (!\! ord (218453))
  713. %ff
  714. % Fonts ammi10, ammi7, ammi5; ordered by index number
  715. (!\!G!a!m!m!a! ord (394126 317121 266467))
  716. (!\!D!e!l!t!a! ord (546133 451470 377742))
  717. (!\!T!h!e!t!a! ord (481689 395400 331866))
  718. (!\!L!a!m!b!d!a! ord (418702 346612 293546))
  719. (!\!X!i! ord (447374 366819 309020))
  720. (!\!P!i! ord (553870 446190 368185))
  721. (!\!S!i!g!m!a! ord (511090 417791 348842))
  722. (!\!U!p!s!i!l!o!n! ord (382293 320398 275342))
  723. (!\!P!h!i! ord (436906 364088 309475))
  724. (!\!P!s!i! ord (419430 354622 304150))
  725. (!\!O!m!e!g!a ord (461596 382217 322806))
  726. (!\!a!l!p!h!a! ord (419233 350253 299280))
  727. (!\!b!e!t!a! ord (370688 303376 259231))
  728. (!\!g!a!m!m!a! ord (353318 296277 256227))
  729. (!\!d!e!l!t!a! ord (273066 229467 203070))
  730. (!\!e!p!s!i!l!o!n! ord (266012 222822 197791))
  731. (!\!z!e!t!a! ord (223686 195060 178221))
  732. (!\!e!t!a! ord (352407 300373 261688))
  733. (!\!t!h!e!t!a! ord (298553 247580 216177))
  734. (!\!i!o!t!a! ord (231955 198883 180224))
  735. (!\!k!a!p!p!a! ord (377590 315392 271246))
  736. (!\!l!a!m!b!d!a! ord (382293 320398 275342))
  737. (!\!m!u! ord (394885 326314 278528))
  738. (!\!n!u! ord (341940 283534 244849))
  739. (!\!x!i! ord (327680 276707 241208))
  740. (!\!p!i! ord (370293 312456 270222))
  741. (!\!r!h!o! ord (329728 269699 232379))
  742. (!\!s!i!g!m!a! ord (361737 300646 258776))
  743. (!\!t!a!u! ord (250083 220910 200430))
  744. (!\!u!p!s!i!l!o!n! ord (354076 299008 259413))
  745. (!\!p!h!i! ord (390485 322764 275888))
  746. (!\!c!h!i! ord (410055 334506 283534))
  747. (!\!p!s!i! ord (426894 357262 304924))
  748. (!\!o!m!e!g!a! ord (407931 339968 290360))
  749. (!\!v!a!r!e!p!s!i!l!o!n! ord (312433 358776 225097))
  750. (!\!v!a!r!t!h!e!t!a! ord (388513 326997 281713))
  751. (!\!v!a!r!p!i! ord (504945 424800 359719))
  752. (!\!v!a!r!r!h!o! ord (329728 369699 232379))
  753. (!\!v!a!r!s!i!g!m!a! ord (312433 258776 225097))
  754. (!\!v!a!r!p!h!i! ord (465123 383749 323675))
  755. % omitted: codes 40-47
  756. (!0 ord (327680 276707 241208))
  757. (!1 ord (327680 276707 241208))
  758. (!2 ord (327680 276707 241208))
  759. (!3 ord (327680 276707 241208))
  760. (!4 ord (327680 276707 241208))
  761. (!5 ord (327680 276707 241208))
  762. (!6 ord (327680 276707 241208))
  763. (!7 ord (327680 276707 241208))
  764. (!8 ord (327680 276707 241208))
  765. (!9 ord (327680 276707 241208))
  766. (!. pct (182044 160198 150186) cons)
  767. (!, rel (182044 160198 150186))
  768. (!\co! rel (182044 160198 150186))
  769. %ff
  770. % omitted: code 60
  771. (!/ bin (327680 262143 204800))
  772. % omitted : codes 62,63
  773. (!\!p!a!r!t!i!a!l! ord (384341 314982 268105) partdf df)
  774. (!A ord (491520 404866 339057))
  775. (!B ord (497095 406550 339569))
  776. (!C ord (542583 439273 363451))
  777. (!D ord (542583 439273 363451))
  778. (!E ord (468400 387026 326360))
  779. (!F ord (412330 331684 277845))
  780. (!G ord (515276 418884 348660))
  781. (!H ord (544768 439409 363520))
  782. (!I ord (288085 236475 204913))
  783. (!J ord (371825 302512 257706))
  784. (!K ord (556373 450104 371598))
  785. (!L ord (446008 369914 312888))
  786. (!M ord (635790 512227 420408))
  787. (!N ord (526563 424846 352142))
  788. (!O ord (499893 409964 343244))
  789. (!P ord (420750 341242 286606))
  790. (!Q ord (518098 424527 354622))
  791. (!R ord (482417 399041 335644))
  792. (!S ord (392760 323128 274887))
  793. (!T ord (382976 318122 272270))
  794. (!U ord (447465 366409 309179))
  795. (!V ord (375011 304014 260266))
  796. (!W ord (577991 469310 389973))
  797. (!X ord (533845 433811 359651))
  798. (!Y ord (388210 317485 270506))
  799. (!Z ord (429170 352256 397642))
  800. % omitted: codes 91-96
  801. (!a ord (346415 291999 253770))
  802. (!b ord (281258 235383 207621))
  803. (!c ord (283610 240571 212810))
  804. (!d ord (341105 277890 242392))
  805. (!e ord (283610 240571 212810))
  806. (!f ord (320853 260778 224369))
  807. (!g ord (300980 247580 215995))
  808. (!h ord (377590 315392 271246))
  809. (!i ord (231500 191601 174762))
  810. (!j ord (238933 198883 177493))
  811. (!k ord (341181 296265 248490))
  812. (!l ord (195546 169756 157468))
  813. (!m ord (575411 479687 402318))
  814. (!n ord (393367 334051 288540))
  815. (!o ord (317667 264510 230377))
  816. (!p ord (329728 277435 242392))
  817. (!q ord (292560 245577 215995))
  818. (!r ord (277466 235292 208668))
  819. (!s ord (307200 253041 219818))
  820. (!t ord (234837 204799 186595))
  821. (!u ord (375163 319487 277162))
  822. (!v ord (317667 269881 236657))
  823. (!w ord (463303 386389 327680))
  824. (!x ord (361813 296732 253951))
  825. (!y ord (321308 273066 239388))
  826. (!z ord (304772 257137 225735))
  827. % omitted: codes 123-127
  828. %ff
  829. % Fonts amsy10, amsy7, amsy5; not ordered.
  830. (!+ bin (509724 422343 354986) plus)
  831. (!- bin (509724 422343 354986) difference minus)
  832. (!* ord (509724 422343 354986) hodge)
  833. (!" ord (509724 422343 354986))
  834. (!\!c!d!o!t! bin (182044 160198 150186) times)
  835. (!= rel (509724 422343 354986) eq equal)
  836. (!:!= rel (691771 550687 468772) setq)
  837. (!\!s!u!m! lop (1000000 700000 500000) sum)
  838. (!\!p!r!o!d! lop (1000000 700000 500000) prod)
  839. (!\!i!n!t! lop (1000000 700000 500000) int)
  840. (!\!l!i!m! ord (910221 771866 678114) limit limit!+ limit!-)
  841. (!\!s!i!n! ord (804635 687398 612123) sin)
  842. (!\!c!o!s! ord (877454 745653 657634) cos)
  843. (!\!t!a!n! ord (946630 800994 700869) tan)
  844. (!\!l!n! ord (700000 600000 500000) log)
  845. (!\!e!x!p! ord (1001243 844685 735003) exp)
  846. (!\!a!r!c!t!a!n! ord (1824539 1543734 1356227) atan)
  847. (!\!w!e!d!g!e! ord (436908 353167 309480) wedge !^)
  848. (!\!b!a!c!k!s!l!a!s!h! ord (327681 268516 241211) !\ setdiff)
  849. (!\!d! ord (364090))
  850. (!\!l!a!n!d! bin (436908 353167 309480) and)
  851. (!\!l!o!r! bin (436908 353167 309480) or)
  852. (!\!l!n!o!t! ord (436908 353167 309480) not)
  853. (!\!c!a!p! bin (436908 353167 309480) intersection)
  854. (!\!c!u!p! bin (436908 353167 309480) union)
  855. (!\!i!n! rel (436908 353167 309480) member)
  856. (!\!t!o! rel (655361 522469 446015))
  857. (!\!u!p!a!r!r!o!w! rel (327681 268516 241211))
  858. (!\!d!o!w!n!a!r!r!o!w! rel (327681 268516 241211))
  859. (!< rel (509726 409601 354991) lessp)
  860. (!> rel (509726 409601 354991) greaterp)
  861. (!\!l!e!q! rel (509726 409601 354991) leq)
  862. (!\!g!e!q! rel (509726 409601 354991) geq)
  863. (!\!n!e!q! rel (509726 402230 336788) neq)
  864. (!\!m!i!d! rel (182045 155648 150188) when)
  865. (!\!f!o!r!a!l!l! ord (364090 296733 263968) !~)
  866. (!\!R!i!g!h!t!a!r!r!o!w! rel (655361 522469 446015) replaceby)
  867. (!( ord (254863 204801 177495))
  868. (!) ord (254863 204801 177495))
  869. (!\!i!n!f!t!y! ord (655361 522469 446015) infinity)
  870. % The rest are non-standard TeX macros defined in tridefs.tex
  871. (!\!c!d!o!t! ord (109224 89505 80403) times)
  872. (!\!a!s!i!n! ord (1132319 906677 780527) asin)
  873. (!\!a!c!o!s! ord (1205136 963111 826038) acos)
  874. (!\!a!t!a!n! ord (1274315 1016723 869275) atan)
  875. (!\!A!l!p!h!a! ord (491521 386847 321314))
  876. (!\!B!e!t!a! ord (464215 366366 306295))
  877. (!\!E!p!s!i!l!o!n! ord (446010 352257 294916))
  878. (!\!Z!e!t!a! ord (400498 317669 268520))
  879. (!\!E!t!a! ord (491521 386847 321314))
  880. (!\!I!o!t!a! ord (236658 189328 162021))
  881. (!\!K!a!p!p!a! ord (509726 400956 332691))
  882. (!\!M!u! ord (600748 471498 389581))
  883. (!\!N!u! ord (491521 386847 321314))
  884. (!\!R!h!o! ord (446010 352257 294916))
  885. (!\!T!a!u! ord (473316 374103 314031))
  886. (!\!C!h!i! ord (491521 386847 321314))
  887. (!\!O!m!e!g!a! ord (473316 374103 314031))
  888. ));
  889. %ff
  890. % ----------------------------------------------------------------------
  891. % You can choose to have some default TEXNAME properties for your
  892. % variables. Function "trimakeset" defines a set of such default names.
  893. % If you want to activate the set, call "TeXassertset(<setname>)" , or
  894. % if you want to deactivate the set, call "TeXretractset(<setname>)" .
  895. % The current <setname>s available are:
  896. % * GREEK : lowercase greek letters
  897. % * LOWERCASE: roman lowercase letters
  898. % ----------------------------------------------------------------------
  899. % handle argument passing
  900. deflist( '((texassertset rlis) (texretractset rlis)), 'stat);
  901. symbolic procedure texassertset(arglist);
  902. if length arglist neq 1 then rederr "Usage: TeXassertset(setname);"
  903. else begin scalar sym; sym:= car arglist;
  904. if get('texsym,sym) then
  905. << assertl(get('texsym,sym)); prin2 "% set ";
  906. prin2 sym; prin2 " asserted"; terpri()
  907. >> else << prin2 "% no such set"; terpri() >>
  908. end;
  909. symbolic procedure texretractset(arglist);
  910. if length arglist neq 1 then rederr "Usage: TeXretractset(setname);"
  911. else begin scalar sym; sym := car arglist;
  912. if get('texsym,sym) then
  913. << retractl(get('texsym,sym)); prin2 "% set ";
  914. prin2 sym; prin2 " retracted"; terpri()
  915. >> else << prin2 "% no such set"; terpri() >>
  916. end;
  917. symbolic procedure trimakeset(sym,a!_set);
  918. <<put('texsym,sym,a!_set); nil>>;
  919. trimakeset('greek,'(
  920. (alpha !\!a!l!p!h!a! )
  921. (beta !\!b!e!t!a! )
  922. (gamma !\!g!a!m!m!a! )
  923. (delta !\!d!e!l!t!a! )
  924. (epsilon !\!e!p!s!i!l!o!n! )
  925. (zeta !\!z!e!t!a! )
  926. (eta !\!e!t!a! )
  927. (theta !\!t!h!e!t!a! )
  928. (iota !\!i!o!t!a! )
  929. (kappa !\!k!a!p!p!a! )
  930. (lambda !\!l!a!m!b!d!a! )
  931. (mu !\!m!u! )
  932. (nu !\!n!u! )
  933. (xi !\!x!i! )
  934. (pi !\!p!i! )
  935. (rho !\!r!h!o! )
  936. (sigma !\!s!i!g!m!a! )
  937. (tau !\!t!a!u! )
  938. (upsilon !\!u!p!s!i!l!o!n! )
  939. (phi !\!p!h!i! )
  940. (chi !\!c!h!i! )
  941. (psi !\!p!s!i! )
  942. (omega !\!o!m!e!g!a! ) ));
  943. trimakeset('lowercase,'(
  944. (a !a) (b !b) (c !c) (d !d) (e !e) (f !f) (g !g) (h !h) (i !i) (j !j)
  945. (k !k) (l !l) (m !m) (n !n) (o !o) (p !p) (q !q) (r !r) (s !s) (t !t)
  946. (u !u) (v !v) (w !w) (x !x) (y !y) (z !z) ));
  947. trimakeset('!Greek,'(
  948. (!Alpha !\!A!l!p!h!a! )
  949. (!Beta !\!B!e!t!a! )
  950. (!Gamma !\!G!a!m!m!a! )
  951. (!Delta !\!D!e!l!t!a! )
  952. (!Epsilon !\!E!p!s!i!l!o!n! )
  953. (!Zeta !\!Z!e!t!a! )
  954. (!Eta !\!E!t!a! )
  955. (!Theta !\!T!h!e!t!a! )
  956. (!Iota !\!I!o!t!a! )
  957. (!Kappa !\!K!a!p!p!a! )
  958. (!Lambda !\!L!a!m!b!d!a! )
  959. (!Mu !\!M!u! )
  960. (!Nu !\!N!u! )
  961. (!Xi !\!X!i! )
  962. (!Pi !\!P!i! )
  963. (!Rho !\!R!h!o! )
  964. (!Sigma !\!S!i!g!m!a! )
  965. (!Tau !\!T!a!u! )
  966. (!Upsilon !\!U!p!s!i!l!o!n! )
  967. (!Phi !\!P!h!i! )
  968. (!Chi !\!C!h!i! )
  969. (!Psi !\!P!s!i! )
  970. (!Omega !\!O!m!e!g!a! ) ));
  971. trimakeset('!Uppercase,'(
  972. (!A !A) (!B !B) (!C !C) (!D !D) (!E !E) (!F !F) (!G !G) (!H !H) (!I !I)
  973. (!J !J) (!K !K) (!L !L) (!M !M) (!N !N) (!O !O) (!P !P) (!Q !Q) (!R !R)
  974. (!S !S) (!T !T) (!U !U) (!V !V) (!W !W) (!X !X) (!Y !Y) (!Z !Z) ));
  975. %ff
  976. % ----------------------------------------------------------------------
  977. % Section 2: Inserting Glue into a TeX-Item-List
  978. % ----------------------------------------------------------------------
  979. %
  980. % Glue Items to be inserted between consecutive TeX-Items (similar to
  981. % what TeX does with its items, but this table is slightly modified.)
  982. %
  983. % Class|ORD|LOP|BIN|REL|OPN|CLO|PCT|INN|
  984. % -----+---+---+---+---+---+---+---+---+
  985. % ORD | 0 | 1 |(2)|(3)| 0 | 0 | 0 | 0 |
  986. % LOP | 1 | 1 | * |(3)| 0 | 0 | 0 |(1)|
  987. % BIN |(2)|(2)| * | * |(2)| * | * |(2)|
  988. % REL |(3)|(3)| * | 0 |(3)| 0 | 0 |(3)| columns: right items
  989. % OPN | 0 | 0 | * | 0 | 0 | 0 | 0 | 0 | lines: left items
  990. % CLO | 0 | 1 |(2)|(3)| 0 | 0 | 0 | 0 |
  991. % PCT |(1)|(1)| * |(1)|(1)|(1)|(1)|(1)|
  992. % INN | 0 | 1 |(2)|(3)|(1)| 0 |(1)| 0 |
  993. % -----+---+---+---+---+---+---+---+---+
  994. %
  995. % The glue items and its meanings:
  996. % 0 ......... no space
  997. % 1 (1) ..... thin space (no space if sub-/superscript)
  998. % 2 (2) ..... medium space (no space if sub-/superscript)
  999. % 3 (3) ..... thick space (no space if sub-/superscript)
  1000. % * ......... this case never arises (really?)
  1001. % ----------------------------------------------------------------------
  1002. symbolic procedure makeglue(mx);
  1003. if null mx then nil else
  1004. begin
  1005. scalar id1,id2,row,col;
  1006. row:=cdr mx; id1:=car mx;
  1007. while(row) do
  1008. << id2:=car mx; col:=car row;
  1009. while (col) do
  1010. << put(car id1,car id2,car col);
  1011. col:=cdr col; id2:=cdr id2
  1012. >>;
  1013. row:=cdr row; id1:=cdr id1
  1014. >>
  1015. end;
  1016. makeglue('(
  1017. (ord lop bin rel opn clo pct inn)
  1018. ( 0 1 -2 -3 0 0 0 0 )
  1019. ( 1 1 0 -3 0 0 0 -1 )
  1020. (-2 -2 0 0 -2 0 0 -2 )
  1021. (-3 -3 0 0 -3 0 0 -3 )
  1022. ( 0 0 0 0 0 0 0 0 )
  1023. ( 0 1 -2 -3 0 0 0 0 )
  1024. (-1 -1 0 -1 -1 -1 -1 -1 )
  1025. ( 0 1 -2 -3 -1 0 -1 0 )
  1026. ));
  1027. smacro procedure kindof(item); get(item,'textag);
  1028. smacro procedure classof(item); get(item,'class);
  1029. %ff
  1030. smacro procedure groupbeg(kind); % beginning of a group
  1031. memq(kind,'(beg sup sub frc mat));
  1032. smacro procedure groupend(kind); (kind='end);
  1033. smacro procedure grouphs(kind); (kind='tab);
  1034. smacro procedure groupvs(kind); % vertical group seperator
  1035. memq(kind,'(esp esb sep cr));
  1036. symbolic procedure interglue(left,right,depth,nesting);
  1037. % compute the glue to be inserted between two TeX items
  1038. % parameters: left,right .......... left/right TeX item
  1039. % depth ............... superscript/subscript level
  1040. % nesting ............. depth of parenthesis level
  1041. % a glue item is a list consisting of two numbers, i.e.
  1042. % (<width> <penalty>)
  1043. % where <width> is the width of the glue in scaled points and <penalty>
  1044. % is a negative numeric value indicating 'merits' for a breakpoint.
  1045. if (null left)or(null right)or(not atom left)or(not atom right) then nil
  1046. else begin
  1047. scalar glue,lc,rc; % glue code and item classes
  1048. lc:=classof(left); rc:=classof(right); glue:=get(lc,rc);
  1049. if null(glue) then return nil;
  1050. if (left='!\co! ) then return(list(0,-10000));
  1051. if glue<0 then if depth>0 then return nil else glue:=(-glue);
  1052. if glue=1 then return(list(80960,nesting*10 +20))
  1053. else if glue=2 then
  1054. << if (left='!+ or left='!-) then return nil;
  1055. if (right='!+) then return(list(163840,nesting*30-390));
  1056. if (right='!- and (lc='ord or lc='clo))
  1057. then return(list(163840,nesting*30-210));
  1058. if (left='!\!c!d!o!t! ) then return(list(163840,nesting*10+50));
  1059. if (right='!\!c!d!o!t! ) then return nil;
  1060. return(list(163840,nesting*10))
  1061. >>
  1062. else if glue=3 then return(list(655360,nesting*10-50)) else return nil
  1063. end;
  1064. symbolic procedure insertglue(term);
  1065. % insert glue into a TeX-Item-List
  1066. begin
  1067. scalar glueitem,succ,pred,prev,backup; integer depth,nesting;
  1068. depth:=nesting:=0; succ:=nil; backup:=term;
  1069. while term do
  1070. << pred:=succ; succ:=car term;
  1071. glueitem:=interglue(pred,succ,depth,nesting);
  1072. if glueitem then rplacd(prev,glueitem.term);
  1073. prev:=term; term:=cdr term;
  1074. if classof(succ)='inn then
  1075. << if (groupbeg kindof succ) and
  1076. (not ((kindof(succ)='frc) and (depth=0)))
  1077. then depth:=depth+1
  1078. else if (groupend kindof succ) and (depth>0) then depth:=depth-1
  1079. >>
  1080. else if classof(succ)='opn then nesting:=nesting+1
  1081. else if classof(succ)='clo then nesting:=nesting-1
  1082. >>;
  1083. return(backup)
  1084. end;
  1085. %ff
  1086. % ----------------------------------------------------------------------
  1087. % Section 3 : Line Breaking
  1088. % ----------------------------------------------------------------------
  1089. %
  1090. % How to break up a TeX item list into several independent lines
  1091. % ----------------------------------------------------------------------
  1092. % Setting break points requires "breaklists". A breaklist is a sequence
  1093. % of passive and active nodes, where each active node is followed by an
  1094. % pasive node and vice versa. Active nodes represent glue items. Passive
  1095. % nodes are integer atoms which represent the width of a sequence of or-
  1096. % dinary TeX items. This sequence must not be interspersed with glue
  1097. % items. Every breaklist consists of at least one passive node surroun-
  1098. % ded by delta nodes representing the beginning and ending of the list.
  1099. % <breaklist> ::= ( <delta-node> <passive-node> <active-node> ...
  1100. % <passive-node> <active_node> ...
  1101. % <passive-node> <delta-node>)
  1102. % <active-node> ::= ( <width> <penalty> <offset> )
  1103. % <passive-node> ::= <width>
  1104. % <delta-node> ::= ( <width> <penalty> <offset>
  1105. % <id-num> <ptr> <demerits> <indentation> )
  1106. % The breaklist will be created using the function "breaklist". Setting
  1107. % the break points (i.e. break items) in the breaklist is done using the
  1108. % functions "trybreak". During this phase, some active nodes are con-
  1109. % sidered to be "feasible" break points. Thus, they will be extended and
  1110. % named "delta nodes" furtheron. By default the first and last node in a
  1111. % breaklist are delta nodes. When trybreak has finished, the <ptr>'s of
  1112. % the delta nodes recursively pointed to from the last delta node's
  1113. % <ptr> represent the best path for breaking the whole breaklist.
  1114. % It is:
  1115. % <width> : width of item (including glue items)
  1116. % <penalty> : a numeric value which prohibits line breaking (if
  1117. % negative, line breaking will be merited)
  1118. % <offset> : distance to most previous opening bracket
  1119. % <id-num> : the identity number of the delta node {1,2,3,...}
  1120. % <ptr> : pointer to the best delta node to come from with
  1121. % respect to the minimal demerits path. note: a zero
  1122. % pointer indicates the very bottom of the stack
  1123. % <demerits> : total demerits distance to delta node which is
  1124. % pointed to by <ptr>
  1125. % <indentation>: amount of indentation when breaking at this point
  1126. % ----------------------------------------------------------------------
  1127. %ff
  1128. symbolic procedure width(item,style);
  1129. begin scalar tag;
  1130. tag:=get(item,'textag);
  1131. if null tag then tri!-error(list("cannot find item ",item),'fatal);
  1132. while (style>0)and(cdr tag) do << tag:=cdr tag; style:=style-1 >>;
  1133. return car tag or 0
  1134. end;
  1135. smacro procedure sp2mm(x); (x/186468); % scaled points to millimeters
  1136. symbolic procedure settolerance(tol);
  1137. << if tol<0 then tol:=0 else if tol>10000 then tol:=10000;
  1138. prin2 "% \tolerance "; print tol; tolerance!*:=tol; nil
  1139. >>;
  1140. symbolic procedure setpagewidth(hsize);
  1141. % hsize can be given either in millimeters or scaled points.
  1142. << if hsize>400 then hsize!*:=hsize else hsize!*:=hsize*186468;
  1143. prin2 "% \hsize="; prin2 sp2mm(hsize!*); prin2 "mm"; terpri();
  1144. hss!*:=float hsize!*/6; % default stretch/shrink width
  1145. hww!*:=float (3*hsize!*)/4; % optimum line width
  1146. >>;
  1147. symbolic procedure setbreak(hsize,tol);
  1148. << settolerance(tol); setpagewidth(hsize) >>;
  1149. smacro procedure badness(hlen,ibadness);
  1150. % The badness is 100*(hlen/hss)**3, corrected for indentation badness
  1151. begin
  1152. real r;
  1153. r:=abs(hlen-hww!*)/hss!*;
  1154. return fix min(10000.0,r*r*r*100.0+ibadness)
  1155. end;
  1156. smacro procedure isglue(l); (not atom l) and (numberp car l);
  1157. smacro procedure isactive(x); not numberp x;
  1158. smacro procedure ispassive(x); numberp x;
  1159. smacro procedure isdelta(x); cdddr x;
  1160. smacro procedure addup(x); if x then eval('plus.x) else 0;
  1161. smacro procedure tpush(stack,item); stack:=item.stack;
  1162. smacro procedure tpop(stack);
  1163. if null stack then nil % Error
  1164. else begin scalar z; z:=car stack; stack:=cdr stack; return(z) end;
  1165. smacro procedure poke(stack,ptr,val);
  1166. if null ptr then stack:=nconc(stack,val.nil)
  1167. else << if val>car(ptr) then rplaca(ptr,val); ptr:=cdr ptr >>;
  1168. smacro procedure concatenate(l);
  1169. begin scalar r;
  1170. for each e in l do r:=nconc(r,explode e);
  1171. return compress r
  1172. end;
  1173. %ff
  1174. % ----------------------------------------------------------------------
  1175. % Section 3.1: Resolving Fraction Expressions
  1176. % ----------------------------------------------------------------------
  1177. symbolic procedure resolve(term);
  1178. % resolve a \frac{...}{...} sequence and transform it into a .../...
  1179. % sequence, where any ... argument may become parenthesized depending on
  1180. % the question if there is any non-ORD-class item within this argument.
  1181. % Furthermore, resolve a \sqrt{...} expression to \(...\)^{\frac{1}{2}}.
  1182. begin
  1183. scalar item,l,m,r,lflag,rflag;
  1184. integer depth;
  1185. l:=term; % save pointer to functor
  1186. depth:=0; m:=r:=lflag:=rflag:=nil; item:=t;
  1187. while term and item do
  1188. << item:=car term; % take first item from list
  1189. if classof(item)='inn then % check inner class item
  1190. << item:=kindof(item);
  1191. if groupbeg(item) then depth:=depth+1
  1192. else if groupend(item) then
  1193. if depth=1 then % outermost level ?
  1194. << r:=term; item:=nil % save pointer to right bracket
  1195. >> % and quit using item as a flag
  1196. else depth:=depth-1
  1197. else if groupvs(item) then % if outermost level then save
  1198. if (depth=1) then m:=term % pointer to intermediate brackets
  1199. >>
  1200. else if not(classof(item)='ord) then % non-ORD-class item ?
  1201. << if m then rflag:=t else lflag:=t
  1202. >>;
  1203. term:=cdr term % step ahead
  1204. >>;
  1205. if car l='!\!f!r!a!c!{ then
  1206. << if lflag and rflag
  1207. then item:=list('!/,list(655360,-10000))
  1208. else item:=list('!/);
  1209. if lflag then << rplaca(l,'!\!(); item:='!\!).item >>
  1210. else rplaca(l,'! );
  1211. if rflag then << rplaca(r,'!\!)); nconc(item,'!\!(.nil) >>
  1212. else rplaca(r,'! );
  1213. rplaca(m,car item); item:=cdr item;
  1214. if item then rplacd(m,nconc(item,cdr m))
  1215. >> else if car l='!\!s!q!r!t!{ then
  1216. << rplaca(l,'!\!(); rplaca(r,'!\!));
  1217. rplacd(r,'!^!{ . '!1 . '!/ . '!2 . '!} . cdr r)
  1218. >>;
  1219. return(l) % return changed list pointer
  1220. end;
  1221. %ff
  1222. % ----------------------------------------------------------------------
  1223. % Section 3.2 : Create a Break List
  1224. % ----------------------------------------------------------------------
  1225. symbolic procedure breaklist(term);
  1226. begin
  1227. scalar item,result,kind,vstack,hstack,fstack,pstack,p,flag,backup;
  1228. integer depth,acc,aux,lopw,total,indent;
  1229. p:=result:=vstack:=hstack:=fstack:=nil; backup:=term;
  1230. depth:=total:=acc:=lopw:=indent:=0;
  1231. while term do
  1232. << item:=car term; flag:=t; % get first item from term
  1233. if null item
  1234. then tri!-error(list("found NIL in term : ",backup),'fatal);
  1235. if (isglue(item)) then % do we have glue ahead ?
  1236. if (depth<1) then % are we on the top level ?
  1237. << % insert a passive node followed by an active node, clear acc.
  1238. total:=total+acc+car item; nconc(item,indent.nil);
  1239. result:=nconc(result,acc.item.nil); acc:=0
  1240. >>
  1241. else acc:=acc+car item % add up glue width
  1242. else if (classof(item)='lop) then lopw:=width(item,depth)
  1243. else if classof(item)='inn then
  1244. << kind:=kindof(item);
  1245. if kind='frc then
  1246. << tpush(fstack,term); tpush(fstack,depth)
  1247. >>;
  1248. if groupend(kind) then % end of TeX group ?
  1249. << depth:=depth-1; % decrement term depth
  1250. if acc>0 % if <acc> hasn't been poked
  1251. then poke(vstack,p,acc); % yet, then poke it
  1252. acc:=tpop(hstack); % get old acc value
  1253. aux:=addup(vstack); % compute vstack width
  1254. if fstack and (depth=car fstack) then
  1255. << tpop(fstack); % first waste depth info
  1256. if aux>hww!* then % check if it doesn't fit
  1257. << term:=resolve tpop fstack;% resolve fraction
  1258. flag:=nil % evaluate new list
  1259. >>
  1260. else % waste fraction term pointer
  1261. << tpop(fstack); acc:=acc+aux
  1262. >>
  1263. >> else acc:=acc+aux;
  1264. p:=tpop(hstack); vstack:=tpop(hstack) % reset old status
  1265. >>
  1266. else if groupbeg(kind) then % begin of TeX group ?
  1267. << depth:=depth+1; % increment term depth
  1268. tpush(hstack,vstack); % save current <vstack> and
  1269. tpush(hstack,p); % current <p> as well as
  1270. tpush(hstack,acc); % current <acc> to <hstack>
  1271. acc:=0; p:=vstack:=nil; % clear vertical stack
  1272. if lopw>0 then poke(vstack,p,lopw); lopw:=0
  1273. >>
  1274. else if grouphs(kind) then % horizontal separator ?
  1275. << poke(vstack,p,acc); acc:=0 % poke <acc> to <vstack>
  1276. >>
  1277. else if groupvs(kind) then % vertical separator ?
  1278. << poke(vstack,p,acc); acc:=0; p:=vstack % reset
  1279. >>
  1280. >>
  1281. %ff
  1282. else if depth<1 then
  1283. << aux:=width(item,depth); % add up item width
  1284. if classof(item)='opn then
  1285. << tpush(pstack,indent); indent:=total+acc+aux
  1286. >>;
  1287. if classof(item)='clo then indent:=tpop(pstack) or 0;
  1288. acc:=acc+aux
  1289. >>
  1290. else acc:=acc+width(item,depth); % add up item width
  1291. if lopw>0 then << acc:=acc+lopw; lopw:=0 >>;
  1292. if flag then term:=cdr term
  1293. >>;
  1294. if acc then total:=total+acc;
  1295. if (total<hsize!*) then return nil % need no breaking
  1296. else return(list(0,0,0,0,0,0,0).nconc(result,acc.
  1297. list(0,0,total,-1,0,2147483647,0).nil)) % return break list
  1298. end;
  1299. %ff
  1300. % ----------------------------------------------------------------------
  1301. % Section 3.3 : Major Line Breaking Routine
  1302. % ----------------------------------------------------------------------
  1303. smacro procedure widthof(deltanode); car deltanode;
  1304. smacro procedure penaltyof(deltanode); cadr deltanode;
  1305. smacro procedure totalof(deltanode); cadr deltanode;
  1306. smacro procedure offsetof(deltanode); caddr deltanode;
  1307. smacro procedure idof(deltanode); cadddr deltanode;
  1308. smacro procedure ptrof(deltanode); car cddddr deltanode;
  1309. smacro procedure indentof(deltanode); caddr cddddr deltanode;
  1310. smacro procedure tailof(deltanode); cddddr deltanode;
  1311. symbolic procedure offsetitem(item);
  1312. concatenate list('!\!o!f!f!{,item,'!} );
  1313. smacro procedure stepahead(ptr,val);
  1314. << if ispassive car ptr then val:=val+car ptr else val:=val+caar ptr;
  1315. ptr:=cdr ptr
  1316. >>;
  1317. smacro procedure findindent(offt,ptr);
  1318. if offt=lastoff and ptr=lastptr then lastindent else
  1319. begin % search the deltastack for previous indentation
  1320. scalar node,p,stack; integer tot;
  1321. stack:=deltastack; p:=lastptr:=ptr; lastoff:=offt;
  1322. while stack do
  1323. << if p=idof (node:=car stack) then
  1324. << p:=ptrof node; tot:=totalof node;
  1325. if tot<offt then stack:=nil
  1326. >>;
  1327. if stack then stack:=cdr stack;
  1328. >>;
  1329. return(lastindent:=offt-tot+indentof node)
  1330. end;
  1331. %ff
  1332. symbolic procedure trybreak(term,brkl);
  1333. % parameters: term .... TeX item list, as created by "interglue"
  1334. % brkl .... the breaklist to be processed by this routine
  1335. begin
  1336. scalar bottom,top,base,item,deltastack,pred;
  1337. integer depth; % depth of expression when rebuilding
  1338. integer feasible,id; % number of feasible delta node
  1339. integer len,total; % current and total length so far
  1340. integer dm,basedm; % current and base demerits
  1341. integer bd; % current badness
  1342. integer penalty;
  1343. integer offset,baseoffset; % current and base parenthesis offset
  1344. integer baseptr; % pointer to best way to come from
  1345. integer indent,baseindent; % current and base indentation
  1346. integer lastoff,lastindent,lastptr; % temp. var. for speedup
  1347. real indentbadness; % correction for indentation badness
  1348. if null brkl then goto retain;
  1349. bottom:=brkl;
  1350. lastoff:=lastptr:=lastindent:=feasible:=indent:=total:=0;
  1351. while bottom do
  1352. << top:=cdr bottom; base:=car bottom; pred:=tailof base;
  1353. id:=idof base; % id of current delta node
  1354. if penaltyof base=-10000 % break item ?
  1355. then rplaca(cdr pred,0); % new line
  1356. basedm:=cadr pred; % demerits so far
  1357. % save the delta node to the delta-stack. thus deltastack holds
  1358. % all the feasible breakpoints in reverse order.
  1359. deltastack:=base.deltastack;
  1360. len:=baseindent:=indentof(base); % indentation for this line
  1361. indentbadness:=2500.0*(float(baseindent)/float(hww!*));
  1362. baseoffset:=offsetof base;% current offset amount
  1363. baseptr:=car pred; % pointer to best node to come from
  1364. total:=total+widthof base;% correct total length
  1365. %--- debug ---
  1366. % prin2 "Base ["; prin2 id; prin2 "] basedm="; prin2 basedm;
  1367. % prin2 " ibd="; prin2 indentbadness;
  1368. % prin2 " indent="; prin2 baseindent; terpri();
  1369. %--- debug ---
  1370. %ff
  1371. while top and len<hsize!* do % loop once thru a potential line
  1372. % note that we use the local hsize instead of the full hsize
  1373. << item:=car top;
  1374. if ispassive(item) then len:=len+item else
  1375. << bd:=badness(len,indentbadness);
  1376. penalty:=penaltyof item;
  1377. offset:=offsetof item;
  1378. if (bd<tolerance!*) % is the breakpoint feasible?
  1379. or (bd+penalty<1) % got a break bonus ?
  1380. or (null cdr top) then % or did we reach last delta node?
  1381. << dm:=bd*bd+basedm+penalty*abs(penalty);
  1382. if isdelta(item) then
  1383. << pred:=tailof item;
  1384. if dm<cadr pred then % found a better path?
  1385. << % save the pointer to best breakpoint to come from
  1386. % and the minimum demerits to reach it
  1387. rplaca(pred,id); rplaca(cdr pred,dm);
  1388. if !*texindent then % save the current indentation
  1389. << if offset>total
  1390. then indent:=offset-total+baseindent
  1391. else if offset<baseoffset
  1392. then indent:=findindent(offset,baseptr)
  1393. else indent:=baseindent;
  1394. rplaca(cddr pred,indent)
  1395. >>
  1396. >>
  1397. >>
  1398. else % create a new delta node
  1399. << feasible:=feasible+1;
  1400. if !*texindent then
  1401. if offset>total
  1402. then indent:=offset-total+baseindent
  1403. else if offset<baseoffset
  1404. then indent:=findindent(offset,baseptr)
  1405. else indent:=baseindent
  1406. else indent:=0;
  1407. rplacd(cddr item,feasible.id.dm.indent.nil)
  1408. >>;
  1409. %--- debug ---
  1410. % prin2 "-->["; prin2 idof item; prin2 "] dm="; prin2 dm;
  1411. % prin2 " bd="; prin2 bd; prin2 " p="; prin2 penalty;
  1412. % if !*TeXindent then << prin2 " ind="; prin2 indent >>; terpri();
  1413. %--- debug ---
  1414. if penalty=-10000 then top:=nil
  1415. >>;
  1416. len:=len+car item % count the length anyway
  1417. >>;
  1418. if top then top:=cdr top
  1419. >>;
  1420. %ff
  1421. rplaca(cdr base,total); % replace penalty by total width so far
  1422. bottom:=cdr bottom; % depart from this delta node
  1423. while bottom and (ispassive(car bottom) or not isdelta(car bottom))
  1424. do stepahead(bottom,total); % move to next delta node in list
  1425. >>;
  1426. bottom:=deltastack; feasible:=-1; top:=nil;
  1427. while bottom do % loop thru the delta-node stack
  1428. << id:=idof car bottom; % id is the current id number
  1429. if id=feasible then % is this node the one pointed to?
  1430. << feasible:=ptrof car bottom; % feasible is the new back-pointer
  1431. top:=id.top; % save the path element
  1432. >>;
  1433. bottom:=cdr bottom % step ahead
  1434. >>; % now deltastack contains the best path
  1435. deltastack:=cdr top; % in forward order
  1436. %--- debug ---
  1437. % print term; print deltastack;
  1438. %--- debug ---
  1439. if car deltastack= -1 then
  1440. << prin2 "% Warning: no suitable way of breaking found"; terpri();
  1441. prin2 "% ======== retry with a greater tolerance..."; terpri();
  1442. prin2 "% (output will produce overfull box if printed)"; terpri()
  1443. >>;
  1444. brkl:=cdr brkl; % strip the dummy node at the list's head
  1445. %ff
  1446. % --------------------------------------------------------------------
  1447. % now remove all glue items but retain all break items
  1448. retain: % ------------------------------------------------------------
  1449. offset:=depth:=0; bottom:=term;
  1450. if brkl then brkl:=cdr brkl; % ensure first item is an active node
  1451. while term and (cdr term) do
  1452. << item:=car term;
  1453. if isglue(item) then % if this is a glue item
  1454. if (depth=0) and brkl then % and we are on the top level
  1455. << top:=car brkl;
  1456. if isdelta(top) then % consider delta nodes only
  1457. << if (idof top=car deltastack) then % break point?
  1458. << deltastack:=cdr deltastack;
  1459. %--- debug ---
  1460. % prin2 "% ["; prin2 idof top; prin2 "] ";
  1461. % prin2 sp2mm(totalof(top)+indentof(top)-offset); terpri();
  1462. % offset:=totalof(top);
  1463. %--- debug ---
  1464. if (len:=indentof top)>0
  1465. then rplacd(pred,'!\!n!l! . offsetitem(len) . cdr term)
  1466. else rplacd(pred,'!\!n!l! . cdr term)
  1467. >>
  1468. else rplacd(pred,cdr term)
  1469. >>
  1470. else rplacd(pred,cdr term);
  1471. if brkl and (cdr brkl) % check for next active node
  1472. then brkl:=cddr brkl % skip to next active node
  1473. >>
  1474. else rplacd(pred,cdr term) % remove glue item
  1475. else if classof(item)='inn then
  1476. << if groupbeg(kindof(item)) then depth:=depth+1 else
  1477. if groupend(kindof(item)) then depth:=depth-1
  1478. >>;
  1479. pred:=term; term:=cdr term
  1480. >>;
  1481. %--- debug ---
  1482. % top:=car term; prin2 "% [-1] ";
  1483. % prin2 sp2mm(totalof(top)+indentof(top)-offset); terpri();
  1484. %--- debug ---
  1485. return(bottom)
  1486. end;
  1487. %ff
  1488. % ----------------------------------------------------------------------
  1489. % Section 4 : Output of TeX-Code
  1490. % ----------------------------------------------------------------------
  1491. symbolic procedure texstrlen(s);
  1492. begin
  1493. integer length;
  1494. scalar flag;
  1495. length:=0; flag:=nil;
  1496. for each c in s do
  1497. if not flag and c='!! then flag:=t
  1498. else << length:=length+1; flag:=nil >>;
  1499. return length
  1500. end;
  1501. smacro procedure newline();
  1502. if nlflag then cc:=indent
  1503. else if (cc>indent) then << terpri(); cc:=indent; nlflag:=t >>;
  1504. %ff
  1505. symbolic procedure texout(itemlist,flag);
  1506. if null itemlist then nil else
  1507. begin
  1508. integer cc,len,indent,ccmax,lines;
  1509. scalar item,class,tag,oldtag,lasttag,indentstack,ispd,nlflag;
  1510. ccmax:=64; cc:=indent:=lines:=0; % initializations
  1511. tag:=ispd:=nlflag:=indentstack:=nil; % initializations
  1512. prin2('!$!$); % begin TeX math group
  1513. if flag then prin2('!\!d!i!s!p!l!a!y!l!i!n!e!s!{!\!q!d!d);
  1514. terpri(); % start new line
  1515. while itemlist do
  1516. << item:=car itemlist; itemlist:=cdr itemlist;
  1517. len:=texstrlen(explode(item)); oldtag:=nil; lasttag:=tag or class;
  1518. class:=classof(item); tag:=(class='inn)and(kindof(item));
  1519. %ispd:=(class='ORD)and itemlist and(classof(car itemlist)='OPN);
  1520. if (tag='mat)or(tag='frc)or(class='opn) %or ispd
  1521. then newline(); % start new line
  1522. if (groupbeg(tag))or(class='opn) then
  1523. << tpush(indentstack,indent); % push it to the stack
  1524. tpush(indentstack,lasttag); % the reason for pushing
  1525. if (cc+cc < ccmax) % within left half of page ?
  1526. then if ((class='opn)and(lasttag='ord))or % predicate?
  1527. (groupbeg(tag)and not((tag='frc)or(tag='mat)))
  1528. then indent:=cc+len % take current position
  1529. else indent:=indent+len % compute new indentation
  1530. >>
  1531. else if (groupend(tag))or(class='clo) then
  1532. << oldtag:=tpop(indentstack); indent:=tpop(indentstack)
  1533. >>;
  1534. if (cc+len > ccmax) or % beyond right margin ?
  1535. (item='!+)or(item='!-)or(class='clo) % important item?
  1536. then newline();
  1537. if nlflag then << nlflag:=nil; spaces(cc) >>;
  1538. if tag='cr then lines:=lines+1;
  1539. if not(item='! ) then prin2(item); % print the item and
  1540. cc:=cc+len; % count the characters
  1541. if groupvs(tag) or % vertical seperator ?
  1542. (groupend(tag) and % end of a large group,
  1543. ((oldtag='frc) or (oldtag='mat)))% i.e. fraction, matrix ?
  1544. or (class='clo) or % closing parenthesis ?
  1545. (((class='rel)or(class='bin))and % binary/relational operator?
  1546. (cc+cc+cc > ccmax+ccmax)) % within last third of page?
  1547. or item='!, or null class
  1548. then newline()
  1549. >>;
  1550. newline(); % start final line
  1551. if flag then
  1552. if lines=0 then prin2('!\!c!r!})
  1553. else prin2('!\!N!l!}); % end multi-line output
  1554. prin2('!$!$); terpri(); return(nil) % end math group
  1555. end;
  1556. %ff
  1557. % ----------------------------------------------------------------------
  1558. % Section 5: User Interface
  1559. % ----------------------------------------------------------------------
  1560. % handle argument passing for following the functions, compelling that
  1561. % properties are used during compile time
  1562. deflist( '((texdisplay rlis) (texlet rlis)), 'stat);
  1563. algebraic procedure texsetbreak(hsize,tol); lisp setbreak(hsize,tol);
  1564. algebraic procedure textolerance(tol); lisp settolerance(tol);
  1565. algebraic procedure texpagewidth(hsize); lisp setpagewidth(hsize);
  1566. symbolic procedure texlet(arglist);
  1567. begin scalar class,sym,item;
  1568. if length arglist neq 2 then rederr "Usage: TeXlet(symbol,item);";
  1569. sym:= car arglist; item:=intern cadr arglist; class:=classof(item);
  1570. if null class then
  1571. << prin2 "% No such TeX symbol available"; terpri()
  1572. >>
  1573. else if (class='inn) then % prevent from TeXequiv'ing inner symbols
  1574. << prin2 "% cannot assign inner TeX symbols yet"; terpri()
  1575. >>
  1576. else triassert(sym,item);
  1577. return nil
  1578. end;
  1579. symbolic procedure texdisplay(arglist);
  1580. begin scalar item,tag,class;
  1581. if length arglist neq 1 then rederr "Usage: TeXdisplay(item);";
  1582. item:=get(car arglist,'texname);
  1583. if not item then
  1584. << prin2 "% "; prin2 car arglist; prin2 " is not defined"; terpri()
  1585. >>;
  1586. if not item then return nil;
  1587. tag:=get(item,'textag); class:=get(item,'class);
  1588. prin2 "% TeX item "; prin2 item; prin2 " is of class "; prin2 class;
  1589. prin2 " and has following widths: "; terpri(); prin2 "% ";
  1590. for each w in tag do
  1591. begin real v; v:=w/65536.0; prin2 v; prin2 "pt " end;
  1592. terpri(); return nil
  1593. end;
  1594. % ----------------------- share name between both modes ----------------
  1595. symbolic operator texlet;
  1596. symbolic operator texitem;
  1597. symbolic operator texdisplay;
  1598. symbolic operator texassertset;
  1599. symbolic operator texretractset;
  1600. % ------------------------ Default Initializations ---------------------
  1601. << prin2 "% TeX-REDUCE-Interface 0.70"; terpri() >>;
  1602. texassertset(greek); texassertset(lowercase);
  1603. texassertset '!Greek; texassertset '!Uppercase;
  1604. textolerance(10); texpagewidth(150);
  1605. endmodule;
  1606. end;