| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Text::ASCIIMathML; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=pod |
|
4
|
|
|
|
|
|
|
=head1 NAME |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
Text::ASCIIMathML - Perl extension for parsing ASCIIMathML text into MathML |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
use Text::ASCIIMathML; |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
$parser=new Text::ASCIIMathML(); |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
$parser->SetAttributes(ForMoz => 1); |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
$ASCIIMathML = "int_0^1 e^x dx"; |
|
17
|
|
|
|
|
|
|
$mathML = $parser->TextToMathML($ASCIIMathML); |
|
18
|
|
|
|
|
|
|
$mathML = $parser->TextToMathML($ASCIIMathML, [title=>$ASCIIMathML]); |
|
19
|
|
|
|
|
|
|
$mathML = $parser->TextToMathML($ASCIIMathML, undef, [displaystyle=>1]); |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
$mathMLTree = $parser->TextToMathMLTree($ASCIIMathML); |
|
22
|
|
|
|
|
|
|
$mathMLTree = $parser->TextToMathMLTree($ASCIIMathML, [title=>$ASCIIMathML]); |
|
23
|
|
|
|
|
|
|
$mathMLTree = $parser->TextToMathMLTree($ASCIIMathML,undef,[displaystyle=>1]); |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
$mathML = $mathMLTree->text(); |
|
26
|
|
|
|
|
|
|
$latex = $mathMLTree->latex(); |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
Text::ASCIIMathML is a parser for ASCIIMathML text which produces |
|
31
|
|
|
|
|
|
|
MathML XML markup strings that are suitable for rendering by any |
|
32
|
|
|
|
|
|
|
MathML-compliant browser. |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
The parser uses the following attributes which are settable through |
|
35
|
|
|
|
|
|
|
the SetAttributes method: |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=over 4 |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=item C |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
Specifies that the fonts should be optimized for Netscape/Mozilla/Firefox. |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=back |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
The output of the TextToMathML method always follows the schema |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
The first argument of TextToMathML is the ASCIIMathML text to be |
|
48
|
|
|
|
|
|
|
parsed into MathML. The second argument is a reference to an array of |
|
49
|
|
|
|
|
|
|
attribute/value pairs to be attached to the |
|
50
|
|
|
|
|
|
|
argument is a reference to an array of attribute/value pairs for the |
|
51
|
|
|
|
|
|
|
node. Common attributes for the |
|
52
|
|
|
|
|
|
|
"xmlns"=>"&mathml;". Common attributes for the node are |
|
53
|
|
|
|
|
|
|
"mathcolor" (for text color), "displaystyle"=>"true" for using display |
|
54
|
|
|
|
|
|
|
style instead of inline style, and "fontfamily". |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head2 ASCIIMathML markup |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
The syntax is very permissive and does not generate syntax |
|
59
|
|
|
|
|
|
|
errors. This allows mathematically incorrect expressions to be |
|
60
|
|
|
|
|
|
|
displayed, which is important for teaching purposes. It also causes |
|
61
|
|
|
|
|
|
|
less frustration when previewing formulas. |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
If you encode 'x^2' or 'a_(mn)' or 'a_{mn}' or '(x+1)/y' or 'sqrtx', |
|
64
|
|
|
|
|
|
|
you pretty much get what you expect. The choice of grouping |
|
65
|
|
|
|
|
|
|
parenthesis is up to you (they don't have to match either). If the |
|
66
|
|
|
|
|
|
|
displayed expression can be parsed uniquely without them, they are |
|
67
|
|
|
|
|
|
|
omitted. Most LaTeX commands are also supported, so the last two |
|
68
|
|
|
|
|
|
|
formulas above can also be written as '\frac{x+1}{y}' and '\sqrt{x}'. |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
The parser uses no operator precedence and only respects the grouping |
|
71
|
|
|
|
|
|
|
brackets, subscripts, superscript, fractions and (square) roots. This |
|
72
|
|
|
|
|
|
|
is done for reasons of efficiency and generality. The resulting MathML |
|
73
|
|
|
|
|
|
|
code can quite easily be processed further to ensure additional |
|
74
|
|
|
|
|
|
|
syntactic requirements of any particular application. |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=head3 The grammar |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
Here is a definition of the grammar used to parse |
|
79
|
|
|
|
|
|
|
ASCIIMathML expressions. In the Backus-Naur form given below, the |
|
80
|
|
|
|
|
|
|
letter on the left of the C<::=> represents a category of symbols that |
|
81
|
|
|
|
|
|
|
could be one of the possible sequences of symbols listed on the right. |
|
82
|
|
|
|
|
|
|
The vertical bar C<|> separates the alternatives. |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=over 4 |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
c ::= [A-z] | numbers | greek letters | other constant symbols |
|
87
|
|
|
|
|
|
|
(see below) |
|
88
|
|
|
|
|
|
|
u ::= 'sqrt' | 'text' | 'bb' | other unary symbols for font commands |
|
89
|
|
|
|
|
|
|
b ::= 'frac' | 'root' | 'stackrel' | 'newcommand' | 'newsymbol' |
|
90
|
|
|
|
|
|
|
binary symbols |
|
91
|
|
|
|
|
|
|
l ::= ( | [ | { | (: | {: left brackets |
|
92
|
|
|
|
|
|
|
r ::= ) | ] | } | :) | :} right brackets |
|
93
|
|
|
|
|
|
|
S ::= c | lEr | uS | bSS | "any" simple expression |
|
94
|
|
|
|
|
|
|
E ::= SE | S/S |S_S | S^S | S_S^S expression (fraction, sub-, |
|
95
|
|
|
|
|
|
|
super-, subsuperscript) |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=back |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=head3 The translation rules |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
Each terminal symbol is translated into a corresponding MathML |
|
102
|
|
|
|
|
|
|
node. The constants are mostly converted to their respective Unicode |
|
103
|
|
|
|
|
|
|
symbols. The other expressions are converted as follows: |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=over 4 |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
lSr -> lSr |
|
108
|
|
|
|
|
|
|
(note that any pair of brackets can be used to |
|
109
|
|
|
|
|
|
|
delimit subexpressions, they don't have to match) |
|
110
|
|
|
|
|
|
|
sqrt S -> S' |
|
111
|
|
|
|
|
|
|
text S -> S' |
|
112
|
|
|
|
|
|
|
"any" -> any |
|
113
|
|
|
|
|
|
|
frac S1 S2 -> S1' S2' |
|
114
|
|
|
|
|
|
|
root S1 S2 -> S2' S1' |
|
115
|
|
|
|
|
|
|
stackrel S1 S2 -> S2' S1' |
|
116
|
|
|
|
|
|
|
S1/S2 -> S1' S2' |
|
117
|
|
|
|
|
|
|
S1_S2 -> S1 S2' |
|
118
|
|
|
|
|
|
|
S1^S2 -> S1 S2' |
|
119
|
|
|
|
|
|
|
S1_S2^S3 -> S1 S2' S3' or |
|
120
|
|
|
|
|
|
|
S1 S2' S3' (in some cases) |
|
121
|
|
|
|
|
|
|
S1^S2_S3 -> S1 S3' S2' or |
|
122
|
|
|
|
|
|
|
S1 S3' S2' (in some cases) |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=back |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
In the rules above, the expression C is the same as C, except that if |
|
127
|
|
|
|
|
|
|
C has an outer level of brackets, then C is the expression inside |
|
128
|
|
|
|
|
|
|
these brackets. |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=head3 Matrices |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
A simple syntax for matrices is also recognized: |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
l(S11,...,S1n),(...),(Sm1,...,Smn)r |
|
135
|
|
|
|
|
|
|
or |
|
136
|
|
|
|
|
|
|
l[S11,...,S1n],[...],[Sm1,...,Smn]r. |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
Here C and C stand for any of the left and right |
|
139
|
|
|
|
|
|
|
brackets (just like in the grammar they do not have to match). Both of |
|
140
|
|
|
|
|
|
|
these expressions are translated to |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
lS11... |
|
143
|
|
|
|
|
|
|
S1n... |
|
144
|
|
|
|
|
|
|
Sm1... |
|
145
|
|
|
|
|
|
|
Smnr. |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
Note that each row must have the same number of expressions, and there |
|
148
|
|
|
|
|
|
|
should be at least two rows. |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
LaTeX matrix commands are not recognized. |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=head3 Tokenization |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
The input formula is broken into tokens using a "longest matching |
|
155
|
|
|
|
|
|
|
initial substring search". Suppose the input formula has been |
|
156
|
|
|
|
|
|
|
processed from left to right up to a fixed position. The longest |
|
157
|
|
|
|
|
|
|
string from the list of constants (given below) that matches the |
|
158
|
|
|
|
|
|
|
initial part of the remainder of the formula is the next token. If |
|
159
|
|
|
|
|
|
|
there is no matching string, then the first character of the remainder |
|
160
|
|
|
|
|
|
|
is the next token. The symbol table at the top of the ASCIIMathML.js |
|
161
|
|
|
|
|
|
|
script specifies whether a symbol is a math operator (surrounded by a |
|
162
|
|
|
|
|
|
|
C<< >> tag) or a math identifier (surrounded by a C<< >> |
|
163
|
|
|
|
|
|
|
tag). For single character tokens, letters are treated as math |
|
164
|
|
|
|
|
|
|
identifiers, and non-alphanumeric characters are treated as math |
|
165
|
|
|
|
|
|
|
operators. For digits, see "Numbers" below. |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
Spaces are significant when they separate characters and thus prevent |
|
168
|
|
|
|
|
|
|
a certain string of characters from matching one of the |
|
169
|
|
|
|
|
|
|
constants. Multiple spaces and end-of-line characters are equivalent |
|
170
|
|
|
|
|
|
|
to a single space. |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=head3 Numbers |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
A string of digits, optionally followed by a decimal point (a period) |
|
175
|
|
|
|
|
|
|
and another string of digits, is parsed as a single token and |
|
176
|
|
|
|
|
|
|
converted to a MathML number, i.e., enclosed with the C<< >> |
|
177
|
|
|
|
|
|
|
tag. |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=head3 Greek letters |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=over 4 |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=item Lowercase letters |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
C C C C C C C C |
|
186
|
|
|
|
|
|
|
C C C C C C C C C |
|
187
|
|
|
|
|
|
|
C C C C C C |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=item Uppercase letters |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
C C C C C C C C |
|
192
|
|
|
|
|
|
|
C C |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=item Variants |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
C C C |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=back |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head3 Standard functions |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
sin cos tan csc sec cot sinh cosh tanh log ln det dim lim mod gcd lcm |
|
203
|
|
|
|
|
|
|
min max |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=head3 Operation symbols |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
Type Description Entity |
|
208
|
|
|
|
|
|
|
+ + + |
|
209
|
|
|
|
|
|
|
- - - |
|
210
|
|
|
|
|
|
|
* Mid dot ⋅ |
|
211
|
|
|
|
|
|
|
** Star ⋆ |
|
212
|
|
|
|
|
|
|
// / / |
|
213
|
|
|
|
|
|
|
\\ \ \ |
|
214
|
|
|
|
|
|
|
xx Cross product × |
|
215
|
|
|
|
|
|
|
-: Divided by ÷ |
|
216
|
|
|
|
|
|
|
@ Compose functions ∘ |
|
217
|
|
|
|
|
|
|
o+ Circle with plus ⊕ |
|
218
|
|
|
|
|
|
|
ox Circle with x ⊗ |
|
219
|
|
|
|
|
|
|
o. Circle with dot ⊙ |
|
220
|
|
|
|
|
|
|
sum Sum for sub- and superscript ∑ |
|
221
|
|
|
|
|
|
|
prod Product for sub- and superscript ∏ |
|
222
|
|
|
|
|
|
|
^^ Logic "and" ∧ |
|
223
|
|
|
|
|
|
|
^^^ Logic "and" for sub- and superscript ⋀ |
|
224
|
|
|
|
|
|
|
vv Logic "or" ∨ |
|
225
|
|
|
|
|
|
|
vvv Logic "or" for sub- and superscript ⋁ |
|
226
|
|
|
|
|
|
|
nn Logic "intersect" ∩ |
|
227
|
|
|
|
|
|
|
nnn Logic "intersect" for sub- and superscript ⋂ |
|
228
|
|
|
|
|
|
|
uu Logic "union" ∪ |
|
229
|
|
|
|
|
|
|
uuu Logic "union" for sub- and superscript ⋃ |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=head3 Relation symbols |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
Type Description Entity |
|
234
|
|
|
|
|
|
|
= = = |
|
235
|
|
|
|
|
|
|
!= Not equals ≠ |
|
236
|
|
|
|
|
|
|
< < < |
|
237
|
|
|
|
|
|
|
> > > |
|
238
|
|
|
|
|
|
|
<= Less than or equal ≤ |
|
239
|
|
|
|
|
|
|
>= Greater than or equal ≥ |
|
240
|
|
|
|
|
|
|
-lt Precedes ≺ |
|
241
|
|
|
|
|
|
|
>- Succeeds ≻ |
|
242
|
|
|
|
|
|
|
in Element of ∈ |
|
243
|
|
|
|
|
|
|
!in Not an element of ∉ |
|
244
|
|
|
|
|
|
|
sub Subset ⊂ |
|
245
|
|
|
|
|
|
|
sup Superset ⊃ |
|
246
|
|
|
|
|
|
|
sube Subset or equal ⊆ |
|
247
|
|
|
|
|
|
|
supe Superset or equal ⊇ |
|
248
|
|
|
|
|
|
|
-= Equivalent ≡ |
|
249
|
|
|
|
|
|
|
~= Congruent to ≅ |
|
250
|
|
|
|
|
|
|
~~ Asymptotically equal to ≈ |
|
251
|
|
|
|
|
|
|
prop Proportional to ∝ |
|
252
|
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=head3 Logical symbols |
|
254
|
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
Type Description Entity |
|
256
|
|
|
|
|
|
|
and And " and " |
|
257
|
|
|
|
|
|
|
or Or " or " |
|
258
|
|
|
|
|
|
|
not Not ¬ |
|
259
|
|
|
|
|
|
|
=> Implies ⇒ |
|
260
|
|
|
|
|
|
|
if If " if " |
|
261
|
|
|
|
|
|
|
iff If and only if ⇔ |
|
262
|
|
|
|
|
|
|
AA For all ∀ |
|
263
|
|
|
|
|
|
|
EE There exists ∃ |
|
264
|
|
|
|
|
|
|
_|_ Perpendicular, bottom ⊥ |
|
265
|
|
|
|
|
|
|
TT Top ⊤ |
|
266
|
|
|
|
|
|
|
|-- Right tee ⊢ |
|
267
|
|
|
|
|
|
|
|== Double right tee ⊨ |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=head3 Grouping brackets |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
Type Description Entity |
|
272
|
|
|
|
|
|
|
( ( ( |
|
273
|
|
|
|
|
|
|
) ) ) |
|
274
|
|
|
|
|
|
|
[ [ [ |
|
275
|
|
|
|
|
|
|
] ] ] |
|
276
|
|
|
|
|
|
|
{ { { |
|
277
|
|
|
|
|
|
|
} } } |
|
278
|
|
|
|
|
|
|
(: Left angle bracket 〈 |
|
279
|
|
|
|
|
|
|
:) Right angle bracket 〉 |
|
280
|
|
|
|
|
|
|
{: Invisible left grouping element |
|
281
|
|
|
|
|
|
|
:} Invisible right grouping element |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
=head3 Miscellaneous symbols |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
Type Description Entity |
|
286
|
|
|
|
|
|
|
int Integral ∫ |
|
287
|
|
|
|
|
|
|
oint Countour integral ∮ |
|
288
|
|
|
|
|
|
|
del Partial derivative &del; |
|
289
|
|
|
|
|
|
|
grad Gradient ∇ |
|
290
|
|
|
|
|
|
|
+- Plus or minus ± |
|
291
|
|
|
|
|
|
|
O/ Null set ∅ |
|
292
|
|
|
|
|
|
|
oo Infinity ∞ |
|
293
|
|
|
|
|
|
|
aleph Hebrew letter aleph ℵ |
|
294
|
|
|
|
|
|
|
& Ampersand & |
|
295
|
|
|
|
|
|
|
/_ Angle ∠ |
|
296
|
|
|
|
|
|
|
:. Therefore ∴ |
|
297
|
|
|
|
|
|
|
... Ellipsis ... |
|
298
|
|
|
|
|
|
|
cdots Three centered dots ⋯ |
|
299
|
|
|
|
|
|
|
\ Non-breaking space ( means space) |
|
300
|
|
|
|
|
|
|
quad Quad space |
|
301
|
|
|
|
|
|
|
diamond Diamond ⋄ |
|
302
|
|
|
|
|
|
|
square Square □ |
|
303
|
|
|
|
|
|
|
|__ Left floor ⌊ |
|
304
|
|
|
|
|
|
|
__| Right floor ⌋ |
|
305
|
|
|
|
|
|
|
|~ Left ceiling ⌈ |
|
306
|
|
|
|
|
|
|
~| Right ceiling ⌉ |
|
307
|
|
|
|
|
|
|
CC Complex numbers ℂ |
|
308
|
|
|
|
|
|
|
NN Natural numbers ℕ |
|
309
|
|
|
|
|
|
|
QQ Rational numbers ℚ |
|
310
|
|
|
|
|
|
|
RR Real numbers ℝ |
|
311
|
|
|
|
|
|
|
ZZ Integers ℤ |
|
312
|
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
=head3 Arrows |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
Type Description Entity |
|
316
|
|
|
|
|
|
|
uarr Up arrow ↑ |
|
317
|
|
|
|
|
|
|
darr Down arrow ↓ |
|
318
|
|
|
|
|
|
|
rarr Right arrow → |
|
319
|
|
|
|
|
|
|
-> Right arrow → |
|
320
|
|
|
|
|
|
|
larr Left arrow ← |
|
321
|
|
|
|
|
|
|
harr Horizontal (two-way) arrow ↔ |
|
322
|
|
|
|
|
|
|
rArr Right double arrow ⇒ |
|
323
|
|
|
|
|
|
|
lArr Left double arrow ⇐ |
|
324
|
|
|
|
|
|
|
hArr Horizontal double arrow ⇔ |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
=head3 Accents |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
Type Description Output |
|
329
|
|
|
|
|
|
|
hat x Hat over x x^ |
|
330
|
|
|
|
|
|
|
bar x Bar over x x¯ |
|
331
|
|
|
|
|
|
|
ul x Underbar under x x_ |
|
332
|
|
|
|
|
|
|
vec x Right arrow over x x→ |
|
333
|
|
|
|
|
|
|
dot x Dot over x x. |
|
334
|
|
|
|
|
|
|
ddot x Double dot over x x.. |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
=head3 Font commands |
|
337
|
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
Type Description |
|
339
|
|
|
|
|
|
|
bb A Bold A |
|
340
|
|
|
|
|
|
|
bbb A Double-struck A |
|
341
|
|
|
|
|
|
|
cc A Calligraphic (script) A |
|
342
|
|
|
|
|
|
|
tt A Teletype (monospace) A |
|
343
|
|
|
|
|
|
|
fr A Fraktur A |
|
344
|
|
|
|
|
|
|
sf A Sans-serif A |
|
345
|
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
=head3 Defining new commands and symbols |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
It is possible to define new commands and symbols using the |
|
349
|
|
|
|
|
|
|
'newcommand' and 'newsymbol' binary operators. The former defines a |
|
350
|
|
|
|
|
|
|
macro that gets expanded and reparsed as ASCIIMathML and the latter |
|
351
|
|
|
|
|
|
|
defines a constant that gets used as a math operator (C<< >>) |
|
352
|
|
|
|
|
|
|
element. Both of the arguments must be text, optionally enclosed in |
|
353
|
|
|
|
|
|
|
grouping operators. The 'newsymbol' operator also allows the |
|
354
|
|
|
|
|
|
|
second argument to be a group of two text strings where the first is |
|
355
|
|
|
|
|
|
|
the mathml operator and the second is the latex code to be output. |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
For example, 'newcommand "DDX" "{:d/dx:}"' would define a new command |
|
358
|
|
|
|
|
|
|
'DDX'. It could then be invoked like 'DDXf(x)', which would |
|
359
|
|
|
|
|
|
|
expand to '{:d/dx:}f(x)'. The text 'newsymbol{"!le"}{"≰"}' |
|
360
|
|
|
|
|
|
|
could be used to create a symbol you could invoke with '!le', as in 'a |
|
361
|
|
|
|
|
|
|
!le b'. |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=head2 Attributes for |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
=over 4 |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=item C |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
The title attribute for the element, if specified. In many browsers, |
|
370
|
|
|
|
|
|
|
this string will appear if you hover over the MathML markup. |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
=item C |
|
373
|
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
The id attribute for the element, if specified. |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=item C |
|
377
|
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
The class attribute for the element, if specified. |
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
=back |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
=head2 Attributes for |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=over 4 |
|
385
|
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
=item C |
|
387
|
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
The displaystyle attribute for the element, if specified. One of the |
|
389
|
|
|
|
|
|
|
values "true" or "false". If the displaystyle is false, then fractions |
|
390
|
|
|
|
|
|
|
are represented with a smaller font size and the placement of |
|
391
|
|
|
|
|
|
|
subscripts and superscripts of sums and integrals changes. |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=item C |
|
394
|
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
The mathvariant attribute for the element, if specified. One of the |
|
396
|
|
|
|
|
|
|
values "normal", "bold", "italic", "bold-italic", "double-struck", |
|
397
|
|
|
|
|
|
|
"bold-fraktur", "script", "bold-script", "fraktur", "sans-serif", |
|
398
|
|
|
|
|
|
|
"bold-sans-serif", "sans-serif-italic", "sans-serif-bold-italic", or |
|
399
|
|
|
|
|
|
|
"monospace". |
|
400
|
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=item C |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
The mathsize attribute for the element, if specified. Either "small", |
|
404
|
|
|
|
|
|
|
"normal" or "big", or of the form "number v-unit". |
|
405
|
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
=item C |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
A string representing the font family. |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
=item C |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
The mathcolor attribute for the element, if specified. It be in one of |
|
413
|
|
|
|
|
|
|
the forms "#rgb" or "#rrggbb", or should be an html-color-name. |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=item C |
|
416
|
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
The mathbackground attribute for the element, if specified. It should |
|
418
|
|
|
|
|
|
|
be in one of the forms "#rgb" or "#rrggbb", or an html-color-name, or |
|
419
|
|
|
|
|
|
|
the keyword "transparent". |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=head1 METHODS |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=head2 C |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
=head3 C |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
Converts C<$text> to a MathML string. If the optional C<$math_attr> |
|
429
|
|
|
|
|
|
|
argument is provided, it should be a reference to a hash of |
|
430
|
|
|
|
|
|
|
attribute/value pairs for the C< |
|
431
|
|
|
|
|
|
|
C<$mstyle_attr> argument is provided, it should be a reference to a |
|
432
|
|
|
|
|
|
|
hash of attribute/value pairs for the C< > node. |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
=head3 C |
|
435
|
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
Like C except that instead of returning a string, it |
|
437
|
|
|
|
|
|
|
returns a C representing the parsed MathML |
|
438
|
|
|
|
|
|
|
structure. |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
=head2 C |
|
441
|
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=head3 C |
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
Returns a MathML string representing the parsed MathML structure |
|
445
|
|
|
|
|
|
|
encoded by the C. |
|
446
|
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=head3 C |
|
448
|
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
Returns a LaTeX string representing the parsed MathML structure |
|
450
|
|
|
|
|
|
|
encoded by the C. |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
=head1 BUGS AND SUGGESTIONS |
|
453
|
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
If you find bugs, think of anything that could improve Text::ASCIIMathML |
|
455
|
|
|
|
|
|
|
or have any questions related to it, feel free to contact the author. |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
=head1 AUTHOR |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
Mark Nodine |
|
460
|
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
462
|
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
MathML::Entities, |
|
464
|
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
|
467
|
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
This Perl module has been created by modifying Peter Jipsen's |
|
469
|
|
|
|
|
|
|
ASCIIMathML.js script. He deserves full credit for the original |
|
470
|
|
|
|
|
|
|
implementation; any bugs have probably been introduced by me. |
|
471
|
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
473
|
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
The Text::ASCIIMathML module is copyright (c) 2006 Mark Nodine, |
|
475
|
|
|
|
|
|
|
USA. All rights reserved. |
|
476
|
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
You may use and distribute them under the terms of either the GNU |
|
478
|
|
|
|
|
|
|
General Public License or the Artistic License, as specified in the |
|
479
|
|
|
|
|
|
|
Perl README file. |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
=cut |
|
482
|
|
|
|
|
|
|
|
|
483
|
1
|
|
|
1
|
|
47331
|
use strict; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
39
|
|
|
484
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
3808
|
|
|
485
|
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
our $VERSION = '0.81'; |
|
487
|
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
# Creates a new Text::ASCIIMathML parser object |
|
489
|
|
|
|
|
|
|
sub new { |
|
490
|
1
|
|
|
1
|
1
|
11230
|
my ($class) = @_; |
|
491
|
1
|
|
|
|
|
5
|
return bless {}, $class; |
|
492
|
|
|
|
|
|
|
} |
|
493
|
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
# Sets an attribute to a given value |
|
495
|
|
|
|
|
|
|
# Arguments: Attribute name, attribute value |
|
496
|
|
|
|
|
|
|
# Returns: None |
|
497
|
|
|
|
|
|
|
# Supported attributes: |
|
498
|
|
|
|
|
|
|
# ForMoz Boolean to optimize for Netscape/Mozilla/Firefox |
|
499
|
|
|
|
|
|
|
sub SetAttribute : method { |
|
500
|
1
|
|
|
1
|
0
|
7
|
my ($self, $attr, $val) = @_; |
|
501
|
1
|
|
|
|
|
11
|
$self->{attr}{$attr} = $val; |
|
502
|
|
|
|
|
|
|
} |
|
503
|
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
# Converts an AsciiMathML string to a MathML one |
|
505
|
|
|
|
|
|
|
# Arguments: AsciiMathML string, |
|
506
|
|
|
|
|
|
|
# optional ref to array of attribute/value pairs for math node, |
|
507
|
|
|
|
|
|
|
# optional ref to array of attribute/value pairs for mstyle node |
|
508
|
|
|
|
|
|
|
# Returns: MathML string |
|
509
|
|
|
|
|
|
|
sub TextToMathML : method { |
|
510
|
275
|
|
|
275
|
1
|
289252
|
my $tree = TextToMathMLTree(@_); |
|
511
|
275
|
100
|
|
|
|
1134
|
return $tree ? $tree->text : ''; |
|
512
|
|
|
|
|
|
|
} |
|
513
|
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
# Converts an AsciiMathML string to a tree of MathML nodes |
|
515
|
|
|
|
|
|
|
# Arguments: AsciiMathML string, |
|
516
|
|
|
|
|
|
|
# optional ref to array of attribute/value pairs for math node, |
|
517
|
|
|
|
|
|
|
# optional ref to array of attribute/value pairs for mstyle node |
|
518
|
|
|
|
|
|
|
# Returns: top Text::ASCIIMathML::Node object or undefined |
|
519
|
|
|
|
|
|
|
sub TextToMathMLTree : method { |
|
520
|
548
|
|
|
548
|
1
|
1196
|
my ($self, $expr, $mathAttr, $mstyleAttr) = @_; |
|
521
|
548
|
50
|
|
|
|
20657
|
$expr = '' unless defined $expr; |
|
522
|
548
|
|
|
|
|
5688
|
my $mstyle = $self->_createElementMathML('mstyle'); |
|
523
|
548
|
50
|
|
|
|
3853
|
$mstyle->setAttribute |
|
|
|
50
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
(ref $mstyleAttr eq 'ARRAY' ? @$mstyleAttr : %$mstyleAttr) |
|
525
|
|
|
|
|
|
|
if $mstyleAttr; |
|
526
|
548
|
|
|
|
|
1007
|
$self->{nestingDepth} = 0; |
|
527
|
548
|
|
|
|
|
1376
|
$expr =~ s/^\s+//; |
|
528
|
548
|
|
|
|
|
1997
|
$mstyle->appendChild(($self->_parseExpr($expr, 0))[0]); |
|
529
|
548
|
100
|
|
|
|
2415
|
return unless $mstyle->childNodes > 0; |
|
530
|
547
|
|
|
|
|
1624
|
my $math = $self->_createMmlNode('math', $mstyle); |
|
531
|
547
|
|
|
|
|
1340
|
$expr =~ s/\n\s*//g; |
|
532
|
547
|
50
|
|
|
|
2163
|
$math->setAttribute(ref $mathAttr eq 'ARRAY' ? @$mathAttr : %$mathAttr) |
|
|
|
100
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
if $mathAttr; |
|
534
|
|
|
|
|
|
|
|
|
535
|
547
|
|
|
|
|
2110
|
return $math; |
|
536
|
|
|
|
|
|
|
} |
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
# Creates an Text::ASCIIMathML::Node object with no tag |
|
541
|
|
|
|
|
|
|
# Arguments: None |
|
542
|
|
|
|
|
|
|
# Returns: node object |
|
543
|
|
|
|
|
|
|
sub _createDocumentFragment : method { |
|
544
|
4069
|
|
|
4069
|
|
5304
|
my ($self) = @_; |
|
545
|
4069
|
|
|
|
|
10489
|
return Text::ASCIIMathML::Node->new($self); |
|
546
|
|
|
|
|
|
|
} |
|
547
|
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
# Creates an Text::ASCIIMathML::Node object |
|
549
|
|
|
|
|
|
|
# Arguments: tag |
|
550
|
|
|
|
|
|
|
# Returns: node object |
|
551
|
|
|
|
|
|
|
sub _createElementMathML : method { |
|
552
|
586
|
|
|
586
|
|
1285
|
my ($self, $t) = @_; |
|
553
|
586
|
|
|
|
|
1977
|
return Text::ASCIIMathML::Node->new($self, $t); |
|
554
|
|
|
|
|
|
|
} |
|
555
|
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
# Creates an Text::ASCIIMathML::Node object and appends a node as a child |
|
557
|
|
|
|
|
|
|
# Arguments: tag, node |
|
558
|
|
|
|
|
|
|
# Returns: node object |
|
559
|
|
|
|
|
|
|
sub _createMmlNode : method { |
|
560
|
4880
|
|
|
4880
|
|
10078
|
my ($self, $t, $obj) = @_; |
|
561
|
4880
|
|
|
|
|
14713
|
my $node = Text::ASCIIMathML::Node->new($self, $t); |
|
562
|
4880
|
|
|
|
|
12341
|
$node->appendChild($obj); |
|
563
|
4880
|
|
|
|
|
41189
|
return $node; |
|
564
|
|
|
|
|
|
|
} |
|
565
|
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
# Creates an Text::ASCIIMathML::Node text object with the given text |
|
567
|
|
|
|
|
|
|
# Arguments: text |
|
568
|
|
|
|
|
|
|
# Returns: node object |
|
569
|
|
|
|
|
|
|
sub _createTextNode : method { |
|
570
|
3193
|
|
|
3193
|
|
5932
|
my ($self, $text) = @_; |
|
571
|
3193
|
|
|
|
|
12802
|
return Text::ASCIIMathML::Node->newText ($self, $text); |
|
572
|
|
|
|
|
|
|
} |
|
573
|
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
# Finds maximal initial substring of str that appears in names |
|
575
|
|
|
|
|
|
|
# return null if there is none |
|
576
|
|
|
|
|
|
|
# Arguments: string |
|
577
|
|
|
|
|
|
|
# Returns: matched input, entry from AMSymbol (if any) |
|
578
|
|
|
|
|
|
|
sub _getSymbol : method { |
|
579
|
10482
|
|
|
10482
|
|
15796
|
my $self = shift; |
|
580
|
10482
|
|
|
|
|
23860
|
my ($input, $symbol) = $self->_getSymbol_(@_); |
|
581
|
10482
|
100
|
|
|
|
37063
|
$self->{previousSymbol} = $symbol->{ttype} if $symbol; |
|
582
|
10482
|
|
|
|
|
40184
|
return $input, $symbol; |
|
583
|
|
|
|
|
|
|
} |
|
584
|
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
BEGIN { |
|
586
|
|
|
|
|
|
|
# character lists for Mozilla/Netscape fonts |
|
587
|
1
|
|
|
1
|
|
7
|
my $AMcal = [0xEF35,0x212C,0xEF36,0xEF37,0x2130,0x2131,0xEF38,0x210B,0x2110,0xEF39,0xEF3A,0x2112,0x2133,0xEF3B,0xEF3C,0xEF3D,0xEF3E,0x211B,0xEF3F,0xEF40,0xEF41,0xEF42,0xEF43,0xEF44,0xEF45,0xEF46]; |
|
588
|
1
|
|
|
|
|
9
|
my $AMfrk = [0xEF5D,0xEF5E,0x212D,0xEF5F,0xEF60,0xEF61,0xEF62,0x210C,0x2111,0xEF63,0xEF64,0xEF65,0xEF66,0xEF67,0xEF68,0xEF69,0xEF6A,0x211C,0xEF6B,0xEF6C,0xEF6D,0xEF6E,0xEF6F,0xEF70,0xEF71,0x2128]; |
|
589
|
1
|
|
|
|
|
4
|
my $AMbbb = [0xEF8C,0xEF8D,0x2102,0xEF8E,0xEF8F,0xEF90,0xEF91,0x210D,0xEF92,0xEF93,0xEF94,0xEF95,0xEF96,0x2115,0xEF97,0x2119,0x211A,0x211D,0xEF98,0xEF99,0xEF9A,0xEF9B,0xEF9C,0xEF9D,0xEF9E,0x2124]; |
|
590
|
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
# Create closure for static variables |
|
592
|
1
|
|
|
|
|
652
|
my %AMSymbol = ( |
|
593
|
|
|
|
|
|
|
"sqrt" => { tag=>"msqrt", output=>"sqrt", tex=>'', ttype=>"UNARY" }, |
|
594
|
|
|
|
|
|
|
"root" => { tag=>"mroot", output=>"root", tex=>'', ttype=>"BINARY" }, |
|
595
|
|
|
|
|
|
|
"frac" => { tag=>"mfrac", output=>"/", tex=>'', ttype=>"BINARY" }, |
|
596
|
|
|
|
|
|
|
"/" => { tag=>"mfrac", output=>"/", tex=>'', ttype=>"INFIX" }, |
|
597
|
|
|
|
|
|
|
"stackrel" => { tag=>"mover", output=>"stackrel", tex=>'', ttype=>"BINARY" }, |
|
598
|
|
|
|
|
|
|
"_" => { tag=>"msub", output=>"_", tex=>'', ttype=>"INFIX" }, |
|
599
|
|
|
|
|
|
|
"^" => { tag=>"msup", output=>"^", tex=>'', ttype=>"INFIX" }, |
|
600
|
|
|
|
|
|
|
"text" => { tag=>"mtext", output=>"text", tex=>'', ttype=>"TEXT" }, |
|
601
|
|
|
|
|
|
|
"mbox" => { tag=>"mtext", output=>"mbox", tex=>'', ttype=>"TEXT" }, |
|
602
|
|
|
|
|
|
|
"\"" => { tag=>"mtext", output=>"mbox", tex=>'', ttype=>"TEXT" }, |
|
603
|
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
# new for perl |
|
605
|
|
|
|
|
|
|
"newcommand" => { ttype=>"BINARY"}, |
|
606
|
|
|
|
|
|
|
"newsymbol" => { ttype=>"BINARY" }, |
|
607
|
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
# some greek symbols |
|
609
|
|
|
|
|
|
|
"alpha" => { tag=>"mi", output=>"α", tex=>'', ttype=>"CONST" }, |
|
610
|
|
|
|
|
|
|
"beta" => { tag=>"mi", output=>"β", tex=>'', ttype=>"CONST" }, |
|
611
|
|
|
|
|
|
|
"chi" => { tag=>"mi", output=>"χ", tex=>'', ttype=>"CONST" }, |
|
612
|
|
|
|
|
|
|
"delta" => { tag=>"mi", output=>"δ", tex=>'', ttype=>"CONST" }, |
|
613
|
|
|
|
|
|
|
"Delta" => { tag=>"mo", output=>"Δ", tex=>'', ttype=>"CONST" }, |
|
614
|
|
|
|
|
|
|
"epsi" => { tag=>"mi", output=>"ε", tex=>"epsilon", ttype=>"CONST" }, |
|
615
|
|
|
|
|
|
|
"varepsilon" => { tag=>"mi", output=>"ɛ", tex=>'', ttype=>"CONST" }, |
|
616
|
|
|
|
|
|
|
"eta" => { tag=>"mi", output=>"η", tex=>'', ttype=>"CONST" }, |
|
617
|
|
|
|
|
|
|
"gamma" => { tag=>"mi", output=>"γ", tex=>'', ttype=>"CONST" }, |
|
618
|
|
|
|
|
|
|
"Gamma" => { tag=>"mo", output=>"Γ", tex=>'', ttype=>"CONST" }, |
|
619
|
|
|
|
|
|
|
"iota" => { tag=>"mi", output=>"ι", tex=>'', ttype=>"CONST" }, |
|
620
|
|
|
|
|
|
|
"kappa" => { tag=>"mi", output=>"κ", tex=>'', ttype=>"CONST" }, |
|
621
|
|
|
|
|
|
|
"lambda" => { tag=>"mi", output=>"λ", tex=>'', ttype=>"CONST" }, |
|
622
|
|
|
|
|
|
|
"Lambda" => { tag=>"mo", output=>"Λ", tex=>'', ttype=>"CONST" }, |
|
623
|
|
|
|
|
|
|
"mu" => { tag=>"mi", output=>"μ", tex=>'', ttype=>"CONST" }, |
|
624
|
|
|
|
|
|
|
"nu" => { tag=>"mi", output=>"ν", tex=>'', ttype=>"CONST" }, |
|
625
|
|
|
|
|
|
|
"omega" => { tag=>"mi", output=>"ω", tex=>'', ttype=>"CONST" }, |
|
626
|
|
|
|
|
|
|
"Omega" => { tag=>"mo", output=>"Ω", tex=>'', ttype=>"CONST" }, |
|
627
|
|
|
|
|
|
|
"phi" => { tag=>"mi", output=>"ϕ", tex=>'', ttype=>"CONST" }, |
|
628
|
|
|
|
|
|
|
"varphi" => { tag=>"mi", output=>"φ", tex=>'', ttype=>"CONST" }, |
|
629
|
|
|
|
|
|
|
"Phi" => { tag=>"mo", output=>"Φ", tex=>'', ttype=>"CONST" }, |
|
630
|
|
|
|
|
|
|
"pi" => { tag=>"mi", output=>"π", tex=>'', ttype=>"CONST" }, |
|
631
|
|
|
|
|
|
|
"Pi" => { tag=>"mo", output=>"Π", tex=>'', ttype=>"CONST" }, |
|
632
|
|
|
|
|
|
|
"psi" => { tag=>"mi", output=>"ψ", tex=>'', ttype=>"CONST" }, |
|
633
|
|
|
|
|
|
|
"Psi" => { tag=>"mi", output=>"Ψ", tex=>'', ttype=>"CONST" }, |
|
634
|
|
|
|
|
|
|
"rho" => { tag=>"mi", output=>"ρ", tex=>'', ttype=>"CONST" }, |
|
635
|
|
|
|
|
|
|
"sigma" => { tag=>"mi", output=>"σ", tex=>'', ttype=>"CONST" }, |
|
636
|
|
|
|
|
|
|
"Sigma" => { tag=>"mo", output=>"Σ", tex=>'', ttype=>"CONST" }, |
|
637
|
|
|
|
|
|
|
"tau" => { tag=>"mi", output=>"τ", tex=>'', ttype=>"CONST" }, |
|
638
|
|
|
|
|
|
|
"theta" => { tag=>"mi", output=>"θ", tex=>'', ttype=>"CONST" }, |
|
639
|
|
|
|
|
|
|
"vartheta" => { tag=>"mi", output=>"ϑ", tex=>'', ttype=>"CONST" }, |
|
640
|
|
|
|
|
|
|
"Theta" => { tag=>"mo", output=>"Θ", tex=>'', ttype=>"CONST" }, |
|
641
|
|
|
|
|
|
|
"upsilon" => { tag=>"mi", output=>"υ", tex=>'', ttype=>"CONST" }, |
|
642
|
|
|
|
|
|
|
"xi" => { tag=>"mi", output=>"ξ", tex=>'', ttype=>"CONST" }, |
|
643
|
|
|
|
|
|
|
"Xi" => { tag=>"mo", output=>"Ξ", tex=>'', ttype=>"CONST" }, |
|
644
|
|
|
|
|
|
|
"zeta" => { tag=>"mi", output=>"ζ", tex=>'', ttype=>"CONST" }, |
|
645
|
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
# binary operation symbols |
|
647
|
|
|
|
|
|
|
"*" => { tag=>"mo", output=>"⋅", tex=>"cdot", ttype=>"CONST" }, |
|
648
|
|
|
|
|
|
|
"**" => { tag=>"mo", output=>"⋆", tex=>"star", ttype=>"CONST" }, |
|
649
|
|
|
|
|
|
|
"//" => { tag=>"mo", output=>"/", tex=>'', ttype=>"CONST" }, |
|
650
|
|
|
|
|
|
|
"\\\\" => { tag=>"mo", output=>"\\", tex=>"backslash", ttype=>"CONST" }, |
|
651
|
|
|
|
|
|
|
"setminus" => { tag=>"mo", output=>"\\", tex=>'', ttype=>"CONST" }, |
|
652
|
|
|
|
|
|
|
"xx" => { tag=>"mo", output=>"×", tex=>"times", ttype=>"CONST" }, |
|
653
|
|
|
|
|
|
|
"-:" => { tag=>"mo", output=>"÷", tex=>"div", ttype=>"CONST" }, |
|
654
|
|
|
|
|
|
|
"@" => { tag=>"mo", output=>"∘", tex=>"circ", ttype=>"CONST" }, |
|
655
|
|
|
|
|
|
|
"o+" => { tag=>"mo", output=>"⊕", tex=>"oplus", ttype=>"CONST" }, |
|
656
|
|
|
|
|
|
|
"ox" => { tag=>"mo", output=>"⊗", tex=>"otimes", ttype=>"CONST" }, |
|
657
|
|
|
|
|
|
|
"o." => { tag=>"mo", output=>"⊙", tex=>"odot", ttype=>"CONST" }, |
|
658
|
|
|
|
|
|
|
"sum" => { tag=>"mo", output=>"∑", tex=>'', ttype=>"UNDEROVER" }, |
|
659
|
|
|
|
|
|
|
"prod" => { tag=>"mo", output=>"∏", tex=>'', ttype=>"UNDEROVER" }, |
|
660
|
|
|
|
|
|
|
"^^" => { tag=>"mo", output=>"∧", tex=>"wedge", ttype=>"CONST" }, |
|
661
|
|
|
|
|
|
|
"^^^" => { tag=>"mo", output=>"⋀", tex=>"bigwedge", ttype=>"UNDEROVER" }, |
|
662
|
|
|
|
|
|
|
"vv" => { tag=>"mo", output=>"∨", tex=>"vee", ttype=>"CONST" }, |
|
663
|
|
|
|
|
|
|
"vvv" => { tag=>"mo", output=>"⋁", tex=>"bigvee", ttype=>"UNDEROVER" }, |
|
664
|
|
|
|
|
|
|
"nn" => { tag=>"mo", output=>"∩", tex=>"cap", ttype=>"CONST" }, |
|
665
|
|
|
|
|
|
|
"nnn" => { tag=>"mo", output=>"⋂", tex=>"bigcap", ttype=>"UNDEROVER" }, |
|
666
|
|
|
|
|
|
|
"uu" => { tag=>"mo", output=>"∪", tex=>"cup", ttype=>"CONST" }, |
|
667
|
|
|
|
|
|
|
"uuu" => { tag=>"mo", output=>"⋃", tex=>"bigcup", ttype=>"UNDEROVER" }, |
|
668
|
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
# binary relation symbols |
|
670
|
|
|
|
|
|
|
"!=" => { tag=>"mo", output=>"≠", tex=>"ne", ttype=>"CONST" }, |
|
671
|
|
|
|
|
|
|
":=" => { tag=>"mo", output=>":=", tex=>'', ttype=>"CONST" }, |
|
672
|
|
|
|
|
|
|
#"lt" => { tag=>"mo", output=>"<", tex=>'', ttype=>"CONST" }, |
|
673
|
|
|
|
|
|
|
"lt" => { tag=>"mo", output=>"<", tex=>'', ttype=>"CONST" }, |
|
674
|
|
|
|
|
|
|
"<=" => { tag=>"mo", output=>"≤", tex=>"le", ttype=>"CONST" }, |
|
675
|
|
|
|
|
|
|
"lt=" => { tag=>"mo", output=>"≤", tex=>"leq", ttype=>"CONST", latex=>1 }, |
|
676
|
|
|
|
|
|
|
">=" => { tag=>"mo", output=>"≥", tex=>"ge", ttype=>"CONST" }, |
|
677
|
|
|
|
|
|
|
"geq" => { tag=>"mo", output=>"≥", tex=>'', ttype=>"CONST", latex=>1 }, |
|
678
|
|
|
|
|
|
|
"-<" => { tag=>"mo", output=>"≺", tex=>"prec", ttype=>"CONST", latex=>1 }, |
|
679
|
|
|
|
|
|
|
"-lt" => { tag=>"mo", output=>"≺", tex=>'', ttype=>"CONST" }, |
|
680
|
|
|
|
|
|
|
">-" => { tag=>"mo", output=>"≻", tex=>"succ", ttype=>"CONST" }, |
|
681
|
|
|
|
|
|
|
"in" => { tag=>"mo", output=>"∈", tex=>'', ttype=>"CONST" }, |
|
682
|
|
|
|
|
|
|
"!in" => { tag=>"mo", output=>"∉", tex=>"notin", ttype=>"CONST" }, |
|
683
|
|
|
|
|
|
|
"sub" => { tag=>"mo", output=>"⊂", tex=>"subset", ttype=>"CONST" }, |
|
684
|
|
|
|
|
|
|
"sup" => { tag=>"mo", output=>"⊃", tex=>"supset", ttype=>"CONST" }, |
|
685
|
|
|
|
|
|
|
"sube" => { tag=>"mo", output=>"⊆", tex=>"subseteq", ttype=>"CONST" }, |
|
686
|
|
|
|
|
|
|
"supe" => { tag=>"mo", output=>"⊇", tex=>"supseteq", ttype=>"CONST" }, |
|
687
|
|
|
|
|
|
|
"-=" => { tag=>"mo", output=>"≡", tex=>"equiv", ttype=>"CONST" }, |
|
688
|
|
|
|
|
|
|
"~=" => { tag=>"mo", output=>"≅", tex=>"cong", ttype=>"CONST" }, |
|
689
|
|
|
|
|
|
|
"~~" => { tag=>"mo", output=>"≈", tex=>"approx", ttype=>"CONST" }, |
|
690
|
|
|
|
|
|
|
"prop" => { tag=>"mo", output=>"∝", tex=>"propto", ttype=>"CONST" }, |
|
691
|
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
# new for perl |
|
693
|
|
|
|
|
|
|
"<" => { tag=>"mo", output=>"<", tex=>'', ttype=>"CONST" }, |
|
694
|
|
|
|
|
|
|
"gt" => { tag=>"mo", output=>">", tex=>'', ttype=>"CONST" }, |
|
695
|
|
|
|
|
|
|
">" => { tag=>"mo", output=>">", tex=>'', ttype=>"CONST" }, |
|
696
|
|
|
|
|
|
|
"\\!" => { tag=>"", output=>'', tex=>'', ttype=>"NOP" }, |
|
697
|
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
# logical symbols |
|
700
|
|
|
|
|
|
|
"and" => { tag=>"mtext", output=>"and", tex=>'', ttype=>"SPACE" }, |
|
701
|
|
|
|
|
|
|
"or" => { tag=>"mtext", output=>"or", tex=>'', ttype=>"SPACE" }, |
|
702
|
|
|
|
|
|
|
"not" => { tag=>"mo", output=>"¬", tex=>"neg", ttype=>"CONST" }, |
|
703
|
|
|
|
|
|
|
"=>" => { tag=>"mo", output=>"⇒", tex=>"implies", ttype=>"CONST" }, |
|
704
|
|
|
|
|
|
|
"if" => { tag=>"mo", output=>"if", tex=>'if', ttype=>"SPACE" }, |
|
705
|
|
|
|
|
|
|
"<=>" => { tag=>"mo", output=>"⇔", tex=>"iff", ttype=>"CONST" }, |
|
706
|
|
|
|
|
|
|
"AA" => { tag=>"mo", output=>"∀", tex=>"forall", ttype=>"CONST" }, |
|
707
|
|
|
|
|
|
|
"EE" => { tag=>"mo", output=>"∃", tex=>"exists", ttype=>"CONST" }, |
|
708
|
|
|
|
|
|
|
"_|_" => { tag=>"mo", output=>"⊥", tex=>"bot", ttype=>"CONST" }, |
|
709
|
|
|
|
|
|
|
"TT" => { tag=>"mo", output=>"⊤", tex=>"top", ttype=>"CONST" }, |
|
710
|
|
|
|
|
|
|
"|--" => { tag=>"mo", output=>"⊢", tex=>"vdash", ttype=>"CONST" }, |
|
711
|
|
|
|
|
|
|
"|==" => { tag=>"mo", output=>"⊨", tex=>"models", ttype=>"CONST" }, |
|
712
|
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
# grouping brackets |
|
714
|
|
|
|
|
|
|
"(" => { tag=>"mo", output=>"(", tex=>'', ttype=>"LEFTBRACKET" }, |
|
715
|
|
|
|
|
|
|
")" => { tag=>"mo", output=>")", tex=>'', ttype=>"RIGHTBRACKET" }, |
|
716
|
|
|
|
|
|
|
"[" => { tag=>"mo", output=>"[", tex=>'', ttype=>"LEFTBRACKET" }, |
|
717
|
|
|
|
|
|
|
"]" => { tag=>"mo", output=>"]", tex=>'', ttype=>"RIGHTBRACKET" }, |
|
718
|
|
|
|
|
|
|
"{" => { tag=>"mo", output=>"{", tex=>'', ttype=>"LEFTBRACKET" }, |
|
719
|
|
|
|
|
|
|
"}" => { tag=>"mo", output=>"}", tex=>'', ttype=>"RIGHTBRACKET" }, |
|
720
|
|
|
|
|
|
|
"|" => { tag=>"mo", output=>"|", tex=>'', ttype=>"LEFTRIGHT" }, |
|
721
|
|
|
|
|
|
|
# {input:"||", tag:"mo", output:"||", tex:null, ttype:LEFTRIGHT}, |
|
722
|
|
|
|
|
|
|
"(:" => { tag=>"mo", output=>"〈", tex=>"langle", ttype=>"LEFTBRACKET" }, |
|
723
|
|
|
|
|
|
|
":)" => { tag=>"mo", output=>"〉", tex=>"rangle", ttype=>"RIGHTBRACKET" }, |
|
724
|
|
|
|
|
|
|
"<<" => { tag=>"mo", output=>"〈", tex=>'langle', ttype=>"LEFTBRACKET" }, |
|
725
|
|
|
|
|
|
|
">>" => { tag=>"mo", output=>"〉", tex=>'rangle', ttype=>"RIGHTBRACKET" }, |
|
726
|
|
|
|
|
|
|
"{:" => { tag=>"mo", output=>"{:", tex=>'', ttype=>"LEFTBRACKET", invisible=>"true" }, |
|
727
|
|
|
|
|
|
|
":}" => { tag=>"mo", output=>":}", tex=>'', ttype=>"RIGHTBRACKET", invisible=>"true" }, |
|
728
|
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
# miscellaneous symbols |
|
730
|
|
|
|
|
|
|
"int" => { tag=>"mo", output=>"∫", tex=>'', ttype=>"CONST" }, |
|
731
|
|
|
|
|
|
|
"dx" => { tag=>"mi", output=>"{:d x:}", tex=>'', ttype=>"DEFINITION" }, |
|
732
|
|
|
|
|
|
|
"dy" => { tag=>"mi", output=>"{:d y:}", tex=>'', ttype=>"DEFINITION" }, |
|
733
|
|
|
|
|
|
|
"dz" => { tag=>"mi", output=>"{:d z:}", tex=>'', ttype=>"DEFINITION" }, |
|
734
|
|
|
|
|
|
|
"dt" => { tag=>"mi", output=>"{:d t:}", tex=>'', ttype=>"DEFINITION" }, |
|
735
|
|
|
|
|
|
|
"oint" => { tag=>"mo", output=>"∮", tex=>'', ttype=>"CONST" }, |
|
736
|
|
|
|
|
|
|
"del" => { tag=>"mo", output=>"∂", tex=>"partial", ttype=>"CONST" }, |
|
737
|
|
|
|
|
|
|
"grad" => { tag=>"mo", output=>"∇", tex=>"nabla", ttype=>"CONST" }, |
|
738
|
|
|
|
|
|
|
"+-" => { tag=>"mo", output=>"±", tex=>"pm", ttype=>"CONST" }, |
|
739
|
|
|
|
|
|
|
"O/" => { tag=>"mo", output=>"∅", tex=>"emptyset", ttype=>"CONST" }, |
|
740
|
|
|
|
|
|
|
"oo" => { tag=>"mo", output=>"∞", tex=>"infty", ttype=>"CONST" }, |
|
741
|
|
|
|
|
|
|
"aleph" => { tag=>"mo", output=>"ℵ", tex=>'', ttype=>"CONST" }, |
|
742
|
|
|
|
|
|
|
"..." => { tag=>"mo", output=>"...", tex=>"ldots", ttype=>"CONST" }, |
|
743
|
|
|
|
|
|
|
":." => { tag=>"mo", output=>"∴", tex=>"therefore", ttype=>"CONST" }, |
|
744
|
|
|
|
|
|
|
"/_" => { tag=>"mo", output=>"∠", tex=>"angle", ttype=>"CONST" }, |
|
745
|
|
|
|
|
|
|
"&" => { tag=>"mo", output=>"&", tex=>'\&', ttype=>"CONST" }, |
|
746
|
|
|
|
|
|
|
"\\ " => { tag=>"mo", output=>" ", tex=>'\,', ttype=>"CONST" }, |
|
747
|
|
|
|
|
|
|
"quad" => { tag=>"mo", output=>" ", tex=>'', ttype=>"CONST" }, |
|
748
|
|
|
|
|
|
|
"qquad" => { tag=>"mo", output=>" ", tex=>'', ttype=>"CONST" }, |
|
749
|
|
|
|
|
|
|
"cdots" => { tag=>"mo", output=>"⋯", tex=>'', ttype=>"CONST" }, |
|
750
|
|
|
|
|
|
|
"vdots" => { tag=>"mo", output=>"⋮", tex=>'', ttype=>"CONST" }, |
|
751
|
|
|
|
|
|
|
"ddots" => { tag=>"mo", output=>"⋱", tex=>'', ttype=>"CONST" }, |
|
752
|
|
|
|
|
|
|
"diamond" => { tag=>"mo", output=>"⋄", tex=>'', ttype=>"CONST" }, |
|
753
|
|
|
|
|
|
|
"square" => { tag=>"mo", output=>"□", tex=>'', ttype=>"CONST" }, |
|
754
|
|
|
|
|
|
|
"|__" => { tag=>"mo", output=>"⌊", tex=>"lfloor", ttype=>"CONST" }, |
|
755
|
|
|
|
|
|
|
"__|" => { tag=>"mo", output=>"⌋", tex=>"rfloor", ttype=>"CONST" }, |
|
756
|
|
|
|
|
|
|
"|~" => { tag=>"mo", output=>"⌈", tex=>"lceil", ttype=>"CONST" }, |
|
757
|
|
|
|
|
|
|
"~|" => { tag=>"mo", output=>"⌉", tex=>"rceil", ttype=>"CONST" }, |
|
758
|
|
|
|
|
|
|
"CC" => { tag=>"mo", output=>"ℂ", tex=>'', ttype=>"CONST" }, |
|
759
|
|
|
|
|
|
|
"NN" => { tag=>"mo", output=>"ℕ", tex=>'', ttype=>"CONST" }, |
|
760
|
|
|
|
|
|
|
"QQ" => { tag=>"mo", output=>"ℚ", tex=>'', ttype=>"CONST" }, |
|
761
|
|
|
|
|
|
|
"RR" => { tag=>"mo", output=>"ℝ", tex=>'', ttype=>"CONST" }, |
|
762
|
|
|
|
|
|
|
"ZZ" => { tag=>"mo", output=>"ℤ", tex=>'', ttype=>"CONST" }, |
|
763
|
|
|
|
|
|
|
"f" => { tag=>"mi", output=>"f", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
764
|
|
|
|
|
|
|
"g" => { tag=>"mi", output=>"g", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
765
|
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
# standard functions |
|
767
|
|
|
|
|
|
|
"lim" => { tag=>"mo", output=>"lim", tex=>'', ttype=>"UNDEROVER" }, |
|
768
|
|
|
|
|
|
|
"Lim" => { tag=>"mo", output=>"Lim", tex=>'', ttype=>"UNDEROVER" }, |
|
769
|
|
|
|
|
|
|
"sin" => { tag=>"mo", output=>"sin", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
770
|
|
|
|
|
|
|
"cos" => { tag=>"mo", output=>"cos", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
771
|
|
|
|
|
|
|
"tan" => { tag=>"mo", output=>"tan", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
772
|
|
|
|
|
|
|
"sinh" => { tag=>"mo", output=>"sinh", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
773
|
|
|
|
|
|
|
"cosh" => { tag=>"mo", output=>"cosh", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
774
|
|
|
|
|
|
|
"tanh" => { tag=>"mo", output=>"tanh", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
775
|
|
|
|
|
|
|
"cot" => { tag=>"mo", output=>"cot", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
776
|
|
|
|
|
|
|
"sec" => { tag=>"mo", output=>"sec", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
777
|
|
|
|
|
|
|
"csc" => { tag=>"mo", output=>"csc", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
778
|
|
|
|
|
|
|
"log" => { tag=>"mo", output=>"log", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
779
|
|
|
|
|
|
|
"ln" => { tag=>"mo", output=>"ln", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
780
|
|
|
|
|
|
|
"det" => { tag=>"mo", output=>"det", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
781
|
|
|
|
|
|
|
"dim" => { tag=>"mo", output=>"dim", tex=>'', ttype=>"CONST" }, |
|
782
|
|
|
|
|
|
|
"mod" => { tag=>"mo", output=>"mod", tex=>'', ttype=>"CONST" }, |
|
783
|
|
|
|
|
|
|
"gcd" => { tag=>"mo", output=>"gcd", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
784
|
|
|
|
|
|
|
"lcm" => { tag=>"mo", output=>"lcm", tex=>'', ttype=>"UNARY", func=>"true" }, |
|
785
|
|
|
|
|
|
|
"lub" => { tag=>"mo", output=>"lub", tex=>'', ttype=>"CONST" }, |
|
786
|
|
|
|
|
|
|
"glb" => { tag=>"mo", output=>"glb", tex=>'', ttype=>"CONST" }, |
|
787
|
|
|
|
|
|
|
"min" => { tag=>"mo", output=>"min", tex=>'', ttype=>"UNDEROVER" }, |
|
788
|
|
|
|
|
|
|
"max" => { tag=>"mo", output=>"max", tex=>'', ttype=>"UNDEROVER" }, |
|
789
|
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
# arrows |
|
791
|
|
|
|
|
|
|
"uarr" => { tag=>"mo", output=>"↑", tex=>"uparrow", ttype=>"CONST" }, |
|
792
|
|
|
|
|
|
|
"darr" => { tag=>"mo", output=>"↓", tex=>"downarrow", ttype=>"CONST" }, |
|
793
|
|
|
|
|
|
|
"rarr" => { tag=>"mo", output=>"→", tex=>"rightarrow", ttype=>"CONST" }, |
|
794
|
|
|
|
|
|
|
"->" => { tag=>"mo", output=>"→", tex=>"to", ttype=>"CONST", latex=>1 }, |
|
795
|
|
|
|
|
|
|
"|->" => { tag=>"mo", output=>"↦", tex=>"mapsto", ttype=>"CONST" }, |
|
796
|
|
|
|
|
|
|
"larr" => { tag=>"mo", output=>"←", tex=>"leftarrow", ttype=>"CONST" }, |
|
797
|
|
|
|
|
|
|
"harr" => { tag=>"mo", output=>"↔", tex=>"leftrightarrow", ttype=>"CONST" }, |
|
798
|
|
|
|
|
|
|
"rArr" => { tag=>"mo", output=>"⇒", tex=>"Rightarrow", ttype=>"CONST", latex=>1 }, |
|
799
|
|
|
|
|
|
|
"lArr" => { tag=>"mo", output=>"⇐", tex=>"Leftarrow", ttype=>"CONST" }, |
|
800
|
|
|
|
|
|
|
"hArr" => { tag=>"mo", output=>"⇔", tex=>"Leftrightarrow", ttype=>"CONST", latex=>1 }, |
|
801
|
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
# commands with argument |
|
803
|
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
"hat" => { tag=>"mover", output=>"^", tex=>'', ttype=>"UNARY", acc=>"true" }, |
|
805
|
|
|
|
|
|
|
"bar" => { tag=>"mover", output=>"¯", tex=>"overline", ttype=>"UNARY", acc=>"true" }, |
|
806
|
|
|
|
|
|
|
"vec" => { tag=>"mover", output=>"→", tex=>'', ttype=>"UNARY", acc=>"true" }, |
|
807
|
|
|
|
|
|
|
"dot" => { tag=>"mover", output=>".", tex=>'', ttype=>"UNARY", acc=>"true" }, |
|
808
|
|
|
|
|
|
|
"ddot" => { tag=>"mover", output=>"..", tex=>'', ttype=>"UNARY", acc=>"true" }, |
|
809
|
|
|
|
|
|
|
"ul" => { tag=>"munder", output=>"̲", tex=>"underline", ttype=>"UNARY", acc=>"true" }, |
|
810
|
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
"bb" => { tag=>"mstyle", atname=>"fontweight", atval=>"bold", output=>"bb", tex=>'', ttype=>"UNARY" }, |
|
812
|
|
|
|
|
|
|
"mathbf" => { tag=>"mstyle", atname=>"fontweight", atval=>"bold", output=>"mathbf", tex=>'', ttype=>"UNARY" }, |
|
813
|
|
|
|
|
|
|
"sf" => { tag=>"mstyle", atname=>"fontfamily", atval=>"sans-serif", output=>"sf", tex=>'', ttype=>"UNARY" }, |
|
814
|
|
|
|
|
|
|
"mathsf" => { tag=>"mstyle", atname=>"fontfamily", atval=>"sans-serif", output=>"mathsf", tex=>'', ttype=>"UNARY" }, |
|
815
|
|
|
|
|
|
|
"bbb" => { tag=>"mstyle", atname=>"mathvariant", atval=>"double-struck", output=>"bbb", tex=>'', ttype=>"UNARY", codes=>$AMbbb }, |
|
816
|
|
|
|
|
|
|
"mathbb" => { tag=>"mstyle", atname=>"mathvariant", atval=>"double-struck", output=>"mathbb", tex=>'', ttype=>"UNARY", codes=>$AMbbb }, |
|
817
|
|
|
|
|
|
|
"cc" => { tag=>"mstyle", atname=>"mathvariant", atval=>"script", output=>"cc", tex=>'', ttype=>"UNARY", codes=>$AMcal }, |
|
818
|
|
|
|
|
|
|
"mathcal" => { tag=>"mstyle", atname=>"mathvariant", atval=>"script", output=>"mathcal", tex=>'', ttype=>"UNARY", codes=>$AMcal }, |
|
819
|
|
|
|
|
|
|
"tt" => { tag=>"mstyle", atname=>"fontfamily", atval=>"monospace", output=>"tt", tex=>'', ttype=>"UNARY" }, |
|
820
|
|
|
|
|
|
|
"mathtt" => { tag=>"mstyle", atname=>"fontfamily", atval=>"monospace", output=>"mathtt", tex=>'', ttype=>"UNARY" }, |
|
821
|
|
|
|
|
|
|
"fr" => { tag=>"mstyle", atname=>"mathvariant", atval=>"fraktur", output=>"fr", tex=>'', ttype=>"UNARY", codes=>$AMfrk }, |
|
822
|
|
|
|
|
|
|
"mathfrak" => { tag=>"mstyle", atname=>"mathvariant", atval=>"fraktur", output=>"mathfrak", tex=>'', ttype=>"UNARY", codes=>$AMfrk }, |
|
823
|
|
|
|
|
|
|
); |
|
824
|
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
# Preprocess AMSymbol for lexer regular expression |
|
826
|
|
|
|
|
|
|
# Preprocess AMSymbol for tex input |
|
827
|
1
|
|
33
|
|
|
268
|
my %AMTexSym = map(($AMSymbol{$_}{tex} || $_, $_), |
|
828
|
|
|
|
|
|
|
grep($AMSymbol{$_}{tex}, keys %AMSymbol)); |
|
829
|
1689
|
|
|
|
|
7104
|
my $Ident_RE = join '|', map("\Q$_\E", |
|
830
|
1
|
|
|
|
|
55
|
sort {length($b) - length($a)} (keys %AMSymbol, |
|
831
|
|
|
|
|
|
|
keys %AMTexSym)); |
|
832
|
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
sub _getSymbol_ : method { |
|
834
|
10482
|
|
|
10482
|
|
20157
|
my ($self, $str) = @_; |
|
835
|
10482
|
|
|
|
|
21594
|
for ($str) { |
|
836
|
10482
|
100
|
100
|
|
|
86743
|
/^(\d+(\.\d+)?)/ || /^(\.\d+)/ |
|
837
|
|
|
|
|
|
|
and return $1, {tag=>'mn', output=>$1, ttype=>'CONST'}; |
|
838
|
9560
|
100
|
100
|
|
|
58463
|
$self->{Definition_RE} && /^($self->{Definition_RE})/ and |
|
839
|
|
|
|
|
|
|
return $1, $self->{Definitions}{$1}; |
|
840
|
9532
|
100
|
|
|
|
57048
|
/^($Ident_RE)/o and |
|
|
|
100
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
return $1,$AMTexSym{$1} ? $AMSymbol{$AMTexSym{$1}} : $AMSymbol{$1}; |
|
842
|
5070
|
100
|
|
|
|
31869
|
/^([A-Za-z])/ and |
|
843
|
|
|
|
|
|
|
return $1, {tag=>'mi', output=>$1, ttype=>'CONST'}; |
|
844
|
2924
|
100
|
100
|
|
|
39037
|
/^(.)/ and |
|
|
|
100
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
return $1 eq '-' && defined $self->{previousSymbol} && |
|
846
|
|
|
|
|
|
|
$self->{previousSymbol} eq 'INFIX' ? |
|
847
|
|
|
|
|
|
|
($1, {tag=>'mo', output=>$1, ttype=>'UNARY', func=>"true"} ) : |
|
848
|
|
|
|
|
|
|
($1, {tag=>'mo', output=>$1, ttype=>'CONST'}); |
|
849
|
|
|
|
|
|
|
} |
|
850
|
|
|
|
|
|
|
} |
|
851
|
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
# Used so that Text::ASCIIMathML::Node can get access to the symbol table |
|
853
|
|
|
|
|
|
|
sub _get_amsymbol_ { |
|
854
|
1
|
|
|
1
|
|
3
|
return \%AMSymbol; |
|
855
|
|
|
|
|
|
|
} |
|
856
|
|
|
|
|
|
|
} |
|
857
|
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
# Parses an E expression |
|
859
|
|
|
|
|
|
|
# Arguments: string to parse, whether to look for a right bracket |
|
860
|
|
|
|
|
|
|
# Returns: parsed node (if successful), remaining unparsed string |
|
861
|
|
|
|
|
|
|
sub _parseExpr : method { |
|
862
|
994
|
|
|
994
|
|
1984
|
my ($self, $str, $rightbracket) = @_; |
|
863
|
994
|
|
|
|
|
3000
|
my $newFrag = $self->_createDocumentFragment(); |
|
864
|
994
|
|
|
|
|
9882
|
my ($node, $input, $symbol); |
|
865
|
994
|
|
100
|
|
|
1107
|
do { |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
866
|
2335
|
|
|
|
|
5824
|
$str = _removeCharsAndBlanks($str, 0); |
|
867
|
2335
|
|
|
|
|
8684
|
($node, $str) = $self->_parseIexpr($str); |
|
868
|
2335
|
|
|
|
|
6963
|
($input, $symbol) = $self->_getSymbol($str); |
|
869
|
2335
|
100
|
100
|
|
|
18720
|
if (defined $symbol && $symbol->{ttype} eq 'INFIX' && $input eq '/') { |
|
|
|
100
|
66
|
|
|
|
|
|
870
|
96
|
|
|
|
|
222
|
$str = _removeCharsAndBlanks($str, length $input); |
|
871
|
96
|
|
|
|
|
244
|
my @result = $self->_parseIexpr($str); |
|
872
|
96
|
50
|
|
|
|
298
|
if ($result[0]) { |
|
873
|
96
|
|
|
|
|
263
|
_removeBrackets($result[0]); |
|
874
|
|
|
|
|
|
|
} |
|
875
|
|
|
|
|
|
|
else { # show box in place of missing argument |
|
876
|
0
|
|
|
|
|
0
|
$result[0] = $self->_createMmlNode |
|
877
|
|
|
|
|
|
|
('mo', $self->_createTextNode('A1;')); |
|
878
|
|
|
|
|
|
|
} |
|
879
|
96
|
|
|
|
|
184
|
$str = $result[1]; |
|
880
|
96
|
|
|
|
|
191
|
_removeBrackets($node); |
|
881
|
96
|
|
|
|
|
270
|
$node = $self->_createMmlNode($symbol->{tag}, $node); |
|
882
|
96
|
|
|
|
|
275
|
$node->appendChild($result[0]); |
|
883
|
96
|
|
|
|
|
207
|
$newFrag->appendChild($node); |
|
884
|
96
|
|
|
|
|
213
|
($input, $symbol) = $self->_getSymbol($str); |
|
885
|
|
|
|
|
|
|
} |
|
886
|
|
|
|
|
|
|
elsif (defined $node) { |
|
887
|
2217
|
|
|
|
|
5615
|
$newFrag->appendChild($node); |
|
888
|
|
|
|
|
|
|
} |
|
889
|
|
|
|
|
|
|
} while (defined $symbol && ($symbol->{ttype} ne 'RIGHTBRACKET' && |
|
890
|
|
|
|
|
|
|
($symbol->{ttype} ne 'LEFTRIGHT' || |
|
891
|
|
|
|
|
|
|
$rightbracket) |
|
892
|
|
|
|
|
|
|
|| $self->{nestingDepth} == 0) && |
|
893
|
|
|
|
|
|
|
$symbol->{output} ne ''); |
|
894
|
994
|
100
|
66
|
|
|
5283
|
if (defined $symbol && $symbol->{ttype} =~ /RIGHTBRACKET|LEFTRIGHT/) { |
|
895
|
434
|
|
|
|
|
1233
|
my @childNodes = $newFrag->childNodes; |
|
896
|
434
|
100
|
100
|
|
|
2310
|
if (@childNodes > 1 && |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
897
|
|
|
|
|
|
|
$childNodes[-1]->nodeName eq 'mrow' && |
|
898
|
|
|
|
|
|
|
$childNodes[-2]->nodeName eq 'mo' && |
|
899
|
|
|
|
|
|
|
$childNodes[-2]->firstChild->nodeValue eq ',') { # matrix |
|
900
|
18
|
|
|
|
|
64
|
my $right = $childNodes[-1]->lastChild->firstChild->nodeValue; |
|
901
|
18
|
50
|
|
|
|
96
|
if ($right =~ /[\)\]]/) { |
|
902
|
18
|
|
|
|
|
61
|
my $left = $childNodes[-1]->firstChild->firstChild->nodeValue; |
|
903
|
18
|
50
|
66
|
|
|
190
|
if ("$left$right" =~ /^\(\)$/ && $symbol->{output} ne '}' || |
|
|
|
|
66
|
|
|
|
|
|
904
|
|
|
|
|
|
|
"$left$right" =~ /^\[\]$/) { |
|
905
|
18
|
|
|
|
|
30
|
my @pos; # positions of commas |
|
906
|
18
|
|
|
|
|
29
|
my $matrix = 1; |
|
907
|
18
|
|
|
|
|
29
|
my $m = @childNodes; |
|
908
|
18
|
|
66
|
|
|
103
|
for (my $i=0; $matrix && $i < $m; $i += 2) { |
|
909
|
38
|
|
|
|
|
67
|
$pos[$i] = []; |
|
910
|
38
|
|
|
|
|
55
|
$node = $childNodes[$i]; |
|
911
|
38
|
50
|
33
|
|
|
117
|
$matrix = |
|
912
|
|
|
|
|
|
|
$node->nodeName eq 'mrow' && |
|
913
|
|
|
|
|
|
|
($i == $m-1 || |
|
914
|
|
|
|
|
|
|
$node->nextSibling->nodeName eq 'mo' && |
|
915
|
|
|
|
|
|
|
$node->nextSibling->firstChild->nodeValue eq ',')&& |
|
916
|
|
|
|
|
|
|
$node->firstChild->firstChild->nodeValue eq $left&& |
|
917
|
|
|
|
|
|
|
$node->lastChild->firstChild->nodeValue eq $right |
|
918
|
|
|
|
|
|
|
if $matrix; |
|
919
|
38
|
50
|
|
|
|
116
|
if ($matrix) { |
|
920
|
38
|
|
|
|
|
117
|
for (my $j=0; $j<($node->childNodes); $j++) { |
|
921
|
210
|
100
|
|
|
|
413
|
if (($node->childNodes)[$j]->firstChild-> |
|
922
|
|
|
|
|
|
|
nodeValue eq ',') { |
|
923
|
40
|
|
|
|
|
46
|
push @{$pos[$i]}, $j; |
|
|
40
|
|
|
|
|
155
|
|
|
924
|
|
|
|
|
|
|
} |
|
925
|
|
|
|
|
|
|
} |
|
926
|
|
|
|
|
|
|
} |
|
927
|
38
|
100
|
66
|
|
|
225
|
if ($matrix && $i > 1) { |
|
928
|
20
|
|
|
|
|
29
|
$matrix = @{$pos[$i]} == @{$pos[$i-2]}; |
|
|
20
|
|
|
|
|
39
|
|
|
|
20
|
|
|
|
|
113
|
|
|
929
|
|
|
|
|
|
|
} |
|
930
|
|
|
|
|
|
|
} |
|
931
|
18
|
50
|
|
|
|
41
|
if ($matrix) { |
|
932
|
18
|
|
|
|
|
44
|
my $table = $self->_createDocumentFragment(); |
|
933
|
18
|
|
|
|
|
72
|
for (my $i=0; $i<$m; $i += 2) { |
|
934
|
38
|
|
|
|
|
130
|
my $row = $self->_createDocumentFragment(); |
|
935
|
38
|
|
|
|
|
91
|
my $frag = $self->_createDocumentFragment(); |
|
936
|
|
|
|
|
|
|
# (-,-,...,-,-) |
|
937
|
38
|
|
|
|
|
83
|
$node = $newFrag->firstChild; |
|
938
|
38
|
|
|
|
|
87
|
my $n = $node->childNodes; |
|
939
|
38
|
|
|
|
|
53
|
my $k = 0; |
|
940
|
38
|
|
|
|
|
88
|
$node->removeChild($node->firstChild); # remove ( |
|
941
|
38
|
|
|
|
|
127
|
for (my $j=1; $j<$n-1; $j++) { |
|
942
|
134
|
100
|
100
|
|
|
144
|
if ($k < @{$pos[$i]} && $j == $pos[$i][$k]) { |
|
|
134
|
|
|
|
|
542
|
|
|
943
|
|
|
|
|
|
|
# remove , |
|
944
|
40
|
|
|
|
|
111
|
$row->appendChild |
|
945
|
|
|
|
|
|
|
($self->_createMmlNode('mtd', $frag)); |
|
946
|
40
|
|
|
|
|
100
|
$frag = $self->_createDocumentFragment(); |
|
947
|
40
|
|
|
|
|
114
|
$k++; |
|
948
|
|
|
|
|
|
|
} |
|
949
|
|
|
|
|
|
|
else { |
|
950
|
94
|
|
|
|
|
204
|
$frag->appendChild($node->firstChild); |
|
951
|
|
|
|
|
|
|
} |
|
952
|
134
|
|
|
|
|
307
|
$node->removeChild($node->firstChild); |
|
953
|
|
|
|
|
|
|
} |
|
954
|
38
|
|
|
|
|
93
|
$row->appendChild |
|
955
|
|
|
|
|
|
|
($self->_createMmlNode('mtd', $frag)); |
|
956
|
38
|
100
|
|
|
|
86
|
if ($newFrag->childNodes > 2) { |
|
957
|
|
|
|
|
|
|
# remove ) |
|
958
|
20
|
|
|
|
|
53
|
$newFrag->removeChild($newFrag->firstChild); |
|
959
|
|
|
|
|
|
|
# remove , |
|
960
|
20
|
|
|
|
|
65
|
$newFrag->removeChild($newFrag->firstChild); |
|
961
|
|
|
|
|
|
|
} |
|
962
|
|
|
|
|
|
|
$table->appendChild |
|
963
|
38
|
|
|
|
|
115
|
($self->_createMmlNode('mtr', $row)); |
|
964
|
|
|
|
|
|
|
} |
|
965
|
18
|
|
|
|
|
52
|
$node = $self->_createMmlNode('mtable', $table); |
|
966
|
18
|
100
|
|
|
|
83
|
$node->setAttribute('columnalign', 'left') |
|
967
|
|
|
|
|
|
|
if $symbol->{invisible}; |
|
968
|
18
|
|
|
|
|
60
|
$newFrag->replaceChild($node, $newFrag->firstChild); |
|
969
|
|
|
|
|
|
|
} |
|
970
|
|
|
|
|
|
|
} |
|
971
|
|
|
|
|
|
|
} |
|
972
|
|
|
|
|
|
|
} |
|
973
|
434
|
|
|
|
|
1170
|
$str = _removeCharsAndBlanks($str, length $input); |
|
974
|
434
|
100
|
|
|
|
1743
|
if (! $symbol->{invisible}) { |
|
975
|
390
|
|
|
|
|
1150
|
$node = $self->_createMmlNode |
|
976
|
|
|
|
|
|
|
('mo', $self->_createTextNode($symbol->{output})); |
|
977
|
390
|
|
|
|
|
934
|
$newFrag->appendChild($node); |
|
978
|
|
|
|
|
|
|
} |
|
979
|
|
|
|
|
|
|
} |
|
980
|
994
|
|
|
|
|
3805
|
return $newFrag, $str; |
|
981
|
|
|
|
|
|
|
} |
|
982
|
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
# Parses an I expression |
|
984
|
|
|
|
|
|
|
# Arguments: string to parse |
|
985
|
|
|
|
|
|
|
# Returns: parsed node (if successful), remaining unparsed string |
|
986
|
|
|
|
|
|
|
sub _parseIexpr : method { |
|
987
|
2431
|
|
|
2431
|
|
6432
|
my ($self, $str) = @_; |
|
988
|
2431
|
|
|
|
|
4376
|
$str = _removeCharsAndBlanks($str, 0); |
|
989
|
2431
|
|
|
|
|
6322
|
my ($in1, $sym1) = $self->_getSymbol($str); |
|
990
|
2431
|
|
|
|
|
3433
|
my $node; |
|
991
|
2431
|
|
|
|
|
6012
|
($node, $str) = $self->_parseSexpr($str); |
|
992
|
2431
|
|
|
|
|
7663
|
my ($input, $symbol) = $self->_getSymbol($str); |
|
993
|
2431
|
100
|
100
|
|
|
22163
|
if (defined $symbol && $symbol->{ttype} eq 'INFIX' && $input ne '/') { |
|
|
|
|
100
|
|
|
|
|
|
994
|
|
|
|
|
|
|
# if (symbol.input == "/") result = AMparseIexpr(str); else ... |
|
995
|
224
|
|
|
|
|
590
|
$str = _removeCharsAndBlanks($str, length $input); |
|
996
|
224
|
|
|
|
|
621
|
my @result = $self->_parseSexpr($str); |
|
997
|
224
|
50
|
|
|
|
661
|
if ($result[0]) { |
|
998
|
224
|
|
|
|
|
805
|
_removeBrackets($result[0]); |
|
999
|
|
|
|
|
|
|
} |
|
1000
|
|
|
|
|
|
|
else { # show box in place of missing argument |
|
1001
|
0
|
|
|
|
|
0
|
$result[0] = $self->_createMmlNode |
|
1002
|
|
|
|
|
|
|
('mo', $self->_createTextNode("A1;")); |
|
1003
|
|
|
|
|
|
|
} |
|
1004
|
224
|
|
|
|
|
599
|
$str = $result[1]; |
|
1005
|
224
|
100
|
|
|
|
887
|
if ($input eq '_') { |
|
|
|
50
|
|
|
|
|
|
|
1006
|
134
|
|
|
|
|
601
|
my ($in2, $sym2) = $self->_getSymbol($str); |
|
1007
|
134
|
|
|
|
|
330
|
my $underover = $sym1->{ttype} eq 'UNDEROVER'; |
|
1008
|
134
|
100
|
|
|
|
442
|
if ($in2 eq '^') { |
|
1009
|
54
|
|
|
|
|
165
|
$str = _removeCharsAndBlanks($str, length $in2); |
|
1010
|
54
|
|
|
|
|
164
|
my @res2 = $self->_parseSexpr($str); |
|
1011
|
54
|
|
|
|
|
373
|
_removeBrackets($res2[0]); |
|
1012
|
54
|
|
|
|
|
118
|
$str = $res2[1]; |
|
1013
|
54
|
100
|
|
|
|
231
|
$node = $self->_createMmlNode |
|
1014
|
|
|
|
|
|
|
($underover ? 'munderover' : 'msubsup', $node); |
|
1015
|
54
|
|
|
|
|
156
|
$node->appendChild($result[0]); |
|
1016
|
54
|
|
|
|
|
265
|
$node->appendChild($res2[0]); |
|
1017
|
54
|
|
|
|
|
116
|
$node = $self->_createMmlNode('mrow',$node); # so sum does not stretch |
|
1018
|
|
|
|
|
|
|
} |
|
1019
|
|
|
|
|
|
|
else { |
|
1020
|
80
|
100
|
|
|
|
249
|
$node = $self->_createMmlNode |
|
1021
|
|
|
|
|
|
|
($underover ? 'munder' : 'msub', $node); |
|
1022
|
80
|
|
|
|
|
205
|
$node->appendChild($result[0]); |
|
1023
|
|
|
|
|
|
|
} |
|
1024
|
|
|
|
|
|
|
} |
|
1025
|
|
|
|
|
|
|
elsif ($input eq '^') { |
|
1026
|
90
|
|
|
|
|
214
|
my ($in2, $sym2) = $self->_getSymbol($str); |
|
1027
|
90
|
|
|
|
|
225
|
my $underover = $sym1->{ttype} eq 'UNDEROVER'; |
|
1028
|
90
|
100
|
|
|
|
184
|
if ($in2 eq '_') { |
|
1029
|
2
|
|
|
|
|
8
|
$str = _removeCharsAndBlanks($str, length $in2); |
|
1030
|
2
|
|
|
|
|
7
|
my @res2 = $self->_parseSexpr($str); |
|
1031
|
2
|
|
|
|
|
5
|
_removeBrackets($res2[0]); |
|
1032
|
2
|
|
|
|
|
3
|
$str = $res2[1]; |
|
1033
|
2
|
50
|
|
|
|
14
|
$node = $self->_createMmlNode |
|
1034
|
|
|
|
|
|
|
($underover ? 'munderover' : 'msubsup', $node); |
|
1035
|
2
|
|
|
|
|
5
|
$node->appendChild($res2[0]); |
|
1036
|
2
|
|
|
|
|
5
|
$node->appendChild($result[0]); |
|
1037
|
2
|
|
|
|
|
6
|
$node = $self->_createMmlNode('mrow',$node); # so sum does not stretch |
|
1038
|
|
|
|
|
|
|
} |
|
1039
|
|
|
|
|
|
|
else { |
|
1040
|
88
|
50
|
|
|
|
250
|
$node = $self->_createMmlNode |
|
1041
|
|
|
|
|
|
|
($underover ? 'mover' : 'msup', $node); |
|
1042
|
88
|
|
|
|
|
194
|
$node->appendChild($result[0]); |
|
1043
|
|
|
|
|
|
|
} |
|
1044
|
|
|
|
|
|
|
} |
|
1045
|
|
|
|
|
|
|
else { |
|
1046
|
0
|
|
|
|
|
0
|
$node = $self->_createMmlNode($symbol->{tag}, $node); |
|
1047
|
0
|
|
|
|
|
0
|
$node->appendChild($result[0]); |
|
1048
|
|
|
|
|
|
|
} |
|
1049
|
|
|
|
|
|
|
} |
|
1050
|
2431
|
|
|
|
|
10306
|
return $node, $str; |
|
1051
|
|
|
|
|
|
|
} |
|
1052
|
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
# Parses an S expression |
|
1054
|
|
|
|
|
|
|
# Arguments: string to parse |
|
1055
|
|
|
|
|
|
|
# Returns: parsed node (if successful), remaining unparsed string |
|
1056
|
|
|
|
|
|
|
sub _parseSexpr : method { |
|
1057
|
2941
|
|
|
2941
|
|
17586
|
my ($self, $str) = @_; |
|
1058
|
2941
|
|
|
|
|
24516
|
my $newFrag = $self->_createDocumentFragment(); |
|
1059
|
2941
|
|
|
|
|
6524
|
$str = _removeCharsAndBlanks($str, 0); |
|
1060
|
2941
|
|
|
|
|
7787
|
my ($input, $symbol) = $self->_getSymbol($str); |
|
1061
|
2941
|
100
|
100
|
|
|
31538
|
return (undef, $str) |
|
|
|
|
66
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
if ! defined $symbol || |
|
1063
|
|
|
|
|
|
|
$symbol->{ttype} eq 'RIGHTBRACKET' && $self->{nestingDepth} > 0; |
|
1064
|
2897
|
100
|
|
|
|
8364
|
if ($symbol->{ttype} eq 'DEFINITION') { |
|
1065
|
24
|
|
|
|
|
83
|
$str = $symbol->{output} . _removeCharsAndBlanks($str, length $input); |
|
1066
|
24
|
|
|
|
|
62
|
($input, $symbol) = $self->_getSymbol($str); |
|
1067
|
|
|
|
|
|
|
} |
|
1068
|
2897
|
|
|
|
|
4225
|
my $ttype = $symbol->{ttype}; |
|
1069
|
2897
|
100
|
|
|
|
16652
|
if ($ttype =~ /UNDEROVER|CONST/) { |
|
1070
|
2167
|
|
|
|
|
5046
|
$str = _removeCharsAndBlanks($str, length $input); |
|
1071
|
|
|
|
|
|
|
return |
|
1072
|
2167
|
|
|
|
|
8130
|
$self->_createMmlNode($symbol->{tag}, |
|
1073
|
|
|
|
|
|
|
$self->_createTextNode($symbol->{output})), |
|
1074
|
|
|
|
|
|
|
$str; |
|
1075
|
|
|
|
|
|
|
} |
|
1076
|
730
|
100
|
|
|
|
2379
|
if ($ttype eq 'LEFTBRACKET') { |
|
1077
|
434
|
|
|
|
|
716
|
$self->{nestingDepth}++; |
|
1078
|
434
|
|
|
|
|
922
|
$str = _removeCharsAndBlanks($str, length $input); |
|
1079
|
434
|
|
|
|
|
1791
|
my @result = $self->_parseExpr($str, 1); |
|
1080
|
434
|
|
|
|
|
1348
|
$self->{nestingDepth}--; |
|
1081
|
434
|
|
|
|
|
468
|
my $node; |
|
1082
|
434
|
100
|
|
|
|
856
|
if ($symbol->{invisible}) { |
|
1083
|
44
|
|
|
|
|
161
|
$node = $self->_createMmlNode('mrow', $result[0]); |
|
1084
|
|
|
|
|
|
|
} |
|
1085
|
|
|
|
|
|
|
else { |
|
1086
|
390
|
|
|
|
|
1611
|
$node = $self->_createMmlNode |
|
1087
|
|
|
|
|
|
|
('mo', $self->_createTextNode($symbol->{output})); |
|
1088
|
390
|
|
|
|
|
963
|
$node = $self->_createMmlNode('mrow', $node); |
|
1089
|
390
|
|
|
|
|
1018
|
$node->appendChild($result[0]); |
|
1090
|
|
|
|
|
|
|
} |
|
1091
|
434
|
|
|
|
|
2954
|
return $node, $result[1]; |
|
1092
|
|
|
|
|
|
|
} |
|
1093
|
296
|
100
|
|
|
|
835
|
if ($ttype eq 'TEXT') { |
|
1094
|
36
|
100
|
|
|
|
86
|
$str = _removeCharsAndBlanks($str, length $input) unless $input eq '"'; |
|
1095
|
36
|
|
|
|
|
43
|
my $st; |
|
1096
|
36
|
100
|
100
|
|
|
378
|
($input, $st) = ($1, $2) |
|
1097
|
|
|
|
|
|
|
if $str =~ /^(\"()\")/ || $str =~ /^(\"((?:\\\\|\\\"|.)+?)\")/; |
|
1098
|
36
|
100
|
33
|
|
|
311
|
($input, $st) = ($1, $2) |
|
|
|
|
66
|
|
|
|
|
|
1099
|
|
|
|
|
|
|
if ($str =~ /^(\((.*?)\))/ || |
|
1100
|
|
|
|
|
|
|
$str =~ /^(\[(.*?)\])/ || |
|
1101
|
|
|
|
|
|
|
$str =~ /^(\{(.*?)\})/); |
|
1102
|
36
|
50
|
|
|
|
66
|
($input, $st) = ($str) x 2 unless defined $st; |
|
1103
|
36
|
100
|
|
|
|
103
|
if (substr($st, 0, 1) eq ' ') { |
|
1104
|
4
|
|
|
|
|
13
|
my $node = $self->_createElementMathML('mspace'); |
|
1105
|
4
|
|
|
|
|
13
|
$node->setAttribute(width=>'1ex'); |
|
1106
|
4
|
|
|
|
|
8
|
$newFrag->appendChild($node); |
|
1107
|
|
|
|
|
|
|
} |
|
1108
|
|
|
|
|
|
|
$newFrag->appendChild |
|
1109
|
36
|
|
|
|
|
100
|
($self->_createMmlNode($symbol->{tag}, |
|
1110
|
|
|
|
|
|
|
$self->_createTextNode($st))); |
|
1111
|
36
|
100
|
|
|
|
113
|
if (substr($st, -1) eq ' ') { |
|
1112
|
6
|
|
|
|
|
14
|
my $node = $self->_createElementMathML('mspace'); |
|
1113
|
6
|
|
|
|
|
14
|
$node->setAttribute(width=>'1ex'); |
|
1114
|
6
|
|
|
|
|
11
|
$newFrag->appendChild($node); |
|
1115
|
|
|
|
|
|
|
} |
|
1116
|
36
|
|
|
|
|
119
|
$str = _removeCharsAndBlanks($str, length $input); |
|
1117
|
36
|
|
|
|
|
92
|
return $self->_createMmlNode('mrow', $newFrag), $str; |
|
1118
|
|
|
|
|
|
|
} |
|
1119
|
260
|
100
|
|
|
|
561
|
if ($ttype eq 'UNARY') { |
|
1120
|
180
|
|
|
|
|
427
|
$str = _removeCharsAndBlanks($str, length $input); |
|
1121
|
180
|
|
|
|
|
1297
|
my @result = $self->_parseSexpr($str); |
|
1122
|
180
|
100
|
|
|
|
570
|
return ($self->_createMmlNode |
|
1123
|
|
|
|
|
|
|
($symbol->{tag}, |
|
1124
|
|
|
|
|
|
|
$self->_createTextNode($symbol->{output})), $str) |
|
1125
|
|
|
|
|
|
|
if ! defined $result[0]; |
|
1126
|
150
|
100
|
|
|
|
388
|
if ($symbol->{func}) { |
|
1127
|
86
|
100
|
|
|
|
377
|
return ($self->_createMmlNode |
|
1128
|
|
|
|
|
|
|
($symbol->{tag}, |
|
1129
|
|
|
|
|
|
|
$self->_createTextNode($symbol->{output})), $str) |
|
1130
|
|
|
|
|
|
|
if $str =~ m!^[\^_/|]!; |
|
1131
|
72
|
|
|
|
|
254
|
my $node = $self->_createMmlNode |
|
1132
|
|
|
|
|
|
|
('mrow', $self->_createMmlNode |
|
1133
|
|
|
|
|
|
|
($symbol->{tag}, $self->_createTextNode($symbol->{output}))); |
|
1134
|
72
|
|
|
|
|
380
|
$node->appendChild($result[0]); |
|
1135
|
72
|
|
|
|
|
365
|
return $node, $result[1]; |
|
1136
|
|
|
|
|
|
|
} |
|
1137
|
64
|
|
|
|
|
200
|
_removeBrackets($result[0]); |
|
1138
|
64
|
100
|
|
|
|
179
|
if ($symbol->{acc}) { # accent |
|
1139
|
20
|
|
|
|
|
159
|
my $node = $self->_createMmlNode($symbol->{tag}, $result[0]); |
|
1140
|
20
|
|
|
|
|
53
|
$node->appendChild |
|
1141
|
|
|
|
|
|
|
($self->_createMmlNode |
|
1142
|
|
|
|
|
|
|
('mo', $self->_createTextNode($symbol->{output}))); |
|
1143
|
20
|
|
|
|
|
118
|
return $node, $result[1]; |
|
1144
|
|
|
|
|
|
|
} |
|
1145
|
44
|
100
|
|
|
|
138
|
if ($symbol->{atname}) { # font change command |
|
1146
|
24
|
100
|
66
|
|
|
175
|
if ($self->{attr}{ForMoz} && $symbol->{codes}) { |
|
1147
|
12
|
|
|
|
|
37
|
my @childNodes = $result[0]->childNodes; |
|
1148
|
12
|
|
|
|
|
32
|
my $nodeName = $result[0]->nodeName; |
|
1149
|
12
|
|
|
|
|
45
|
for (my $i=0; $i<@childNodes; $i++) { |
|
1150
|
18
|
50
|
66
|
|
|
43
|
if ($childNodes[$i]->nodeName eq 'mi'||$nodeName eq 'mi') { |
|
1151
|
18
|
100
|
|
|
|
73
|
my $st = $nodeName eq 'mi' ? |
|
1152
|
|
|
|
|
|
|
$result[0] ->firstChild->nodeValue : |
|
1153
|
|
|
|
|
|
|
$childNodes[$i]->firstChild->nodeValue; |
|
1154
|
18
|
|
|
|
|
89
|
$st =~ s/([A-Z])/sprintf "%X;",$symbol->{codes}[ord($1)-65]/ge; |
|
|
18
|
|
|
|
|
105
|
|
|
1155
|
18
|
100
|
|
|
|
157
|
if ($nodeName eq 'mi') { |
|
1156
|
6
|
|
|
|
|
12
|
$result[0] = $self->_createTextNode($st); |
|
1157
|
|
|
|
|
|
|
} |
|
1158
|
|
|
|
|
|
|
else { |
|
1159
|
12
|
|
|
|
|
32
|
$result[0]->replaceChild |
|
1160
|
|
|
|
|
|
|
($self->_createTextNode($st), $childNodes[$i]); |
|
1161
|
|
|
|
|
|
|
} |
|
1162
|
|
|
|
|
|
|
} |
|
1163
|
|
|
|
|
|
|
} |
|
1164
|
|
|
|
|
|
|
} |
|
1165
|
24
|
|
|
|
|
274
|
my $node = $self->_createMmlNode($symbol->{tag}, $result[0]); |
|
1166
|
24
|
|
|
|
|
160
|
$node->setAttribute($symbol->{atname}=>$symbol->{atval}); |
|
1167
|
24
|
|
|
|
|
149
|
return $node, $result[1]; |
|
1168
|
|
|
|
|
|
|
} |
|
1169
|
20
|
|
|
|
|
74
|
return $self->_createMmlNode($symbol->{tag}, $result[0]), $result[1]; |
|
1170
|
|
|
|
|
|
|
} |
|
1171
|
80
|
100
|
|
|
|
215
|
if ($ttype eq 'BINARY') { |
|
1172
|
24
|
|
|
|
|
66
|
$str = _removeCharsAndBlanks($str, length $input); |
|
1173
|
24
|
|
|
|
|
66
|
my @result = $self->_parseSexpr($str); |
|
1174
|
24
|
50
|
|
|
|
74
|
return ($self->_createMmlNode |
|
1175
|
|
|
|
|
|
|
('mo', $self->_createTextNode($input)), $str) |
|
1176
|
|
|
|
|
|
|
if ! defined $result[0]; |
|
1177
|
24
|
|
|
|
|
64
|
_removeBrackets($result[0]); |
|
1178
|
24
|
|
|
|
|
91
|
my @result2 = $self->_parseSexpr($result[1]); |
|
1179
|
24
|
50
|
|
|
|
79
|
return ($self->_createMmlNode |
|
1180
|
|
|
|
|
|
|
('mo', $self->_createTextNode($input)), $str) |
|
1181
|
|
|
|
|
|
|
if ! defined $result2[0]; |
|
1182
|
24
|
|
|
|
|
66
|
_removeBrackets($result2[0]); |
|
1183
|
24
|
100
|
|
|
|
112
|
if ($input =~ /new(command|symbol)/) { |
|
1184
|
10
|
|
|
|
|
28
|
my $what = $1; |
|
1185
|
|
|
|
|
|
|
# Look for text in both arguments |
|
1186
|
10
|
|
|
|
|
18
|
my $text1 = $result[0]; |
|
1187
|
10
|
|
|
|
|
15
|
my $haveTextArgs = 0; |
|
1188
|
10
|
|
|
|
|
26
|
$text1 = $text1->firstChild while $text1->nodeName eq 'mrow'; |
|
1189
|
10
|
50
|
|
|
|
26
|
if ($text1->nodeName eq 'mtext') { |
|
1190
|
10
|
|
|
|
|
12
|
my $text2 = $result2[0]; |
|
1191
|
10
|
|
|
|
|
22
|
$text2 = $text2->firstChild while $text2->nodeName eq 'mrow'; |
|
1192
|
10
|
|
|
|
|
24
|
my $latex; |
|
1193
|
10
|
100
|
66
|
|
|
26
|
if ($result2[0]->childNodes > 1 && $input eq 'newsymbol') { |
|
1194
|
|
|
|
|
|
|
# Process the latex string for a newsymbol |
|
1195
|
4
|
|
|
|
|
14
|
my $latexdef = $result2[0]->child(1); |
|
1196
|
4
|
|
|
|
|
13
|
$latexdef = $latexdef->firstChild |
|
1197
|
|
|
|
|
|
|
while $latexdef->nodeName eq 'mrow'; |
|
1198
|
4
|
|
|
|
|
10
|
$latex = $latexdef->firstChild->nodeValue; |
|
1199
|
|
|
|
|
|
|
} |
|
1200
|
10
|
100
|
|
|
|
54
|
if ($text2->nodeName eq 'mtext') { |
|
1201
|
8
|
100
|
|
|
|
23
|
$self->{Definitions}{$text1->firstChild->nodeValue} = { |
|
1202
|
|
|
|
|
|
|
tag =>'mo', |
|
1203
|
|
|
|
|
|
|
output=>$text2->firstChild->nodeValue, |
|
1204
|
|
|
|
|
|
|
ttype =>$what eq 'symbol' ? 'CONST' : 'DEFINITION', |
|
1205
|
|
|
|
|
|
|
}; |
|
1206
|
12
|
|
|
|
|
48
|
$self->{Definition_RE} = join '|', |
|
1207
|
8
|
|
|
|
|
56
|
map("\Q$_\E", sort {length($b) - length($a)} |
|
1208
|
8
|
|
|
|
|
24
|
keys %{$self->{Definitions}}); |
|
1209
|
8
|
100
|
|
|
|
36
|
$self->{Latex}{$text2->firstChild->nodeValue} = $latex |
|
1210
|
|
|
|
|
|
|
if defined $latex; |
|
1211
|
8
|
|
|
|
|
20
|
$haveTextArgs = 1; |
|
1212
|
|
|
|
|
|
|
} |
|
1213
|
|
|
|
|
|
|
} |
|
1214
|
10
|
100
|
|
|
|
27
|
if (! $haveTextArgs) { |
|
1215
|
2
|
|
|
|
|
6
|
$newFrag->appendChild($self->_createMmlNode |
|
1216
|
|
|
|
|
|
|
('mo', $self->_createTextNode($input)), |
|
1217
|
|
|
|
|
|
|
$result[0], $result2[0]); |
|
1218
|
2
|
|
|
|
|
6
|
return $self->_createMmlNode('mrow', $newFrag), $result2[1]; |
|
1219
|
|
|
|
|
|
|
} |
|
1220
|
8
|
|
|
|
|
46
|
return undef, $result2[1]; |
|
1221
|
|
|
|
|
|
|
} |
|
1222
|
14
|
100
|
|
|
|
63
|
if ($input =~ /root|stackrel/) { |
|
1223
|
6
|
|
|
|
|
14
|
$newFrag->appendChild($result2[0]); |
|
1224
|
|
|
|
|
|
|
} |
|
1225
|
14
|
|
|
|
|
44
|
$newFrag->appendChild($result[0]); |
|
1226
|
14
|
100
|
|
|
|
34
|
if ($input eq 'frac') { |
|
1227
|
8
|
|
|
|
|
18
|
$newFrag->appendChild($result2[0]); |
|
1228
|
|
|
|
|
|
|
} |
|
1229
|
14
|
|
|
|
|
42
|
return $self->_createMmlNode($symbol->{tag}, $newFrag), $result2[1]; |
|
1230
|
|
|
|
|
|
|
} |
|
1231
|
56
|
100
|
|
|
|
138
|
if ($ttype eq 'INFIX') { |
|
1232
|
16
|
|
|
|
|
36
|
$str = _removeCharsAndBlanks($str, length $input); |
|
1233
|
16
|
|
|
|
|
50
|
return $self->_createMmlNode |
|
1234
|
|
|
|
|
|
|
('mo', $self->_createTextNode($symbol->{output})), $str; |
|
1235
|
|
|
|
|
|
|
} |
|
1236
|
40
|
100
|
|
|
|
152
|
if ($ttype eq 'SPACE') { |
|
1237
|
14
|
|
|
|
|
54
|
$str = _removeCharsAndBlanks($str, length $input); |
|
1238
|
14
|
|
|
|
|
39
|
my $node = $self->_createElementMathML('mspace'); |
|
1239
|
14
|
|
|
|
|
41
|
$node->setAttribute('width', '1ex'); |
|
1240
|
14
|
|
|
|
|
36
|
$newFrag->appendChild($node); |
|
1241
|
14
|
|
|
|
|
47
|
$newFrag->appendChild |
|
1242
|
|
|
|
|
|
|
($self->_createMmlNode($symbol->{tag}, |
|
1243
|
|
|
|
|
|
|
$self->_createTextNode($symbol->{output}))); |
|
1244
|
14
|
|
|
|
|
34
|
$node = $self->_createElementMathML('mspace'); |
|
1245
|
14
|
|
|
|
|
36
|
$node->setAttribute('width', '1ex'); |
|
1246
|
14
|
|
|
|
|
34
|
$newFrag->appendChild($node); |
|
1247
|
14
|
|
|
|
|
35
|
return $self->_createMmlNode('mrow', $newFrag), $str; |
|
1248
|
|
|
|
|
|
|
} |
|
1249
|
26
|
100
|
|
|
|
63
|
if ($ttype eq 'LEFTRIGHT') { |
|
1250
|
12
|
|
|
|
|
20
|
$self->{nestingDepth}++; |
|
1251
|
12
|
|
|
|
|
29
|
$str = _removeCharsAndBlanks($str, length $input); |
|
1252
|
12
|
|
|
|
|
35
|
my @result = $self->_parseExpr($str, 0); |
|
1253
|
12
|
|
|
|
|
34
|
$self->{nestingDepth}--; |
|
1254
|
12
|
50
|
|
|
|
40
|
my $st = $result[0]->lastChild ? |
|
1255
|
|
|
|
|
|
|
$result[0]->lastChild->firstChild->nodeValue : ''; |
|
1256
|
12
|
|
|
|
|
41
|
my $node = $self->_createMmlNode |
|
1257
|
|
|
|
|
|
|
('mo',$self->_createTextNode($symbol->{output})); |
|
1258
|
12
|
|
|
|
|
39
|
$node = $self->_createMmlNode('mrow', $node); |
|
1259
|
12
|
50
|
|
|
|
40
|
if ($st eq '|') { # it's an absolute value subterm |
|
1260
|
12
|
|
|
|
|
27
|
$node->appendChild($result[0]); |
|
1261
|
12
|
|
|
|
|
74
|
return $node, $result[1]; |
|
1262
|
|
|
|
|
|
|
} |
|
1263
|
|
|
|
|
|
|
# the "|" is a \mid |
|
1264
|
0
|
|
|
|
|
0
|
return $node, $str; |
|
1265
|
|
|
|
|
|
|
} |
|
1266
|
14
|
100
|
|
|
|
29
|
if ($ttype eq 'NOP') { |
|
1267
|
2
|
|
|
|
|
7
|
$str = _removeCharsAndBlanks($str, length $input); |
|
1268
|
2
|
|
|
|
|
8
|
return $self->_parseSexpr($str); |
|
1269
|
|
|
|
|
|
|
} |
|
1270
|
12
|
|
|
|
|
28
|
$str = _removeCharsAndBlanks($str, length $input); |
|
1271
|
12
|
|
|
|
|
44
|
return $self->_createMmlNode |
|
1272
|
|
|
|
|
|
|
($symbol->{tag}, # it's a constant |
|
1273
|
|
|
|
|
|
|
$self->_createTextNode($symbol->{output})), $str; |
|
1274
|
|
|
|
|
|
|
} |
|
1275
|
|
|
|
|
|
|
|
|
1276
|
|
|
|
|
|
|
# Removes brackets at the beginning or end of an mrow node |
|
1277
|
|
|
|
|
|
|
# Arguments: node object |
|
1278
|
|
|
|
|
|
|
# Returns: None |
|
1279
|
|
|
|
|
|
|
# Side-effects: may change children of node object |
|
1280
|
|
|
|
|
|
|
sub _removeBrackets { |
|
1281
|
584
|
|
|
584
|
|
881
|
my ($node) = @_; |
|
1282
|
584
|
100
|
|
|
|
1497
|
if ($node->nodeName eq 'mrow') { |
|
1283
|
242
|
|
|
|
|
779
|
my $st = $node->firstChild->firstChild->nodeValue; |
|
1284
|
242
|
100
|
|
|
|
1487
|
$node->removeChild($node->firstChild) if $st =~ /^[\(\[\{]$/; |
|
1285
|
242
|
|
|
|
|
725
|
$st = $node->lastChild->firstChild->nodeValue; |
|
1286
|
242
|
100
|
|
|
|
1142
|
$node->removeChild($node->lastChild) if $st =~ /^[\)\]\}]$/; |
|
1287
|
|
|
|
|
|
|
} |
|
1288
|
|
|
|
|
|
|
} |
|
1289
|
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
# Removes the first n characters and any following blanks |
|
1291
|
|
|
|
|
|
|
# Arguments: string, n |
|
1292
|
|
|
|
|
|
|
# Returns: resultant string |
|
1293
|
|
|
|
|
|
|
sub _removeCharsAndBlanks { |
|
1294
|
11440
|
|
|
11440
|
|
19864
|
my ($str, $n) = @_; |
|
1295
|
11440
|
100
|
|
|
|
36692
|
my $st = substr($str, |
|
1296
|
|
|
|
|
|
|
substr($str, $n) =~ /^\\[^\\ ,!]/ ? $n+1 : $n); |
|
1297
|
11440
|
|
|
|
|
27209
|
$st =~ s/^[\x00-\x20]+//; |
|
1298
|
11440
|
|
|
|
|
27194
|
return $st; |
|
1299
|
|
|
|
|
|
|
} |
|
1300
|
|
|
|
|
|
|
|
|
1301
|
|
|
|
|
|
|
# Removes outermost parenthesis |
|
1302
|
|
|
|
|
|
|
# Arguments: string |
|
1303
|
|
|
|
|
|
|
# Returns: string with parentheses removed |
|
1304
|
|
|
|
|
|
|
sub _unparen { |
|
1305
|
0
|
|
|
0
|
|
0
|
my ($s) = @_; |
|
1306
|
0
|
|
|
|
|
0
|
$s =~ s!^()[\(\[\{]!$1!; |
|
1307
|
0
|
|
|
|
|
0
|
$s =~ s![\)\]\}]()$!$1!; |
|
1308
|
0
|
|
|
|
|
0
|
$s; |
|
1309
|
|
|
|
|
|
|
} |
|
1310
|
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
BEGIN { |
|
1312
|
1
|
|
|
1
|
|
233
|
my %Conversion = ('<'=>'lt', '>'=>'gt', '"'=>'quot', '&'=>'amp'); |
|
1313
|
|
|
|
|
|
|
|
|
1314
|
|
|
|
|
|
|
# Encodes special xml characters |
|
1315
|
|
|
|
|
|
|
# Arguments: string |
|
1316
|
|
|
|
|
|
|
# Returns: encoded string |
|
1317
|
|
|
|
|
|
|
sub _xml_encode { |
|
1318
|
1131
|
|
|
1131
|
|
1512
|
my ($s) = @_; |
|
1319
|
1131
|
|
|
|
|
3238
|
$s =~ s/([<>\"&])/&$Conversion{$1};/g; |
|
1320
|
1131
|
|
|
|
|
5950
|
$s; |
|
1321
|
|
|
|
|
|
|
} |
|
1322
|
|
|
|
|
|
|
} |
|
1323
|
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
package Text::ASCIIMathML::Node; |
|
1325
|
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
{ |
|
1327
|
|
|
|
|
|
|
# Create a closure for the following attributes |
|
1328
|
|
|
|
|
|
|
my %parser_of; |
|
1329
|
|
|
|
|
|
|
|
|
1330
|
|
|
|
|
|
|
# Creates a new Text::ASCIIMathML::Node object |
|
1331
|
|
|
|
|
|
|
# Arguments: Text::ASCIIMathML object, optional tag |
|
1332
|
|
|
|
|
|
|
# Returns: new object |
|
1333
|
|
|
|
|
|
|
sub new { |
|
1334
|
9536
|
|
|
9536
|
|
22965
|
my ($class, $parser, $tag) = @_; |
|
1335
|
9536
|
|
|
|
|
42409
|
my $obj = bless { children=>[] }, $class; |
|
1336
|
9536
|
100
|
|
|
|
29418
|
if (defined $tag) { $obj->{tag} = $tag } |
|
|
5466
|
|
|
|
|
18195
|
|
|
1337
|
4070
|
|
|
|
|
10920
|
else { $obj->{frag} = 1 } |
|
1338
|
9536
|
|
|
|
|
39639
|
$parser_of{$obj} = $parser; |
|
1339
|
9536
|
|
|
|
|
31164
|
return $obj; |
|
1340
|
|
|
|
|
|
|
} |
|
1341
|
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
# Creates a new Text::ASCIIMathML::Node text object |
|
1343
|
|
|
|
|
|
|
# Arguments: Text::ASCIIMathML object, text |
|
1344
|
|
|
|
|
|
|
# Returns: new object |
|
1345
|
|
|
|
|
|
|
sub newText { |
|
1346
|
3193
|
|
|
3193
|
|
5115
|
my ($class, $parser, $text) = @_; |
|
1347
|
3193
|
|
|
|
|
20999
|
$text =~ s/^\s*(.*?)\s*$/$1/; # Delete leading/trailing spaces |
|
1348
|
3193
|
|
|
|
|
14451
|
my $obj = bless { text=>$text }, $class; |
|
1349
|
3193
|
|
|
|
|
14132
|
$parser_of{$obj} = $parser; |
|
1350
|
3193
|
|
|
|
|
10816
|
return $obj; |
|
1351
|
|
|
|
|
|
|
} |
|
1352
|
|
|
|
|
|
|
|
|
1353
|
|
|
|
|
|
|
my %Parent; |
|
1354
|
|
|
|
|
|
|
my $Null; |
|
1355
|
|
|
|
|
|
|
BEGIN { |
|
1356
|
1
|
|
|
1
|
|
8
|
$Null = new Text::ASCIIMathML::Node; |
|
1357
|
|
|
|
|
|
|
} |
|
1358
|
|
|
|
|
|
|
|
|
1359
|
|
|
|
|
|
|
# Appends one or more node objects to the children of an object |
|
1360
|
|
|
|
|
|
|
# Arguments: list of objects to append |
|
1361
|
|
|
|
|
|
|
# Returns: self |
|
1362
|
|
|
|
|
|
|
sub appendChild : method { |
|
1363
|
9329
|
|
|
9329
|
|
24289
|
my $self = shift; |
|
1364
|
9329
|
100
|
|
|
|
45126
|
my @new = map $_->{frag} ? @{$_->{children}} : $_, @_; |
|
|
1194
|
|
|
|
|
3888
|
|
|
1365
|
9329
|
|
|
|
|
11451
|
push @{$self->{children}}, @new; |
|
|
9329
|
|
|
|
|
21513
|
|
|
1366
|
9329
|
|
|
|
|
14245
|
map do {$Parent{$_} = $self}, @new; |
|
|
11134
|
|
|
|
|
62885
|
|
|
1367
|
9329
|
|
|
|
|
33888
|
return $self; |
|
1368
|
|
|
|
|
|
|
} |
|
1369
|
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
# Returns a the value for an attribute of a node object |
|
1371
|
|
|
|
|
|
|
# Arguments: Attribute name |
|
1372
|
|
|
|
|
|
|
# Returns: Value for the attribute |
|
1373
|
|
|
|
|
|
|
sub attribute { |
|
1374
|
0
|
|
|
0
|
|
0
|
my ($self, $attr) = @_; |
|
1375
|
0
|
|
|
|
|
0
|
return $self->{attr}{$attr}; |
|
1376
|
|
|
|
|
|
|
} |
|
1377
|
|
|
|
|
|
|
|
|
1378
|
|
|
|
|
|
|
# Returns a list of the attributes of a node object |
|
1379
|
|
|
|
|
|
|
# Arguments: None |
|
1380
|
|
|
|
|
|
|
# Returns: Array of attribute names |
|
1381
|
|
|
|
|
|
|
sub attributeList { |
|
1382
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
|
1383
|
0
|
0
|
|
|
|
0
|
return $self->{attrlist} ? @{$self->{attrlist}} : (); |
|
|
0
|
|
|
|
|
0
|
|
|
1384
|
|
|
|
|
|
|
} |
|
1385
|
|
|
|
|
|
|
|
|
1386
|
|
|
|
|
|
|
# Returns a child with a given index in the array of children of a node |
|
1387
|
|
|
|
|
|
|
# Arguments: index |
|
1388
|
|
|
|
|
|
|
# Returns: Array of node objects |
|
1389
|
|
|
|
|
|
|
sub child { |
|
1390
|
7
|
|
|
7
|
|
18
|
my ($self, $index) = @_; |
|
1391
|
7
|
100
|
66
|
|
|
28
|
return $self->{children} && @{$self->{children}} > $index ? |
|
1392
|
|
|
|
|
|
|
$self->{children}[$index] : $Null; |
|
1393
|
|
|
|
|
|
|
} |
|
1394
|
|
|
|
|
|
|
|
|
1395
|
|
|
|
|
|
|
# Returns an array of children of a node |
|
1396
|
|
|
|
|
|
|
# Arguments: None |
|
1397
|
|
|
|
|
|
|
# Returns: Array of node objects |
|
1398
|
|
|
|
|
|
|
sub childNodes { |
|
1399
|
1538
|
|
|
1538
|
|
6297
|
my ($self) = @_; |
|
1400
|
1538
|
50
|
|
|
|
3495
|
return $self->{children} ? @{$self->{children}} : (); |
|
|
1538
|
|
|
|
|
5238
|
|
|
1401
|
|
|
|
|
|
|
} |
|
1402
|
|
|
|
|
|
|
|
|
1403
|
|
|
|
|
|
|
# Returns the first child of a node; ignores any fragments |
|
1404
|
|
|
|
|
|
|
# Arguments: None |
|
1405
|
|
|
|
|
|
|
# Returns: node object or self |
|
1406
|
|
|
|
|
|
|
sub firstChild { |
|
1407
|
1812
|
|
|
1812
|
|
2392
|
my ($self) = @_; |
|
1408
|
1812
|
50
|
33
|
|
|
12316
|
return $self->{children} && @{$self->{children}} ? |
|
1409
|
|
|
|
|
|
|
$self->{children}[0] : $Null; |
|
1410
|
|
|
|
|
|
|
} |
|
1411
|
|
|
|
|
|
|
|
|
1412
|
|
|
|
|
|
|
# Returns true if the object is a fragment |
|
1413
|
|
|
|
|
|
|
# Arguments: None |
|
1414
|
|
|
|
|
|
|
# Returns: Boolean |
|
1415
|
|
|
|
|
|
|
sub isFragment { |
|
1416
|
0
|
|
|
0
|
|
0
|
return $_[0]->{frag}; |
|
1417
|
|
|
|
|
|
|
} |
|
1418
|
|
|
|
|
|
|
|
|
1419
|
|
|
|
|
|
|
# Returns true if the object is a named node |
|
1420
|
|
|
|
|
|
|
# Arguments: None |
|
1421
|
|
|
|
|
|
|
# Returns: Boolean |
|
1422
|
|
|
|
|
|
|
sub isNamed { |
|
1423
|
0
|
|
|
0
|
|
0
|
return $_[0]->{tag}; |
|
1424
|
|
|
|
|
|
|
} |
|
1425
|
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
# Returns true if the object is a text node |
|
1427
|
|
|
|
|
|
|
# Arguments: None |
|
1428
|
|
|
|
|
|
|
# Returns: Boolean |
|
1429
|
|
|
|
|
|
|
sub isText { |
|
1430
|
0
|
|
|
0
|
|
0
|
return defined $_[0]->{text}; |
|
1431
|
|
|
|
|
|
|
} |
|
1432
|
|
|
|
|
|
|
|
|
1433
|
|
|
|
|
|
|
# Returns the last child of a node |
|
1434
|
|
|
|
|
|
|
# Arguments: None |
|
1435
|
|
|
|
|
|
|
# Returns: node object or self |
|
1436
|
|
|
|
|
|
|
sub lastChild { |
|
1437
|
528
|
|
|
528
|
|
824
|
my ($self) = @_; |
|
1438
|
528
|
50
|
33
|
|
|
1373
|
return $self->{children} && @{$self->{children}} ? |
|
1439
|
|
|
|
|
|
|
$self->{children}[-1] : $Null; |
|
1440
|
|
|
|
|
|
|
} |
|
1441
|
|
|
|
|
|
|
|
|
1442
|
|
|
|
|
|
|
BEGIN { |
|
1443
|
|
|
|
|
|
|
# Creates closure for following "static" variables |
|
1444
|
1
|
|
|
1
|
|
966
|
my (%LatexSym, %LatexMover, %LatexFont, %LatexOp); |
|
1445
|
|
|
|
|
|
|
|
|
1446
|
|
|
|
|
|
|
# Returns a latex representation of a node object |
|
1447
|
|
|
|
|
|
|
# Arguments: None |
|
1448
|
|
|
|
|
|
|
# Returns: Text string |
|
1449
|
|
|
|
|
|
|
sub latex : method { |
|
1450
|
3689
|
|
|
3689
|
|
6898
|
my ($self) = @_; |
|
1451
|
|
|
|
|
|
|
|
|
1452
|
3689
|
|
|
|
|
11881
|
my $parser = $parser_of{$self}; |
|
1453
|
3689
|
100
|
|
|
|
14189
|
if (! %LatexSym) { |
|
1454
|
|
|
|
|
|
|
# Build the entity to latex symbol translator |
|
1455
|
1
|
|
|
|
|
4
|
my $amsymbol = Text::ASCIIMathML::_get_amsymbol_(); |
|
1456
|
1
|
|
|
|
|
58
|
foreach my $sym (keys %$amsymbol) { |
|
1457
|
203
|
100
|
100
|
|
|
1200
|
next unless (defined $amsymbol->{$sym}{output} && |
|
1458
|
|
|
|
|
|
|
$amsymbol->{$sym}{output} =~ /&\#x.*;/); |
|
1459
|
125
|
|
|
|
|
424
|
my ($output, $tex) = map $amsymbol->{$sym}{$_}, qw(output tex); |
|
1460
|
125
|
100
|
100
|
|
|
342
|
next if defined $LatexSym{$output} && ! $amsymbol->{$sym}{latex}; |
|
1461
|
118
|
100
|
|
|
|
217
|
$tex = $sym if $tex eq ''; |
|
1462
|
118
|
|
|
|
|
359
|
$LatexSym{$output} = "\\$tex"; |
|
1463
|
|
|
|
|
|
|
} |
|
1464
|
1
|
|
|
|
|
22
|
my %math_font = (bbb => 'mathds', |
|
1465
|
|
|
|
|
|
|
mathbb => 'mathds', |
|
1466
|
|
|
|
|
|
|
cc => 'cal', |
|
1467
|
|
|
|
|
|
|
mathcal => 'cal', |
|
1468
|
|
|
|
|
|
|
fr => 'mathfrak', |
|
1469
|
|
|
|
|
|
|
mathfrak => 'mathfrak', |
|
1470
|
|
|
|
|
|
|
); |
|
1471
|
|
|
|
|
|
|
# Add character codes |
|
1472
|
1
|
|
|
|
|
89
|
foreach my $coded (grep $amsymbol->{$_}{codes}, keys %$amsymbol) { |
|
1473
|
6
|
|
|
|
|
294
|
@LatexSym{map(sprintf("%X;", $_), |
|
1474
|
6
|
|
|
|
|
204
|
@{$amsymbol->{$coded}{codes}})} = |
|
1475
|
|
|
|
|
|
|
map("\\$math_font{$coded}\{$_}", ('A' .. 'Z')); |
|
1476
|
|
|
|
|
|
|
} |
|
1477
|
|
|
|
|
|
|
# Post-process protected symbols |
|
1478
|
1
|
|
|
|
|
116
|
$LatexSym{$_} =~ s/^\\\\/\\/ foreach keys %LatexSym; |
|
1479
|
1
|
|
|
|
|
20
|
%LatexMover = ('^' => '\hat', |
|
1480
|
|
|
|
|
|
|
'\overline' => '\overline', |
|
1481
|
|
|
|
|
|
|
'\to' => '\vec', |
|
1482
|
|
|
|
|
|
|
'\vec' => '\vec', |
|
1483
|
|
|
|
|
|
|
'\rightarrow' => '\vec', |
|
1484
|
|
|
|
|
|
|
'.' => '\dot', |
|
1485
|
|
|
|
|
|
|
'..' => '\ddot', |
|
1486
|
|
|
|
|
|
|
); |
|
1487
|
1
|
|
|
|
|
8
|
%LatexFont = (bold => '\bf', |
|
1488
|
|
|
|
|
|
|
'double-struck' => '\mathds', |
|
1489
|
|
|
|
|
|
|
fraktur => '\mathfrak', |
|
1490
|
|
|
|
|
|
|
monospace => '\tt', |
|
1491
|
|
|
|
|
|
|
'sans-serif' => '\sf', |
|
1492
|
|
|
|
|
|
|
script => '\cal', |
|
1493
|
|
|
|
|
|
|
); |
|
1494
|
1
|
|
|
|
|
12
|
%LatexOp = (if => '\mbox{if }', |
|
1495
|
|
|
|
|
|
|
lcm => '\mbox{lcm}', |
|
1496
|
|
|
|
|
|
|
newcommand => '\mbox{newcommand}', |
|
1497
|
|
|
|
|
|
|
"\\" => '\backslash', |
|
1498
|
|
|
|
|
|
|
'<' => '<', |
|
1499
|
|
|
|
|
|
|
'>' => '>', |
|
1500
|
|
|
|
|
|
|
'&' => '\&', |
|
1501
|
|
|
|
|
|
|
'...' => '\ldots', |
|
1502
|
|
|
|
|
|
|
); |
|
1503
|
|
|
|
|
|
|
} |
|
1504
|
3689
|
100
|
|
|
|
22347
|
if (defined $self->{text}) { |
|
1505
|
1294
|
|
|
|
|
2719
|
my $text = $self->{text}; |
|
1506
|
1294
|
|
|
|
|
2990
|
$text =~ s/([{}])/\\$1/; |
|
1507
|
1294
|
|
|
|
|
5353
|
$text =~ s/(&\#x.*?;)/ |
|
1508
|
260
|
50
|
|
|
|
2934
|
defined $parser->{Latex}{$1} ? $parser->{Latex}{$1} : |
|
|
|
100
|
|
|
|
|
|
|
1509
|
|
|
|
|
|
|
defined $LatexSym{$1} ? $LatexSym{$1} : $1/eg; |
|
1510
|
1294
|
|
|
|
|
1804
|
$text =~ s/([\#])/\\$1/; |
|
1511
|
1294
|
|
|
|
|
5252
|
return $text; |
|
1512
|
|
|
|
|
|
|
} |
|
1513
|
2395
|
|
|
|
|
4571
|
my $tag = $self->{tag}; |
|
1514
|
2395
|
|
|
|
|
2924
|
my @child_str; |
|
1515
|
2395
|
|
|
|
|
3084
|
my $child_str = ''; |
|
1516
|
2395
|
100
|
|
|
|
2787
|
if (@{$self->{children}}) { |
|
|
2395
|
|
|
|
|
7672
|
|
|
1517
|
2373
|
|
|
|
|
3314
|
foreach (@{$self->{children}}) { |
|
|
2373
|
|
|
|
|
5222
|
|
|
1518
|
3416
|
|
|
|
|
14150
|
push @child_str, $_->latex($parser); |
|
1519
|
|
|
|
|
|
|
} |
|
1520
|
|
|
|
|
|
|
} |
|
1521
|
|
|
|
|
|
|
|
|
1522
|
|
|
|
|
|
|
# mo |
|
1523
|
2395
|
100
|
|
|
|
12155
|
if ($tag eq 'mo') { |
|
1524
|
|
|
|
|
|
|
# Need to distinguish bmod from pmod |
|
1525
|
623
|
|
|
|
|
2028
|
my $parent = $self->parent; |
|
1526
|
623
|
100
|
66
|
|
|
2453
|
return $self eq $parent->child(1) && |
|
|
|
100
|
|
|
|
|
|
|
1527
|
|
|
|
|
|
|
$parent->firstChild->firstChild->{text} eq '(' |
|
1528
|
|
|
|
|
|
|
? '\pmod' : '\bmod' |
|
1529
|
|
|
|
|
|
|
if $child_str[0] eq 'mod'; |
|
1530
|
620
|
100
|
|
|
|
1532
|
return $LatexOp{$child_str[0]} if $LatexOp{$child_str[0]}; |
|
1531
|
597
|
100
|
|
|
|
6017
|
return $child_str[0] =~ /^\w+$/ ? "\\$child_str[0]" : $child_str[0]; |
|
1532
|
|
|
|
|
|
|
} |
|
1533
|
|
|
|
|
|
|
|
|
1534
|
|
|
|
|
|
|
# mrow |
|
1535
|
1772
|
100
|
|
|
|
3557
|
if ($tag eq 'mrow') { |
|
1536
|
279
|
|
|
|
|
1265
|
@child_str = grep $_ ne '', @child_str; |
|
1537
|
|
|
|
|
|
|
# Check for pmod function |
|
1538
|
279
|
100
|
100
|
|
|
1322
|
if (@child_str > 1 && $child_str[1] eq '\pmod') { |
|
1539
|
1
|
50
|
|
|
|
6
|
pop @child_str if $child_str[-1] eq ')'; |
|
1540
|
1
|
|
|
|
|
4
|
splice @child_str, 0, 2; |
|
1541
|
1
|
|
|
|
|
111
|
return "\\pmod{@child_str}"; |
|
1542
|
|
|
|
|
|
|
} |
|
1543
|
|
|
|
|
|
|
# Check if we need \left ... \right |
|
1544
|
278
|
|
|
|
|
1988
|
my $is_tall = grep(/[_^]|\\(begin\{array\}|frac|sqrt|stackrel)/, |
|
1545
|
|
|
|
|
|
|
@child_str); |
|
1546
|
278
|
100
|
100
|
|
|
1243
|
if ($is_tall && @child_str > 1 && |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
1547
|
|
|
|
|
|
|
($child_str[0] =~ /^([\(\[|]|\\\{)$/ || |
|
1548
|
|
|
|
|
|
|
$child_str[-1] =~ /^([\)\]|]|\\\})$/)) { |
|
1549
|
27
|
50
|
|
|
|
134
|
if ($child_str[0] =~ /^([\(\[|]|\\\{)$/) { |
|
1550
|
27
|
|
|
|
|
69
|
$child_str[0] = "\\left$child_str[0]"; |
|
1551
|
|
|
|
|
|
|
} |
|
1552
|
|
|
|
|
|
|
else { |
|
1553
|
0
|
|
|
|
|
0
|
unshift @child_str, "\\left."; |
|
1554
|
|
|
|
|
|
|
} |
|
1555
|
27
|
100
|
|
|
|
206
|
if ($child_str[-1] =~ /^([\)\]|]|\\\})$/) { |
|
1556
|
26
|
|
|
|
|
67
|
$child_str[-1] = "\\right$child_str[-1]"; |
|
1557
|
|
|
|
|
|
|
} |
|
1558
|
|
|
|
|
|
|
else { |
|
1559
|
1
|
|
|
|
|
4
|
push @child_str, "\\right."; |
|
1560
|
|
|
|
|
|
|
} |
|
1561
|
|
|
|
|
|
|
} |
|
1562
|
278
|
|
|
|
|
1759
|
return "@child_str"; |
|
1563
|
|
|
|
|
|
|
} |
|
1564
|
|
|
|
|
|
|
|
|
1565
|
|
|
|
|
|
|
|
|
1566
|
|
|
|
|
|
|
# mi |
|
1567
|
|
|
|
|
|
|
# mn |
|
1568
|
|
|
|
|
|
|
# math |
|
1569
|
|
|
|
|
|
|
# mtd |
|
1570
|
1493
|
100
|
|
|
|
10634
|
if ($tag =~ /^m([in]|ath|row|td)$/) { |
|
1571
|
963
|
|
|
|
|
3610
|
@child_str = grep $_ ne '', @child_str; |
|
1572
|
963
|
|
|
|
|
5220
|
return "@child_str"; |
|
1573
|
|
|
|
|
|
|
} |
|
1574
|
|
|
|
|
|
|
|
|
1575
|
|
|
|
|
|
|
# msub |
|
1576
|
|
|
|
|
|
|
# msup |
|
1577
|
|
|
|
|
|
|
# msubsup |
|
1578
|
|
|
|
|
|
|
# munderover |
|
1579
|
530
|
100
|
|
|
|
1976
|
if ($tag =~ /^(msu[bp](sup)?|munderover)$/) { |
|
1580
|
108
|
|
|
|
|
235
|
my $base = shift @child_str; |
|
1581
|
108
|
100
|
|
|
|
248
|
$base = '\mbox{}' if $base eq ''; |
|
1582
|
|
|
|
|
|
|
# Put {} around arguments with more than one character |
|
1583
|
108
|
100
|
|
|
|
882
|
@child_str = map length($_) > 1 ? "{$_}" : $_, @child_str; |
|
1584
|
108
|
100
|
|
|
|
880
|
return ($tag eq 'msub' ? "${base}_$child_str[0]" : |
|
|
|
100
|
|
|
|
|
|
|
1585
|
|
|
|
|
|
|
$tag eq 'msup' ? "${base}^$child_str[0]" : |
|
1586
|
|
|
|
|
|
|
"${base}_$child_str[0]^$child_str[1]"); |
|
1587
|
|
|
|
|
|
|
} |
|
1588
|
|
|
|
|
|
|
|
|
1589
|
|
|
|
|
|
|
# mover |
|
1590
|
422
|
100
|
|
|
|
906
|
if ($tag eq 'mover') { |
|
1591
|
|
|
|
|
|
|
# Need to special-case math mode accents |
|
1592
|
|
|
|
|
|
|
return |
|
1593
|
11
|
100
|
66
|
|
|
100
|
($child_str[1] eq '\overline' && length($child_str[0]) == 1 ? |
|
|
|
100
|
|
|
|
|
|
|
1594
|
|
|
|
|
|
|
"\\bar{$child_str[0]}" : |
|
1595
|
|
|
|
|
|
|
$LatexMover{$child_str[1]} ? |
|
1596
|
|
|
|
|
|
|
"$LatexMover{$child_str[1]}\{$child_str[0]\}" : |
|
1597
|
|
|
|
|
|
|
"\\stackrel{$child_str[1]}{$child_str[0]}"); |
|
1598
|
|
|
|
|
|
|
} |
|
1599
|
|
|
|
|
|
|
|
|
1600
|
|
|
|
|
|
|
# munder |
|
1601
|
411
|
100
|
|
|
|
1359
|
if ($tag eq 'munder') { |
|
1602
|
5
|
100
|
|
|
|
36
|
return $child_str[1] eq '\underline' ? "$child_str[1]\{$child_str[0]}" |
|
1603
|
|
|
|
|
|
|
: "$child_str[0]_\{$child_str[1]\}"; |
|
1604
|
|
|
|
|
|
|
} |
|
1605
|
|
|
|
|
|
|
|
|
1606
|
|
|
|
|
|
|
# mfrac |
|
1607
|
406
|
100
|
|
|
|
992
|
if ($tag eq 'mfrac') { |
|
1608
|
52
|
|
|
|
|
285
|
return "\\frac{$child_str[0]}{$child_str[1]}"; |
|
1609
|
|
|
|
|
|
|
} |
|
1610
|
|
|
|
|
|
|
|
|
1611
|
|
|
|
|
|
|
# msqrt |
|
1612
|
354
|
100
|
|
|
|
863
|
if ($tag eq 'msqrt') { |
|
1613
|
10
|
|
|
|
|
76
|
return "\\sqrt{$child_str[0]}"; |
|
1614
|
|
|
|
|
|
|
} |
|
1615
|
|
|
|
|
|
|
|
|
1616
|
|
|
|
|
|
|
# mroot |
|
1617
|
344
|
100
|
|
|
|
719
|
if ($tag eq 'mroot') { |
|
1618
|
1
|
|
|
|
|
7
|
return "\\sqrt[$child_str[1]]{$child_str[0]}"; |
|
1619
|
|
|
|
|
|
|
} |
|
1620
|
|
|
|
|
|
|
|
|
1621
|
|
|
|
|
|
|
# mtext |
|
1622
|
343
|
100
|
|
|
|
1047
|
if ($tag eq 'mtext') { |
|
1623
|
11
|
|
|
|
|
24
|
my $text = $child_str[0]; |
|
1624
|
11
|
|
|
|
|
33
|
my $next = $self->nextSibling; |
|
1625
|
11
|
|
|
|
|
40
|
my $prev = $self->previousSibling; |
|
1626
|
11
|
100
|
66
|
|
|
56
|
if (defined $next->{tag} && $next->{tag} eq 'mspace') { |
|
1627
|
6
|
|
|
|
|
20
|
$text = "$text "; |
|
1628
|
|
|
|
|
|
|
} |
|
1629
|
11
|
100
|
66
|
|
|
48
|
if (defined $prev->{tag} && $prev->{tag} eq 'mspace') { |
|
1630
|
5
|
|
|
|
|
11
|
$text = " $text"; |
|
1631
|
|
|
|
|
|
|
} |
|
1632
|
11
|
100
|
|
|
|
330
|
$text = ' ' if $text eq ' '; |
|
1633
|
11
|
|
|
|
|
56
|
return "\\mbox{$text}"; |
|
1634
|
|
|
|
|
|
|
} |
|
1635
|
|
|
|
|
|
|
|
|
1636
|
|
|
|
|
|
|
|
|
1637
|
|
|
|
|
|
|
# mspace |
|
1638
|
332
|
100
|
|
|
|
657
|
if ($tag eq 'mspace') { |
|
1639
|
19
|
|
|
|
|
77
|
return ''; |
|
1640
|
|
|
|
|
|
|
} |
|
1641
|
|
|
|
|
|
|
|
|
1642
|
|
|
|
|
|
|
# mtable |
|
1643
|
313
|
100
|
|
|
|
652
|
if ($tag eq 'mtable') { |
|
1644
|
9
|
|
|
|
|
31
|
my $cols = ($child_str[0] =~ tr/&//) + 1; |
|
1645
|
9
|
100
|
100
|
|
|
70
|
my $colspec = ($self->{attr}{columnalign} || '') eq 'left' ? 'l' : 'c'; |
|
1646
|
9
|
|
|
|
|
36
|
my $colspecs = $colspec x $cols; |
|
1647
|
9
|
|
|
|
|
91
|
return ("\\begin{array}{$colspecs}\n" . |
|
1648
|
|
|
|
|
|
|
join('', map(" $_ \\\\\n", @child_str)) . |
|
1649
|
|
|
|
|
|
|
"\\end{array}\n"); |
|
1650
|
|
|
|
|
|
|
} |
|
1651
|
|
|
|
|
|
|
|
|
1652
|
|
|
|
|
|
|
# mtr |
|
1653
|
304
|
100
|
|
|
|
672
|
if ($tag eq 'mtr') { |
|
1654
|
19
|
|
|
|
|
89
|
return join ' & ', @child_str; |
|
1655
|
|
|
|
|
|
|
} |
|
1656
|
|
|
|
|
|
|
|
|
1657
|
|
|
|
|
|
|
# mstyle |
|
1658
|
285
|
50
|
|
|
|
1439
|
if ($tag eq 'mstyle') { |
|
1659
|
285
|
|
|
|
|
1385
|
@child_str = grep $_ ne '', @child_str; |
|
1660
|
285
|
100
|
|
|
|
793
|
if ($self->parent->{tag} eq 'math') { |
|
1661
|
273
|
100
|
|
|
|
745
|
push @child_str, ' ' unless @child_str; |
|
1662
|
|
|
|
|
|
|
# The top-level mstyle |
|
1663
|
273
|
50
|
33
|
|
|
3553
|
return (defined $self->{attr}{displaystyle} && |
|
1664
|
|
|
|
|
|
|
$self->{attr}{displaystyle} eq 'true') ? |
|
1665
|
|
|
|
|
|
|
"\$\$@child_str\$\$" : "\$@child_str\$"; |
|
1666
|
|
|
|
|
|
|
} |
|
1667
|
|
|
|
|
|
|
else { |
|
1668
|
|
|
|
|
|
|
# It better be a font changing command |
|
1669
|
12
|
100
|
|
|
|
62
|
return $child_str[0] if $self->{attr}{mathvariant}; |
|
1670
|
6
|
|
|
|
|
33
|
my ($attr) = map($self->{attr}{$_}, |
|
1671
|
|
|
|
|
|
|
grep $self->{attr}{$_}, |
|
1672
|
|
|
|
|
|
|
qw(fontweight fontfamily)); |
|
1673
|
6
|
50
|
33
|
|
|
155
|
return $attr && $LatexFont{$attr} ? |
|
1674
|
|
|
|
|
|
|
"$LatexFont{$attr}\{$child_str[0]}" : $child_str[0]; |
|
1675
|
|
|
|
|
|
|
} |
|
1676
|
|
|
|
|
|
|
} |
|
1677
|
|
|
|
|
|
|
} |
|
1678
|
|
|
|
|
|
|
} |
|
1679
|
|
|
|
|
|
|
|
|
1680
|
|
|
|
|
|
|
# Returns the next sibling of a node |
|
1681
|
|
|
|
|
|
|
# Arguments: None |
|
1682
|
|
|
|
|
|
|
# Returns: node object or undef |
|
1683
|
|
|
|
|
|
|
sub nextSibling { |
|
1684
|
51
|
|
|
51
|
|
79
|
my ($self) = @_; |
|
1685
|
51
|
|
|
|
|
119
|
my $parent = $self->parent; |
|
1686
|
51
|
|
|
|
|
104
|
for (my $i=0; $i<@{$parent->{children}}; $i++) { |
|
|
64
|
|
|
|
|
194
|
|
|
1687
|
64
|
100
|
|
|
|
379
|
return $parent->{children}[$i+1] if $self eq $parent->{children}[$i]; |
|
1688
|
|
|
|
|
|
|
} |
|
1689
|
0
|
|
|
|
|
0
|
return $Null; |
|
1690
|
|
|
|
|
|
|
} |
|
1691
|
|
|
|
|
|
|
|
|
1692
|
|
|
|
|
|
|
# Returns the tag of a node |
|
1693
|
|
|
|
|
|
|
# Arguments: None |
|
1694
|
|
|
|
|
|
|
# Returns: string |
|
1695
|
|
|
|
|
|
|
sub nodeName : method { |
|
1696
|
1098
|
|
100
|
1098
|
|
6707
|
return $_[0]{tag} || ''; |
|
1697
|
|
|
|
|
|
|
} |
|
1698
|
|
|
|
|
|
|
|
|
1699
|
|
|
|
|
|
|
# Returns the text of a text node |
|
1700
|
|
|
|
|
|
|
# Arguments: None |
|
1701
|
|
|
|
|
|
|
# Returns: string |
|
1702
|
|
|
|
|
|
|
sub nodeValue : method { |
|
1703
|
910
|
|
100
|
910
|
|
4158
|
return $_[0]{text} || ''; |
|
1704
|
|
|
|
|
|
|
} |
|
1705
|
|
|
|
|
|
|
|
|
1706
|
|
|
|
|
|
|
# Returns the parent of a node |
|
1707
|
|
|
|
|
|
|
# Arguments: none |
|
1708
|
|
|
|
|
|
|
# Returns: parent node object or undef |
|
1709
|
|
|
|
|
|
|
sub parent : method { |
|
1710
|
970
|
|
33
|
970
|
|
10665
|
return $Parent{$_[0]} || $Null; |
|
1711
|
|
|
|
|
|
|
} |
|
1712
|
|
|
|
|
|
|
|
|
1713
|
|
|
|
|
|
|
# Returns the previous sibling of a node |
|
1714
|
|
|
|
|
|
|
# Arguments: None |
|
1715
|
|
|
|
|
|
|
# Returns: node object or undef |
|
1716
|
|
|
|
|
|
|
sub previousSibling { |
|
1717
|
11
|
|
|
11
|
|
16
|
my ($self) = @_; |
|
1718
|
11
|
|
|
|
|
25
|
my $parent = $self->parent; |
|
1719
|
11
|
|
|
|
|
24
|
for (my $i=1; $i<@{$parent->{children}}; $i++) { |
|
|
12
|
|
|
|
|
37
|
|
|
1720
|
6
|
100
|
|
|
|
33
|
return $parent->{children}[$i-1] if $self eq $parent->{children}[$i]; |
|
1721
|
|
|
|
|
|
|
} |
|
1722
|
6
|
|
|
|
|
14
|
return $Null; |
|
1723
|
|
|
|
|
|
|
} |
|
1724
|
|
|
|
|
|
|
|
|
1725
|
|
|
|
|
|
|
# Removes a given child node from a node |
|
1726
|
|
|
|
|
|
|
# Arguments: child node |
|
1727
|
|
|
|
|
|
|
# Returns: None |
|
1728
|
|
|
|
|
|
|
# Side-effects: May affect children of the node |
|
1729
|
|
|
|
|
|
|
sub removeChild : method { |
|
1730
|
626
|
|
|
626
|
|
1230
|
my ($self, $child) = @_; |
|
1731
|
626
|
50
|
|
|
|
1618
|
@{$self->{children}} = grep $_ ne $child, @{$self->{children}} |
|
|
626
|
|
|
|
|
2234
|
|
|
|
626
|
|
|
|
|
7991
|
|
|
1732
|
|
|
|
|
|
|
if $self->{children}; |
|
1733
|
626
|
|
|
|
|
3136
|
delete $Parent{$child}; |
|
1734
|
|
|
|
|
|
|
} |
|
1735
|
|
|
|
|
|
|
|
|
1736
|
|
|
|
|
|
|
# Replaces one child node object with another |
|
1737
|
|
|
|
|
|
|
# Arguments: old child node object, new child node object |
|
1738
|
|
|
|
|
|
|
# Returns: None |
|
1739
|
|
|
|
|
|
|
sub replaceChild : method { |
|
1740
|
30
|
|
|
30
|
|
65
|
my ($self, $new, $old) = @_; |
|
1741
|
30
|
100
|
|
|
|
40
|
@{$self->{children}} = map $_ eq $old ? $new : $_, @{$self->{children}}; |
|
|
30
|
|
|
|
|
8342
|
|
|
|
30
|
|
|
|
|
248
|
|
|
1742
|
30
|
|
|
|
|
659
|
delete $Parent{$old}; |
|
1743
|
30
|
|
|
|
|
213
|
$Parent{$new} = $self; |
|
1744
|
|
|
|
|
|
|
} |
|
1745
|
|
|
|
|
|
|
|
|
1746
|
|
|
|
|
|
|
# Sets one or more attributes on a node object |
|
1747
|
|
|
|
|
|
|
# Arguments: set of attribute/value pairs |
|
1748
|
|
|
|
|
|
|
# Returns: None |
|
1749
|
|
|
|
|
|
|
sub setAttribute : method { |
|
1750
|
892
|
|
|
892
|
|
1406
|
my $self = shift; |
|
1751
|
892
|
50
|
|
|
|
3195
|
if (@_) { |
|
1752
|
892
|
50
|
|
|
|
3142
|
$self->{attr} = {} unless $self->{attr}; |
|
1753
|
892
|
50
|
|
|
|
3558
|
$self->{attrlist} = [] unless $self->{attrlist}; |
|
1754
|
|
|
|
|
|
|
} |
|
1755
|
892
|
|
|
|
|
4462
|
while (my($aname, $aval) = splice(@_, 0, 2)) { |
|
1756
|
1988
|
|
|
|
|
3480
|
$aval =~ s/\n//g; |
|
1757
|
1988
|
50
|
|
|
|
6110
|
push @{$self->{attrlist}}, $aname unless defined $self->{attr}{$aname}; |
|
|
1988
|
|
|
|
|
4580
|
|
|
1758
|
1988
|
|
|
|
|
12232
|
$self->{attr}{$aname} = $aval; |
|
1759
|
|
|
|
|
|
|
} |
|
1760
|
|
|
|
|
|
|
} |
|
1761
|
|
|
|
|
|
|
|
|
1762
|
|
|
|
|
|
|
# Returns the ASCII representation of a node object |
|
1763
|
|
|
|
|
|
|
# Arguments: None |
|
1764
|
|
|
|
|
|
|
# Returns: Text string |
|
1765
|
|
|
|
|
|
|
sub text : method { |
|
1766
|
3697
|
|
|
3697
|
|
4232
|
my ($self) = @_; |
|
1767
|
3697
|
100
|
|
|
|
19475
|
return $self->{text} if defined $self->{text}; |
|
1768
|
2400
|
|
|
|
|
3576
|
my $tag = $self->{tag}; |
|
1769
|
2400
|
|
|
|
|
7578
|
my $attr = join '', map(" $_=\"" . |
|
1770
|
|
|
|
|
|
|
($_ eq 'xmlns' ? $self->{attr}{$_} : |
|
1771
|
|
|
|
|
|
|
Text::ASCIIMathML::_xml_encode($self->{attr}{$_})) . |
|
1772
|
2400
|
50
|
|
|
|
4506
|
"\"", @{$self->{attrlist}}) |
|
|
|
50
|
|
|
|
|
|
|
1773
|
|
|
|
|
|
|
if $tag; |
|
1774
|
2400
|
100
|
|
|
|
3120
|
if (@{$self->{children}}) { |
|
|
2400
|
|
|
|
|
5736
|
|
|
1775
|
2378
|
|
|
|
|
9058
|
my $child_str; |
|
1776
|
2378
|
|
|
|
|
2891
|
foreach (@{$self->{children}}) { |
|
|
2378
|
|
|
|
|
4696
|
|
|
1777
|
3423
|
|
|
|
|
8414
|
$child_str .= $_->text; |
|
1778
|
|
|
|
|
|
|
} |
|
1779
|
2378
|
50
|
|
|
|
14023
|
return $tag ? "<$tag$attr>$child_str$tag>" : $child_str; |
|
1780
|
|
|
|
|
|
|
} |
|
1781
|
22
|
50
|
|
|
|
99
|
return $tag ? "<$tag$attr/>" : ''; |
|
1782
|
|
|
|
|
|
|
} |
|
1783
|
|
|
|
|
|
|
} |
|
1784
|
|
|
|
|
|
|
|
|
1785
|
|
|
|
|
|
|
1; |