1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
6 ;; (c) copyright 1987, Richard J. Fateman
7 ;; small corrections and additions: Andrey Grozin, 2001
8 ;; additional additions: Judah Milgram (JM), September 2001
9 ;; additional corrections: Barton Willis (BLW), October 2001
11 ;; Usage: tex(d8,"/tmp/foo.tex"); tex(d10,"/tmp/foo.tex"); ..
12 ;; to append lines d8 and d10 to the tex file. If given only
13 ;; one argument the result goes to standard output.
15 ;; Extract from permission letter to wfs:
16 ;; Date: Sat, 2 Apr 88 18:06:16 PST
17 ;; From: fateman%vangogh.Berkeley.EDU@ucbvax.Berkeley.EDU (Richard Fateman)
18 ;; To: wfs@rascal.ics.UTEXAS.EDU
19 ;; Subject: about tex...
20 ;; You have my permission to put it in NESC or give it to anyone
21 ;; else who might be interested in it....
24 ;; There are changes by wfs to allow use inside MAXIMA which runs
25 ;; in COMMON LISP. For original FRANZ LISP version contact rfw.
27 ;; intended environment: vaxima (Vax or Sun). Parser should be
28 ;; equivalent (in lbp/rbp data) to 1986 NESC Vaxima.
31 ;;;(export '($tex $texinit))
32 ;;;;; we'd like to just
33 ;;;(import '(user::$bothcases user::lbp user::rbp user::nformat))
34 ;;;(use-package 'user)
40 ;; Producing TeX from a macsyma internal expression is done by
41 ;; a reversal of the parsing process. Fundamentally, a
42 ;; traversal of the expression tree is produced by the tex programs,
43 ;; with appropriate substitutions and recognition of the
44 ;; infix / prefix / postfix / matchfix relations on symbols. Various
45 ;; changes are made to this so that TeX will like the results.
46 ;; It is important to understand the binding powers of the operators
47 ;; in Macsyma, in mathematics, and in TeX so that parentheses will
48 ;; be inserted when necessary. Because TeX has different kinds of
49 ;; groupings (e.g. in superscripts, within sqrts), not all
50 ;; parentheses are explicitly need.
53 ;; in macsyma, type tex(<expression>); or tex(<label>); or
54 ;; tex(<expr-or-label>, <file-name>); In the case of a label,
55 ;; a left-equation-number will be produced.
56 ;; in case a file-name is supplied, the output will be sent
57 ;; (perhaps appended) to that file.
59 (declare-top (special lop rop
))
61 (defvar *tex-environment-default
* '("$$" .
"$$"))
63 (defmfun $get_tex_environment_default
()
64 `((mlist) ,(car *tex-environment-default
*) ,(cdr *tex-environment-default
*)))
66 (defmfun $get_tex_environment
(x)
67 (if (getopr x
) (setq x
(getopr x
)))
68 (let ((e (get-tex-environment x
)))
69 `((mlist) ,(car e
) ,(cdr e
))))
71 (defmfun $set_tex_environment_default
(env-open env-close
)
72 (setq env-open
($sconcat env-open
))
73 (setq env-close
($sconcat env-close
))
74 (setq *tex-environment-default
* `(,env-open .
,env-close
))
75 ($get_tex_environment_default
))
77 (defmfun $set_tex_environment
(x env-open env-close
)
78 (setq env-open
($sconcat env-open
))
79 (setq env-close
($sconcat env-close
))
80 (if (getopr x
) (setq x
(getopr x
)))
81 (setf (get x
'tex-environment
) `(,env-open .
,env-close
))
82 ($get_tex_environment x
))
84 (defun get-tex-environment (x)
87 (or (get x
'tex-environment
) *tex-environment-default
*))
89 *tex-environment-default
*)
91 (get-tex-environment (caar x
)))))
93 (setf (get 'mdefine
'tex-environment
)
94 `(,(format nil
"~%\\begin{verbatim}~%") .
,(format nil
";~%\\end{verbatim}~%")))
96 (setf (get 'mdefmacro
'tex-environment
)
97 `(,(format nil
"~%\\begin{verbatim}~%") .
,(format nil
";~%\\end{verbatim}~%")))
99 (setf (get 'mlabel
'tex-environment
)
100 `(,(format nil
"~%\\begin{verbatim}~%") .
,(format nil
";~%\\end{verbatim}~%")))
102 ;; top level command the result of tex'ing the expression x.
103 ;; Lots of messing around here to get C-labels verbatim printed
104 ;; and function definitions verbatim "ground"
106 (defmspec $tex
(l) ;; mexplabel, and optional filename or stream
107 ;;if filename or stream supplied but 'nil' then return a string
108 (let ((args (cdr l
)))
109 (unless (member (length args
) '(1 2))
111 (cond ((and (cdr args
) (null (cadr args
)))
112 (let ((*standard-output
* (make-string-output-stream)))
114 (get-output-stream-string *standard-output
*)
117 (t (apply 'tex1 args
)))))
119 (defun quote-chars (sym ch-str
)
120 (let* ((strsym (string sym
))
121 (pos (position-if #'(lambda (c) (find c ch-str
)) strsym
)))
123 (concatenate 'string
(subseq strsym
0 pos
) "\\" (subseq strsym pos
(1+ pos
))
124 (quote-chars (subseq strsym
(1+ pos
)) ch-str
))
128 (quote-chars sym
"$%&_"))
130 (defun tex1 (mexplabel &optional filename-or-stream
) ;; mexplabel, and optional filename or stream
131 (prog (mexp texport x y itsalabel need-to-close-texport
)
133 ;; collect the file-name, if any, and open a port if needed
134 (setq filename-or-stream
(meval filename-or-stream
))
137 ((null filename-or-stream
) *standard-output
*)
138 ((eq filename-or-stream t
) *standard-output
*)
139 ((streamp filename-or-stream
) filename-or-stream
)
141 (setq need-to-close-texport t
)
142 (open (namestring (maxima-string filename-or-stream
))
145 :if-does-not-exist
:create
))))
146 ;; go back and analyze the first arg more thoroughly now.
147 ;; do a normal evaluation of the expression in macsyma
148 (setq mexp
(meval mexplabel
))
149 (cond ((member mexplabel $labels
:test
#'eq
) ; leave it if it is a label
150 (setq mexplabel
(concatenate 'string
"(" (print-invert-case (stripdollar mexplabel
))
153 (t (setq mexplabel nil
))) ;flush it otherwise
155 ;; maybe it is a function?
156 (cond((symbolp (setq x mexp
)) ;;exclude strings, numbers
157 (setq x
($verbify x
))
158 (cond ((setq y
(mget x
'mexpr
))
159 (setq mexp
(list '(mdefine) (cons (list x
) (cdadr y
)) (caddr y
))))
160 ((setq y
(mget x
'mmacro
))
161 (setq mexp
(list '(mdefmacro) (cons (list x
) (cdadr y
)) (caddr y
))))
162 ((setq y
(mget x
'aexpr
))
163 (setq mexp
(list '(mdefine) (cons (list x
'array
) (cdadr y
)) (caddr y
)))))))
164 (cond ((and (null(atom mexp
))
165 (member (caar mexp
) '(mdefine mdefmacro
) :test
#'eq
))
166 (format texport
(car (get-tex-environment (caar mexp
))))
167 (cond (mexplabel (format texport
"~a " mexplabel
)))
168 (mgrind mexp texport
) ;write expression as string
169 (format texport
(cdr (get-tex-environment (caar mexp
)))))
171 itsalabel
;; but is it a user-command-label?
172 ;; THE FOLLOWING TESTS SEEM PRETTY STRANGE --
173 ;; WHY CHECK INITIAL SUBSTRING IF SYMBOL IS ON THE $LABELS LIST ??
174 ;; PROBABLY IT IS A HOLDOVER FROM THE DAYS WHEN LABELS WERE C AND D INSTEAD OF %I AND %O
175 (<= (length (string $inchar
)) (length (string mexplabel
)))
176 (string= (subseq (maybe-invert-string-case (string $inchar
)) 1 (length (string $inchar
)))
177 (subseq (string mexplabel
) 1 (length (string $inchar
))))
178 ;; Check to make sure it isn't an outchar in disguise
181 (<= (length (string $outchar
)) (length (string mexplabel
)))
182 (string= (subseq (maybe-invert-string-case (string $outchar
)) 1 (length (string $outchar
)))
183 (subseq (string mexplabel
) 1 (length (string $outchar
)))))))
184 ;; aha, this is a C-line: do the grinding:
185 (format texport
(car (get-tex-environment 'mlabel
)))
186 (format texport
"~a" mexplabel
)
187 (mgrind mexp texport
) ;write expression as string
188 (format texport
(cdr (get-tex-environment 'mlabel
))))
190 (if mexplabel
(setq mexplabel
(quote-% mexplabel
)))
191 ; display the expression for TeX now:
192 (myprinc (car (get-tex-environment mexp
)) texport
)
193 (mapc #'(lambda (x) (myprinc x texport
))
194 ;;initially the left and right contexts are
195 ;; empty lists, and there are implicit parens
196 ;; around the whole expression
197 (tex mexp nil nil
'mparen
'mparen
))
199 (format texport
"\\leqno{\\tt ~a}" mexplabel
)))
200 (format texport
(cdr (get-tex-environment mexp
)))))
202 (if need-to-close-texport
206 ;;; myprinc is an intelligent low level printing routine. it keeps track of
207 ;;; the size of the output for purposes of allowing the TeX file to
208 ;;; have a reasonable line-line. myprinc will break it at a space
209 ;;; once it crosses a threshold.
210 ;;; this has nothing to do with breaking the resulting equations.
212 ;;- arg: chstr - string or number to princ
213 ;;- scheme: This function keeps track of the current location
214 ;;- on the line of the cursor and makes sure
215 ;;- that a value is all printed on one line (and not divided
216 ;;- by the crazy top level os routines)
219 (defun reset-ccol () (setq ccol
1))
221 (defun myprinc (chstr &optional
(texport nil
))
223 (cond ((and (> (+ (length (setq chlst
(exploden chstr
))) ccol
) $linel
)
224 (or (stringp chstr
) (equal chstr
'| |
)))
225 (terpri texport
) ;would have exceeded the line length
227 (myprinc " " texport
))) ; lead off with a space for safetyso we split it up.
228 (do ((ch chlst
(cdr ch
))
229 (colc ccol
(1+ colc
)))
230 ((null ch
) (setq ccol colc
))
231 (write-char (car ch
) texport
)))))
233 (defun tex (x l r lop rop
)
234 ;; x is the expression of interest; l is the list of strings to its
235 ;; left, r to its right. lop and rop are the operators on the left
236 ;; and right of x in the tree, and will determine if parens must
239 (cond ((atom x
) (tex-atom x l r
))
240 ((or (<= (tex-lbp (caar x
)) (tex-rbp lop
)) (> (tex-lbp rop
) (tex-rbp (caar x
))))
242 ;; special check needed because macsyma notates arrays peculiarly
243 ((member 'array
(cdar x
) :test
#'eq
) (tex-array x l r
))
244 ;; dispatch for object-oriented tex-ifiying
245 ((get (caar x
) 'tex
) (funcall (get (caar x
) 'tex
) x l r
))
246 (t (tex-function x l r nil
))))
248 (defun tex-atom (x l r
) ;; atoms: note: can we lose by leaving out {}s ?
250 (list (cond ((numberp x
) (texnumformat x
))
251 ((and (symbolp x
) (or (get x
'texword
) (get (get x
'reversealias
) 'texword
))))
253 (tex-string (quote-%
(if $stringdisp
(concatenate 'string
"``" x
"''") x
))))
254 ((characterp x
) (tex-char x
))
255 ((symbolp x
) (tex-stripdollar (or (get x
'reversealias
) x
)))
257 (let ((x (if (member (marray-type x
) '(array hash-table $functional
))
259 (format nil
"~A" x
))))
260 ;; Do not apply stringdisp here -- we are outputting a string
261 ;; only because we don't have a better way to handle Lisp arrays.
262 (tex-string (quote-chars x
"#$%&_"))))))
265 (defun tex-string (x)
266 (cond ((equal x
"") "")
267 ((eql (elt x
0) #\\) x
)
268 (t (concatenate 'string
"\\mbox{ " x
" }"))))
271 (if (eql x
#\|
) "\\mbox{\\verb/|/}"
272 (concatenate 'string
"\\mbox{\\verb|" (string x
) "|}")))
274 ;; Read forms from file F1 and output them to F2
275 (defun tex-forms (f1 f2
&aux tem
(eof nil
))
276 (with-open-file (st f1
)
277 (loop while
(not (eq (setq tem
(mread-raw st eof
)) eof
))
278 do
(tex1 (third tem
) f2
))))
280 ;; Detect and extract groups of trailing digits, e.g. foo_mm_nn.
281 ;; and then punt foo[mm, nn] to TEX-ARRAY.
282 ;; Otherwise, treat SYM as a simple symbol.
284 (defun tex-stripdollar (sym)
286 ((nn-list (extract-trailing-digits (symbol-name sym
))))
288 ;; SYM matches foo_mm_nn.
289 (apply #'concatenate
'string
(tex-array `((,(intern (first nn-list
)) 'array
) ,@(rest nn-list
)) nil nil
))
290 ;; SYM is a simple symbol.
291 (let ((s (maybe-invert-string-case (quote-%
(stripdollar sym
)))))
293 (concatenate 'string
"{\\it " s
"}")
296 ;; Given a string foo_mm_nn, return foo, mm, and nn,
297 ;; where mm and nn are integers (not strings of digits).
298 ;; Return NIL if argument doesn't have trailing digits.
299 (defun extract-trailing-digits (s)
301 ;; OK (loop while (funcall #.(maxima-nregex::regex-compile "[^_](__*)([0-9][0-9]*)$") s)
302 ;; NOPE (loop while (funcall #.(maxima-nregex::regex-compile "[^0-9_](_*)([0-9][0-9]*)$") s)
305 (let ((matches (pregexp:pregexp-match-positions
306 '#.
(pregexp:pregexp
"[^_](__*)([0-9][0-9]*)$")
310 ((group-_ (elt matches
1))
311 (group-nn (elt matches
2)))
312 (setq nn-string
(subseq s
(car group-nn
) (cdr group-nn
)))
313 (setq s
(subseq s
0 (car group-_
)))))))
315 (let ((matches (pregexp:pregexp-match-positions
316 '#.
(pregexp:pregexp
"[^_]([0-9][0-9]*)$")
319 (let* ((group-nn (elt matches
1)))
320 (setq nn-string
(subseq s
(car group-nn
) (cdr group-nn
)))
321 (setq s
(subseq s
0 (car group-nn
))))))))
322 do
(push (parse-integer nn-string
) nn-list
))
323 (and nn-list
(cons s nn-list
))))
325 (defun strcat (&rest args
)
326 (apply #'concatenate
'string
(mapcar #'string args
)))
328 ;; 10/14/87 RJF convert 1.2e20 to 1.2 \cdot 10^{20}
329 ;; 03/30/01 RLT make that 1.2 \times 10^{20}
330 (defun texnumformat(atom)
331 (let (r firstpart exponent
)
332 (cond ((integerp atom
)
333 (coerce (exploden atom
) 'string
))
335 (setq r
(exploden atom
))
336 (setq exponent
(member 'e r
:test
#'string-equal
)) ;; is it ddd.ddde+EE
342 (nreverse (cdr (member 'e
(reverse r
) :test
#'string-equal
))))
343 (strcat (apply #'strcat firstpart
)
345 (apply #'strcat
(cdr exponent
))
348 (defun tex-paren (x l r
)
349 (tex x
(append l
'("\\left(")) (cons "\\right)" r
) 'mparen
'mparen
))
351 (defun tex-array (x l r
)
352 (tex-array-display-indices x l r
))
354 (defun tex-array-display-indices (x l r
)
356 ((base-symbol (caar x
))
358 (display-indices (safe-mget base-symbol
'display-indices
)))
359 (if (or (not display-indices
) (not (= (length display-indices
) (length indices
))))
360 ;; Ignore DISPLAY-INDICES if it's empty, or nonempty and not the same size as INDICES.
361 (tex-array-simple x l r
)
363 ((pre-subscripts (extract-indices indices display-indices
'$presubscript
))
364 (pre-superscripts (extract-indices indices display-indices
'$presuperscript
))
365 (post-subscripts (extract-indices indices display-indices
'$postsubscript
))
366 (post-superscripts (extract-indices indices display-indices
'$postsuperscript
)))
367 (when (or pre-subscripts pre-superscripts
)
370 (if pre-subscripts
(cons "_{" (tex-list pre-subscripts nil
(list "}") ",")))
371 (if pre-superscripts
(cons "^{" (tex-list pre-superscripts nil
(list "}") ","))))))
372 (when (or post-subscripts post-superscripts
)
373 (setq r
(append (if post-subscripts
(cons "_{" (tex-list post-subscripts nil
(list "}") ",")))
374 (if post-superscripts
(cons "^{" (tex-list post-superscripts nil
(list "}") ","))) r
)))
375 (tex-atom base-symbol l r
)))))
377 (defun tex-array-simple (x l r
)
379 ;; I believe this test always fails; TEX-MQAPPLY calls TEX-ARRAY w/ X = second argument of MQAPPLY.
380 (if (eq 'mqapply
(caar x
))
383 l
(tex f
(append l
(list "\\left(")) (list "\\right)") 'mparen
'mparen
))
385 l
(tex f l nil lop
'mfunction
)))
387 r
(nconc (tex-list (cdr x
) nil
(list "}") ",") r
))
388 (nconc l
(list "_{") r
)))
391 ;; we could patch this so sin x rather than sin(x), but instead we made sin a prefix
394 (defun tex-function (x l r op
) op
395 (setq l
(tex (caar x
) l nil
'mparen
'mparen
)
396 r
(tex (cons '(mprogn) (cdr x
)) nil r
'mparen
'mparen
))
399 ;; set up a list , separated by symbols (, * ...) and then tack on the
400 ;; ending item (e.g. "]" or perhaps ")"
402 (defun tex-list (x l r sym
)
406 (setq nl
(nconc nl
(tex (car x
) l r
'mparen
'mparen
)))
408 (setq nl
(nconc nl
(tex (car x
) l
(list sym
) 'mparen
'mparen
))
412 (defun tex-prefix (x l r
)
413 (tex (cadr x
) (append l
(texsym (caar x
))) r
(caar x
) rop
))
415 (defun tex-infix (x l r
)
417 (setq l
(tex (cadr x
) l nil lop
(caar x
)))
418 (tex (caddr x
) (append l
(texsym (caar x
))) r
(caar x
) rop
))
420 (defun tex-postfix (x l r
)
421 (tex (cadr x
) l
(append (texsym (caar x
)) r
) lop
(caar x
)))
423 (defun tex-nary (x l r
)
424 (let* ((op (caar x
)) (sym (texsym op
)) (y (cdr x
)) (ext-lop lop
) (ext-rop rop
))
425 (cond ((null y
) (tex-function x l r t
)) ; this should not happen
426 ((null (cdr y
)) (tex-function x l r t
)) ; this should not happen, too
427 (t (do ((nl) (lop ext-lop op
) (rop op
(if (null (cdr y
)) ext-rop op
)))
428 ((null (cdr y
)) (setq nl
(append nl
(tex (car y
) l r lop rop
))) nl
)
429 (setq nl
(append nl
(tex (car y
) l sym lop rop
))
433 (defun tex-nofix (x l r
) (tex (car (texsym (caar x
))) l r
(caar x
) rop
))
435 (defun tex-matchfix (x l r
)
436 (setq l
(append l
(car (texsym (caar x
))))
437 ;; car of texsym of a matchfix operator is the lead op
438 r
(append (list (nth 1 (texsym (caar x
)))) r
)
439 ;; cdr is the trailing op
440 x
(tex-list (cdr x
) nil r
(or (nth 2 (texsym (caar x
))) " , ")))
444 (or (get x
'texsym
) (get x
'strsym
)
452 (defprop bigfloat tex-bigfloat tex
)
454 ; For 1.2345b678, generate TeX output 1.2345_B \times 10^{678} .
455 ; If the exponent is 0, then ... \times 10^{0} is generated
456 ; (no attempt to strip off zero exponent).
458 (defun tex-bigfloat (x l r
)
459 (let ((formatted (fpformat x
)))
460 ; There should always be a '|b| or '|B| in the FPFORMAT output.
461 ; Play it safe -- check anyway.
462 (if (or (find '|b| formatted
) (find '|B| formatted
))
468 #'(lambda (e) (if (or (eq e
'|b|
) (eq e
'|B|
))
469 '("_B" | |
"\\times" | |
"10^{")
473 (append l spell-out-expt r
))
474 (append l formatted r
))))
476 (defprop mprog
"\\mathbf{block}\\;" texword
)
477 (defprop %erf
"\\mathrm{erf}" texword
)
478 (defprop $erf
"\\mathrm{erf}" texword
) ;; etc for multicharacter names
479 (defprop $true
"\\mathbf{true}" texword
)
480 (defprop $false
"\\mathbf{false}" texword
)
481 (defprop $done
"\\mathbf{done}" texword
)
483 (defprop mprogn tex-matchfix tex
) ;; mprogn is (<progstmnt>, ...)
484 (defprop mprogn
(("\\left(") "\\right)") texsym
)
486 (defprop mlist tex-matchfix tex
)
487 (defprop mlist
(("\\left[ ")" \\right] ") texsym
)
488 (setf (get '%mlist
'tex
) (get 'mlist
'tex
))
489 (setf (get '%mlist
'texsym
) (get 'mlist
'texsym
))
492 (defprop mabs tex-matchfix tex
)
493 (defprop mabs
(("\\left| ")"\\right| ") texsym
)
495 (defprop mqapply tex-mqapply tex
)
497 (defun tex-mqapply (x l r
)
498 (setq l
(tex (cadr x
) l
(list "(" ) lop
'mfunction
)
499 r
(tex-list (cddr x
) nil
(cons ")" r
) ","))
500 (append l r
)) ;; fixed 9/24/87 RJF
502 (defprop $%i
"i" texword
)
503 (defprop $%e
"e" texword
)
504 (defprop $inf
"\\infty " texword
)
505 (defprop $minf
" -\\infty " texword
)
506 (defprop %laplace
"\\mathcal{L}" texword
)
508 (defprop $alpha
"\\alpha" texword
)
509 (defprop $beta
"\\beta" texword
)
510 (defprop $gamma
"\\gamma" texword
)
511 (defprop %gamma
"\\gamma" texword
)
513 (defprop %gamma tex-gamma tex
)
514 (defun tex-gamma (x l r
)
515 (tex (cadr x
) (append l
'("\\Gamma\\left(")) (append '("\\right)") r
) 'mparen
'mparen
))
517 (defprop $%gamma
"\\gamma" texword
)
518 (defprop %gamma_incomplete
"\\Gamma" texword
)
519 (defprop %gamma_incomplete_regularized
"Q" texword
)
520 (defprop %gamma_incomplete_generalized
"\\Gamma" texword
)
521 (defprop $gamma_incomplete_lower
"\\gamma" texword
)
522 (defprop $delta
"\\delta" texword
)
523 (defprop $epsilon
"\\varepsilon" texword
)
524 (defprop $zeta
"\\zeta" texword
)
525 (defprop $eta
"\\eta" texword
)
526 (defprop $theta
"\\vartheta" texword
)
527 (defprop $iota
"\\iota" texword
)
528 (defprop $kappa
"\\kappa" texword
)
529 (defprop lambda
"\\lambda" texword
)
530 (defprop $lambda
"\\lambda" texword
)
531 (defprop $mu
"\\mu" texword
)
532 (defprop $nu
"\\nu" texword
)
533 (defprop $xi
"\\xi" texword
)
534 (defprop $omicron
" o" texword
)
535 (defprop $%pi
"\\pi" texword
)
536 (defprop $pi
"\\pi" texword
)
537 (defprop $rho
"\\rho" texword
)
538 (defprop $sigma
"\\sigma" texword
)
539 (defprop $tau
"\\tau" texword
)
540 (defprop $upsilon
"\\upsilon" texword
)
541 (defprop $phi
"\\varphi" texword
)
542 (defprop $%phi
"\\varphi" texword
)
543 (defprop $chi
"\\chi" texword
)
544 (defprop $psi
"\\psi" texword
)
545 (defprop $omega
"\\omega" texword
)
547 (defprop |$Alpha|
"{\\rm A}" texword
)
548 (defprop |$Beta|
"{\\rm B}" texword
)
549 (defprop |$Gamma|
"\\Gamma" texword
)
550 (defprop |$Delta|
"\\Delta" texword
)
551 (defprop |$Epsilon|
"{\\rm E}" texword
)
552 (defprop |$Zeta|
"{\\rm Z}" texword
)
553 (defprop |$Eta|
"{\\rm H}" texword
)
554 (defprop |$Theta|
"\\Theta" texword
)
555 (defprop |$Iota|
"{\\rm I}" texword
)
556 (defprop |$Kappa|
"{\\rm K}" texword
)
557 (defprop |$Lambda|
"\\Lambda" texword
)
558 (defprop |$Mu|
"{\\rm M}" texword
)
559 (defprop |$Nu|
"{\\rm N}" texword
)
560 (defprop |$Xi|
"\\Xi" texword
)
561 (defprop |$Omicron|
"{\\rm O}" texword
)
562 (defprop |$Pi|
"\\Pi" texword
)
563 (defprop |$Rho|
"{\\rm P}" texword
)
564 (defprop |$Sigma|
"\\Sigma" texword
)
565 (defprop |$Tau|
"{\\rm T}" texword
)
566 (defprop |$Upsilon|
"\\Upsilon" texword
)
567 (defprop |$Phi|
"\\Phi" texword
)
568 (defprop |$Chi|
"{\\rm X}" texword
)
569 (defprop |$Psi|
"\\Psi" texword
)
570 (defprop |$Omega|
"\\Omega" texword
)
572 (defprop mquote tex-prefix tex
)
573 (defprop mquote
("\\mbox{{}'{}}") texsym
)
575 (defprop msetq tex-infix tex
)
576 (defprop msetq
(":") texsym
)
578 (defprop mset tex-infix tex
)
579 (defprop mset
("::") texsym
)
581 (defprop mdefine tex-infix tex
)
582 (defprop mdefine
(":=") texsym
)
584 (defprop mdefmacro tex-infix tex
)
585 (defprop mdefmacro
("::=") texsym
)
587 (defprop marrow tex-infix tex
)
588 (defprop marrow
("\\rightarrow ") texsym
)
590 (defprop mfactorial tex-postfix tex
)
591 (defprop mfactorial
("!") texsym
)
593 (defprop mexpt tex-mexpt tex
)
595 (defprop %sum
110. tex-rbp
) ;; added by BLW, 1 Oct 2001
596 (defprop %product
115. tex-rbp
) ;; added by BLW, 1 Oct 2001
598 ;; If the number contains a exponent marker when printed, we need to
599 ;; put parens around it.
600 (defun numneedsparen (number)
601 (unless (integerp number
)
602 (let ((r (exploden number
)))
603 (member 'e r
:test
#'string-equal
))))
605 (defvar *tex-mexpt-trig-like-fns
* '(%sin %cos %tan %csc %sec %cot %sinh %cosh %tanh %asin %acos %atan %asinh %acosh %atanh
))
606 (defun tex-mexpt-trig-like-fn-p (f)
607 (member f
*tex-mexpt-trig-like-fns
*))
608 (defun maybe-tex-mexpt-trig-like (x l r
)
609 ;; here is where we have to check for f(x)^b to be displayed
610 ;; as f^b(x), as is the case for sin(x)^2 .
611 ;; which should be sin^2 x rather than (sin x)^2 or (sin(x))^2.
612 ;; yet we must not display (a+b)^2 as +^2(a,b)...
613 ;; or (sin(x))^(-1) as sin^(-1)x, which would be arcsine x
615 ((fx (cadr x
)) ; this is f(x)
616 (f (and (not (atom fx
)) (atom (caar fx
)) (caar fx
))) ; this is f [or nil]
617 (bascdr (and f
(cdr fx
))) ; this is (x) [maybe (x,y..), or nil]
618 (expon (caddr x
)) ;; this is the exponent
620 f
; there is such a function
621 (tex-mexpt-trig-like-fn-p f
) ; f is trig-like
622 ;; I THINK THIS NEXT TEST IS UNNECESSARY BECAUSE IF IT PASSES THE PRECEDING TEST, IT IS ACCEPTABLE. REVISIT.
623 (member (get-first-char f
) '(#\%
#\$
) :test
#'char
=) ;; insist it is a % or $ function
624 (not (member 'array
(cdar fx
) :test
#'eq
)) ; fix for x[i]^2
625 ;; I THINK THIS NEXT TEST IS UNNECESSARY BECAUSE NFORMAT CHANGES (...)^-1 TO 1/(...) AND (...)^(1/2) TO SQRT(...). REVISIT.
626 (or (and (atom expon
) (not (numberp expon
))) ; f(x)^y is ok
627 (and (atom expon
) (numberp expon
) (> expon
0))))))
628 ; f(x)^3 is ok, but not f(x)^-1, which could
629 ; inverse of f, if written f^-1 x
630 ; what else? f(x)^(1/2) is sqrt(f(x)), ??
632 (setq l
(tex `((mexpt) ,f
,expon
) l nil
'mparen
'mparen
))
633 (if (and (null (cdr bascdr
))
634 (eq (get f
'tex
) 'tex-prefix
))
635 (setq r
(tex (car bascdr
) nil r f
'mparen
))
636 (setq r
(tex (cons '(mprogn) bascdr
) nil r
'mparen
'mparen
)))
638 (t nil
))) ; won't doit. fall through
641 ;; insert left-angle-brackets for mncexpt. a^<n> is how a^^n looks.
642 (defun tex-mexpt (x l r
)
643 (let((nc (eq (caar x
) 'mncexpt
))) ; true if a^^b rather than a^b
644 (cond ;; this whole clause
645 ;; should be deleted if this hack is unwanted and/or the
646 ;; time it takes is of concern.
647 ;; it shouldn't be too expensive.
648 ((and (eq (caar x
) 'mexpt
) ; don't do this hack for mncexpt
649 (maybe-tex-mexpt-trig-like x l r
))) ; fall through if f is not trig-like
650 (t (setq l
(cond ((or ($bfloatp
(cadr x
))
651 (and (numberp (cadr x
)) (numneedsparen (cadr x
))))
652 ; ACTUALLY THIS TREATMENT IS NEEDED WHENEVER (CAAR X) HAS GREATER BINDING POWER THAN MTIMES ...
653 (tex (cadr x
) (append l
'("\\left(")) '("\\right)") lop
(caar x
)))
654 (t (tex (cadr x
) l nil lop
(caar x
))))
655 r
(if (mmminusp (setq x
(nformat (caddr x
))))
656 ;; the change in base-line makes parens unnecessary
658 (tex (cadr x
) '("^ {-\\langle ") (cons "\\rangle }" r
) 'mparen
'mparen
)
659 (tex (cadr x
) '("^ {- ") (cons " }" r
) 'mminus
'mparen
))
661 (tex x
(list "^{\\langle ") (cons "\\rangle}" r
) 'mparen
'mparen
)
662 (if (and (integerp x
) (< x
10))
663 (tex x
(list "^")(cons "" r
) 'mparen
'mparen
)
664 (tex x
(list "^{")(cons "}" r
) 'mparen
'mparen
)))))
667 (defprop mncexpt tex-mexpt tex
)
669 (defprop mnctimes tex-nary tex
)
670 (defprop mnctimes
("\\cdot ") texsym
)
672 (defprop mtimes tex-nary tex
)
673 (defprop mtimes
("\\,") texsym
)
675 (defprop %sqrt tex-sqrt tex
)
677 (defun tex-sqrt(x l r
)
678 ;; format as \\sqrt { } assuming implicit parens for sqr grouping
679 (tex (cadr x
) (append l
'("\\sqrt{")) (append '("}") r
) 'mparen
'mparen
))
681 ;; macsyma doesn't know about cube (or nth) roots,
682 ;; but if it did, this is what it would look like.
683 (defprop $cubrt tex-cubrt tex
)
685 (defun tex-cubrt (x l r
)
686 (tex (cadr x
) (append l
'("\\root 3 \\of{")) (append '("}") r
) 'mparen
'mparen
))
688 (defprop mquotient tex-mquotient tex
)
689 (defprop mquotient
("\\over") texsym
)
691 (defun tex-mquotient (x l r
)
693 (setq l
(tex (cadr x
) (append l
'("{{")) nil
'mparen
'mparen
)
694 ;the divide bar groups things
695 r
(tex (caddr x
) (list "}\\over{") (append '("}}")r
) 'mparen
'mparen
))
698 (defprop $matrix tex-matrix tex
)
700 ;; Tex dialects either offer a \pmatrix command or a pmatrix environment
701 ;; so we let the TeX decide which one to use.
702 (defun tex-matrix(x l r
) ;;matrix looks like ((mmatrix)((mlist) a b) ...)
703 (append l
`("\\ifx\\endpmatrix\\undefined\\pmatrix{\\else\\begin{pmatrix}\\fi ")
705 (tex-list (cdr y
) nil
(list "\\cr ") "&"))
707 '("\\ifx\\endpmatrix\\undefined}\\else\\end{pmatrix}\\fi ") r
))
709 ;; macsyma sum or prod is over integer range, not low <= index <= high
710 ;; TeX is lots more flexible .. but
712 (defprop %sum tex-sum tex
)
713 (defprop %lsum tex-lsum tex
)
714 (defprop %product tex-sum tex
)
716 ;; easily extended to union, intersect, otherops
718 (defun tex-lsum(x l r
)
719 (let ((op (cond ((eq (caar x
) '%lsum
) "\\sum_{")
722 ;; gotta be one of those above
723 ;; 4th arg of tex is changed from mparen to (caar x)
724 ;; to reflect the operator preceedance correctly.
725 ;; This change improves the how to put paren.
726 (s1 (tex (cadr x
) nil nil
(caar x
) rop
)) ;; summand
727 (index ;; "index = lowerlimit"
728 (tex `((min simp
) , (caddr x
), (cadddr x
)) nil nil
'mparen
'mparen
)))
729 (append l
`( ,op
,@index
"}}{" ,@s1
"}") r
)))
731 (defun tex-sum(x l r
)
732 (let ((op (cond ((eq (caar x
) '%sum
) "\\sum_{")
733 ((eq (caar x
) '%product
) "\\prod_{")
736 ;; gotta be one of those above
737 ;; 4th arg of tex is changed from mparen to (caar x)
738 ;; to reflect the operator preceedance correctly.
739 ;; This change improves the how to put paren.
740 (s1 (tex (cadr x
) nil nil
(caar x
) rop
)) ;; summand
741 (index ;; "index = lowerlimit"
742 (tex `((mequal simp
) ,(caddr x
),(cadddr x
)) nil nil
'mparen
'mparen
))
743 (toplim (tex (car(cddddr x
)) nil nil
'mparen
'mparen
)))
744 (append l
`( ,op
,@index
"}^{" ,@toplim
"}{" ,@s1
"}") r
)))
746 (defprop %integrate tex-int tex
)
747 (defun tex-int (x l r
)
748 (let ((s1 (tex (cadr x
) nil nil
'mparen
'mparen
)) ;;integrand delims / & d
749 (var (tex (caddr x
) nil nil
'mparen rop
))) ;; variable
750 (cond((= (length x
) 3)
751 (append l
`("\\int {" ,@s1
"}{\\;d" ,@var
"}") r
))
752 (t ;; presumably length 5
753 (let ((low (tex (nth 3 x
) nil nil
'mparen
'mparen
))
755 (hi (tex (nth 4 x
) nil nil
'mparen
'mparen
)))
756 (append l
`("\\int_{" ,@low
"}^{" ,@hi
"}{" ,@s1
"\\;d" ,@var
"}") r
))))))
758 (defprop %limit tex-limit tex
)
760 (defun tex-limit (x l r
)
763 ((s1 (tex (cadr x
) nil nil
'mparen rop
))
764 (direction (fifth x
))
765 ;; the thing underneath "limit"
767 (subst (or (and (eq direction
'$plus
) "\\downarrow ")
768 (and (eq direction
'$minus
) "\\uparrow ")
771 (tex `((mequal simp
) ,(caddr x
),(cadddr x
))
772 nil nil
'mparen
'mparen
))))
773 (append l
`("\\lim_{" ,@subfun
"}{" ,@s1
"}") r
)))
775 (defprop %at tex-at tex
)
777 ;; e.g. at(diff(f(x)),x=a)
778 (defun tex-at (x l r
)
779 (let ((s1 (tex (cadr x
) nil nil lop rop
))
780 (sub (tex (caddr x
) nil nil
'mparen
'mparen
)))
781 (append l
'("\\left.") s1
'("\\right|_{") sub
'("}") r
)))
783 (defprop mbox tex-mbox tex
)
785 ;; \boxed is defined in amsmath.sty,
786 ;; \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}}
788 (defun tex-mbox (x l r
)
789 (append l
'("\\boxed{") (tex (cadr x
) nil nil
'mparen
'mparen
) '("}") r
))
791 (defprop mlabox tex-mlabox tex
)
793 (defun tex-mlabox (x l r
)
794 (append l
'("\\stackrel{") (tex (caddr x
) nil nil
'mparen
'mparen
)
795 '("}{\\boxed{") (tex (cadr x
) nil nil
'mparen
'mparen
) '("}}") r
))
797 ;;binomial coefficients
799 (defprop %binomial tex-choose tex
)
801 (defun tex-choose (x l r
)
804 (tex (cadr x
) nil nil
'mparen
'mparen
)
806 (tex (caddr x
) nil nil
'mparen
'mparen
)
810 (defprop rat tex-rat tex
)
811 (defun tex-rat(x l r
) (tex-mquotient x l r
))
813 (defprop mplus tex-mplus tex
)
815 (defun tex-mplus (x l r
)
816 ;(declare (fixnum w))
817 (cond ((member 'trunc
(car x
) :test
#'eq
) (setq r
(cons "+\\cdots " r
))))
818 (cond ((null (cddr x
))
820 (tex-function x l r t
)
821 (tex (cadr x
) (cons "+" l
) r
'mplus rop
)))
822 (t (setq l
(tex (cadr x
) l nil lop
'mplus
)
824 (do ((nl l
) (dissym))
826 (if (mmminusp (car x
)) (setq l
(cadar x
) dissym
(list "-"))
827 (setq l
(car x
) dissym
(list "+")))
828 (setq r
(tex l dissym r
'mplus rop
))
830 (if (mmminusp (car x
)) (setq l
(cadar x
) dissym
(list "-"))
831 (setq l
(car x
) dissym
(list "+")))
832 (setq nl
(append nl
(tex l dissym nil
'mplus
'mplus
))
835 (defprop mminus tex-prefix tex
)
836 (defprop mminus
("-") texsym
)
838 ;; MIN = "Maxima in", apparently -- not to be confused with the least value of a set.
839 ;; MIN is not known to the parser, although it seems stuff like "x in S" could make use of MIN.
841 (defprop min tex-infix tex
)
842 (defprop min
("\\in{") texsym
)
843 (defprop min
80. tex-lbp
)
844 (defprop min
80. tex-rbp
)
846 (defprop mequal tex-infix tex
)
847 (defprop mequal
(=) texsym
)
849 (defprop mnotequal tex-infix tex
)
850 (defprop mnotequal
("\\neq ") texsym
)
852 (defprop mgreaterp tex-infix tex
)
853 (defprop mgreaterp
(>) texsym
)
855 (defprop mgeqp tex-infix tex
)
856 (defprop mgeqp
("\\geq ") texsym
)
858 (defprop mlessp tex-infix tex
)
859 (defprop mlessp
(<) texsym
)
861 (defprop mleqp tex-infix tex
)
862 (defprop mleqp
("\\leq ") texsym
)
864 (defprop mnot tex-prefix tex
)
865 (defprop mnot
("\\neg ") texsym
)
867 (defprop mand tex-nary tex
)
868 (defprop mand
("\\land ") texsym
)
870 (defprop mor tex-nary tex
)
871 (defprop mor
("\\lor ") texsym
)
873 ;; make sin(x) display as sin x , but sin(x+y) as sin(x+y)
879 (setf (get a
'tex
) 'tex-prefix
)
880 (setf (get a
'texword
) b
) ;This means "sin" will always be roman
881 (setf (get a
'texsym
) (list b
))
882 (setf (get a
'tex-rbp
) 130)))
885 ;; I WONDER IF ALL BUILT-IN FUNCTIONS SHOULD BE SET IN ROMAN TYPE
886 (defprop %atan2
"{\\rm atan2}" texword
)
888 ;; JM 09/01 expand and re-order to follow table of "log-like" functions,
889 ;; see table in Lamport, 2nd edition, 1994, p. 44, table 3.9.
890 ;; I don't know if these are Latex-specific so you may have to define
891 ;; them if you use plain Tex.
899 ; Latex's arg(x) is ... ?
905 ; Latex's "deg" is ... ?
906 (%determinant
"\\det ")
910 ; Latex's "hom" is ... ?
911 (%inf
"\\inf ") ; many will prefer "\\infty". Hmmm.
912 ; Latex's "ker" is ... ?
913 ; Latex's "lg" is ... ?
914 ; lim is handled by tex-limit.
915 ; Latex's "liminf" ... ?
916 ; Latex's "limsup" ... ?
925 ; Latex's "sup" ... ?
928 ;; (%erf "{\\rm erf}") this would tend to set erf(x) as erf x. Unusual
929 ;(%laplace "{\\cal L}")
931 ; Maxima built-in functions which do not have corresponding TeX symbols.
933 (%asec
"{\\rm arcsec}\\; ")
934 (%acsc
"{\\rm arccsc}\\; ")
935 (%acot
"{\\rm arccot}\\; ")
937 (%sech
"{\\rm sech}\\; ")
938 (%csch
"{\\rm csch}\\; ")
940 (%asinh
"{\\rm asinh}\\; ")
941 (%acosh
"{\\rm acosh}\\; ")
942 (%atanh
"{\\rm atanh}\\; ")
944 (%asech
"{\\rm asech}\\; ")
945 (%acsch
"{\\rm acsch}\\; ")
946 (%acoth
"{\\rm acoth}\\; ")
950 (defprop mcond tex-mcond tex
)
951 (defprop %mcond tex-mcond tex
)
953 (defprop %del tex-prefix tex
)
954 (defprop %del
("d") texsym
)
956 (defprop %derivative tex-derivative tex
)
957 (defun tex-derivative (x l r
)
958 (tex (if $derivabbrev
960 (tex-d x
'$d
)) l r lop rop
))
962 (defun tex-d(x dsym
) ;dsym should be $d or "$\\partial"
963 ;; format the macsyma derivative form so it looks
964 ;; sort of like a quotient times the deriva-dand.
966 ((arg (cadr x
)) ;; the function being differentiated
967 (difflist (cddr x
)) ;; list of derivs e.g. (x 1 y 2)
968 (ords (odds difflist
0)) ;; e.g. (1 2)
969 (vars (odds difflist
1)) ;; e.g. (x y)
970 (numer `((mexpt) ,dsym
((mplus) ,@ords
))) ; d^n numerator
971 (denom (cons '(mtimes)
972 (mapcan #'(lambda(b e
)
973 `(,dsym
,(simplifya `((mexpt) ,b
,e
) nil
)))
976 ((mquotient) ,(simplifya numer nil
) ,denom
)
979 (defun tex-dabbrev (x)
980 ;; Format diff(f,x,1,y,1) so that it looks like
984 ((arg (cadr x
)) ;; the function being differentiated
985 (difflist (cddr x
)) ;; list of derivs e.g. (x 1 y 2)
986 (ords (odds difflist
0)) ;; e.g. (1 2)
987 (vars (odds difflist
1))) ;; e.g. (x y)
991 `((mqapply array
) ,arg
))
992 (if (and (= (length vars
) 1)
995 `(((mtimes) ,@(mapcan #'(lambda (var ord
)
996 (make-list ord
:initial-element var
))
1001 (1 (loop for e in list by
#'cddr collect e
)) ;; get the odd terms (first, third...)
1002 (0 (loop for e in
(cdr list
) by
#'cddr collect e
)))) ;; get the (second, fourth ... ) element
1004 ;; The format of MCOND expressions is documented above the definition
1005 ;; of DIM-MCOND in displa.lisp. Here are some examples:
1007 ;; ((%mcond) $a $b t nil) <==> 'if a then b
1008 ;; ((%mcond) $a $b t $d) <==> 'if a then b else d
1009 ;; ((%mcond) $a $b $c nil t nil) <==> 'if a then b elseif c then false
1010 ;; ((%mcond) $a $b $c $d t nil) <==> 'if a then b elseif c then d
1011 ;; ((%mcond) $a $b $c $d t $f) <==> 'if a then b elseif c then d else f
1013 ;; Note that DIM-MCOND omits display of the final "else" in three
1014 ;; cases illustrated below, so we do the same here:
1016 ;; ((%mcond) $a $b $c $d t $false) <==> '(if a then b elseif c then d)
1017 ;; ((%mcond) $a $b $c $d t nil) <==> 'if a then b elseif c then d
1018 ;; ((%mcond) $a $b $c $d) ==> 'if a then b elseif c then d
1020 ;; The first two cases occur in practice, as can be seen by evaluating
1021 ;; ?print('(if a then b)) and ?print(if a then b). The parser
1022 ;; produces the first case, which is transformed into the second case
1023 ;; during evaluation. The third case is handled equivalently by the
1024 ;; evaluator and DIM-MCOND, and might plausibly be created by some
1025 ;; code, so we handle it here as well.
1027 ;; The use of '$false (instead of nil) may be a hack that is no longer
1028 ;; needed. For more information on this, search for $false in
1029 ;; PARSE-CONDITION of nparse.lisp and DIM-MCOND of displa.lisp. Also
1030 ;; see the mailing list thread with subject "Bugs in tex-mcond" which
1031 ;; took place in January 2011. -MHW
1033 (defun tex-mcond (x l r
)
1037 (tex (car x
) l
'("\\;\\mathbf{then}\\;") 'mparen
'mparen
)
1038 (cond ((member (cddr x
) '(() (t nil
) (t $false
)) :test
#'equal
)
1039 (tex (second x
) nil r
'mcond rop
))
1040 ((and (eq (third x
) t
) (null (nthcdr 4 x
)))
1042 (tex (second x
) nil nil
'mparen
'mparen
)
1043 (tex (fourth x
) '("\\;\\mathbf{else}\\;") r
'mcond rop
)))
1045 (tex (second x
) nil nil
'mparen
'mparen
)
1046 (recurse (cddr x
) '("\\;\\mathbf{elseif}\\;"))))))))
1047 (append l
(recurse (cdr x
) '("\\mathbf{if}\\;")))))
1049 (defprop mdo tex-mdo tex
)
1050 (defprop mdoin tex-mdoin tex
)
1052 (defprop %mdo tex-mdo tex
)
1053 (defprop %mdoin tex-mdoin tex
)
1055 (defun tex-lbp(x)(cond((get x
'tex-lbp
))(t(lbp x
))))
1056 (defun tex-rbp(x)(cond((get x
'tex-rbp
))(t(rbp x
))))
1058 ;; these aren't quite right
1060 (defun tex-mdo (x l r
)
1061 (tex-list (texmdo x
) l r
"\\;"))
1063 (defun tex-mdoin (x l r
)
1064 (tex-list (texmdoin x
) l r
"\\;"))
1067 (nconc (cond ((second x
) `("\\mathbf{for}" ,(second x
))))
1068 (cond ((equal 1 (third x
)) nil
)
1069 ((third x
) `("\\mathbf{from}" ,(third x
))))
1070 (cond ((equal 1 (fourth x
)) nil
)
1071 ((fourth x
) `("\\mathbf{step}" ,(fourth x
)))
1072 ((fifth x
) `("\\mathbf{next}" ,(fifth x
))))
1073 (cond ((sixth x
) `("\\mathbf{thru}" ,(sixth x
))))
1074 (cond ((null (seventh x
)) nil
)
1075 ((eq 'mnot
(caar (seventh x
)))
1076 `("\\mathbf{while}" ,(cadr (seventh x
))))
1077 (t `("\\mathbf{unless}" ,(seventh x
))))
1078 `("\\mathbf{do}" ,(eighth x
))))
1081 (nconc `("\\mathbf{for}" ,(second x
) "\\mathbf{in}" ,(third x
))
1082 (cond ((sixth x
) `("\\mathbf{thru}" ,(sixth x
))))
1083 (cond ((null (seventh x
)) nil
)
1084 ((eq 'mnot
(caar (seventh x
)))
1085 `("\\mathbf{while}" ,(cadr (seventh x
))))
1086 (t `("\\mathbf{unless}" ,(seventh x
))))
1087 `("\\mathbf{do}" ,(eighth x
))))
1089 (defprop mtext tex-mtext tex
)
1090 (defprop text-string tex-mtext tex
)
1091 (defprop mlabel tex-mlabel tex
)
1092 (defprop spaceout tex-spaceout tex
)
1094 ;; Additions by Marek Rychlik (rychlik@u.arizona.edu)
1095 ;; This stuff handles setting of LET rules
1097 (defprop | --
> |
"\\longrightarrow " texsym
)
1098 (defprop #.
(intern (format nil
" ~A " 'where
)) "\\;\\mathbf{where}\\;" texsym
)
1100 ;; end of additions by Marek Rychlik
1102 (defun tex-try-sym (x)
1104 (let ((tx (get x
'texsym
))) (if tx tx x
))
1107 (defun tex-mtext (x l r
)
1108 (tex-list (map 'list
#'tex-try-sym
(cdr x
)) l r
""))
1110 (defun tex-mlabel (x l r
)
1114 (list (format nil
"\\mbox{\\tt\\red(~A) \\black}" (tex-stripdollar (cadr x
))))
1118 (defun tex-spaceout (x l r
)
1119 (append l
(cons (format nil
"\\hspace{~dmm}" (* 3 (cadr x
))) r
)))
1121 ;; run some code initialize file before $tex is run
1122 (defmfun $texinit
(file)
1123 (declare (ignore file
))
1126 ;; this just prints a \\end on the file; this is something a TeXnician would
1127 ;; probably have no trouble spotting, and will generally be unnecessary, since
1128 ;; we anticipate almost all use of tex would be involved in inserting this
1129 ;; stuff into larger files that would have their own \\end or equivalent.
1130 (defmfun $texend
(filename)
1131 (with-open-file (st (stripdollar filename
) :direction
:output
1132 :if-exists
:append
:if-does-not-exist
:create
)
1133 (format st
"\\end~%"))
1136 ;; Construct a Lisp function and attach it to the TEX property of
1137 ;; operator OP. The constructed function calls a Maxima function F
1138 ;; to generate TeX output for OP.
1139 ;; F must take 1 argument (an expression which has operator OP)
1140 ;; and must return a string (the TeX output).
1142 (defun make-maxima-tex-glue (op f previous-f
)
1144 ((glue-f (gensym "TEX-GLUE-"))
1145 (f-body `(let ((f-x (mfuncall ',f x
)))
1146 (cond ((stringp f-x
) (append l
(list f-x
) r
))
1149 (funcall ',previous-f x l r
)
1150 (tex-function x l r nil
)))
1151 (t (merror (intl:gettext
"tex: function ~s returned something other than a string or 'false'.~%") ($sconcat
',f
)))))
1153 (setf (symbol-function glue-f
) (coerce `(lambda (x l r
) ,f-body
) 'function
))
1154 (setf (get op
'tex
) glue-f
))
1157 ;; Convenience function to allow user to process expression X
1158 ;; and get a string (TeX output for X) in return.
1160 (defmfun $tex1
(x) (reduce #'strcat
(tex x nil nil
'mparen
'mparen
)))
1162 ;; Undone and trickier:
1163 ;; handle reserved symbols stuff, just in case someone
1164 ;; has a macsyma variable named (yuck!!) \over or has a name with
1166 ;; Maybe do some special hacking for standard notations for
1167 ;; hypergeometric fns, alternative summation notations 0<=n<=inf, etc.
1169 ;;Undone and really pretty hard: line breaking
1171 ;; The texput function was written by Barton Willis.
1173 (defmfun $texput
(e s
&optional tx
)
1177 (setq e
($verbify e
)))
1179 (merror (intl:gettext
"texput: first argument must be a string or a symbol; found: ~M") e
)))
1181 (setq s
(if ($listp s
) (margs s
) (list s
)))
1185 ;; texput was called as texput(op, foo) where foo is a string
1186 ;; or a symbol; when foo is a string, assign TEXWORD property,
1187 ;; when foo is a symbol, construct glue function to call
1188 ;; the Maxima function named by foo.
1189 (let ((s0 (nth 0 s
)))
1192 (when (get e
'texsym
) (putprop e
(list s0
) 'texsym
))
1193 (putprop e s0
'texword
))
1194 (make-maxima-tex-glue e s0
(get e
'tex
))))) ;; assigns TEX property
1196 (putprop e
'tex-matchfix
'tex
)
1197 (cond ((< (length s
) 2)
1198 (merror (intl:gettext
"texput: expected a list of two items for matchfix operator.")))
1200 (putprop e
(list (list (first s
)) (second s
)) 'texsym
))
1202 (putprop e
(list (list (first s
)) (second s
) (third s
)) 'texsym
)))
1206 (putprop e
'tex-nofix
'tex
)
1207 (putprop e s
'texsym
)
1208 (when (get e
'texword
) (putprop e
(nth 0 s
) 'texword
))
1212 (putprop e
'tex-prefix
'tex
)
1213 (when (null (get e
'grind
))
1214 (putprop e
180 'tex-rbp
))
1215 (putprop e s
'texsym
)
1216 (when (get e
'texword
) (putprop e
(nth 0 s
) 'texword
))
1220 (putprop e
'tex-infix
'tex
)
1221 (when (null (get e
'grind
))
1222 (putprop e
180 'tex-lbp
)
1223 (putprop e
180 'tex-rbp
))
1224 (putprop e s
'texsym
)
1225 (when (get e
'texword
) (putprop e
(nth 0 s
) 'texword
))
1229 (putprop e
'tex-nary
'tex
)
1230 (when (null (get e
'grind
))
1231 (putprop e
180 'tex-lbp
)
1232 (putprop e
180 'tex-rbp
))
1233 (putprop e s
'texsym
)
1234 (when (get e
'texword
) (putprop e
(nth 0 s
) 'texword
))
1238 (putprop e
'tex-postfix
'tex
)
1239 (when (null (get e
'grind
))
1240 (putprop e
180 'tex-lbp
))
1241 (putprop e s
'texsym
)
1242 (when (get e
'texword
) (putprop e
(nth 0 s
) 'texword
))