1 ;;;;;;;;;;;;;;;;; File: mathml-maxima.lsp ;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;; Purpose: Enabling maxima to receive mathml contentent-coded input
4 ;; Usage: compile this file with UNIX command
6 ;; which produces mathml-maxima.o
8 ;; load into MAXIMA by MAXIMA top-level command
9 ;; loadfile("mathml-maxima.lsp");
11 ;; Author: Paul S. Wang
14 ; Authors: Paul S. Wang, Kent State University
15 ; This work was supported by NSF/USA.
16 ; Permission to use this work for any purpose is granted provided that
17 ; the copyright notice, author and support credits above are retained.
19 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23 (declaim (special *tag
* *special-proc
* *parse-stream
* *in
* parse-tyipeek
))
25 (defvar *in
* *parse-stream
* "input stream to read")
27 (setq parse-tyipeek nil
) ;; look-ahead in nparse.lisp
29 (defvar *tag
* nil
"tag of element returned by ml2ma")
32 ;;;;; mltoma is the top-level mathml input function
35 (meval (mltoma *parse-stream
*)))
37 (defun mltoma(&optional
*in
*)
39 (if (null *in
*) (setq *in
* t
))
41 (if (not (eq g
'math
)) (return nil
))
43 (setq g
(get-tag)) ;; this should be </math>
47 (multiple-value-bind (tag attributes
) (get-tag)
50 ((eq tag
'ci
) (ml-ci attributes
))
51 ((eq tag
'cn
) (ml-cn attributes
))
52 ((eq tag
'apply
) (ml-apply))
53 ((member tag
'(bvar lowlimit uplimit
) :test
#'eq
)
54 (setq ans
(ml2ma)) (get-tag) ans
)
55 ((eq tag
'/apply
) nil
)
56 (t (merror "unknown or invalid mathml tag: ~A" tag
)))))
59 (prog(op *special-proc
* ans
)
62 (if *special-proc
* (return (apply *special-proc
* nil
))
63 (merror "internal error: null mct-proc"))
65 (do ((operand (ml2ma) (ml2ma))) ;; returns nil after seeing </apply>
66 ((null operand
) (setq ans
(cons op
(nreverse ans
)))) ;; done
67 (setq ans
(cons operand ans
))
72 ;; <diff/> <apply> <fn>G</fn><ci>X</ci> </apply>
73 ;; <bvar><ci>X</ci><degree><cn type="integer">2</cn></degree></bvar>
75 ;;(($DIFF) (($F) $X) $X 2)
78 (let ((fn (ml2ma)) (var-deg (diff-bvar)))
79 (get-tag) ;; lose </apply>
80 (cons (list '$diff
) (cons fn var-deg
))))
83 (prog(var nt ll up grand
)
86 (cond ((eq *tag
* 'lowlimit
)
89 (cond ((eq *tag
* 'uplimit
)
91 (get-tag) ;; lose </apply> for <int\>
92 (return (list '($integrate
) grand var ll up
)))
93 (t (merror "definite intergral error"))
98 (get-tag) ;; lose </apply>
99 (return (list '($integrate
) grand var
))))
104 (if (not (eq tag
'bvar
)) (merror "Expecting bvar but got ~A" tag
))
106 (get-tag) ;; lose </bvar>
113 (if (not (eq tag
'bvar
)) (merror "Expecting bvar but got ~A" tag
))
116 (if (not (eq tag
'degree
)) (merror "Expecting degree but got ~A" tag
))
118 (get-tag)(get-tag) ;; skip closing tags
122 (defun ml-cn (attributes)
124 (setq type
(find-attribute "type" attributes
)) ;; always has type
126 ((or (equal type
"integer") (equal type
"float"))
127 (setq number
(get-number)))
128 ((equal type
"constant")
129 (setq number
(coerce (get-token) 'string
))
130 (setq number
(mathml-constant-to-maxima-constant number
)))
132 ;; Dunno what we could do here to handle an arbitrary type.
133 ;; For now, just raise an error.
134 (merror "Unrecognized type ``%a'' in <cn> tag.~%" type
)))
135 (get-token) ;; skip to >
138 (defun ml-ci (attributes)
139 (prog(parse-tyipeek a
*parse-stream
* type
)
140 (setq type
(find-attribute "type" attributes
)) ;; may or may not have type
142 ((equal type
"constant") ;; math constants
143 (setq a
(coerce (get-token) 'string
))
144 (setq a
(mathml-constant-to-maxima-constant a
)))
147 (setq a
(read-from-string (concatenate 'string
"$" (get-token))))))
148 (get-token) ;; skip to >
151 (defun mathml-constant-to-maxima-constant (name-string)
153 ((equal name-string
"π") '$%pi
)
154 ((equal name-string
"ⅇ") '$%e
)
155 ((equal name-string
"ⅈ") '$%i
)
156 ((equal name-string
"γ") '$%gamma
)
159 ((bare-name (string-left-trim "&" (string-right-trim ";" name-string
))))
160 (read-from-string (concatenate 'string
"$" bare-name
))))))
163 (let ((s (get-str #\
<)))
164 (if s
(read-from-string s
))))
166 ;; returns next non-white non #\> char (or -1?)
168 (do (c) (nil) ; Gobble whitespace
169 (if (member (setq c
(tyi *in
* -
1))
170 '(#\
> #\tab
#\space
#\linefeed
#\return
#\page
))
176 (defun get-tag(&optional
(endc #\
>))
179 (if (not (char= c
#\
<)) (return nil
))
180 (return (get-atag endc
))
183 (defun get-atag(&optional endc
)
185 (setq str
(get-str endc
))
186 (if (null str
) (return nil
))
190 (split-string str
'(#\tab
#\space
#\linefeed
#\return
#\page
)))
191 (tag (car tag
+attributes
))
192 (attributes (mapcar #'split-attribute
(cdr tag
+attributes
))))
193 (values (read-from-string tag
) attributes
)))))
195 ;; Split "FOO=\"BAR\"" into ("FOO" . "BAR")
196 (defun split-attribute (attr-string)
197 (let ((i (position #\
= attr-string
)))
201 ((name (subseq attr-string
0 i
))
202 (value (dequotify (subseq attr-string
(+ i
1)))))
203 `(,name .
,value
)))))
205 ;; Remove first character and last characters if the first character
206 ;; is a single or double quote and last character is the same as the first.
207 ;; (Do not call STRING-TRIM, because might strip off multiple characters.)
210 (if (or (null s
) (< (length s
) 2))
213 ((first-char (aref s
0))
214 (last-char (aref s
(1- (length s
)))))
217 (or (eql first-char
#\") (eql first-char
#\'))
218 (eql last-char first-char
))
219 (subseq (subseq s
1) 0 (- (length s
) 2))
222 (defun find-attribute (attr attrs-list
)
223 (cdr (assoc attr attrs-list
:test
#'equal
)))
225 (defun get-str(&optional endc
)
227 (setq str
(get-token endc
))
229 (return (coerce str
'string
))
234 ;; returns list of chars for next token
235 (defun get-token (&optional endc
)
236 ; Read at least one char ...
237 (do ((c (tyi *in
* -
1) (tyi *in
* -
1))
241 (and endc
(char= c endc
))
242 (and (not endc
) (member c
'(#\
< #\
> #\tab
#\space
#\linefeed
#\return
#\page
))))
243 (nreverse (or l
(ncons (tyi *in
* -
1)))))))
251 (merror "get-op: invalid null function")
253 (setq opa
(read-from-string op
))
254 (setq opa
(get opa
'mmfun
))
256 (if opa
(return (list opa
)))
257 (return (list (read-from-string
258 (concatenate 'string
"$" op
))))
260 ((setq proc
(get op
'mct-proc
))
261 (setq *special-proc
* proc
)
265 (setq mop
(get op
'mmfun
))
266 (if mop
(return (list mop
))
267 (return (list op
)) ;; should not reach here
271 ;;;(defmacro upcase (operator)
272 ;;;`(setq operator (intern (string-upcase (string ,operator)))))
274 (defun set-table (arg)
276 (cond ((equal (length arg
) 2)
277 (setq a
(cadadr arg
))
279 (if (stringp a
) (setq a
(read-from-string a
)))
280 (setf (get a b
) (car arg
))
282 ((equal (length arg
) 3)
284 (setq b
(car arg
) a
(cadr arg
))
286 (if (stringp a
) (setq a
(read-from-string a
)))
287 (setf (get a
(car b
)) (cadr b
))
292 ;;;;;;;;;;; tables ;;;;;;;;;;;;
293 ;;(set-table '(%sin (mmfun "sin/")))
294 ;;(set-table '(%cos (mmfun "cos/")))
295 ;;(set-table '(%tan (mmfun "tan/")))
296 ;;(set-table '(%cot (mmfun "cot/")))
297 ;;(set-table '(%sec (mmfun "sec/")))
298 ;;(set-table '(%csc (mmfun "csc/")))
300 ;;(set-table '(%asin (mmfun "arcsin/")))
301 ;;(set-table '(%acos (mmfun "arccos/")))
302 ;;(set-table '(%atan (mmfun "arctan/")))
303 ;;(set-table '(%acot (mmfun "acot/")))
304 ;;(set-table '(%asec (mmfun "asec/")))
305 ;;(set-table '(%acsc (mmfun "acsc/")))
306 ;;(set-table '(%sinh (mmfun "sinh/")))
307 ;;(set-table '(%cosh (mmfun "cosh/")))
308 ;;(set-table '(%tanh (mmfun "tanh/")))
309 ;;(set-table '(%coth (mmfun "coth/")))
310 ;;(set-table '(%sech (mmfun "sec/")))
311 ;;(set-table '(%csch (mmfun "csch/")))
314 ;;(set-table '(%asinh (mmfun "asinh/")))
315 ;;(set-table '(%acosh (mmfun "acosh/")))
316 ;;(set-table '(%atanh (mmfun "atanh/")))
317 ;;(set-table '(%acoth (mmfun "acoth/")))
318 ;;(set-table '(%asech (mmfun "asec/")))
319 ;;(set-table '(%acsch (mmfun "acsch/")))
321 (set-table '(%ln
(mmfun "ln/")))
322 (set-table '(%log
(mmfun "log/")))
324 (set-table '($sin
(mmfun "sin/")))
325 (set-table '($cos
(mmfun "cos/")))
326 (set-table '($tan
(mmfun "tan/")))
327 (set-table '($cot
(mmfun "cot/")))
328 (set-table '($sec
(mmfun "sec/")))
329 (set-table '($csc
(mmfun "csc/")))
331 (set-table '($asin
(mmfun "arcsin/")))
332 (set-table '($acos
(mmfun "arccos/")))
333 (set-table '($atan
(mmfun "arctan/")))
334 (set-table '($acot
(mmfun "acot/")))
335 (set-table '($asec
(mmfun "asec/")))
336 (set-table '($acsc
(mmfun "acsc/")))
338 (set-table '($sinh
(mmfun "sinh/")))
339 (set-table '($cosh
(mmfun "cosh/")))
340 (set-table '($tanh
(mmfun "tanh/")))
341 (set-table '($coth
(mmfun "coth/")))
342 (set-table '($sech
(mmfun "sec/")))
343 (set-table '($csch
(mmfun "csch/")))
345 (set-table '($asinh
(mmfun "asinh/")))
346 (set-table '($acosh
(mmfun "acosh/")))
347 (set-table '($atanh
(mmfun "atanh/")))
348 (set-table '($acoth
(mmfun "acoth/")))
349 (set-table '($asech
(mmfun "asec/")))
350 (set-table '($acsch
(mmfun "acsch/")))
351 (set-table '($ln
(mmfun "ln/")))
352 (set-table '($log
(mmfun "log/")))
356 ;;(set-table '(mlist (mct-proc mctlist)))
357 ;;(set-table '($matrix (mct-proc mctmatrix)))
358 ;;(set-table '($vector (mct-proc mctvector)))
360 ;;;;;;; Operators and functions
361 (set-table '(mand (mmfun "and/")))
362 (set-table '(mor (mmfun "or/")))
363 (set-table '(mnot (mmfun "not/")))
364 (set-table '($xor
(mmfun "xor/")))
366 (set-table '(mplus (mmfun "plus/")))
367 (set-table '(mminus (mmfun "minus/")))
368 ;;(set-table '($minus (mmfun "minus/")))
369 ;;(set-table '(mdif (mmfun "minus/")))
370 (set-table '($remainder
(mmfun "rem/")))
371 (set-table '($max
(mmfun "max/")))
372 (set-table '($min
(mmfun "min/")))
373 (set-table '(mfactorial (mmfun "factorial/")))
374 (set-table '(mabs (mmfun "abs/")))
375 (set-table '(%abs
(mct-proc abs
)))
376 ;;(set-table '(mnctimes (mmfun "times/ type=\"noncommutative\"")))
377 (set-table '(mtimes (mmfun "times/")))
378 (set-table '(mexpt (mmfun "power/")))
379 (set-table '(mquotient (mmfun "quotient/")))
380 (set-table '(%sqrt
(mmfun "sqrt/")))
381 (set-table '(mquote (mmfun "quote/")))
383 (set-table '(mgreaterp (mct-proc relation
) (mmfun "gt/")))
384 (set-table '(mgeqp (mct-proc relation
) (mmfun "geq/")))
385 (set-table '(mequal (mct-proc relation
) (mmfun "eq/")))
386 (set-table '(mnotequal (mct-proc relation
) (mmfun "neq/")))
387 (set-table '(mleqp (mct-proc relation
) (mmfun "leq/")))
388 (set-table '(mlessp (mct-proc relation
) (mmfun "lt/")))
390 (set-table '(mdefine (mct-proc def-fun
)))
392 (set-table '(msetq (mmfun "≔")))
393 ;;(set-table '(mset (mmfun "≔"))) ;;; This is not math
394 ;;(set-table '(marrow (mmfun "→")))
395 ;;(set-table '(mrarrow (mmfun "→")))
396 ;;(set-table '(%at (mct-proc mPr-at)))
397 ;;(set-table '($at (mct-proc mPr-at)))
398 ;;(set-table '($det (mct-proc mPr-det)))
399 ;;(set-table '(%determinant (mct-proc det)))
400 ;;(set-table '($binomial (mct-proc binomial)))
401 ;;(set-table '(%binomial (mct-proc binomial)))
403 (set-table '(%sum
(mct-proc sumprod
)(mmfun "sum/")))
404 ;;(set-table '($sum (mct-proc sumprod)(mmfun "sum/")))
405 ;;(set-table '($product (mct-proc sumprod)(mmfun "product/")))
406 (set-table '(%product
(mct-proc sumprod
)(mmfun "product/")))
407 ;;(set-table '($integrate (mct-proc mctintegrate)(mmfun "int/")))
408 (set-table '(%integrate
(mct-proc mctintegrate
)(mmfun "int/")))
409 (set-table '($diff
(mct-proc mctdiff
)(mmfun "diff/")))
410 ;;(set-table '(%derivative (mct-proc mctdiff)(mmfun "diff/")))
411 (set-table '($limit
(mct-proc mctlimit
)(mmfun "limit/")))
412 ;;(set-table '(%limit (mct-proc mctlimit)(mmfun "limit/")))
414 ;;(set-table '(mprog (mmfun "block")))
415 ;;(set-table '($block (mmfun "block")))
416 ;;(set-table '($$boldif (mmfun "if/")))
417 ;;(set-table '($$boldthen (mmfun "then/")))
418 ;;(set-table '($$boldelse (mmfun "else/")))