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; |