fricas
(1) -> <spad>
fricas
)abbrev domain TEX TexFormat
++ Author: Robert S. Sutor
++ Date Created: 1987 through 1992
++ Basic Operations: coerce, convert, display, epilogue,
++ tex, new, prologue, setEpilogue!, setTex!, setPrologue!
++ Related Constructors: TexFormat1
++ Also See: ScriptFormulaFormat
++ AMS Classifications:
++ Keywords: TeX, LaTeX, output, format
++ References: \TeX{} is a trademark of the American Mathematical Society.
++ Description:
++ \spadtype{TexFormat} provides a coercion from \spadtype{OutputForm} to
++ \TeX{} format. The particular dialect of \TeX{} used is \LaTeX{}.
++ The basic object consists of three parts: a prologue, a
++ tex part and an epilogue. The functions \spadfun{prologue},
++ \spadfun{tex} and \spadfun{epilogue} extract these parts,
++ respectively. The main guts of the expression go into the tex part.
++ The other parts can be set (\spadfun{setPrologue!},
++ \spadfun{setEpilogue!}) so that contain the appropriate tags for
++ printing. For example, the prologue and epilogue might simply
++ contain ``\verb+\[+'' and ``\verb+\]+'', respectively, so that
++ the TeX section will be printed in LaTeX display math mode.
++ Revision:
++ 25-FEB-2020 ... op PRIME (line 356), Greek characters x% (565 ff.)
++
TexFormat() : public == private where
E ==> OutputForm
I ==> Integer
L ==> List
S ==> String
Sy ==> Symbol
US ==> UniversalSegment(Integer)
public == SetCategory with
coerce : E -> %
++ coerce(o) changes o in the standard output format to TeX
++ format.
convert : (E, I) -> %
++ convert(o, step) changes o in standard output format to
++ TeX format and also adds the given step number. This is useful
++ if you want to create equations with given numbers or have the
++ equation numbers correspond to the interpreter step numbers.
convert : (E, I, E) -> %
++ convert(o, step, type) changes o in standard output format to
++ TeX format and also adds the given step number and type. This
++ is useful if you want to create equations with given numbers
++ or have the equation numbers correspond to the interpreter step
++ numbers.
display : (%, I) -> Void
++ display(t, width) outputs the TeX formatted code t so that each
++ line has length less than or equal to \spadvar{width}.
display : % -> Void
++ display(t) outputs the TeX formatted code t so that each
++ line has length less than or equal to the value set by
++ the system command \spadsyscom{set output length}.
epilogue : % -> L S
++ epilogue(t) extracts the epilogue section of a TeX form t.
tex : % -> L S
++ tex(t) extracts the TeX section of a TeX form t.
new : () -> %
++ new() create a new, empty object. Use \spadfun{setPrologue!},
++ \spadfun{setTex!} and \spadfun{setEpilogue!} to set the various
++ components of this object.
prologue : % -> L S
++ prologue(t) extracts the prologue section of a TeX form t.
setEpilogue! : (%, L S) -> L S
++ setEpilogue!(t, strings) sets the epilogue section of a TeX form t to strings.
setTex! : (%, L S) -> L S
++ setTex!(t, strings) sets the TeX section of a TeX form t to strings.
setPrologue! : (%, L S) -> L S
++ setPrologue!(t, strings) sets the prologue section of a TeX form t to strings.
private == add
import from OutputForm
import from Character
import from Integer
import from List OutputForm
import from List String
import from OutputFormTools
Rep := Record(prolog : L S, TeX : L S, epilog : L S)
-- local variable declarations and definitions
expr : E
prec, opPrec : I
str : S
blank : S := " \ "
maxPrec : I := 1000000
minPrec : I := 0
unaryOps : L Sy := ["-"::Sy]$(L Sy)
unaryPrecs : L I := [710]$(L I)
-- the precedence of / in the following is relatively low because
-- the bar obviates the need for parentheses.
binaryOps : L Sy := ["+->"::Sy, "|"::Sy, "^"::Sy, "/"::Sy, "="::Sy,
"~="::Sy, "<"::Sy, "<="::Sy, ">"::Sy, ">="::Sy,
'OVER, 'LET]
binaryPrecs : L I := [0, 0, 900, 700, 400,
400, 400, 400, 400, 400,
700, 125]$(L I)
naryOps : L Sy := ["-"::Sy, "+"::Sy, "*"::Sy, ","::Sy, ";"::Sy,
'ROW, 'STRSEP, 'TENSOR]
naryPrecs : L I := [700, 700, 800, 110, 110,
0, 0, 850]$(L I)
naryNGOps : L Sy := ['ROW]
plexOps : L Sy := ['SIGMA, 'SIGMA2, 'PI, 'PI2, 'INTSIGN]
plexPrecs : L I := [ 750, 750, 750, 750, 700]$(L I)
specialOps : L Sy := ['MATRIX, 'BRACKET, 'BRACE, 'CONCATB, 'VCONCAT, _
'AGGLST, 'CONCAT, 'OVERBAR, 'ROOT, 'SUB, 'TAG, _
'SUPERSUB, 'ZAG, 'AGGSET, 'SC, 'PAREN, _
'SEGMENT, 'QUOTE, 'theMap, 'SLASH, 'PRIME]
-- the next two lists provide translations for some strings for
-- which TeX provides special macros.
specialStrings : L Sy :=
['cos, 'cot, 'csc, 'log, 'sec, 'sin, 'tan,
'cosh, 'coth, 'csch, 'sech, 'sinh, 'tanh,
'acos, 'asin, 'atan, 'erf, "..."::Sy, "$"::Sy, 'infinity,
'Gamma]
specialStringsInTeX : L S :=
["\cos","\cot","\csc","\log","\sec","\sin","\tan",
"\cosh","\coth","\csch","\sech","\sinh","\tanh",
"\arccos","\arcsin","\arctan","\erf","\ldots","\$","\infty",
"\Gamma"]
-- local function signatures
addBraces : S -> S
addBrackets : S -> S
group : S -> S
formatBinary : (Sy, L E, I) -> S
formatFunction : (E, L E, I) -> S
formatMatrix : L E -> S
formatNary : (Sy, S, I, L E, I) -> S
formatNaryNoGroup : (Sy, S, I, L E, I) -> S
formatNullary : Sy -> S
formatPlex : (Sy, L E, I) -> S
formatSpecial : (Sy, L E, I) -> S
formatUnary : (Sy, E, I) -> S
formatExpr : (E, I) -> S
newWithNum : I -> %
parenthesize : S -> S
postcondition : S -> S
splitLong : (S, I) -> L S
splitLong1 : (S, I) -> L S
stringify : E -> S
ungroup : S -> S
-- public function definitions
new() : % ==
-- [["\["]$(L S), [""]$(L S), ["\]"]$(L S)]$Rep
[["$$"]$(L S), [""]$(L S), ["$$"]$(L S)]$Rep
newWithNum(stepNum : I) : % ==
-- num : S := concat("%FRICAS STEP NUMBER: ",string(stepNum)$S)
-- [["\["]$(L S), [""]$(L S), ["\]",num]$(L S)]$Rep
num : S := concat(concat("\leqno(",string(stepNum)$S),")")$S
[["$$"]$(L S), [""]$(L S), [num,"$$"]$(L S)]$Rep
coerce(expr : E) : % ==
f : % := new()$%
f.TeX := [postcondition
formatExpr(precondition expr, minPrec)]$(L S)
f
convert(expr : E, stepNum : I) : % ==
f : % := newWithNum(stepNum)
f.TeX := [postcondition
formatExpr(precondition expr, minPrec)]$(L S)
f
sayExpr(s : S) : Void ==
sayTeX$Lisp s
display(f : %, len : I) ==
s, t : S
for s in f.prolog repeat sayExpr s
for s in f.TeX repeat
for t in splitLong(s, len) repeat sayExpr t
for s in f.epilog repeat sayExpr s
void()$Void
display(f : %) ==
display(f, _$LINELENGTH$Lisp pretend I)
prologue(f : %) == f.prolog
tex(f : %) == f.TeX
epilogue(f : %) == f.epilog
setPrologue!(f : %, l : L S) == f.prolog := l
setTex!(f : %, l : L S) == f.TeX := l
setEpilogue!(f : %, l : L S) == f.epilog := l
coerce(f : %) : E ==
s, t : S
l : L S := []
for s in f.prolog repeat l := concat(s, l)
for s in f.TeX repeat
for t in splitLong(s, (_$LINELENGTH$Lisp pretend Integer) - 4) repeat
l := concat(t, l)
for s in f.epilog repeat l := concat(s, l)
(reverse l) :: E
-- local function definitions
ungroup(str : S) : S ==
len : I := #str
len < 2 => str
lbrace : Character := char "{"
rbrace : Character := char "}"
-- drop leading and trailing braces
if (str.1 =$Character lbrace) and (str.len =$Character rbrace) then
u : US := segment(2, len-1)$US
str := str.u
str
postcondition(str : S) : S ==
str := ungroup str
len : I := #str
plus : Character := char "+"
minus : Character := char "-"
len < 4 => str
for i in 1..(len-1) repeat
if (str.i =$Character plus) and (str.(i+1) =$Character minus)
then setelt!(str, i, char " ")$S
str
stringify expr == (mathObject2String$Lisp expr) pretend S
lineConcat( line : S, lines : L S ) : L S ==
length := #line
if ( length > 0 ) then
-- If the last character is a backslash then split at "\ ".
-- Reinstate the blank.
if (line.length = char "\" ) then line := concat(line, " ")
-- Remark: for some reason, "\%" at the beginning
-- of a line has the "\" erased when printed
if ( line.1 = char "%" ) then line := concat(" \", line)
else if ( line.1 = char "\" ) and length > 1 and ( line.2 = char "%" ) then
line := concat(" ", line)
lines := concat(line, lines)$List(S)
lines
splitLong(str : S, len : I) : L S ==
-- this blocks into lines
if len < 20 then len := _$LINELENGTH$Lisp
splitLong1(str, len)
splitLong1(str : S, len : I) ==
-- We first build the list of lines backwards and then we
-- reverse it.
l : List S := []
s : S := ""
ls : I := 0
ss : S
lss : I
for ss in split(str,char " ") repeat
-- have the newline macro end a line (even if it means the line
-- is slightly too long)
ss = "\\" =>
l := lineConcat( concat(s, ss), l )
s := ""
ls := 0
lss := #ss
-- place certain tokens on their own lines for clarity
ownLine : Boolean :=
u : US := segment(1, 4)$US
(lss > 3) and ("\end" = ss.u) => true
u := segment(1, 5)$US
(lss > 4) and ("\left" = ss.u) => true
u := segment(1, 6)$US
(lss > 5) and (("\right" = ss.u) or ("\begin" = ss.u)) => true
false
if ownLine or (ls + lss > len) then
if not empty? s then l := lineConcat( s, l )
s := ""
ls := 0
ownLine or lss > len => l := lineConcat( ss, l )
(lss = 1) and (ss.1 = char "\") =>
ls := ls + lss + 2
s := concat(s,concat(ss," ")$S)$S
ls := ls + lss + 1
s := concat(s,concat(ss," ")$S)$S
if ls > 0 then l := lineConcat( s, l )
reverse l
group str ==
concat ["{",str,"}"]
addBraces str ==
concat ["\left\{ ",str," \right\}"]
addBrackets str ==
concat ["\left[ ",str," \right]"]
parenthesize str ==
concat ["\left( ",str," \right)"]
formatSpecial(op : Sy, args : L E, prec : I) : S ==
arg : E
prescript : Boolean := false
op = 'theMap => "\mbox{theMap(...)}"
op = 'AGGLST =>
formatNary(","::Sy, "", 0, args, prec)
op = 'AGGSET =>
formatNary(";"::Sy, "", 0, args, prec)
op = 'TAG =>
group concat [formatExpr(first args, prec),
"\rightarrow",
formatExpr(second args, prec)]
op = 'SLASH =>
group concat [formatExpr(first args, prec),
"/", formatExpr(second args, prec)]
op = 'VCONCAT =>
group concat("\begin{array}{c}",
concat(concat([concat(formatExpr(u, minPrec), "\\")
for u in args]::L S),