aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ChangeLog13
-rw-r--r--src/algebra/Makefile.in8
-rw-r--r--src/algebra/Makefile.pamphlet9
-rw-r--r--src/algebra/exposed.lsp.pamphlet1
-rw-r--r--src/algebra/mathml.spad.pamphlet1463
-rw-r--r--src/interp/i-output.boot12
-rw-r--r--src/interp/setvars.boot109
-rw-r--r--src/interp/setvart.boot51
8 files changed, 1659 insertions, 7 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 543c3177..4b3a5d14 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,16 @@
+2008-03-16 Alfredo Portes <doyenatccny@gmail.com>
+ Arthur Ralfs <acralfs@shaw.ca>
+
+ * algebra/mathml.spad.pamphlet: Add Arthur Ralfs's MathML package.
+ * algebra/Makefile.in: Add MathML to the build process.
+ * algebra/Makefile.pamphlet: Likewise.
+ * algebra/exposed.lsp.pamphlet: Likewise.
+ * interp/setvart.boot: Create an output MathML section in
+ patterned after the tex section.
+ * interp/setvars.boot: Likewise.
+ * interp/i-output.boot: Add the coerce and display functions
+ from MathMLFormat actually gets called.
+
2008-03-16 Gabriel Dos Reis <gdr@cs.tamu.edu>
* boot/translator.boot: Switch to new native type translation.
diff --git a/src/algebra/Makefile.in b/src/algebra/Makefile.in
index dc5e3d24..f0eb327f 100644
--- a/src/algebra/Makefile.in
+++ b/src/algebra/Makefile.in
@@ -86,7 +86,8 @@ SPADFILES= \
${OUTSRC}/list.spad ${OUTSRC}/lmdict.spad ${OUTSRC}/lodof.spad \
${OUTSRC}/lodop.spad ${OUTSRC}/lodo.spad \
${OUTSRC}/manip.spad ${OUTSRC}/mappkg.spad ${OUTSRC}/matcat.spad \
- ${OUTSRC}/matfuns.spad ${OUTSRC}/matrix.spad ${OUTSRC}/matstor.spad \
+ ${OUTSRC}/matfuns.spad ${OUTSRC}/mathml.spad \
+ ${OUTSRC}/matrix.spad ${OUTSRC}/matstor.spad \
${OUTSRC}/mesh.spad ${OUTSRC}/mfinfact.spad ${OUTSRC}/misc.spad \
${OUTSRC}/mkfunc.spad ${OUTSRC}/mkrecord.spad \
${OUTSRC}/mlift.spad ${OUTSRC}/moddfact.spad ${OUTSRC}/modgcd.spad \
@@ -242,7 +243,8 @@ DOCFILES= \
${DOC}/list.spad.dvi ${DOC}/lmdict.spad.dvi ${DOC}/lodof.spad.dvi \
${DOC}/lodop.spad.dvi ${DOC}/lodo.spad.dvi \
${DOC}/manip.spad.dvi ${DOC}/mappkg.spad.dvi ${DOC}/matcat.spad.dvi \
- ${DOC}/matfuns.spad.dvi ${DOC}/matrix.spad.dvi ${DOC}/matstor.spad.dvi \
+ ${DOC}/matfuns.spad.dvi ${DOC}/mathml.spad.dvi \
+ ${DOC}/matrix.spad.dvi ${DOC}/matstor.spad.dvi \
${DOC}/mesh.spad.dvi ${DOC}/mfinfact.spad.dvi ${DOC}/misc.spad.dvi \
${DOC}/mkfunc.spad.dvi ${DOC}/mkrecord.spad.dvi ${DOC}/mlift.spad.jhd.dvi \
${DOC}/mlift.spad.dvi ${DOC}/moddfact.spad.dvi ${DOC}/modgcd.spad.dvi \
@@ -684,7 +686,7 @@ axiom_algebra_layer_16_objects = \
$(addsuffix .$(FASLEXT),$(axiom_algebra_layer_16)))
axiom_algebra_layer_17 = \
CCLASS FSAGG2 GALFACT IALGFACT \
- IBACHIN NORMMA ODERED OMSAGG \
+ IBACHIN MMLFORM NORMMA ODERED OMSAGG \
PERM PERMGRP PRIMES PWFFINTB \
RDIST SAE SAEFACT SAERFFC \
SGCF TBAGG TBAGG- VIEW3D
diff --git a/src/algebra/Makefile.pamphlet b/src/algebra/Makefile.pamphlet
index 835df3b3..451c934b 100644
--- a/src/algebra/Makefile.pamphlet
+++ b/src/algebra/Makefile.pamphlet
@@ -851,6 +851,7 @@ aggcat.spad.pamphlet (AGG HOAGG CLAGG BGAGG SKAGG QUAGG DQAGG PRQAGG DIOPS
aggcat2.spad.pamphlet (FLAGG2 FSAGG2)
galfact.spad.pamphlet (GALFACT)
intfact.spad.pamphlet (PRIMES IROOT INTFACT)
+mathml.spad.pamphlet (MMLFORM)
padiclib.spad.pamphlet (IBPTOOLS IBACHIN PWFFINTB)
perm.spad.pamphlet (PERMCAT PERM)
permgrps.spad.pamphlet (PERMGRP PGE)
@@ -863,7 +864,7 @@ view3D.spad.pamphlet (VIEW3D)
<<layer17>>=
axiom_algebra_layer_17 = \
CCLASS FSAGG2 GALFACT IALGFACT \
- IBACHIN NORMMA ODERED OMSAGG \
+ IBACHIN MMLFORM NORMMA ODERED OMSAGG \
PERM PERMGRP PRIMES PWFFINTB \
RDIST SAE SAEFACT SAERFFC \
SGCF TBAGG TBAGG- VIEW3D
@@ -1418,7 +1419,8 @@ SPADFILES= \
${OUTSRC}/list.spad ${OUTSRC}/lmdict.spad ${OUTSRC}/lodof.spad \
${OUTSRC}/lodop.spad ${OUTSRC}/lodo.spad \
${OUTSRC}/manip.spad ${OUTSRC}/mappkg.spad ${OUTSRC}/matcat.spad \
- ${OUTSRC}/matfuns.spad ${OUTSRC}/matrix.spad ${OUTSRC}/matstor.spad \
+ ${OUTSRC}/matfuns.spad ${OUTSRC}/mathml.spad \
+ ${OUTSRC}/matrix.spad ${OUTSRC}/matstor.spad \
${OUTSRC}/mesh.spad ${OUTSRC}/mfinfact.spad ${OUTSRC}/misc.spad \
${OUTSRC}/mkfunc.spad ${OUTSRC}/mkrecord.spad \
${OUTSRC}/mlift.spad ${OUTSRC}/moddfact.spad ${OUTSRC}/modgcd.spad \
@@ -1582,7 +1584,8 @@ DOCFILES= \
${DOC}/list.spad.dvi ${DOC}/lmdict.spad.dvi ${DOC}/lodof.spad.dvi \
${DOC}/lodop.spad.dvi ${DOC}/lodo.spad.dvi \
${DOC}/manip.spad.dvi ${DOC}/mappkg.spad.dvi ${DOC}/matcat.spad.dvi \
- ${DOC}/matfuns.spad.dvi ${DOC}/matrix.spad.dvi ${DOC}/matstor.spad.dvi \
+ ${DOC}/matfuns.spad.dvi ${DOC}/mathml.spad.dvi \
+ ${DOC}/matrix.spad.dvi ${DOC}/matstor.spad.dvi \
${DOC}/mesh.spad.dvi ${DOC}/mfinfact.spad.dvi ${DOC}/misc.spad.dvi \
${DOC}/mkfunc.spad.dvi ${DOC}/mkrecord.spad.dvi ${DOC}/mlift.spad.jhd.dvi \
${DOC}/mlift.spad.dvi ${DOC}/moddfact.spad.dvi ${DOC}/modgcd.spad.dvi \
diff --git a/src/algebra/exposed.lsp.pamphlet b/src/algebra/exposed.lsp.pamphlet
index 3c12b66c..2492f004 100644
--- a/src/algebra/exposed.lsp.pamphlet
+++ b/src/algebra/exposed.lsp.pamphlet
@@ -213,6 +213,7 @@
(|MappingPackage1| . MAPPKG1)
(|MappingPackage2| . MAPPKG2)
(|MappingPackage3| . MAPPKG3)
+ (|MathMLFormat| . MMLFORM)
(|Matrix| . MATRIX)
(|MatrixCategoryFunctions2| . MATCAT2)
(|MatrixCommonDenominator| . MCDEN)
diff --git a/src/algebra/mathml.spad.pamphlet b/src/algebra/mathml.spad.pamphlet
new file mode 100644
index 00000000..747dbfca
--- /dev/null
+++ b/src/algebra/mathml.spad.pamphlet
@@ -0,0 +1,1463 @@
+\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 easily 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 from 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(14159/100000)
+ c. c := continuedFraction(3,repeating [1], repeating [3,6])
+
+14. F := operator F
+ x := operator x
+ y := operator y
+ a := F(x z,y z,z**2) + x y(z+1)
+ D(a,z)
+
+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 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 it 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 everything 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
+an 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 what 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 variable 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","Gamma"]
+ 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>&#x2026;</mo>","<mo>$</mo>","<mo>&#x221E;</mo>","<mo>&#x0413;</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)$Lisp@Boolean) 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)$Lisp@Boolean) 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 == (mathObject2String$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>&#x02192;</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'>&#x000AF;</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 &#x2032; 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.
+ -- It doesn't work in all cases and may not be workable, use
+ -- formatSub1 below for now.
+ -- 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>&#x02202;</mo><mi>"tmpS"</mi><mrow>"
+ else
+ s : S := "<mfrac><mrow><msup><mo>&#x02202;</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>&#x02202;</mo><mi>"tmpS"</mi>"
+ else
+ s := s"<mo>&#x02202;</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
+ tmpS := formatMml(first args,minPrec)
+ args := rest args
+ s := s"<mi>"tmpS"</mi>"
+ if i < #posLS then s := s"<mo>,</mo>"
+ i := i+1
+ s := s"<mo>)</mo>"
+
+ formatSuperSub(expr : E, args : L E, opPrec : I) : S ==
+ -- this produces prime 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 SUPERSUB1</mtext>"
+ #args ^= 1 => "<mtext>Mistake in SuperSub1: #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>&#x02032;</mo>"
+ j := j + 1
+ s := s"</mrow></msup><mo>&#x02061;</mo><mo>(</mo>"formatMml(first args,minPrec)"<mo>)</mo>"
+
+ formatSuperSub1(expr : E, args : L E, opPrec : I) : S ==
+ -- This one produces ordinary derivatives with differential notation,
+ -- it needs a little more work yet.
+ -- 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>&#x02146;</mo><mn>"string(ndiffs)"</mn></msup><mi>"funcS"</mi></mrow><mrow><mo>&#x02146;</mo><msup><mi>"formatMml(first args,minPrec)"</mi><mn>"string(ndiffs)"</mn></msup></mrow></mfrac><mo>&#x02061;</mo><mo>(</mo><mi>"formatMml(first args,minPrec)"</mi><mo>)</mo>"
+
+ formatPlex(op : S, args : L E, prec : I) : S ==
+ checkarg:Boolean := false
+ 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" =>
+ checkarg := true
+ "<mo>&#x02211;</mo>"
+ -- Sum
+ op = "SIGMA2" =>
+ checkarg := true
+ "<mo>&#x02211;</mo>"
+ -- Sum
+ op = "PI" =>
+ checkarg := true
+ "<mo>&#x0220F;</mo>"
+ -- Product
+ op = "PI2" =>
+ checkarg := true
+ "<mo>&#x0220F;</mo>"
+ -- Product
+-- op = "INTSIGN" => "<mo>&#x0222B;</mo>"
+ -- Integral, int
+ op = "INDEFINTEGRAL" => "<mo>&#x0222B;</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
+ -- if checkarg true need to test op arg for "+" at least
+ -- and wrap parentheses if so
+ if checkarg then
+ la : L E := (first args pretend L E)
+ opa : S := stringify first la
+ if opa = "+" then
+ s := concat [s,"<mo>(</mo>",formatMml(first args,minPrec),"<mo>)</mo>"]
+ else s := concat [s,formatMml(first args,minPrec)]
+ else 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>&#x0222B;</mo>" integrand "<mo>&#x02146;</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>&#x0222B;</mo><mi>" lowlim "</mi><mi>" highlim "</mi></munderover>" integrand "<mo>&#x02146;</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
+ -- if base op is product or sum need to add parentheses
+ if ATOM(first args)$Lisp@Boolean then
+ opa:S := stringify first args
+ else
+ la : L E := (first args pretend L E)
+ opa : S := stringify first la
+ if (opa = "SIGMA" or opa = "SIGMA2" or opa = "PI" or opa = "PI2") and op = "**" then
+ s1 : S := concat ["<mo>(</mo>",formatMml(first args, opPrec),"<mo>)</mo>"]
+ else
+ 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 ==
+ checkargs:Boolean := false
+ null args => ""
+ p : I := position(op,naryOps)
+ p < 1 => error "unknown nary op"
+ -- need to test for "ZAG" case and divert it here
+ -- ex 1. continuedFraction(314159/100000)
+ -- {{+}{3}{{ZAG}{1}{7}}{{ZAG}{1}{15}}{{ZAG}{1}{1}}{{ZAG}{1}{25}}
+ -- {{ZAG}{1}{1}}{{ZAG}{1}{7}}{{ZAG}{1}{4}}}
+ -- this is the preconditioned output form
+ -- including "op", the args list would be the rest of this
+ -- i.e op = '+' and args = {{3}{{ZAG}{1}{7}}{{ZAG}{1}{15}}
+ -- {{ZAG}{1}{1}}{{ZAG}{1}{25}}{{ZAG}{1}{1}}{{ZAG}{1}{7}}{{ZAG}{1}{4}}}
+ -- ex 2. continuedFraction(14159/100000)
+ -- this one doesn't have the leading integer
+ -- {{+}{{ZAG}{1}{7}}{{ZAG}{1}{15}}{{ZAG}{1}{1}}{{ZAG}{1}{25}}
+ -- {{ZAG}{1}{1}}{{ZAG}{1}{7}}{{ZAG}{1}{4}}}
+ --
+ -- ex 3. continuedFraction(3,repeating [1], repeating [3,6])
+ -- {{+}{3}{{ZAG}{1}{3}}{{ZAG}{1}{6}}{{ZAG}{1}{3}}{{ZAG}{1}{6}}
+ -- {{ZAG}{1}{3}}{{ZAG}{1}{6}}{{ZAG}{1}{3}}{{ZAG}{1}{6}}
+ -- {{ZAG}{1}{3}}{{ZAG}{1}{6}}{...}}
+ -- In each of these examples the args list consists of the terms
+ -- following the '+' op
+ -- so the first arg 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 contains "ZAG".
+ -- Note that since the resulting MathML <mfrac>s are nested we need
+ -- to handle the whole continued fraction at once, i.e. we can't
+ -- just look for, e.g., {{ZAG}{1}{6}}
+ (#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)]
+ -- At least for the ops "*","+","-" we need to test to see if a sigma or pi
+ -- is one of their arguments because we might need parentheses as indicated
+ -- by the problem with summation(operator(f)(i),i=1..n)+1 versus
+ -- summation(operator(f)(i)+1,i=1..n) having identical displays as of
+ -- 2007-12-21
+ op :=
+ op = "," => "<mo>,</mo>" --originally , \:
+ op = ";" => "<mo>;</mo>" --originally ; \: should figure these out
+ op = "*" =>
+ checkargs := true
+ "<mo>&#x02062;</mo>"
+ -- InvisibleTimes
+ op = " " => "<mspace width='0.5em'/>"
+ op = "ROW" => "</mtd><mtd>"
+ op = "+" =>
+ checkargs := true
+ "<mo>+</mo>"
+ op = "-" =>
+ checkargs := true
+ "<mo>-</mo>"
+ op
+ l : L S := nil
+ opPrec := naryPrecs.p
+ -- if checkargs is true check each arg except last one to see if it's
+ -- a sigma or pi and if so add parentheses. Other op's may have to be
+ -- checked for in future
+ count:I := 1
+ for a in args repeat
+ if checkargs then
+ if count < #args then
+ -- check here for sum or product
+ if ATOM(a)$Lisp@Boolean then
+ opa:S := stringify a
+ else
+ la : L E := (a pretend L E)
+ opa : S := stringify first la
+ if opa = "SIGMA" or opa = "SIGMA2" or opa = "PI" or opa = "PI2" then
+ l := concat(op,concat(concat ["<mo>(</mo>",formatMml(a,opPrec),"<mo>)</mo>"],l)$L(S))$L(S)
+ else l := concat(op,concat(formatMml(a,opPrec),l)$L(S))$L(S)
+ else l := concat(op,concat(formatMml(a,opPrec),l)$L(S))$L(S)
+ else l := concat(op,concat(formatMml(a,opPrec),l)$L(S))$L(S)
+ count := count + 1
+ s : S := concat reverse rest l
+ opPrec < prec => parenthesize s
+ s
+
+ formatZag(args : L E) : S ==
+ -- args will be a list of things like this {{ZAG}{1}{7}}, the ZAG
+ -- must be there, the '1' and '7' could conceivably be more complex
+ -- expressions
+ tmpZag : L E := first args pretend L E
+ -- may want to test that tmpZag contains 'ZAG'
+ #args > 1 => "<mfrac>"formatMml(first rest tmpZag,minPrec)"<mrow><mn>"formatMml(first rest rest tmpZag,minPrec)"</mn><mo>+</mo>"formatZag(rest args)"</mrow></mfrac>"
+ (first args = "...":: E)@Boolean => "<mo>&#x2026;</mo>"
+ op:S := stringify first args
+ position("ZAG",op,1) > 0 =>
+ "<mfrac>"formatMml(first rest tmpZag,minPrec)formatMml(first rest rest tmpZag,minPrec)"</mfrac>"
+ error "formatZag: Last argument in ZAG construct has unknown operator: "op
+
+ 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>"
+ (first args = "...":: E)@Boolean => "<mo>&#x2026;</mo>"
+ error "formatZag1: Unexpected kind of ZAG"
+
+ formatMml(expr : E,prec : I) ==
+ i,len : Integer
+ intSplitLen : Integer := 20
+ ATOM(expr)$Lisp@Boolean =>
+ 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>&#x003C0;</mi>"
+ -- pi
+ str = "%e" => "<mi>&#x02147;</mi>"
+ -- ExponentialE
+ str = "%i" => "<mi>&#x02148;</mi>"
+ -- ImaginaryI
+ 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
+ -- 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 =>
+ formatSub1(first l,args,minPrec)
+
+ -- 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)
+
+ 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}
diff --git a/src/interp/i-output.boot b/src/interp/i-output.boot
index f08cf82f..2f45ce54 100644
--- a/src/interp/i-output.boot
+++ b/src/interp/i-output.boot
@@ -1377,11 +1377,22 @@ texFormat1 expr ==
FORCE_-OUTPUT $texOutputStream
NIL
+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
+
output(expr,domain) ==
if isWrapped expr then expr := unwrap expr
isMapExpr expr =>
if $formulaFormat then formulaFormat expr
if $texFormat then texFormat expr
+ if $mathmlFormat then mathmlFormat expr
if $algebraFormat then mathprintWithNumber expr
categoryForm? domain or domain in '((Mode) (Domain) (Type)) =>
if $algebraFormat then
@@ -1398,6 +1409,7 @@ output(expr,domain) ==
if $algebraFormat then
mathprintWithNumber x
if $texFormat then texFormat x
+ if $mathmlFormat then mathmlFormat x
(FUNCTIONP(opOf domain)) and
(printfun := compiledLookup("<<",'(TextWriter TextWriter $), evalDomain domain))
and (textwrit := compiledLookup("print", '($), TextWriter())) =>
diff --git a/src/interp/setvars.boot b/src/interp/setvars.boot
index c32d85d9..f0836086 100644
--- a/src/interp/setvars.boot
+++ b/src/interp/setvars.boot
@@ -1238,6 +1238,115 @@ describeSetOutputFortran() ==
'"The current setting is: ",'%b,setOutputFortran "%display%",'%d)
+-- See the section mathml in setvart.boot.pamphlet
+--
+-- ----------------------- The mathml Option ------------------------
+--
+-- Description: create output in MathML style
+--
+-- )set output mathml is used to tell AXIOM to turn MathML-style output
+-- printing on and off, and where to place the output. By default,
+-- the destination for the output is the screen but printing is
+-- turned off.
+--
+-- Syntax: )set output mathml <arg>
+-- where arg can be one of
+-- on turn MathML printing on
+-- off turn MathML printing off (default state)
+-- console send MathML output to screen (default state)
+-- fp<.fe> send MathML output to file with file prefix fp
+-- and file extension .fe. If not given,
+-- .fe defaults to .stex.
+--
+-- If you wish to send the output to a file, you must issue
+-- this command twice: once with on and once with the file name.
+-- For example, to send MathML output to the file polymer.stex,
+-- issue the two commands
+--
+-- )set output mathml on
+-- )set output mathml polymer
+--
+-- The output is placed in the directory from which you invoked
+-- OpenAxiom or the one you set with the )cd system command.
+-- The current setting is: Off:CONSOLE
+
+setOutputMathml arg ==
+
+ arg = "%initialize%" =>
+ $mathmlOutputStream :=
+ DEFIOSTREAM('((MODE . OUTPUT) (DEVICE . CONSOLE)),255,0)
+ $mathmlOutputFile := '"CONSOLE"
+ $mathmlFormat := NIL
+
+ arg = "%display%" =>
+ if $mathmlFormat then label := '"On:" else label := '"Off:"
+ STRCONC(label,$mathmlOutputFile)
+
+ (null arg) or (arg = "%describe%") or (first arg = '_?) =>
+ describeSetOutputMathml()
+
+ -- try to figure out what the argument is
+
+ if arg is [fn] and
+ fn in '(Y N YE YES NO O ON OF OFF CONSOLE y n ye yes no o on of off console)
+ then 'ok
+ else arg := [fn,'smml]
+
+ arg is [fn] =>
+ UPCASE(fn) in '(Y N YE O OF) =>
+ sayKeyedMsg("S2IV0002",'(MathML mathml))
+ UPCASE(fn) in '(NO OFF) => $mathmlFormat := NIL
+ UPCASE(fn) in '(YES ON) => $mathmlFormat := true
+ UPCASE(fn) = 'CONSOLE =>
+ SHUT $mathmlOutputStream
+ $mathmlOutputStream :=
+ DEFIOSTREAM('((MODE . OUTPUT) (DEVICE . CONSOLE)),255,0)
+ $mathmlOutputFile := '"CONSOLE"
+
+ (arg is [fn,ft]) or (arg is [fn,ft,fm]) => -- aha, a file
+ if (ptype := pathnameType fn) then
+ fn := STRCONC(pathnameDirectory fn,pathnameName fn)
+ ft := ptype
+ if null fm then fm := 'A
+ filename := $FILEP(fn,ft,fm)
+ null filename =>
+ sayKeyedMsg("S2IV0003",[fn,ft,fm])
+ (testStream := MAKE_-OUTSTREAM(filename,255,0)) =>
+ SHUT $mathmlOutputStream
+ $mathmlOutputStream := testStream
+ $mathmlOutputFile := object2String filename
+ sayKeyedMsg("S2IV0004",['"MathML",$mathmlOutputFile])
+ sayKeyedMsg("S2IV0003",[fn,ft,fm])
+
+ sayKeyedMsg("S2IV0005",NIL)
+ describeSetOutputMathml()
+
+describeSetOutputMathml() ==
+ sayBrightly LIST ('%b,'")set output mathml",'%d,_
+ '"is used to tell AXIOM to turn MathML-style output",'%l,_
+ '"printing on and off, and where to place the output. By default, the",'%l,_
+ '"destination for the output is the screen but printing is turned off.",'%l,_ '
+ '%l,_
+ '"Syntax: )set output mathml <arg>",'%l,_
+ '" where arg can be one of",'%l,_
+ '" on turn MathML printing on",'%l,_
+ '" off turn MathML printing off (default state)",'%l,_
+ '" console send MathML output to screen (default state)",'%l,_
+ '" fp<.fe> send MathML output to file with file prefix fp and file",'%l,_
+ '" extension .fe. If not given, .fe defaults to .stex.",'%l,
+ '%l,_
+ '"If you wish to send the output to a file, you must issue this command",'%l,_
+ '"twice: once with",'%b,'"on",'%d,'"and once with the file name. For example, to send",'%l,_
+ '"MathML output to the file",'%b,'"polymer.smml,",'%d,'"issue the two commands",'%l,_
+ '%l,_
+ '" )set output mathml on",'%l,_
+ '" )set output mathml polymer",'%l,_
+ '%l,_
+ '"The output is placed in the directory from which you invoked OpenAxiom or",'%l,_
+ '"the one you set with the )cd system command.",'%l,_
+ '"The current setting is: ",'%b,setOutputMathml "%display%",'%d)
+
+
-- See the subsection output openmath in setvart.boot
--
-- ------------------ The openmath Option ------------------------
diff --git a/src/interp/setvart.boot b/src/interp/setvart.boot
index e2c3ca28..310fe79d 100644
--- a/src/interp/setvart.boot
+++ b/src/interp/setvart.boot
@@ -1136,7 +1136,8 @@ $setOptions := '(
-- length line length of output displays 77
-- scripts show subscripts,... linearly off
-- showeditor view output of )show in editor off
--- tex create output in TeX style Off:CONSOLE
+-- tex create output in TeX style Off:CONSOLE
+-- mathml create output in MathML style Off:CONSOLE
(output
"view and set some output options"
interpreter
@@ -1502,6 +1503,54 @@ $setOptions := '(
NIL)
))
+-- ----------------------- The mathml Option ------------------------
+--
+-- Description: create output in MathML style
+--
+-- )set output mathml is used to tell OpenAxiom to turn MathML-style output
+-- printing on and off, and where to place the output. By default,
+-- the destination for the output is the screen but printing is
+-- turned off.
+--
+-- Syntax: )set output mathml <arg>
+-- where arg can be one of
+-- on turn MathML printing on
+-- off turn MathML printing off (default state)
+-- console send MathML output to screen (default state)
+-- fp<.fe> send MathML output to file with file prefix fp
+-- and file extension .fe. If not given,
+-- .fe defaults to .smml.
+--
+-- If you wish to send the output to a file, you must issue
+-- this command twice: once with on and once with the file name.
+-- For example, to send MathML output to the file polymer.smml,
+-- issue the two commands
+--
+-- )set output mathml on
+-- )set output mathml polymer
+--
+-- The output is placed in the directory from which you invoked
+-- OpenAxiom or the one you set with the )cd system command.
+-- The current setting is: Off:CONSOLE
+
+ (mathml
+ "create output in MathML style"
+ interpreter
+ FUNCTION
+ setOutputMathml
+ (("create output in MathML format"
+ LITERALS
+ $mathmlFormat
+ (off on)
+ off)
+ (break $mathmlFormat)
+ ("where MathML output goes (enter {\em console} or a pathname)"
+ FILENAME
+ $mathmlOutputFile
+ chkOutputFileName
+ "console"))
+ NIL)
+
-- ----------------------- The quit Option -----------------------
--
-- Description: protected or unprotected quit