Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / third_party / libvpx / source / libvpx / examples / includes / ASCIIMathPHP-2.0 / ASCIIMathPHP-2.0.class.php
1 <?php
2
3 /****
4  * ASCIIMathPHP and associated classes:
5  * -- XMLNode
6  * -- MathMLNode extends XMLNode
7  *
8  * These classes are a PHP port of ASCIIMath
9  * Version 1.3 Feb 19 2004, (c) Peter Jipsen http://www.chapman.edu/~jipsen
10  *
11  * ASCIIMathPHP Version 1.11, 26 April 2006, (c) Kee-Lin Steven Chan (kc56@cornell.edu)
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or (at
16  * your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * General Public License (at http://www.gnu.org/copyleft/gpl.html)
22  * for more details.
23  *
24  * ChangeLog
25  *
26  * Ver 2.0
27  * -- PHP5 only version of ASCIIMathPHP
28  *
29  * Ver 1.12.1
30  * -- Included the missing setCurrExpr() method
31  *
32  * Ver 1.12
33  * -- Added changes that David Lippman <DLippman@pierce.ctc.edu> made to bring ASCIIMathPHP up to
34  * ASCIIMath 1.4.7 functionality.
35  * -- Added parseIntExpr, for intermediate expression parsing rule, allowing x^2/x^3 to render as (x^2)/(x^3)
36  * -- Added quotes as another way of designating text; "hello" is equivalent to text(hello)
37  * -- Added FUNC designator to allow sin, cos, etc to act as functions, so sin(x)/x renders as {sin(x)}/x
38  *
39  * Ver 1.11
40  * -- Fixed bug that stopped script execution for incomplete expressions
41  * -- Changed the algorithm for parsing expressions so that it matches the longest string possible (greedy)
42  *
43  * Ver 1.10
44  * -- Added definition support
45  * -- Added stackrel support
46  * -- Added a bunch of different symbols etc. >>, << and definitions like dx, dy, dz etc.
47  *
48  * Ver 1.02
49  * -- Fixed bug with mbox and text
50  * -- Fixed spacing bug with mbox and text
51  *
52  * Ver 1.01
53  * -- Fixed Bug that did not parse symbols greater than a single character
54  * correctly when appearing at end of expression.
55  *
56  ***/
57
58 class XMLNode
59 {
60     // Private variables
61     var $_id;
62     var $_name;
63     var $_content;
64     var $_mt_elem_flg;
65     var $_attr_arr;
66     var $_child_arr;
67     var $_nmspc;
68     var $_nmspc_alias;
69     var $_parent_id;
70     var $_parent_node;
71
72     function XMLNode($id = NULL)
73     {
74         $this->_id = isset($id) ? $id : md5(uniqid(rand(),1));
75         $this->_name = '';
76         $this->_content = '';
77         $this->_mt_elem_flg = FALSE;
78         $this->_attr_arr = array();
79         $this->_child_arr = array();
80         $this->_nmspc = '';
81         $this->_nmspc_alias = '';
82         $this->_parent_id = FALSE;
83         $this->_parent_node = NULL;
84     }
85
86     function addChild(&$node)
87     {
88         $this->_child_arr[$node->getId()] = $node;
89         $node->setParentId($this->_id);
90         $node->setParentNode($this);
91     }
92
93     function addChildArr(&$node_arr)
94     {
95         $key_arr = array_keys($node_arr);
96         $num_key = count($key_arr);
97
98         for ($i = 0; $i < $num_key; $i++) {
99             $node = $node_arr[$key_arr[$i]];
100             $this->addChild($node);
101         }
102     }
103
104     function insertChildBefore($idx,&$node)
105     {
106         $key_arr = array_keys($this->_child_arr);
107         $num_key = count($key_arr);
108         $tmp_arr = arry();
109
110         for ($i = 0;$i < $num_key;$i++) {
111             if ($i == $idx) {
112                 $tmp_arr[$node->getId()] = $node;
113             }
114             $tmp_arr[$key_arr[$i]] = $this->_child_arr[$key_arr[$i]];
115         }
116         $this->_child_arr = $tmp_arr;
117     }
118
119     function insertChildAfter($idx,&$node)
120     {
121         $key_arr = array_keys($this->_child_arr);
122         $num_key = count($key_arr);
123         $tmp_arr = arry();
124
125         for ($i = 0;$i < $num_key;$i++) {
126             $tmp_arr[$key_arr[$i]] = $this->_child_arr[$key_arr[$i]];
127             if ($i == $idx) {
128                 $tmp_arr[$node->getId()] = $node;
129             }
130         }
131         $this->_child_arr = $tmp_arr;
132     }
133
134     function setId($id)
135     {
136         $this->_id = $id;
137     }
138
139     function setName($name)
140     {
141         $this->_name = $name;
142     }
143
144     function setNamepace($nmspc)
145     {
146         $this->_nmspc = $nmspc;
147     }
148
149     function setNamespaceAlias($nmspc_alias)
150     {
151         $this->_nmspc_alias = $nmspc_alias;
152     }
153
154     function setContent($content)
155     {
156         $this->_content = $content;
157     }
158
159     function setEmptyElem($mt_elem_flg)
160     {
161         $this->_mt_elem_flg = $mt_elem_flg;
162     }
163
164     function setAttr($attr_nm,$attr_val)
165     {
166         $this->_attr_arr[$attr_nm] = $attr_val;
167     }
168
169     function setAttrArr($attr_arr)
170     {
171         $this->_attr_arr = $attr_arr;
172     }
173
174     function setParentId($id)
175     {
176         $this->_parent_id = $id;
177     }
178
179     function setParentNode(&$node)
180     {
181         $this->_parent_node = $node;
182     }
183
184     function getId()
185     {
186         return($this->_id);
187     }
188
189     function getName()
190     {
191         return($this->_name);
192     }
193
194     function getNamespace()
195     {
196         return($this->_nmspc);
197     }
198
199     function getNamespaceAlias()
200     {
201         return($this->_nmspc_alias);
202     }
203
204     function getContent()
205     {
206         return($this->_content);
207     }
208
209     function getAttr($attr_nm)
210     {
211         if (isset($this->_attr_arr[$attr_nm])) {
212             return($this->_attr_arr[$attr_nm]);
213         } else {
214             return(NULL);
215         }
216     }
217
218     function getAttrArr()
219     {
220         return($this->_attr_arr);
221     }
222
223     function getParentId()
224     {
225         return($this->parent_id);
226     }
227
228     function getParentNode()
229     {
230         return($this->_parent_node);
231     }
232
233     function getChild($id)
234     {
235         if (isset($this->_child_arr[$id])) {
236             return($this->_child_arr[$id]);
237         } else {
238             return(FALSE);
239         }
240     }
241
242     function getFirstChild()
243     {
244         $id_arr = array_keys($this->_child_arr);
245         $num_child = count($id_arr);
246
247         if ($num_child > 0) {
248             return($this->_child_arr[$id_arr[0]]);
249         } else {
250             return(FALSE);
251         }
252     }
253
254     function getLastChild()
255     {
256         $id_arr = array_keys($this->_child_arr);
257         $num_child = count($id_arr);
258
259         if ($num_child > 0) {
260             return($this->_child_arr[$id_arr[$num_child - 1]]);
261         } else {
262             return(FALSE);
263         }
264     }
265
266     function getChildByIdx($idx)
267     {
268         $id_arr = array_keys($this->_child_arr);
269
270         if (isset($this->_child_arr[$id_arr[$idx]])) {
271             return($this->_child_arr[$id_arr[$idx]]);
272         } else {
273             return(FALSE);
274         }
275     }
276
277     function getNumChild()
278     {
279         return(count($this->_child_arr));
280     }
281
282     function removeChild($id)
283     {
284         unset($this->_child_arr[$id]);
285     }
286
287     function removeChildByIdx($idx)
288     {
289         $key_arr = array_keys($this->_child_arr);
290         unset($this->_child_arr[$key_arr[$idx]]);
291     }
292
293     function removeFirstChild()
294     {
295         $key_arr = array_keys($this->_child_arr);
296         unset($this->_child_arr[$key_arr[0]]);
297     }
298
299     function removeLastChild()
300     {
301         $key_arr = array_keys($this->_child_arr);
302         unset($this->_child_arr[$key_arr[count($key_arr)-1]]);
303     }
304
305     function dumpXML($indent_str = "\t")
306     {
307         $attr_txt = $this->_dumpAttr();
308         $name = $this->_dumpName();
309         $xmlns = $this->_dumpXmlns();
310         $lvl = $this->_getCurrentLevel();
311         $indent = str_pad('',$lvl,$indent_str);
312
313         if ($this->_mt_elem_flg) {
314             $tag = "$indent<$name$xmlns$attr_txt />";
315             return($tag);
316         } else {
317             $key_arr = array_keys($this->_child_arr);
318             $num_child = count($key_arr);
319
320             $tag = "$indent<$name$xmlns$attr_txt>$this->_content";
321
322             for ($i = 0;$i < $num_child;$i++) {
323                 $node = $this->_child_arr[$key_arr[$i]];
324
325                 $child_txt = $node->dumpXML($indent_str);
326                 $tag .= "\n$child_txt";
327             }
328
329             $tag .= ($num_child > 0 ? "\n$indent</$name>" : "</$name>");
330             return($tag);
331         }
332     }
333
334     function _dumpAttr()
335     {
336         $id_arr = array_keys($this->_attr_arr);
337         $id_arr_cnt = count($id_arr);
338         $attr_txt = '';
339
340         for($i = 0;$i < $id_arr_cnt;$i++) {
341             $key = $id_arr[$i];
342             $attr_txt .= " $key=\"{$this->_attr_arr[$key]}\"";
343         }
344
345         return($attr_txt);
346     }
347
348     function _dumpName()
349     {
350         $alias = $this->getNamespaceAlias();
351         if ($alias == '') {
352             return($this->getName());
353         } else {
354             return("$alias:" . $this->getName());
355         }
356     }
357
358     function _dumpXmlns()
359     {
360         $nmspc = $this->getNamespace();
361         $alias = $this->getNamespaceAlias();
362
363         if ($nmspc != '') {
364             if ($alias == '') {
365                 return(" xmlns=\"" . $nmspc . "\"");
366             } else {
367                 return(" xmlns:$alias=\"" . $nmspc . "\"");
368             }
369         } else {
370             return('');
371         }
372     }
373
374     function _getCurrentLevel()
375     {
376         if ($this->_parent_id === FALSE) {
377             return(0);
378         } else {
379             $node = $this->getParentNode();
380             $lvl = $node->_getCurrentLevel();
381             $lvl++;
382             return($lvl);
383         }
384     }
385 }
386
387 class MathMLNode extends XMLNode
388 {
389     function MathMLNode($id = NULL)
390     {
391         parent::XMLNode($id);
392     }
393
394     function removeBrackets()
395     {
396         if ($this->_name == 'mrow') {
397             if ($c_node_0 = $this->getFirstChild()) {
398                 $c_node_0->isLeftBracket() ? $this->removeFirstChild() : 0;
399             }
400
401             if ($c_node_0 = $this->getLastChild()) {
402                 $c_node_0->isRightBracket() ? $this->removeLastChild() : 0;
403             }
404         }
405     }
406
407     function isLeftBracket()
408     {
409         switch ($this->_content) {
410             case '{':
411             case '[':
412             case '(':
413                 return(TRUE);
414                 break;
415         }
416         return(FALSE);
417     }
418
419     function isRightBracket()
420     {
421         switch ($this->_content) {
422             case '}':
423             case ']':
424             case ')':
425                 return(TRUE);
426                 break;
427         }
428         return(FALSE);
429     }
430 }
431
432 class ASCIIMathPHP
433 {
434     var $_expr;
435     var $_curr_expr;
436     var $_prev_expr;
437     var $_symbol_arr;
438     var $_node_arr;
439     var $_node_cntr;
440
441     function ASCIIMathPHP($symbol_arr,$expr = NULL)
442     {
443         $this->_symbol_arr = $symbol_arr;
444         if (isset($expr)) {
445             $this->setExpr($expr);
446         }
447     }
448
449     /**
450      * Returns an empty node (containing a non-breaking space) 26-Apr-2006
451      *
452      * Used when an expression is incomplete
453      *
454      * @return object
455      *
456      * @access private
457      */
458     function emptyNode()
459     {
460         $tmp_node = $this->createNode();
461         $tmp_node->setName('mn');
462         $tmp_node->setContent('&#' . hexdec('200B') . ';');
463         return $tmp_node;
464     }
465
466     function pushExpr($prefix) // 2005-06-11 wes
467     {
468         $this->_curr_expr = $prefix . $this->_curr_expr;
469     }
470
471     function setExpr($expr)
472     {
473         $this->_expr = $expr;
474         $this->_curr_expr = $expr;
475         $this->_prev_expr = $expr;
476
477         $this->_node_arr = array();
478         $this->_node_cntr = 0;
479     }
480
481     function genMathML($attr_arr = NULL)
482     {
483         // <math> node
484         $node_0 = $this->createNode();
485         $node_0->setName('math');
486         $node_0->setNamepace('http://www.w3.org/1998/Math/MathML');
487
488         // <mstyle> node
489         if (isset($attr_arr)) {
490             $node_1 = $this->createNode();
491             $node_1->setName('mstyle');
492             $node_1->setAttrArr($attr_arr);
493
494             $node_arr = $this->parseExpr();
495
496             $node_1->addChildArr($node_arr);
497             $node_0->addChild($node_1);
498         } else {
499             $node_arr = $this->parseExpr();
500             $node_0->addChildArr($node_arr);
501         }
502
503         return TRUE;
504     }
505
506     /*
507     function  mergeNodeArr(&$node_arr_0,&$node_arr_1)
508     {
509         $key_arr_0 = array_keys($node_arr_0);
510         $key_arr_1 = array_keys($node_arr_1);
511
512         $num_key_0 = count($key_arr_0);
513         $num_key_1 = count($key_arr_1);
514
515         $merge_arr = array();
516
517         for ($i = 0;$i < $num_key_0;$i++) {
518             $merge_arr[$key_arr_0[$i]] = $node_arr_0[$key_arr_0[$i]];
519         }
520
521         for ($j = 0;$j < $num_key_1;$i++) {
522             $merge_arr[$key_arr_1[$i]] = $node_arr_1[$key_arr_1[$i]];
523         }
524
525         return($merge_arr);
526     }
527     */
528
529     //Broken out of parseExpr Sept 7, 2006 David Lippman for
530     //ASCIIMathML 1.4.7 compatibility
531     function  parseIntExpr()
532     {
533         $sym_0 = $this->getSymbol();
534         $node_0 = $this->parseSmplExpr();
535         $sym = $this->getSymbol();
536
537         if (isset($sym['infix']) && $sym['input'] != '/') {
538             $this->chopExpr($sym['symlen']);
539             $node_1 = $this->parseSmplExpr();
540
541             if ($node_1 === FALSE) { //show box in place of missing argument
542                 $node_1 = $this->emptyNode();//??
543             } else {
544                 $node_1->removeBrackets();
545             }
546
547             // If 'sub' -- subscript
548             if ($sym['input'] == '_') {
549
550                 $sym_1 = $this->getSymbol();
551
552                 // If 'sup' -- superscript
553                 if ($sym_1['input'] == '^') {
554                     $this->chopExpr($sym_1['symlen']);
555                     $node_2 = $this->parseSmplExpr();
556                     $node_2->removeBrackets();
557
558                     $node_3 = $this->createNode();
559                     $node_3->setName(isset($sym_0['underover']) ? 'munderover' : 'msubsup');
560                     $node_3->addChild($node_0);
561                     $node_3->addChild($node_1);
562                     $node_3->addChild($node_2);
563
564                     $node_4 = $this->createNode();
565                     $node_4->setName('mrow');
566                     $node_4->addChild($node_3);
567
568                     return $node_4;
569                 } else {
570                     $node_2 = $this->createNode();
571                     $node_2->setName(isset($sym_0['underover']) ? 'munder' : 'msub');
572                     $node_2->addChild($node_0);
573                     $node_2->addChild($node_1);
574
575                     return $node_2;
576                 }
577             } else {
578                 $node_2 = $this->createNode();
579                 $node_2->setName($sym['tag']);
580                 $node_2->addChild($node_0);
581                 $node_2->addChild($node_1);
582
583                 return($node_2);
584             }
585         } elseif ($node_0 !== FALSE) {
586             return($node_0);
587         } else {
588             return $this->emptyNode();
589         }
590
591     }
592
593     function  parseExpr()
594     {
595         // Child/Fragment array
596         $node_arr = array();
597
598         // Deal whole expressions like 'ax + by + c = 0' etc.
599         do {
600             $sym_0 = $this->getSymbol();
601             $node_0 = $this->parseIntExpr();
602             $sym = $this->getSymbol();
603             // var_dump($sym);
604
605             if (isset($sym['infix']) && $sym['input'] == '/') {
606                 $this->chopExpr($sym['symlen']);
607                 $node_1 = $this->parseIntExpr();
608
609                 if ($node_1 === FALSE) { //should show box in place of missing argument
610                     $node_1 = $this->emptyNode();
611                     continue;
612                 }
613
614                 $node_1->removeBrackets();
615
616                 // If 'div' -- divide
617                 $node_0->removeBrackets();
618                 $node_2 = $this->createNode();
619                 $node_2->setName($sym['tag']);
620                 $node_2->addChild($node_0);
621                 $node_2->addChild($node_1);
622                 $node_arr[$node_2->getId()] = $node_2;
623
624             } elseif ($node_0 !== FALSE) {
625                 $node_arr[$node_0->getId()] = $node_0;
626             }
627         } while (!isset($sym['right_bracket']) && $sym !== FALSE && $sym['output'] != '');
628
629         //var_dump($sym);
630         // Possibly to deal with matrices
631         if (isset($sym['right_bracket'])) {
632             $node_cnt = count($node_arr);
633             $key_node_arr = array_keys($node_arr);
634
635             if ($node_cnt > 1) {
636                 $node_5 = $node_arr[$key_node_arr[$node_cnt-1]];
637                 $node_6 = $node_arr[$key_node_arr[$node_cnt-2]];
638             } else {
639                 $node_5 = FALSE;
640                 $node_6 = FALSE;
641             }
642
643             // Dealing with matrices
644             if ($node_5 !== FALSE && $node_6 !== FALSE &&
645                 $node_cnt > 1 &&
646                 $node_5->getName() == 'mrow' &&
647                 $node_6->getName() == 'mo' &&
648                 $node_6->getContent() == ',') {
649
650                 // Checking if Node 5 has a LastChild
651                 if ($node_7 = $node_5->getLastChild()) {
652                     $node_7_cntnt = $node_7->getContent();
653                 } else {
654                     $node_7_cntnt = FALSE;
655                 }
656
657                 // If there is a right bracket
658                 if ($node_7 !== FALSE && ($node_7_cntnt == ']' || $node_7_cntnt == ')')) {
659
660                     // Checking if Node 5 has a firstChild
661                     if ($node_8 = $node_5->getFirstChild()) {
662                         $node_8_cntnt = $node_8->getContent();
663                     } else {
664                         $node_8_cntnt = FALSE;
665                     }
666
667                     // If there is a matching left bracket
668                     if ($node_8 !== FALSE &&
669                         (($node_8_cntnt == '(' && $node_7_cntnt == ')' && $sym['output'] != '}') ||
670                         ($node_8_cntnt == '[' && $node_7_cntnt == ']'))) {
671
672                         $is_mtrx_flg = TRUE;
673                         $comma_pos_arr = array();
674
675                         $i = 0;
676
677                         while ($i < $node_cnt && $is_mtrx_flg) {
678                             $tmp_node = $node_arr[$key_node_arr[$i]];
679
680                             if($tmp_node_first = $tmp_node->getFirstChild()) {
681                                 $tnfc = $tmp_node_first->getContent();
682                             } else {
683                                 $tnfc = FALSE;
684                             }
685
686                             if($tmp_node_last = $tmp_node->getLastChild()) {
687                                 $tnlc = $tmp_node_last->getContent();
688                             } else {
689                                 $tnlc = FALSE;
690                             }
691
692                             if (isset($key_node_arr[$i+1])) {
693                                 $next_tmp_node = $node_arr[$key_node_arr[$i+1]];
694                                 $ntnn = $next_tmp_node->getName();
695                                 $ntnc = $next_tmp_node->getContent();
696                             } else {
697                                 $ntnn = FALSE;
698                                 $ntnc = FALSE;
699                             }
700
701                             // Checking each node in node array for matrix criteria
702                             if ($is_mtrx_flg) {
703                                 $is_mtrx_flg = $tmp_node->getName() == 'mrow' &&
704                                     ($i == $node_cnt-1 || $ntnn == 'mo' && $ntnc == ',') &&
705                                     $tnfc == $node_8_cntnt && $tnlc == $node_7_cntnt;
706                             }
707
708                             if ($is_mtrx_flg) {
709                                 for ($j = 0;$j < $tmp_node->getNumChild();$j++) {
710                                     $tmp_c_node = $tmp_node->getChildByIdx($j);
711
712                                     if ($tmp_c_node->getContent() == ',') {
713                                         $comma_pos_arr[$i][] = $j;
714                                     }
715                                 }
716                             }
717
718                             if ($is_mtrx_flg && $i > 1) {
719
720                                 $cnt_cpan = isset($comma_pos_arr[$i]) ? count($comma_pos_arr[$i]) : NULL;
721                                 $cnt_cpap = isset($comma_pos_arr[$i-2]) ? count($comma_pos_arr[$i-2]) : NULL;
722                                 $is_mtrx_flg = $cnt_cpan == $cnt_cpap;
723                             }
724
725                             $i += 2;
726                         }
727
728                         // If the node passes the matrix tests
729                         if ($is_mtrx_flg) {
730                             $tab_node_arr = array();
731
732                             for ($i = 0;$i < $node_cnt;$i += 2) {
733                                 $tmp_key_node_arr = array_keys($node_arr);
734                                 if (!($tmp_node = $node_arr[$tmp_key_node_arr[0]])) {
735                                     break;
736                                 }
737                                 $num_child = $tmp_node->getNumChild();
738                                 $k = 0;
739
740                                 $tmp_node->removeFirstChild();
741
742                                 $row_node_arr = array();
743                                 $row_frag_node_arr = array();
744
745                                 for ($j = 1;$j < ($num_child-1);$j++) {
746                                     if (isset($comma_pos_arr[$i][$k]) &&
747                                         $j == $comma_pos_arr[$i][$k]) {
748
749                                         $tmp_node->removeFirstChild();
750
751                                         $tmp_c_node = $this->createNode();
752                                         $tmp_c_node->setName('mtd');
753                                         $tmp_c_node->addChildArr($row_frag_node_arr);
754                                         $row_frag_node_arr = array();
755
756                                         $row_node_arr[$tmp_c_node->getId()] = $tmp_c_node;
757
758                                         $k++;
759                                     } else {
760
761                                         if ($tmp_c_node = $tmp_node->getFirstChild()) {
762                                             $row_frag_node_arr[$tmp_c_node->getId()] = $tmp_c_node;
763                                             $tmp_node->removeFirstChild();
764                                         }
765                                     }
766                                 }
767
768                                 $tmp_c_node = $this->createNode();
769                                 $tmp_c_node->setName('mtd');
770                                 $tmp_c_node->addChildArr($row_frag_node_arr);
771
772                                 $row_node_arr[$tmp_c_node->getId()] = $tmp_c_node;
773
774                                 if (count($node_arr) > 2) {
775                                     $tmp_key_node_arr = array_keys($node_arr);
776                                     unset($node_arr[$tmp_key_node_arr[0]]);
777                                     unset($node_arr[$tmp_key_node_arr[1]]);
778                                 }
779
780                                 $tmp_c_node = $this->createNode();
781                                 $tmp_c_node->setName('mtr');
782                                 $tmp_c_node->addChildArr($row_node_arr);
783
784                                 $tab_node_arr[$tmp_c_node->getId()] = $tmp_c_node;
785                             }
786
787                             $tmp_c_node = $this->createNode();
788                             $tmp_c_node->setName('mtable');
789                             $tmp_c_node->addChildArr($tab_node_arr);
790
791                             if (isset($sym['invisible'])) {
792                                 $tmp_c_node->setAttr('columnalign','left');
793                             }
794
795                             $key_node_arr = array_keys($node_arr);
796                             $tmp_c_node->setId($key_node_arr[0]);
797
798                             $node_arr[$tmp_c_node->getId()] = $tmp_c_node;
799                         }
800                     }
801                 }
802             }
803
804             $this->chopExpr($sym['symlen']);
805             if (!isset($sym['invisible'])) {
806                 $node_7 = $this->createNode();
807                 $node_7->setName('mo');
808                 $node_7->setContent($sym['output']);
809                 $node_arr[$node_7->getId()] = $node_7;
810             }
811         }
812
813         return($node_arr);
814     }
815
816     function  parseSmplExpr()
817     {
818         $sym = $this->getSymbol();
819
820         if (!$sym || isset($sym['right_bracket'])) //return FALSE;
821             return $this->emptyNode();
822
823         $this->chopExpr($sym['symlen']);
824
825         // 2005-06-11 wes: add definition type support
826         if(isset($sym['definition'])) {
827             $this->pushExpr($sym['output']);
828             $sym = $this->getSymbol();
829             $this->chopExpr($sym['symlen']);
830         }
831
832         if (isset($sym['left_bracket'])) {
833             $node_arr = $this->parseExpr();
834
835             if (isset($sym['invisible'])) {
836                 $node_0 = $this->createNode();
837                 $node_0->setName('mrow');
838                 $node_0->addChildArr($node_arr);
839
840                 return($node_0);
841             } else {
842                 $node_0 = $this->createNode();
843                 $node_0->setName('mo');
844                 $node_0->setContent($sym['output']);
845
846                 $node_1 = $this->createNode();
847                 $node_1->setName('mrow');
848                 $node_1->addChild($node_0);
849                 $node_1->addChildArr($node_arr);
850
851                 return($node_1);
852             }
853         } elseif (isset($sym['unary'])) {
854
855             if ($sym['input'] == 'sqrt') {
856                 $node_0 = $this->parseSmplExpr();
857                 $node_0->removeBrackets();
858
859                 $node_1 = $this->createNode();
860                 $node_1->setName($sym['tag']);
861                 $node_1->addChild($node_0);
862
863                 return($node_1);
864             } elseif (isset($sym['func'])) { //added 2006-9-7 David Lippman
865                 $expr = ltrim($this->getCurrExpr());
866                 $st = $expr{0};
867                 $node_0 = $this->parseSmplExpr();
868                 //$node_0->removeBrackets();
869                 if ($st=='^' || $st == '_' || $st=='/' || $st=='|' || $st==',') {
870                     $node_1 = $this->createNode();
871                     $node_1->setName($sym['tag']);
872                     $node_1->setContent($sym['output']);
873                     $this->setCurrExpr($expr);
874                     return($node_1);
875                 } else {
876                     $node_1 = $this->createNode();
877                     $node_1->setName('mrow');
878                     $node_2 = $this->createNode();
879                     $node_2->setName($sym['tag']);
880                     $node_2->setContent($sym['output']);
881                     $node_1->addChild($node_2);
882                     $node_1->addChild($node_0);
883                     return($node_1);
884                 }
885             } elseif ($sym['input'] == 'text' || $sym['input'] == 'mbox' || $sym['input'] == '"') {
886                 $expr = ltrim($this->getCurrExpr());
887                 if ($sym['input']=='"') {
888                     $end_brckt = '"';
889                     $txt = substr($expr,0,strpos($expr,$end_brckt));
890                 } else {
891                     switch($expr{0}) {
892                         case '(':
893                             $end_brckt = ')';
894                             break;
895                         case '[':
896                             $end_brckt = ']';
897                             break;
898                         case '{':
899                             $end_brckt = '}';
900                             break;
901                         default:
902                             $end_brckt = chr(11); // A character that will never be matched.
903                             break;
904                     }
905                     $txt = substr($expr,1,strpos($expr,$end_brckt)-1);
906                 }
907
908                 //$txt = substr($expr,1,strpos($expr,$end_brckt)-1);
909                 $len = strlen($txt);
910
911                 $node_0 = $this->createNode();
912                 $node_0->setName('mrow');
913
914                 if ($len > 0) {
915                     if ($txt{0} == " ") {
916                         $node_1 = $this->createNode();
917                         $node_1->setName('mspace');
918                         $node_1->setAttr('width','1ex');
919
920                         $node_0->addChild($node_1);
921                     }
922
923                     $node_3 = $this->createNode();
924                     $node_3->setName($sym['tag']);
925                     $node_3->setContent(trim($txt));
926
927                     $node_0->addChild($node_3);
928
929                     if ($len > 1 && $txt{$len-1} == " ") {
930                         $node_2 = $this->createNode();
931                         $node_2->setName('mspace');
932                         $node_2->setAttr('width','1ex');
933
934                         $node_0->addChild($node_2);
935                     }
936
937                     $this->chopExpr($len+2);
938                 }
939                 return($node_0);
940
941             } elseif (isset($sym['acc'])) {
942                 $node_0 = $this->parseSmplExpr();
943                 $node_0->removeBrackets();
944
945                 $node_1 = $this->createNode();
946                 $node_1->setName($sym['tag']);
947                 $node_1->addChild($node_0);
948
949                 $node_2 = $this->createNode();
950                 $node_2->setName('mo');
951                 $node_2->setContent($sym['output']);
952
953                 $node_1->addChild($node_2);
954                 return($node_1);
955             } else {
956                 // Font change commands -- to complete
957             }
958         } elseif (isset($sym['binary'])) {
959             $node_arr = array();
960
961             $node_0 = $this->parseSmplExpr();
962             $node_0->removeBrackets();
963
964             $node_1 = $this->parseSmplExpr();
965             $node_1->removeBrackets();
966
967             /* 2005-06-05 wes: added stackrel */
968             if ($sym['input'] == 'root' || $sym['input'] == 'stackrel') {
969                 $node_arr[$node_1->getId()] = $node_1;
970                 $node_arr[$node_0->getId()] = $node_0;
971             } elseif ($sym['input'] == 'frac') {
972                 $node_arr[$node_0->getId()] = $node_0;
973                 $node_arr[$node_1->getId()] = $node_1;
974             }
975
976             $node_2 = $this->createNode();
977             $node_2->setName($sym['tag']);
978             $node_2->addChildArr($node_arr);
979
980             return($node_2);
981         } elseif (isset($sym['infix'])) {
982             $node_0 = $this->createNode();
983             $node_0->setName('mo');
984             $node_0->setContent($sym['output']);
985
986             return($node_0);
987         } elseif (isset($sym['space'])) {
988             $node_0 = $this->createNode();
989             $node_0->setName('mrow');
990
991             $node_1 = $this->createNode();
992             $node_1->setName('mspace');
993             $node_1->setAttr('width',$sym['space']);
994
995             $node_2 = $this->createNode();
996             $node_2->setName($sym['tag']);
997             $node_2->setContent($sym['output']);
998
999             $node_3 = $this->createNode();
1000             $node_3->setName('mspace');
1001             $node_3->setAttr('width',$sym['space']);
1002
1003             $node_0->addChild($node_1);
1004             $node_0->addChild($node_2);
1005             $node_0->addChild($node_3);
1006
1007             return($node_0);
1008         } else {
1009
1010             // A constant
1011             $node_0 = $this->createNode();
1012             $node_0->setName($sym['tag']);
1013             $node_0->setContent($sym['output']);
1014             return($node_0);
1015         }
1016
1017         // Return an empty node
1018         return $this->emptyNode();
1019     }
1020
1021     function getMathML()
1022     {
1023         $root = $this->_node_arr[0];
1024         return($root->dumpXML());
1025     }
1026
1027     function getCurrExpr()
1028     {
1029         return($this->_curr_expr);
1030     }
1031
1032     function setCurrExpr($str)
1033     {
1034         $this->_curr_expr = $str;
1035     }
1036
1037     function getExpr()
1038     {
1039         return($this->_expr);
1040     }
1041
1042     function getPrevExpr()
1043     {
1044         return($this->_prev_expr);
1045     }
1046
1047     function  createNode()
1048     {
1049         $node = new MathMLNode($this->_node_cntr);
1050         // $node->setNamespaceAlias('m');
1051         $this->_node_arr[$this->_node_cntr] = $node;
1052         $this->_node_cntr++;
1053         return($node);
1054     }
1055
1056     /**
1057      * Gets the largest symbol in the expression (greedy). Changed from non-greedy 26-Apr-2006
1058      *
1059      * @parameter boolean[optional] Chop original string?
1060      *
1061      * @return mixed
1062      *
1063      * @access private
1064      */
1065     function getSymbol($chop_flg = FALSE)
1066     {
1067         // Implemented a reverse symbol matcher.
1068         // Instead of going front to back, it goes back to front. Steven 26-Apr-2006
1069         $chr_cnt = strlen($this->_curr_expr);
1070
1071         if ($chr_cnt == 0) return FALSE;
1072
1073         for ($i = $chr_cnt; $i > 0; $i--) {
1074             $sym_0 = substr($this->_curr_expr,0,$i);
1075
1076             // Reading string for numeric values
1077             if (is_numeric($sym_0)) {
1078
1079                 if ($chop_flg) $this->chopExpr($i);
1080                 return array('input'=>$sym_0, 'tag'=>'mn', 'output'=>$sym_0, 'symlen'=>$i);
1081
1082             } elseif (isset($this->_symbol_arr[$sym_0])) {
1083
1084                 if ($chop_flg) $this->chopExpr($i);
1085                 $sym_arr = $this->_symbol_arr[$sym_0];
1086                 $sym_arr['symlen'] = $i;
1087                 return $sym_arr;
1088             }
1089         }
1090
1091         // Reading string for alphabetic constants and the minus sign
1092         $char = $this->_curr_expr{0};
1093         $len_left = $chop_flg ? $this->chopExpr(1) : strlen($this->_curr_expr)-1;
1094
1095         // Deals with expressions of length 1
1096         if ($len_left == 0 && isset($this->_symbol_arr[$char])) {
1097             $sym_arr = $this->_symbol_arr[$char];
1098             $sym_arr['symlen'] = 1;
1099             return $sym_arr;
1100         } else {
1101             $tag = preg_match('/[a-z]/i',$char) ? 'mi' : 'mo';
1102             return array('input'=>$char, 'tag'=>$tag, 'output'=>$char, 'symlen'=>1);
1103         }
1104     }
1105
1106     function chopExpr($strlen)
1107     {
1108         $this->_prev_expr = $this->_curr_expr;
1109
1110         if ($strlen == strlen($this->_curr_expr)) {
1111             $this->_curr_expr = '';
1112             return(0);
1113         } else {
1114             $this->_curr_expr = ltrim(substr($this->_curr_expr,$strlen));
1115             return(strlen($this->_curr_expr));
1116         }
1117     }
1118 }
1119 ?>