Changes http://wiki.axiom-developer.org/MathmlSpad/diff
--
\documentclass{article}
\usepackage{axiom}
\begin{document}
\title{\$SPAD/src/algebra mathml.spad}
\author{Arthur C. Ralfs}
\maketitle
\begin{abstract}
MathMLFormat is a package to produce presentation mathematical
markup language from OutputForm.
\end{abstract}
\eject
\tableofcontents
\eject
\section{Preface}
Both this code and documentation are still under development and
I don't pretend they are anywhere close to perfect or even finished.
However the code does work and I hope it might be useful to somebody
both for it's ability to output MathML from Axiom and as an example
of how to write a new output form.
\section{Introduction to Mathematical Markup Language}
MathML exists in two forms: presentation and content.
At this time (2007-02-11) the package only has a presentation
package. A content package is in the
works however it is more difficult. Unfortunately Axiom does
not make its semantics easliy available. The \spadtype{OutputForm}
domain mediates between the individual Axiom domains and the
user visible output but \spadtype{OutputForm} does not provide full
semantic information. From my currently incomplete understanding
of Axiom it appears that remedying this would entail going back
to the individual domains and rewriting a lot of code.
However some semantics are conveyed directly by \spadtype{OutputForm} and other
things can be deduced from \spadtype{OutputForm} or form the original
user command.
\section{Displaying MathML}
The MathML string produced by ")set output mathml on" can be pasted
directly into an appropriate xhtml page and then viewed in Firefox
or some other MathML aware browser. The boiler plate code needed for
a test page, testmathml.xml, is:
\begin{verbatim}
<?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN"
"http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd" [
<!ENTITY mathml "http://www.w3.org/1998/Math/MathML">
]>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xlink="http://www.w3.org/1999/xlink" >
<head>
<title>MathML Test </title>
</head>
<body>
</body>
</html>
\end{verbatim}
Paste the MathML string into the body element and it should display
nicely in Firefox.
\section{Test Cases}
Here's a list of test cases that currently format correctly:
1. (x+y)**2
2. integrate(x**x,x)
3. integral(x**x,x)
4. (5 + sqrt 63 + sqrt 847)**(1/3)
5. set $[$1,2,3$]$
6. multiset $[$x rem 5 for x in primes(2,1000)$]$
7. series(sin(a*x),x=0)
8. matrix $[$ $[$x**i + y**j for i in 1..10$]$ for j in 1..10$]$
9. y := operator 'y
a. D(y(x,z),$[$x,x,z,x$]$)
b. D(y x,x,2)
10. x := series 'x
a. sin(1+x)
11. series(1/log(y),y=1)
12. y:UTS(FLOAT,'z,0) := exp(z)
13. a. c := continuedFraction(314159/100000)
b. c := continuedFraction(314159/100000)
The \spadtype{TexFormat} domain has the capability to format an object with
subscripts, superscripts, presubscripts and presuperscripts however
I don't know of any Axiom command that produces such an object. In
fact at present I see the case of "SUPERSUB" being used for putting
primes in the superscript position to denote ordinary differentiation.
I also only see the "SUB" case being only used to denote partial
derivatives.
\section{)set output mathml on}
Making mathml appear as output during a normal Axiom session
by invoking ")set output mathml on" proved to be a bit tedious
and seems to be undocumented. I document my experience here
in case in proves useful to somebody else trying to get a new
output format from Axiom.
In \spadtype{MathMLFormat} the functions
\spadfun{coerce(expr : OutputForm) : String} and
\spadfun{display(s : String) : Void} provide the desired mathml output.
Note that this package was constructed by close examination of
Robert Sutor's \spadtype{TexFormat} domain and much remains from that source.
To have mathml displayed as output we need to get Axiom to
call display(coerce(expr)) at the appropriate place. Here's what
I did to get that to happen. Note that my starting point here was
an attempt by Andrey Grozin to do the same. To figure things out
I searched through files for "tex" to see what was done for the
\spadtype{TexFormat} domain, and used grep to find which files had mention of
\spadtype{TexFormat}.
\subsection{File src/interp/setvars.boot.pamphlet}
Create an output mathml section by analogy to the tex section.
Remember to add the code chunk "outputmathmlCode" at the end.
setvars.boot is a bootstrap file which means that it has to be
precompiled into lisp code and then that code has to be inserted
back into setvars.boot. To do this extract the boot code by running
"notangle" on it. I did this from the "tmp" directory.
>From inside axiom run ")lisp (bbottran::boottocl "tmp/setvars.boot")
which put "setvars.clisp" into "int/interp/setvars.clisp". Then
replace the lisp in "setvars.boot.pamphlet" with that in the newly
generated "setvars.clisp".
The relevant code chunks appearing in "setvars.boot.pamphlet" are:
\begin{verbatim}
outputmathmlCode
setOutputMathml
describeSetOutputMathml
\end{verbatim}
and the relevant variables are:
\begin{verbatim}
setOutputMathml
$mathmlOutputStream
$mathmlOutputFile
$mathmlFormat
describeSetOutputMathml
\end{verbatim}
\subsection{File setvart.boot.pamphlet}
Create an output mathml section in "setvart.boot.pamphlet" again
patterned after the tex section. I changed the default file
extension from ".stex" to ".smml".
To the "section{output}" table I added the line
\begin{verbatim}
mathml created output in MathML style Off:CONSOLE
\end{verbatim}
Added the code chunk "outputmathml" to the code chunk "output"
in "section{output}".
Relevant code chunks:
\begin{verbatim}
outputmathml
\end{verbatim}
Relevant variables:
\begin{verbatim}
setOutputMathml
$mathmlFormat
$mathmlOutputFile
\end{verbatim}
Note when copying the tex stuff I changed occurrences of "tex"
to "mathml", "Tex" to "Mathml" and "TeX" to "MathML".
\subsection{File src/algebra/Makefile.pamphlet}
The file "src/algebra/tex.spad.pamphlet" contains
the domain \spadtype{TexFormat} (TEX) and the package
\spadtype{TexFormat1} (TEX1).
However the sole function of \spadtype{TexFormat1} is to \spadfun{coerce}
objects from a domain into \spadtype{OutputForm} and then apply
\spadtype{TexFormat}
to them. It is to save programmers the trouble of doing
the coercion themselves from inside spad code. It does
not appear to be used for the main purpose of delivering
Axiom output in TeX format. In order to keep the mathml
package as simple as possible, and because I didn't see much
use for this, I didn't copy the \spadtype{TexFormat1} package. So
no analog of the TEX1 entries in "Makefile.pamphlet" were
needed. One curiosity I don't understand is why TEX1
appears in layer 4 when it seems to depend on TEX which
appears in layer 14.
Initially I added "\${OUT}/MMLFORM.o" to layer 14 and
"mathml.spad.pamphlet" to completed spad files in layer 14.
When trying to compile the build failed at MMLFORM. It left
"MMLFORM.erlib" in "int/algebra" instead of "MMLFORM.NRLIB"
which confused me at first because mathml.spad compiled
under a running axiom. By examining the file "obj/tmp/trace"
I saw that a new dependency had been introduced, compared
to TexFormat, with the function eltName depending on the
domain FSAGG in layer 16. So the lines had to be moved
from layer 14 to layer 17.
Added appropriate lines to "SPADFILES" and "DOCFILES".
\subsection{File src/algebra/exposed.lsp.pamphlet}
Add the line "(|MathMLFormat| . MMLFORM)"
\subsection{File src/algebra/Lattice.pamphlet}
I don't see that this file is used anywhere but I made
the appropriate changes anyway by searching for "TEX" and
mimicing everthing for MMLFORM.
\subsection{File src/doc/axiom.bib.pamphlet}
Added mathml.spad subsection to "src/doc/axiom.bib.pamphlet".
\subsection{File interp/i-output.boot.pamphlet}
This is where the \spadfun{coerce} and \spadfun{display} functions
from MathMLFormat
actually get called. The following was added:
\begin{verbatim}
mathmlFormat expr ==
mml := '(MathMLFormat)
mmlrep := '(String)
formatFn := getFunctionFromDomain("coerce",mml,[$OutputForm])
displayFn := getFunctionFromDomain("display",mml,[mmlrep])
SPADCALL(SPADCALL(expr,formatFn),displayFn)
TERPRI $mathmlOutputStream
FORCE_-OUTPUT $mathmlOutputStream
NIL
\end{verbatim}
Note that compared to the texFormat function there are a couple
of differences. Since \spadtype{MathMLFormat} is currently a package rather
than a domain there is the "mmlrep" variable whereas in texFormat
the argument of the "display" function is an instance of the
domain. Also the \spadfun{coerce} function here only has one argument,
namely "\$OutputForm".
Also for the function "output(expr,domain)" add lines for mathml,
e.g. "if \$mathmlFormat then mathmlFormat expr".
After these changes Axiom compiled with mathml enabled under
)set output.
\section{package MMLFORM MathMLFormat}
\subsection{Public Declarations}
The declarations
\begin{verbatim}
E ==> OutputForm
I ==> Integer
L ==> List
S ==> String
US ==> UniversalSegment(Integer)
\end{verbatim}
provide abbreviations for domains used heavily in the code.
The publicly exposed functions are:
\spadfun{coerce: E -$>$ S} This function is the main one for converting
and expression in domain OutputForm into a MathML string.
\spadfun{coerceS: E -$>$ S} This function is for use from the command line.
It converts an OutputForm expression into a MathML string and does
some formatting so that the output is not one long line. If you take
the output from this function, stick it in an emacs buffer in
nxml-mode and then indent according to mode, you'll get something that's
nicer to look at than comes from coerce. Note that coerceS returns
the same value as coerce but invokes a display function as well so that
the result will be printed twice in different formats. The need for this
is that the output from coerce is automatically formatted with line breaks
by Axiom's output routine that are not in the right place.
\spadfun{coerceL: E -$>$ S} Similar to coerceS except that the displayed
result
is the MathML string in one long line. These functions can be used,
for instance, to get the MathML for the previous result by typing
coerceL(%)\$MMLFORM.
\spadfun{exprex: E -$>$ S} Converts \spadtype{OutputForm} to
\spadtype{String} with
the structure preserved with braces. This is useful in developing this
package. Actually this is not quite accurate. The function
\spadfun{precondition} is first applied to the \spadtype{OutputForm}
expression before \spadfun{exprex}. Raw \spadtype{OutputForm} and the nature
of the \spadfun{precondition} function is still obscure to me at the time of
this writing (2007-02-14), however I probably need to understand it to make
sure I'm not missing any semantics. The spad function \spadfun{precondition}
is just a wrapper for the lisp function outputTran\$Lisp, which I guess is
compiled from boot.
\spadfun{display: S -$>$ Void} This one prints the string returned by
coerce as one
long line, adding "math" tags: <math ...$>$ ... </math$>$. Thus the output
from this can be stuck directly into an appropriate html/xhtml page and will
be displayed nicely by a MathML aware browser.
\spadfun{displayF: S -$>$ Void} This function doesn't exist
yet but it would be nice
to have a humanly readable formatted output as well. The basics do exist in
the coerceS function however the formatting still needs some work to be
really good.
<<public declarations>>=
)abbrev domain MMLFORM MathMLFormat
++ Author: Arthur C. Ralfs
++ Date: January 2007
++ This package is based on the TeXFormat domain by Robert S. Sutor
++ without which I wouldn't have known where to start.
++ Basic Operations: coerce, coerceS, coerceL, exprex, display
++ Description:
++ \spadtype{MathMLFormat} provides a coercion from \spadtype{OutputForm}
++ to MathML format.
MathMLFormat(): public == private where
E ==> OutputForm
I ==> Integer
L ==> List
S ==> String
US ==> UniversalSegment(Integer)
public == SetCategory with
coerce: E -> S
++ coerceS(o) changes o in the standard output format to MathML
++ format.
coerceS: E -> S
++ coerceS(o) changes o in the standard output format to MathML
++ format and displays formatted result.
coerceL: E -> S
++ coerceS(o) changes o in the standard output format to MathML
++ format and displays result as one long string.
exprex: E -> S
++ coverts \spadtype{OutputForm} to \spadtype{String} with the
++ structure preserved with braces. Actually this is not quite
++ accurate. The function \spadfun{precondition} is first
++ applied to the
++ \spadtype{OutputForm} expression before \spadfun{exprex}.
++ The raw \spadtype{OutputForm} and
++ the nature of the \spadfun{precondition} function is
++ still obscure to me
++ at the time of this writing (2007-02-14).
display: S -> Void
++ prints the string returned by coerce, adding <math ...> tags.
@
\subsection{Private Constant Declarations}
<<private constant declarations>>=
private == add
import OutputForm
import Character
import Integer
import List OutputForm
import List String
-- local variables declarations and definitions
expr: E
prec,opPrec: I
str: S
blank : S := " \ "
maxPrec : I := 1000000
minPrec : I := 0
unaryOps : L S := ["-","^"]$(L S)
unaryPrecs : L I := [700,260]$(L I)
-- the precedence of / in the following is relatively low because
-- the bar obviates the need for parentheses.
binaryOps : L S := ["+->","|","**","/","<",">","=","OVER"]$(L S)
binaryPrecs : L I := [0,0,900, 700,400,400,400, 700]$(L I)
naryOps : L S := ["-","+","*",blank,",",";"," ","ROW","",
" \cr ","&","</mtd></mtr><mtr><mtd>"]$(L S)
naryPrecs : L I := [700,700,800, 800,110,110, 0, 0, 0,
0, 0, 0]$(L I)
naryNGOps : L S := ["ROW","&"]$(L S)
plexOps : L S :=
["SIGMA","SIGMA2","PI","PI2","INTSIGN","INDEFINTEGRAL"]$(L S)
plexPrecs : L I := [ 700, 800, 700, 800 , 700, 700]$(L I)
specialOps : L S := ["MATRIX","BRACKET","BRACE","CONCATB","VCONCAT", _
"AGGLST","CONCAT","OVERBAR","ROOT","SUB","TAG", _
"SUPERSUB","ZAG","AGGSET","SC","PAREN", _
"SEGMENT","QUOTE","theMap" ]
-- the next two lists provide translations for some strings for
-- which MML provides special macros.
specialStrings : L S :=
["cos", "cot", "csc", "log", "sec", "sin", "tan",
"cosh", "coth", "csch", "sech", "sinh", "tanh",
"acos","asin","atan","erf","...","$","infinity"]
specialStringsInMML : L S :=
["<mo>cos</mo>","<mo>cot</mo>","<mo>csc</mo>","<mo>log</mo>","<mo>sec</mo>","<mo>sin</mo>","<mo>tan</mo>",
"<mo>cosh</mo>","<mo>coth</mo>","<mo>csch</mo>","<mo>sech</mo>","<mo>sinh</mo>","<mo>tanh</mo>",
"<mo>arccos</mo>","<mo>arcsin</mo>","<mo>arctan</mo>","<mo>erf</mo>","<mo>…</mo>","<mo>$</mo>","<mo>∞</mo>"]
@
\subsection{Private Function Declarations}
These are the local functions:
addBraces:S -$>$ S
addBrackets:S -$>$ S
atomize:E -$>$ L E
displayElt:S -$>$ Void
function for recursively displaying mathml nicely formatted
eltLimit:(S,I,S) -$>$ I
demarcates end postion of mathml element with name:S starting at
position i:I in mathml string s:S and returns end of end tag as
i:I position in mathml string, i.e. find start and end of
substring: <name ...$>$...</name$>$
eltName:(I,S) -$>$ S
find name of mathml element starting at position i:I in string s:S
group:S -$>$ S
formatBinary:(S,L E, I) -$>$ S
formatFunction:(S,L E, I) -$>$ S
formatMatrix:L E -$>$ S
formatNary:(S,L E, I) -$>$ S
formatNaryNoGroup:(S,L E, I) -$>$ S
formatNullary:S -$>$ S
formatPlex:(S,L E, I) -$>$ S
formatSpecial:(S,L E, I) -$>$ S
formatUnary:(S, E, I) -$>$ S
formatMml:(E,I) -$>$ S
newWithNum:I -$>$ \$
this is a relic from tex.spad and is not used here so far. I'll
probably remove it.
parenthesize:S -$>$ S
precondition:E -$>$ E
this function is applied to the OutputForm expression before
doing anything else.
postcondition:S -$>$ S
this function is applied after all other OutputForm -$>$ MathML
transformations. In the TexFormat domain the ungroup function
first peels off the outermost set of braces however I have
replaced braces with <mrow$>$s here and sometimes the outermost set
of <mrow$>$s is necessary to get proper display in Firefox. For instance
with getting the correct size of brackets on a matrix the whole
expression needs to be enclosed in a mrow element. It also checks
for +- and removes the +.
stringify:E -$>$ S
tagEnd:(S,I,S) -$>$ I
finds closing "$>$" of start or end tag for mathML element for formatting
MathML string for human readability. No analog in TexFormat.
ungroup:S -$>$ S
<<private function declarations>>=
-- local function signatures
addBraces: S -> S
addBrackets: S -> S
atomize: E -> L E
displayElt: S -> Void
++ function for recursively displaying mathml nicely formatted
eltLimit: (S,I,S) -> I
++ demarcates end postion of mathml element with name:S starting at
++ position i:I in mathml string s:S and returns end of end tag as
++ i:I position in mathml string, i.e. find start and end of
++ substring: <name ...>...</name>
eltName: (I,S) -> S
++ find name of mathml element starting at position i:I in string s:S
group: S -> S
formatBinary: (S,L E, I) -> S
formatFunction: (S,L E, I) -> S
formatIntSign: (L E, I) -> S
formatMatrix: L E -> S
formatNary: (S,L E, I) -> S
formatNaryNoGroup: (S,L E, I) -> S
formatNullary: S -> S
formatPlex: (S,L E, I) -> S
formatSpecial: (S,L E, I) -> S
formatSub: (E, L E, I) -> S
formatSuperSub: (E, L E, I) -> S
formatSuperSub1: (E, L E, I) -> S
formatUnary: (S, E, I) -> S
formatMml: (E,I) -> S
formatZag: L E -> S
formatZag1: L E -> S
newWithNum: I -> $
parenthesize: S -> S
precondition: E -> E
postcondition: S -> S
stringify: E -> S
tagEnd: (S,I,S) -> I
++ finds closing ">" of start or end tag for mathML element
ungroup: S -> S
@
\subsection{Public Function Definitions}
Note that I use the function sayTeX$Lisp much as I would printf in a
C program. I've noticed in grepping the code that there are other "say"
functions, sayBrightly and sayMessage for instance, but I have no idea
what the difference is between them at this point. sayTeX$Lisp does the
job so for the time being I'll use that until I learn more.
The functions coerceS and coerceL should probably be changed to display
functions, {\it i.e.}\/ \spadfun{displayS} and \spadfun{display L},
returning Void. I really only need the one coerce function.
<<public function definitions>>=
-- public function definitions
coerce(expr : E): S ==
s : S := postcondition formatMml(precondition expr, minPrec)
s
coerceS(expr : E): S ==
s : S := postcondition formatMml(precondition expr, minPrec)
sayTeX$Lisp "<math xmlns=_"http://www.w3.org/1998/Math/MathML_"
mathsize=_"big_" display=_"block_">"
displayElt(s)
sayTeX$Lisp "</math>"
s
coerceL(expr : E): S ==
s : S := postcondition formatMml(precondition expr, minPrec)
sayTeX$Lisp "<math xmlns=_"http://www.w3.org/1998/Math/MathML_"
mathsize=_"big_" display=_"block_">"
sayTeX$Lisp s
sayTeX$Lisp "</math>"
s
display(mathml : S): Void ==
sayTeX$Lisp "<math xmlns=_"http://www.w3.org/1998/Math/MathML_"
mathsize=_"big_" display=_"block_">"
sayTeX$Lisp mathml
sayTeX$Lisp "</math>"
void()$Void
exprex(expr : E): S ==
-- This breaks down an expression into atoms and returns it as
-- a string. It's for developmental purposes to help understand
-- the expressions.
a : E
expr := precondition expr
-- sayTeX$Lisp "0: "stringify expr
(ATOM(expr)[EMAIL PROTECTED]) or (stringify expr = "NOTHING") =>
concat ["{",stringify expr,"}"]
le : L E := (expr pretend L E)
op := first le
sop : S := exprex op
args : L E := rest le
nargs : I := #args
-- sayTeX$Lisp concat ["1: ",stringify first le," : ",string(nargs)$S]
s : S := concat ["{",sop]
if nargs > 0 then
for a in args repeat
-- sayTeX$Lisp concat ["2: ",stringify a]
s1 : S := exprex a
s := concat [s,s1]
s := concat [s,"}"]
@
\subsection{Private Function Definitions}
\subsubsection{Display Functions}
displayElt(mathml:S):Void
eltName(pos:I,mathml:S):S
eltLimit(name:S,pos:I,mathml:S):I
tagEnd(name:S,pos:I,mathml:S):I
<<display functions>>=
displayElt(mathML:S): Void ==
-- Takes a string of syntactically complete mathML
-- and formats it for display.
-- sayTeX$Lisp "****displayElt1****"
-- sayTeX$Lisp mathML
enT:I -- marks end of tag, e.g. "<name>"
enE:I -- marks end of element, e.g. "<name> ... </name>"
end:I -- marks end of mathML string
u:US
end := #mathML
length:I := 60
-- sayTeX$Lisp "****displayElt1.1****"
name:S := eltName(1,mathML)
-- sayTeX$Lisp name
-- sayTeX$Lisp concat("****displayElt1.2****",name)
enE := eltLimit(name,2+#name,mathML)
-- sayTeX$Lisp "****displayElt2****"
if enE < length then
-- sayTeX$Lisp "****displayElt3****"
u := segment(1,enE)$US
sayTeX$Lisp mathML.u
else
-- sayTeX$Lisp "****displayElt4****"
enT := tagEnd(name,1,mathML)
u := segment(1,enT)$US
sayTeX$Lisp mathML.u
u := segment(enT+1,enE-#name-3)$US
displayElt(mathML.u)
u := segment(enE-#name-2,enE)$US
sayTeX$Lisp mathML.u
if end > enE then
-- sayTeX$Lisp "****displayElt5****"
u := segment(enE+1,end)$US
displayElt(mathML.u)
void()$Void
eltName(pos:I,mathML:S): S ==
-- Assuming pos is the position of "<" for a start tag of a mathML
-- element finds and returns the element's name.
i:I := pos+1
--sayTeX$Lisp "eltName:mathmML string: "mathML
while member?(mathML.i,lowerCase()$CharacterClass)$CharacterClass repeat
i := i+1
u:US := segment(pos+1,i-1)
name:S := mathML.u
eltLimit(name:S,pos:I,mathML:S): I ==
-- Finds the end of a mathML element like "<name ...> ... </name>"
-- where pos is the position of the space after name in the start tag
-- although it could point to the closing ">". Returns the position
-- of the ">" in the end tag.
pI:I := pos
startI:I
endI:I
startS:S := concat ["<",name]
endS:S := concat ["</",name,">"]
level:I := 1
--sayTeX$Lisp "eltLimit: element name: "name
while (level > 0) repeat
startI := position(startS,mathML,pI)$String
endI := position(endS,mathML,pI)$String
if (startI = 0) then
level := level-1
--sayTeX$Lisp "****eltLimit 1******"
pI := tagEnd(name,endI,mathML)
else
if (startI < endI) then
level := level+1
pI := tagEnd(name,startI,mathML)
else
level := level-1
pI := tagEnd(name,endI,mathML)
pI
tagEnd(name:S,pos:I,mathML:S):I ==
-- Finds the closing ">" for either a start or end tag of a mathML
-- element, so the return value is the position of ">" in mathML.
pI:I := pos
while (mathML.pI ^= char ">") repeat
pI := pI+1
u:US := segment(pos,pI)$US
--sayTeX$Lisp "tagEnd: "mathML.u
pI
@
\subsubsection{Formatting Functions}
Still need to format \\zag in formatSpecial!
In formatPlex the case op = "INTSIGN" is now passed off to
formatIntSign which is a change from the TexFormat domain.
This is done here for presentation mark up to replace the
ugly bound variable that Axiom delivers. For content mark up
this has to be done anyway.
The formatPlex function also allows for op = "INDEFINTEGRAL".
However I don't know what Axiom command gives rise to this case.
The INTSIGN case already allows for both definite and indefinite
integrals.
In the function formatSpecial various cases are handled including
SUB and SUPERSUB. These cases are now caught in formatMml and so
the code in formatSpecial doesn't get executed. The only cases
I know of using these are partial derivatives for SUB and ordinary
derivatives or SUPERSUB however in TexFormat the capability is there
to handle multiscripts, i.e. an object with subscripts, superscripts,
pre-subscripts and pre-superscripts but I am so far unaware of any
Axiom command that produces such a multiscripted object.
Another question is how to represent derivatives. At present I have
differential notation for partials and prime notation for ordinary
derivatives,
but it would be nice to allow for different derivative notations in
different circumstances, maybe some options to )set output mathml on.
Ordinary derivatives are formatted in formatSuperSub and there are
2 versions, formatSuperSub and formatSuperSub1, which at this point
have to be switched by swapping names.
<<formatting functions>>=
atomize(expr : E): L E ==
-- This breaks down an expression into a flat list of atomic expressions.
-- expr should be preconditioned.
le : L E := nil()
a : E
letmp : L E
(ATOM(expr)[EMAIL PROTECTED]) or (stringify expr = "NOTHING") =>
le := append(le,list(expr))
letmp := expr pretend L E
for a in letmp repeat
le := append(le,atomize a)
le
ungroup(str: S): S ==
len : I := #str
len < 14 => str
lrow : S := "<mrow>"
rrow : S := "</mrow>"
-- drop leading and trailing mrows
u1 : US := segment(1,6)$US
u2 : US := segment(len-6,len)$US
if (str.u1 =$S lrow) and (str.u2 =$S rrow) then
u : US := segment(7,len-7)$US
str := str.u
str
postcondition(str: S): S ==
-- str := ungroup str
len : I := #str
plusminus : S := "<mo>+</mo><mo>-</mo>"
pos : I := position(plusminus,str,1)
if pos > 0 then
ustart:US := segment(1,pos-1)$US
uend:US := segment(pos+20,len)$US
str := concat [str.ustart,"<mo>-</mo>",str.uend]
if pos < len-18 then
str := postcondition(str)
str
stringify expr == (object2String$Lisp expr)@S
group str ==
concat ["<mrow>",str,"</mrow>"]
addBraces str ==
concat ["<mo>{</mo>",str,"<mo>}</mo>"]
addBrackets str ==
concat ["<mo>[</mo>",str,"<mo>]</mo>"]
parenthesize str ==
concat ["<mo>(</mo>",str,"<mo>)</mo>"]
precondition expr ==
outputTran$Lisp expr
formatSpecial(op : S, args : L E, prec : I) : S ==
arg : E
prescript : Boolean := false
op = "theMap" => "<mtext>theMap(...)</mtext>"
op = "AGGLST" =>
formatNary(",",args,prec)
op = "AGGSET" =>
formatNary(";",args,prec)
op = "TAG" =>
group concat [formatMml(first args,prec),
"<mo>→</mo>",
formatMml(second args,prec)]
--RightArrow
op = "VCONCAT" =>
group concat("<mtable><mtr>",
concat(concat([concat("<mtd>",concat(formatMml(u,
minPrec),"</mtd>"))
for u in args]::L S),
"</mtr></mtable>"))
op = "CONCATB" =>
formatNary(" ",args,prec)
op = "CONCAT" =>
formatNary("",args,minPrec)
op = "QUOTE" =>
group concat("<mo>'</mo>",formatMml(first args, minPrec))
op = "BRACKET" =>
group addBrackets ungroup formatMml(first args, minPrec)
op = "BRACE" =>
group addBraces ungroup formatMml(first args, minPrec)
op = "PAREN" =>
group parenthesize ungroup formatMml(first args, minPrec)
op = "OVERBAR" =>
null args => ""
group concat ["<mover accent='true'><mrow>",formatMml(first
args,minPrec),"</mrow><mo stretchy='true'>¯</mo></mover>"]
--OverBar
op = "ROOT" =>
null args => ""
tmp : S := group formatMml(first args, minPrec)
null rest args => concat ["<msqrt>",tmp,"</msqrt>"]
group concat
["<mroot><mrow>",tmp,"</mrow>",formatMml(first rest args,
minPrec),"</mroot>"]
op = "SEGMENT" =>
tmp : S := concat [formatMml(first args, minPrec),"<mo>..</mo>"]
group
null rest args => tmp
concat [tmp,formatMml(first rest args, minPrec)]
-- SUB should now be diverted in formatMml although I'll leave
-- the code here for now.
op = "SUB" =>
group concat ["<msub>",formatMml(first args, minPrec),
formatSpecial("AGGLST",rest args,minPrec),"</msub>"]
-- SUPERSUB should now be diverted in formatMml although I'll leave
-- the code here for now.
op = "SUPERSUB" =>
base:S := formatMml(first args, minPrec)
args := rest args
if #args = 1 then
"<msub><mrow>"base"</mrow><mrow>"formatMml(first args,
minPrec)"</mrow></msub>"
else if #args = 2 then
-- it would be nice to substitue ′ for , in the case of
-- an ordinary derivative, it looks a lot better.
"<msubsup><mrow>"base"</mrow><mrow>"formatMml(first
args,minPrec)"</mrow><mrow>"formatMml(first rest args,
minPrec)"</mrow></msubsup>"
else if #args = 3 then
"<mmultiscripts><mrow>"base"</mrow><mrow>"formatMml(first
args,minPrec)"</mrow><mrow>"formatMml(first rest
args,minPrec)"</mrow><mprescripts/><mrow>"formatMml(first rest rest
args,minPrec)"</mrow><none/></mmultiscripts>"
else if #args = 4 then
"<mmultiscripts><mrow>"base"</mrow><mrow>"formatMml(first
args,minPrec)"</mrow><mrow>"formatMml(first rest
args,minPrec)"</mrow><mprescripts/><mrow>"formatMml(first rest rest
args,minPrec)"</mrow><mrow>"formatMml(first rest rest rest
args,minPrec)"</mrow></mmultiscripts>"
else
"<mtext>Problem with multiscript object</mtext>"
op = "SC" =>
-- need to handle indentation someday
null args => ""
tmp := formatNaryNoGroup("</mtd></mtr><mtr><mtd>", args, minPrec)
group concat ["<mtable><mtr><mtd>",tmp,"</mtd></mtr></mtable>"]
op = "MATRIX" => formatMatrix rest args
op = "ZAG" =>
--
{{+}{3}{{ZAG}{1}{7}}{{ZAG}{1}{15}}{{ZAG}{1}{1}}{{ZAG}{1}{25}}{{ZAG}{1}{1}}{{ZAG}{1}{7}}{{ZAG}{1}{4}}}
-- to format continued fraction traditionally need to intercept it at the
-- formatNary of the "+"
concat [" \zag{",formatMml(first args, minPrec),"}{",
formatMml(first rest args,minPrec),"}"]
concat ["<mtext>not done yet for: ",op,"</mtext>"]
formatSub(expr : E, args : L E, opPrec : I) : S ==
-- This one produces differential notation partial derivatives.
-- At this time this is only to handle partial derivatives.
-- If the SUB case handles anything else I'm not aware of it.
-- This an example of the 4th partial of y(x,z) w.r.t. x,x,z,x
--
{{{SUB}{y}{{CONCAT}{{CONCAT}{{CONCAT}{{CONCAT}{,}{1}}{{CONCAT}{,}{1}}}{{CONCAT}{,}{2}}}{{CONCAT}{,}{1}}}}{x}{z}}
atomE : L E := atomize(expr)
op : S := stringify first atomE
op ^= "SUB" => "<mtext>Mistake in formatSub: no SUB</mtext>"
stringify first rest rest atomE ^= "CONCAT" => "<mtext>Mistake in
formatSub: no CONCAT</mtext>"
-- expecting form for atomE like
--[{SUB}{func}{CONCAT}...{CONCAT}{,}{n}{CONCAT}{,}{n}...{CONCAT}{,}{n}],
--counting the first CONCATs before the comma gives the number of
--derivatives
ndiffs : I := 0
tmpLE : L E := rest rest atomE
while stringify first tmpLE = "CONCAT" repeat
ndiffs := ndiffs+1
tmpLE := rest tmpLE
numLS : L S := nil
i : I := 1
while i < ndiffs repeat
numLS := append(numLS,list(stringify first rest tmpLE))
tmpLE := rest rest rest tmpLE
i := i+1
numLS := append(numLS,list(stringify first rest tmpLE))
-- numLS contains the numbers of the bound variables as strings
-- for the differentiations, thus for the differentiation [x,x,z,x]
-- for y(x,z) numLS = ["1","1","2","1"]
posLS : L S := nil
i := 0
-- sayTeX$Lisp "formatSub: nargs = "string(#args)
while i < #args repeat
posLS := append(posLS,list(string(i+1)))
i := i+1
-- posLS contains the positions of the bound variables in args
-- as a list of strings, e.g. for the above example ["1","2"]
tmpS: S := stringify atomE.2
if ndiffs = 1 then
s : S := "<mfrac><mo>∂</mo><mi>"tmpS"</mi><mrow>"
else
s : S :=
"<mfrac><mrow><msup><mo>∂</mo><mn>"string(ndiffs)"</mn></msup><mi>"tmpS"</mi></mrow><mrow>"
-- need to find the order of the differentiation w.r.t. the i-th
-- variable
i := 1
j : I
k : I
tmpS: S
while i < #posLS+1 repeat
j := 0
k := 1
while k < #numLS + 1 repeat
if numLS.k = string i then j := j + 1
k := k+1
if j > 0 then
tmpS := stringify args.i
if j = 1 then
s := s"<mo>∂</mo><mi>"tmpS"</mi>"
else
s :=
s"<mo>∂</mo><msup><mi>"tmpS"</mi><mn>"string(j)"</mn></msup>"
i := i + 1
s := s"</mrow></mfrac><mo>(</mo>"
i := 1
while i < #posLS+1 repeat
tmpS := stringify args.i
s := s"<mi>"tmpS"</mi>"
if i < #posLS then s := s"<mo>,</mo>"
i := i+1
s := s"<mo>)</mo>"
formatSub1(expr : E, args : L E, opPrec : I) : S ==
-- This one produces partial derivatives notated by ",n" as
-- subscripts.
-- At this time this is only to handle partial derivatives.
-- If the SUB case handles anything else I'm not aware of it.
-- This an example of the 4th partial of y(x,z) w.r.t. x,x,z,x
-- {{{SUB}{y}{{CONCAT}{{CONCAT}{{CONCAT}{{CONCAT}{,}{1}}
-- {{CONCAT}{,}{1}}}{{CONCAT}{,}{2}}}{{CONCAT}{,}{1}}}}{x}{z}},
-- here expr is everything in the first set of braces and
-- args is {{x}{z}}
atomE : L E := atomize(expr)
op : S := stringify first atomE
op ^= "SUB" => "<mtext>Mistake in formatSub: no SUB</mtext>"
stringify first rest rest atomE ^= "CONCAT" => "<mtext>Mistake in
formatSub: no CONCAT</mtext>"
-- expecting form for atomE like
--[{SUB}{func}{CONCAT}...{CONCAT}{,}{n}{CONCAT}{,}{n}...{CONCAT}{,}{n}],
--counting the first CONCATs before the comma gives the number of
--derivatives
ndiffs : I := 0
tmpLE : L E := rest rest atomE
while stringify first tmpLE = "CONCAT" repeat
ndiffs := ndiffs+1
tmpLE := rest tmpLE
numLS : L S := nil
i : I := 1
while i < ndiffs repeat
numLS := append(numLS,list(stringify first rest tmpLE))
tmpLE := rest rest rest tmpLE
i := i+1
numLS := append(numLS,list(stringify first rest tmpLE))
-- numLS contains the numbers of the bound variables as strings
-- for the differentiations, thus for the differentiation [x,x,z,x]
-- for y(x,z) numLS = ["1","1","2","1"]
posLS : L S := nil
i := 0
-- sayTeX$Lisp "formatSub: nargs = "string(#args)
while i < #args repeat
posLS := append(posLS,list(string(i+1)))
i := i+1
-- posLS contains the positions of the bound variables in args
-- as a list of strings, e.g. for the above example ["1","2"]
funcS: S := stringify atomE.2
s : S := "<msub><mi>"funcS"</mi><mrow>"
i := 1
while i < #numLS+1 repeat
s := s"<mo>,</mo><mn>"numLS.i"</mn>"
i := i + 1
s := s"</mrow></msub><mo>(</mo>"
i := 1
while i < #posLS+1 repeat
tmpS := stringify args.i
s := s"<mi>"tmpS"</mi>"
if i < #posLS then s := s"<mo>,</mo>"
i := i+1
s := s"<mo>)</mo>"
formatSuperSub1(expr : E, args : L E, opPrec : I) : S ==
-- this produces differential notation ordinary derivatives.
-- first have to divine the semantics, add cases as needed
atomE : L E := atomize(expr)
op : S := stringify first atomE
op ^= "SUPERSUB" => "<mtext>Mistake in formatSuperSub: no
SUPERSUB</mtext>"
#args ^= 1 => "<mtext>Mistake in SuperSub: #args <> 1</mtext>"
var : E := first args
-- should be looking at something like {{SUPERSUB}{var}{ }{,,...,}} for
-- example here's the second derivative of y w.r.t. x
-- {{{SUPERSUB}{y}{ }{,,}}{x}}, expr is the first {} and args is the
-- {x}
funcS : S := stringify first rest atomE
bvarS : S := stringify first args
-- count the number of commas
commaS : S := stringify first rest rest rest atomE
commaTest : S := ","
i : I := 0
while position(commaTest,commaS,1) > 0 repeat
i := i+1
commaTest := commaTest","
s : S := "<msup><mi>"funcS"</mi><mrow>"
j : I := 0
while j < i repeat
s := s"<mo>′</mo>"
j := j + 1
s :=
s"</mrow></msup><mo>⁡</mo><mo>(</mo><mi>"bvarS"</mi><mo>)</mo>"
formatSuperSub(expr : E, args : L E, opPrec : I) : S ==
-- This one produces ordinary derivatives with prime notation.
-- first have to divine the semantics, add cases as needed
atomE : L E := atomize(expr)
op : S := stringify first atomE
op ^= "SUPERSUB" => "<mtext>Mistake in formatSuperSub: no
SUPERSUB</mtext>"
#args ^= 1 => "<mtext>Mistake in SuperSub: #args <> 1</mtext>"
var : E := first args
-- should be looking at something like {{SUPERSUB}{var}{ }{,,...,}} for
-- example here's the second derivative of y w.r.t. x
-- {{{SUPERSUB}{y}{ }{,,}}{x}}, expr is the first {} and args is the
-- {x}
funcS : S := stringify first rest atomE
bvarS : S := stringify first args
-- count the number of commas
commaS : S := stringify first rest rest rest atomE
commaTest : S := ","
ndiffs : I := 0
while position(commaTest,commaS,1) > 0 repeat
ndiffs := ndiffs+1
commaTest := commaTest","
s : S :=
"<mfrac><mrow><msup><mo>ⅆ</mo><mn>"string(ndiffs)"</mn></msup><mi>"funcS"</mi></mrow><mrow><mo>ⅆ</mo><msup><mi>"bvarS"</mi><mn>"string(ndiffs)"</mn></msup></mrow></mfrac><mo>⁡</mo><mo>(</mo><mi>"bvarS"</mi><mo>)</mo>"
formatPlex(op : S, args : L E, prec : I) : S ==
hold : S
p : I := position(op,plexOps)
p < 1 => error "unknown plex op"
op = "INTSIGN" => formatIntSign(args,minPrec)
opPrec := plexPrecs.p
n : I := #args
(n ^= 2) and (n ^= 3) => error "wrong number of arguments for plex"
s : S :=
op = "SIGMA" => "<mo>∑</mo>"
-- Sum
op = "SIGMA2" => "<mo>∑</mo>"
-- Sum
op = "PI" => "<mo>∏</mo>"
-- Product
op = "PI2" => "<mo>∏</mo>"
-- Product
-- op = "INTSIGN" => "<mo>∫</mo>"
-- Integral, int
op = "INDEFINTEGRAL" => "<mo>∫</mo>"
-- Integral, int
"????"
hold := formatMml(first args,minPrec)
args := rest args
if op ^= "INDEFINTEGRAL" then
if hold ^= "" then
s := concat ["<munderover>",s,group hold]
else
s := concat ["<munderover>",s,group " "]
if not null rest args then
hold := formatMml(first args,minPrec)
if hold ^= "" then
s := concat [s,group hold,"</munderover>"]
else
s := concat [s,group " ","</munderover>"]
args := rest args
s := concat [s,formatMml(first args,minPrec)]
else
hold := group concat [hold,formatMml(first args,minPrec)]
s := concat [s,hold]
-- if opPrec < prec then s := parenthesize s
-- getting ugly parentheses on fractions
group s
formatIntSign(args : L E, opPrec : I) : S ==
-- the original OutputForm expression looks something like this:
-- {{INTSIGN}{NOTHING or lower limit?}
-- {bvar or upper limit?}{{*}{integrand}{{CONCAT}{d}{axiom var}}}}
-- the args list passed here consists of the rest of this list, i.e.
-- starting at the NOTHING or ...
(stringify first args) = "NOTHING" =>
-- the bound variable is the second one in the argument list
bvar : E := first rest args
bvarS : S := stringify bvar
tmpS : S
i : I := 0
u1 : US
u2 : US
-- this next one atomizes the integrand plus differential
atomE : L E := atomize(first rest rest args)
-- pick out the bound variable used by axiom
varRS : S := stringify last(atomE)
tmpLE : L E := ((first rest rest args) pretend L E)
integrand : S := formatMml(first rest tmpLE,minPrec)
-- replace the bound variable, i.e. axiom uses someting of the form
-- %A for the bound variable and puts the original variable used
-- in the input command as a superscript on the integral sign.
-- I'm assuming that the axiom variable is 2 characters.
while (i := position(varRS,integrand,i+1)) > 0 repeat
u1 := segment(1,i-1)$US
u2 := segment(i+2,#integrand)$US
integrand := concat [integrand.u1,bvarS,integrand.u2]
concat ["<mrow><mo>∫</mo>" integrand "<mo>ⅆ</mo><mi>"
bvarS "</mi></mrow>"]
lowlim : S := stringify first args
highlim : S := stringify first rest args
bvar : E := last atomize(first rest rest args)
bvarS : S := stringify bvar
tmpLE : L E := ((first rest rest args) pretend L E)
integrand : S := formatMml(first rest tmpLE,minPrec)
concat ["<mrow><munderover><mo>∫</mo><mi>" lowlim "</mi><mi>"
highlim "</mi></munderover>" integrand "<mo>ⅆ</mo><mi>" bvarS
"</mi></mrow>"]
formatMatrix(args : L E) : S ==
-- format for args is [[ROW ...],[ROW ...],[ROW ...]]
-- generate string for formatting columns (centered)
group addBrackets concat
["<mtable><mtr><mtd>",formatNaryNoGroup("</mtd></mtr><mtr><mtd>",args,minPrec),
"</mtd></mtr></mtable>"]
formatFunction(op : S, args : L E, prec : I) : S ==
group concat ["<mo>",op,"</mo>",parenthesize formatNary(",",args,minPrec)]
formatNullary(op : S) ==
op = "NOTHING" => ""
group concat ["<mo>",op,"</mo><mo>(</mo><mo>)</mo>"]
formatUnary(op : S, arg : E, prec : I) ==
p : I := position(op,unaryOps)
p < 1 => error "unknown unary op"
opPrec := unaryPrecs.p
s : S := concat ["<mo>",op,"</mo>",formatMml(arg,opPrec)]
opPrec < prec => group parenthesize s
op = "-" => s
group s
formatBinary(op : S, args : L E, prec : I) : S ==
p : I := position(op,binaryOps)
p < 1 => error "unknown binary op"
opPrec := binaryPrecs.p
s1 : S := formatMml(first args, opPrec)
s2 : S := formatMml(first rest args, opPrec)
op :=
op = "|" => s := concat
["<mrow>",s1,"</mrow><mo>",op,"</mo><mrow>",s2,"</mrow>"]
op = "**" => s := concat
["<msup><mrow>",s1,"</mrow><mrow>",s2,"</mrow></msup>"]
op = "/" => s := concat
["<mfrac><mrow>",s1,"</mrow><mrow>",s2,"</mrow></mfrac>"]
op = "OVER" => s := concat
["<mfrac><mrow>",s1,"</mrow><mrow>",s2,"</mrow></mfrac>"]
op = "+->" => s := concat
["<mrow>",s1,"</mrow><mo>",op,"</mo><mrow>",s2,"</mrow>"]
s := concat ["<mrow>",s1,"</mrow><mo>",op,"</mo><mrow>",s2,"</mrow>"]
group
op = "OVER" => s
-- opPrec < prec => parenthesize s
-- ugly parentheses?
s
formatNary(op : S, args : L E, prec : I) : S ==
group formatNaryNoGroup(op, args, prec)
formatNaryNoGroup(op : S, args : L E, prec : I) : S ==
null args => ""
p : I := position(op,naryOps)
p < 1 => error "unknown nary op"
-- need to test for "ZAG" case and divert it here, here's an
-- example including "op", the args list would be the rest of this
-- {{+}{3}{{ZAG}{1}{7}}{{ZAG}{1}{15}}{{ZAG}{1}{1}}{{ZAG}{1}{25}}
-- {{ZAG}{1}{1}}{{ZAG}{1}{7}}{{ZAG}{1}{4}}}
-- The first arg, the "3" in this case, could be a "ZAG" or something
-- else, but the second arg looks like it has to be "ZAG", so maybe
-- test for #args > 1 and args.2 is "ZAG".
-- This test should work so long as axiom doesn't try to evaluate
-- the second half of the "and" when the first half is false.
(#args > 1) and (position("ZAG",stringify first rest args,1) > 0) =>
tmpS : S := stringify first args
position("ZAG",tmpS,1) > 0 => formatZag(args)
-- position("ZAG",tmpS,1) > 0 => formatZag1(args)
concat [formatMml(first args,minPrec) "<mo>+</mo>" formatZag(rest
args)]
op :=
op = "," => "<mo>,</mo>" --originally , \:
op = ";" => "<mo>;</mo>" --originally ; \: should figure these out
op = "*" => "<mo>⁢</mo>"
-- InvisibleTimes
op = " " => "<mspace width='0.5em'/>"
op = "ROW" => "</mtd><mtd>"
op = "+" => "<mo>+</mo>"
op = "-" => "<mo>-</mo>"
op
l : L S := nil
opPrec := naryPrecs.p
for a in args repeat
l := concat(op,concat(formatMml(a,opPrec),l)$L(S))$L(S)
s : S := concat reverse rest l
opPrec < prec => parenthesize s
s
formatZag(args : L E) : S ==
-- {{ZAG}{1}{7}}
tmpZag : L E := first args pretend L E
#args > 1 => "<mfrac>"formatMml(first rest
tmpZag,minPrec)"<mrow><mn>"formatMml(first rest rest
tmpZag,minPrec)"</mn><mo>+</mo>"formatZag(rest args)"</mrow></mfrac>"
"<mfrac>"formatMml(first rest tmpZag,minPrec)formatMml(first rest rest
tmpZag,minPrec)"</mfrac>"
formatZag1(args : L E) : S ==
-- make alternative ZAG format without diminishing fonts, maybe
-- use a table
-- {{ZAG}{1}{7}}
tmpZag : L E := first args pretend L E
#args > 1 => "<mfrac>"formatMml(first rest
tmpZag,minPrec)"<mrow><mn>"formatMml(first rest rest
tmpZag,minPrec)"</mn><mo>+</mo>"formatZag(rest args)"</mrow></mfrac>"
"<mfrac>"formatMml(first rest tmpZag,minPrec)formatMml(first rest rest
tmpZag,minPrec)"</mfrac>"
formatMml(expr : E,prec : I) ==
i,len : Integer
intSplitLen : Integer := 20
ATOM(expr)[EMAIL PROTECTED] =>
str := stringify expr
len := #str
-- this bit seems to deal with integers
FIXP$Lisp expr =>
i := expr pretend Integer
if (i < 0) or (i > 9)
then
group
nstr : String := ""
-- insert some blanks into the string, if too long
while ((len := #str) > intSplitLen) repeat
nstr := concat [nstr," ",
elt(str,segment(1,intSplitLen)$US)]
str := elt(str,segment(intSplitLen+1)$US)
empty? nstr => concat ["<mn>",str,"</mn>"]
nstr :=
empty? str => nstr
concat [nstr," ",str]
concat ["<mn>",elt(nstr,segment(2)$US),"</mn>"]
else str := concat ["<mn>",str,"</mn>"]
str = "%pi" => "<mi>π</mi>"
-- pi
str = "%e" => "<mi>ⅇ</mi>"
-- ExponentialE
str = "%i" => "<mi>ⅈ</mi>"
-- ImaginaryI
-- what sort of atom starts with %%? need an example
len > 1 and str.1 = char "%" and str.2 = char "%" =>
u : US := segment(3,len)$US
concat(concat("<mi>",str.u),"</mi>")
len > 0 and str.1 = char "%" => concat(concat("<mi>",str),"</mi>")
len > 1 and digit? str.1 => concat ["<mn>",str,"</mn>"] -- should
handle floats
-- presumably this is a literal string
len > 0 and str.1 = char "_"" =>
concat(concat("<mtext>",str),"</mtext>")
len = 1 and str.1 = char " " => " "
(i := position(str,specialStrings)) > 0 =>
specialStringsInMML.i
(i := position(char " ",str)) > 0 =>
-- We want to preserve spacing, so use a roman font.
-- What's this for? Leave the \rm in for now so I can see
-- where it arises. Removed 2007-02-14
concat(concat("<mtext>",str),"</mtext>")
-- if we get to here does that mean it's a variable?
concat ["<mi>",str,"</mi>"]
l : L E := (expr pretend L E)
null l => blank
op : S := stringify first l
args : L E := rest l
nargs : I := #args
-- special cases
member?(op, specialOps) => formatSpecial(op,args,prec)
member?(op, plexOps) => formatPlex(op,args,prec)
-- nullary case
0 = nargs => formatNullary op
-- unary case
(1 = nargs) and member?(op, unaryOps) =>
formatUnary(op, first args, prec)
-- binary case
(2 = nargs) and member?(op, binaryOps) =>
formatBinary(op, args, prec)
-- nary case
member?(op,naryNGOps) => formatNaryNoGroup(op,args, prec)
member?(op,naryOps) => formatNary(op,args, prec)
-- need to test here in case first l is SUPERSUB case and then
-- pass first l and args to formatSuperSub.
position("SUPERSUB",op,1) > 0 =>
formatSuperSub(first l,args,minPrec)
-- now test for SUB
position("SUB",op,1) > 0 =>
formatSub(first l,args,minPrec)
op := formatMml(first l,minPrec)
formatFunction(op,args,prec)
@
\section{Mathematical Markup Language Form}
<<package MMLFORM MathMLForm>>=
<<public declarations>>
<<private constant declarations>>
<<private function declarations>>
<<public function definitions>>
<<display functions>>
<<formatting functions>>
@
\section{License}
<<license>>=
--Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
--All rights reserved.
--
--Redistribution and use in source and binary forms, with or without
--modification, are permitted provided that the following conditions are
--met:
--
-- - Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
--
-- - Redistributions in binary form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in
-- the documentation and/or other materials provided with the
-- distribution.
--
-- - Neither the name of The Numerical ALgorithms Group Ltd. nor the
-- names of its contributors may be used to endorse or promote products
-- derived from this software without specific prior written permission.
--
--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
--IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
--TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
--PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
--OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
--EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
--PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
--PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
--LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
--NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@
<<*>>=
<<license>>
<<package MMLFORM MathMLForm>>
@
\eject
\begin{thebibliography}{99}
\bibitem{1} nothing
\end{thebibliography}
\end{document}
--
forwarded from http://wiki.axiom-developer.org/[EMAIL PROTECTED]