]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/ASCIIMathPHP/ASCIIMathPHP.class.php
new MathML plugin and lib
[SourceForge/phpwiki.git] / lib / ASCIIMathPHP / ASCIIMathPHP.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.02, 02 Oct 2004, (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  * Ver 1.02
26  * -- Fixed bug with mbox and text
27  * -- Fixed spacing bug with mbox and text
28  *
29  * Ver 1.01
30  * -- Fixed Bug that did not parse symbols greater than a single character
31  * correctly when appearing at end of expression.
32  *
33 ****/
34
35 class XMLNode
36 {
37         // Private variables
38         var $_id;
39         var $_name;
40         var $_content;
41         var $_mt_elem_flg;
42         var $_attr_arr;
43         var $_child_arr;
44         var $_nmspc;
45         var $_nmspc_alias;
46         var $_parent_id;
47         var $_parent_node;
48         
49         function & XMLNode($id = NULL)
50         {
51                 $this->_id = isset($id) ? $id : md5(uniqid(rand(),1));
52                 $this->_name = '';
53                 $this->_content = '';
54                 $this->_mt_elem_flg = FALSE;
55                 $this->_attr_arr = array();
56                 $this->_child_arr = array();
57                 $this->_nmspc = '';
58                 $this->_nmspc_alias = '';
59                 $this->_parent_id = FALSE;
60                 $this->_parent_node = NULL;
61         }
62         
63         function addChild(&$node)
64         {
65                 $this->_child_arr[$node->getId()] =& $node;
66                 $node->setParentId($this->_id);
67                 $node->setParentNode($this);
68         }
69         
70         function addChildArr(&$node_arr)
71         {
72                 $key_arr = array_keys($node_arr);
73                 $num_key = count($key_arr);
74                 
75                 for ($i = 0; $i < $num_key; $i++) {
76                         $node =& $node_arr[$key_arr[$i]];
77                         $this->addChild($node);
78                 }
79         }
80         
81         function insertChildBefore($idx,&$node)
82         {
83                 $key_arr = array_keys($this->_child_arr);
84                 $num_key = count($key_arr);
85                 $tmp_arr = arry();
86                 
87                 for ($i = 0;$i < $num_key;$i++) {
88                         if ($i == $idx) {
89                                 $tmp_arr[$node->getId()] =& $node;
90                         }
91                         $tmp_arr[$key_arr[$i]] =& $this->_child_arr[$key_arr[$i]];
92                 }
93                 $this->_child_arr =& $tmp_arr;
94         }
95         
96         function insertChildAfter($idx,&$node)
97         {
98                 $key_arr = array_keys($this->_child_arr);
99                 $num_key = count($key_arr);
100                 $tmp_arr = arry();
101                 
102                 for ($i = 0;$i < $num_key;$i++) {
103                         $tmp_arr[$key_arr[$i]] =& $this->_child_arr[$key_arr[$i]];
104                         if ($i == $idx) {
105                                 $tmp_arr[$node->getId()] =& $node;
106                         }
107                 }
108                 $this->_child_arr =& $tmp_arr;
109         }
110         
111         function setId($id)
112         {
113                 $this->_id = $id;
114         }
115         
116         function setName($name)
117         {
118                 $this->_name = $name;
119         }
120         
121         function setNamepace($nmspc)
122         {
123                 $this->_nmspc = $nmspc;
124         }
125         
126         function setNamespaceAlias($nmspc_alias)
127         {
128                 $this->_nmspc_alias = $nmspc_alias;
129         }
130         
131         function setContent($content)
132         {
133                 $this->_content = $content;
134         }
135         
136         function setEmptyElem($mt_elem_flg)
137         {
138                 $this->_mt_elem_flg = $mt_elem_flg;
139         }
140         
141         function setAttr($attr_nm,$attr_val)
142         {
143                 $this->_attr_arr[$attr_nm] = $attr_val;
144         }
145         
146         function setAttrArr($attr_arr)
147         {
148                 $this->_attr_arr = $attr_arr;
149         }
150         
151         function setParentId($id)
152         {
153                 $this->_parent_id = $id;
154         }
155         
156         function setParentNode(&$node)
157         {
158                 $this->_parent_node =& $node;
159         }
160         
161         function getId()
162         {
163                 return($this->_id);
164         }
165         
166         function getName()
167         {
168                 return($this->_name);
169         }
170         
171         function getNamespace()
172         {
173                 return($this->_nmspc);
174         }
175         
176         function getNamespaceAlias()
177         {
178                 return($this->_nmspc_alias);
179         }
180         
181         function getContent()
182         {
183                 return($this->_content);
184         }
185         
186         function getAttr($attr_nm)
187         {
188                 if (isset($this->_attr_arr[$attr_nm])) {
189                         return($this->_attr_arr[$attr_nm]);
190                 } else {
191                         return(NULL);
192                 }
193         }
194         
195         function getAttrArr()
196         {
197                 return($this->_attr_arr);
198         }
199         
200         function getParentId()
201         {
202                 return($this->parent_id);
203         }
204         
205         function & getParentNode()
206         {
207                 return($this->_parent_node);
208         }
209         
210         function & getChild($id)
211         {
212                 if (isset($this->_child_arr[$id])) {
213                         return($this->_child_arr[$id]);
214                 } else {
215                         return(FALSE);
216                 }
217         }
218         
219         function & getFirstChild()
220         {
221                 $id_arr = array_keys($this->_child_arr);
222                 $num_child = count($id_arr);
223                 
224                 if ($num_child > 0) {
225                         return($this->_child_arr[$id_arr[0]]);
226                 } else {
227                         return(FALSE);
228                 }
229         }
230         
231         function & getLastChild()
232         {
233                 $id_arr = array_keys($this->_child_arr);
234                 $num_child = count($id_arr);
235                 
236                 if ($num_child > 0) {
237                         return($this->_child_arr[$id_arr[$num_child - 1]]);
238                 } else {
239                         return(FALSE);
240                 }
241         }
242         
243         function & getChildByIdx($idx)
244         {
245                 $id_arr = array_keys($this->_child_arr);
246                 
247                 if (isset($this->_child_arr[$id_arr[$idx]])) {
248                         return($this->_child_arr[$id_arr[$idx]]);
249                 } else {
250                         return(FALSE);
251                 }
252         }
253         
254         function getNumChild()
255         {
256                 return(count($this->_child_arr));
257         }
258         
259         function removeChild($id)
260         {
261                 unset($this->_child_arr[$id]);
262         }
263         
264         function removeChildByIdx($idx)
265         {
266                 $key_arr = array_keys($this->_child_arr);
267                 unset($this->_child_arr[$key_arr[$idx]]);
268         }
269         
270         function removeFirstChild()
271         {
272                 $key_arr = array_keys($this->_child_arr);
273                 unset($this->_child_arr[$key_arr[0]]);
274         }
275         
276         function removeLastChild()
277         {
278                 $key_arr = array_keys($this->_child_arr);
279                 unset($this->_child_arr[$key_arr[count($key_arr)-1]]);
280         }
281         
282         function dumpXML($indent_str = "\t")
283         {
284                 $attr_txt = $this->_dumpAttr();
285                 $name = $this->_dumpName();
286                 $xmlns = $this->_dumpXmlns();
287                 $lvl = $this->_getCurrentLevel();
288                 $indent = str_pad('',$lvl,$indent_str);
289                 
290                 if ($this->_mt_elem_flg) {
291                         $tag = "$indent<$name$xmlns$attr_txt />";
292                         return($tag);
293                 } else {
294                         $key_arr = array_keys($this->_child_arr);
295                         $num_child = count($key_arr);
296                         
297                         $tag = "$indent<$name$xmlns$attr_txt>$this->_content";
298                         
299                         for ($i = 0;$i < $num_child;$i++) {
300                                 $node =& $this->_child_arr[$key_arr[$i]];
301                                 
302                                 $child_txt = $node->dumpXML($indent_str);
303                                 $tag .= "\n$child_txt";
304                         }
305                         
306                         $tag .= ($num_child > 0 ? "\n$indent</$name>" : "</$name>");
307                         return($tag);
308                 }
309         }
310         
311         function _dumpAttr()
312         {
313                 $id_arr = array_keys($this->_attr_arr);
314                 $id_arr_cnt = count($id_arr);
315                 $attr_txt = '';
316                 
317                 for($i = 0;$i < $id_arr_cnt;$i++) {
318                         $key = $id_arr[$i];
319                         $attr_txt .= " $key=\"{$this->_attr_arr[$key]}\"";
320                 }
321                 
322                 return($attr_txt);
323         }
324         
325         function _dumpName()
326         {
327                 $alias = $this->getNamespaceAlias();
328                 if ($alias == '') {
329                         return($this->getName());
330                 } else {
331                         return("$alias:" . $this->getName());
332                 }
333         }
334         
335         function _dumpXmlns()
336         {
337                 $nmspc = $this->getNamespace();
338                 $alias = $this->getNamespaceAlias();
339                 
340                 if ($nmspc != '') {
341                         if ($alias == '') {
342                                 return(" xmlns=\"" . $nmspc . "\"");
343                         } else {
344                                 return(" xmlns:$alias=\"" . $nmspc . "\"");
345                         }
346                 } else {
347                         return('');
348                 }
349         }
350         
351         function _getCurrentLevel()
352         {
353                 if ($this->_parent_id === FALSE) {
354                         return(0);
355                 } else {
356                         $node =& $this->getParentNode();
357                         $lvl = $node->_getCurrentLevel();
358                         $lvl++;
359                         return($lvl);
360                 }
361         }
362 }
363
364 class MathMLNode extends XMLNode
365 {
366         function & MathMLNode($id = NULL)
367         {
368                 parent::XMLNode($id);
369         }
370         
371         function removeBrackets()
372         {
373                 if ($this->_name == 'mrow') {
374                         if ($c_node_0 =& $this->getFirstChild()) {
375                                 $c_node_0->isLeftBracket() ? $this->removeFirstChild() : 0;
376                         }
377                         
378                         if ($c_node_0 =& $this->getLastChild()) {
379                                 $c_node_0->isRightBracket() ? $this->removeLastChild() : 0;
380                         }
381                 }
382         }
383         
384         function isLeftBracket()
385         {
386                 switch ($this->_content) {
387                         case '{':
388                         case '[':
389                         case '(':
390                                 return(TRUE);
391                                 break;
392                 }
393                 return(FALSE);
394         }
395         
396         function isRightBracket()
397         {
398                 switch ($this->_content) {
399                         case '}':
400                         case ']':
401                         case ')':
402                                 return(TRUE);
403                                 break;
404                 }
405                 return(FALSE);
406         }
407 }
408
409 class ASCIIMathPHP
410 {
411         var $_expr;
412         var $_curr_expr;
413         var $_prev_expr;
414         var $_symbol_arr;
415         var $_node_arr;
416         var $_node_cntr;
417         
418         function ASCIIMathPHP($symbol_arr,$expr = NULL)
419         {
420                 $this->_symbol_arr = $symbol_arr;
421                 if (isset($expr)) {
422                         $this->setExpr($expr);
423                 }
424         }
425         
426         function setExpr($expr)
427         {
428                 $this->_expr = $expr;
429                 $this->_curr_expr = $expr;
430                 $this->_prev_expr = $expr;
431                 
432                 $this->_node_arr = array();
433                 $this->_node_cntr = 0;
434         }
435         
436         function genMathML($attr_arr = NULL)
437         {
438                 // <math> node
439                 $node_0 =& $this->createNode();
440                 $node_0->setName('math');
441                 $node_0->setNamepace('http://www.w3.org/1998/Math/MathML');
442                 
443                 // <mstyle> node
444                 if (isset($attr_arr)) {
445                         $node_1 =& $this->createNode();
446                         $node_1->setName('mstyle');
447                         $node_1->setAttrArr($attr_arr);
448                         
449                         $node_arr =& $this->parseExpr();
450                         
451                         $node_1->addChildArr($node_arr);
452                         $node_0->addChild($node_1);
453                 } else {
454                         $node_arr =& $this->parseExpr();
455                         $node_0->addChildArr($node_arr);
456                 }
457                 
458                 return(TRUE);
459         }
460         
461         /*
462         function & mergeNodeArr(&$node_arr_0,&$node_arr_1)
463         {
464                 $key_arr_0 = array_keys($node_arr_0);
465                 $key_arr_1 = array_keys($node_arr_1);
466                 
467                 $num_key_0 = count($key_arr_0);
468                 $num_key_1 = count($key_arr_1);
469                 
470                 $merge_arr = array();
471                 
472                 for ($i = 0;$i < $num_key_0;$i++) {
473                         $merge_arr[$key_arr_0[$i]] =& $node_arr_0[$key_arr_0[$i]];
474                 }
475                 
476                 for ($j = 0;$j < $num_key_1;$i++) {
477                         $merge_arr[$key_arr_1[$i]] =& $node_arr_1[$key_arr_1[$i]];
478                 }
479                 
480                 return($merge_arr);
481         }
482         */
483         
484         function & parseExpr()
485         {
486                 // Child/Fragment array
487                 $node_arr = array();
488                 
489                 // Deal whole expressions like 'ax + by + c = 0' etc.
490                 do {
491                         $sym_0 = $this->getSymbol();
492                         $node_0 =& $this->parseSmplExpr();
493                         $sym = $this->getSymbol();
494                         // var_dump($sym);
495                         
496                         if (isset($sym['infix'])) {
497                                 $this->chopExpr($sym['symlen']);
498                                 $node_1 =& $this->parseSmplExpr();
499
500                                 if ($node_1 === FALSE) {
501                                         continue;
502                                 }
503
504                                 $node_1->removeBrackets();
505                                 
506                                 // If 'div' -- divide
507                                 if ($sym['input'] == '/') { 
508                                         $node_0->removeBrackets();
509                                 }
510                                 
511                                 // If 'sub' -- subscript
512                                 if ($sym['input'] == '_') { 
513                                         $sym_1 = $this->getSymbol();
514                                         
515                                         // If 'sup' -- superscript
516                                         if ($sym_1['input'] == '^') { 
517                                                 $this->chopExpr($sym_1['symlen']);
518                                                 $node_2 =& $this->parseSmplExpr();
519                                                 $node_2->removeBrackets();
520                                                 
521                                                 $node_3 =& $this->createNode();
522                                                 $node_3->setName(isset($sym_0['underover']) ? 'munderover' : 'msubsup');
523                                                 $node_3->addChild($node_0);
524                                                 $node_3->addChild($node_1);
525                                                 $node_3->addChild($node_2);
526                                                 
527                                                 $node_4 =& $this->createNode();
528                                                 $node_4->setName('mrow');
529                                                 $node_4->addChild($node_3);
530                                                 
531                                                 $node_arr[$node_4->getId()] =& $node_4;
532                                         } else {
533                                                 $node_2 =& $this->createNode();
534                                                 $node_2->setName(isset($sym_0['underover']) ? 'munder' : 'msub');
535                                                 $node_2->addChild($node_0);
536                                                 $node_2->addChild($node_1);
537                                                 
538                                                 $node_arr[$node_2->getId()] =& $node_2;
539                                         }
540                                 } else {
541                                         $node_2 =& $this->createNode();
542                                         $node_2->setName($sym['tag']);
543                                         $node_2->addChild($node_0);
544                                         $node_2->addChild($node_1);
545                                         
546                                         $node_arr[$node_2->getId()] =& $node_2;
547                                 }
548                                 
549                         } elseif ($node_0 !== FALSE) {
550                                 $node_arr[$node_0->getId()] =& $node_0;
551                         }
552                 } while (!isset($sym['right_bracket']) && $sym !== FALSE && $sym['output'] != '');
553                 
554                 //var_dump($sym);
555                 // Possibly to deal with matrices
556                 if (isset($sym['right_bracket'])) {
557                         $node_cnt = count($node_arr);
558                         $key_node_arr = array_keys($node_arr);
559                         
560                         if ($node_cnt > 1) {
561                                 $node_5 =& $node_arr[$key_node_arr[$node_cnt-1]];
562                                 $node_6 =& $node_arr[$key_node_arr[$node_cnt-2]];
563                         } else {
564                                 $node_5 = FALSE;
565                                 $node_6 = FALSE;
566                         }
567                         
568                         // Dealing with matrices
569                         if ($node_5 !== FALSE && $node_6 !== FALSE &&
570                                 $node_cnt > 1 && 
571                                 $node_5->getName() == 'mrow' && 
572                                 $node_6->getName() == 'mo' &&
573                                 $node_6->getContent() == ',') {
574                                 
575                                 // Checking if Node 5 has a LastChild
576                                 if ($node_7 =& $node_5->getLastChild()) {
577                                         $node_7_cntnt = $node_7->getContent();
578                                 } else {
579                                         $node_7_cntnt = FALSE;
580                                 }
581                                 
582                                 // If there is a right bracket
583                                 if ($node_7 !== FALSE && ($node_7_cntnt == ']' || $node_7_cntnt == ')')) {
584                                         
585                                         // Checking if Node 5 has a firstChild
586                                         if ($node_8 =& $node_5->getFirstChild()) {
587                                                 $node_8_cntnt = $node_8->getContent();
588                                         } else {
589                                                 $node_8_cntnt = FALSE;
590                                         }
591                                         
592                                         // If there is a matching left bracket
593                                         if ($node_8 !== FALSE && 
594                                                 (($node_8_cntnt == '(' && $node_7_cntnt == ')' && $sym['output'] != '}') ||
595                                                 ($node_8_cntnt == '[' && $node_7_cntnt == ']'))) {
596                                                         
597                                                 $is_mtrx_flg = TRUE;
598                                                 $comma_pos_arr = array();
599                                                 
600                                                 $i = 0;
601                                                 
602                                                 while ($i < $node_cnt && $is_mtrx_flg) {
603                                                         $tmp_node =& $node_arr[$key_node_arr[$i]];
604                                                         
605                                                         if($tmp_node_first =& $tmp_node->getFirstChild()) {
606                                                                 $tnfc = $tmp_node_first->getContent();
607                                                         } else {
608                                                                 $tnfc = FALSE;
609                                                         }
610                                                         
611                                                         if($tmp_node_last =& $tmp_node->getLastChild()) {
612                                                                 $tnlc = $tmp_node_last->getContent();
613                                                         } else {
614                                                                 $tnlc = FALSE;
615                                                         }
616                                                         
617                                                         if (isset($key_node_arr[$i+1])) {
618                                                                 $next_tmp_node =& $node_arr[$key_node_arr[$i+1]];
619                                                                 $ntnn = $next_tmp_node->getName();
620                                                                 $ntnc = $next_tmp_node->getContent();
621                                                         } else {
622                                                                 $ntnn = FALSE;
623                                                                 $ntnc = FALSE;
624                                                         }
625                                                         
626                                                         // Checking each node in node array for matrix criteria
627                                                         if ($is_mtrx_flg) {
628                                                                 $is_mtrx_flg = $tmp_node->getName() == 'mrow' &&
629                                                                         ($i == $node_cnt-1 || $ntnn == 'mo' && $ntnc == ',') &&
630                                                                         $tnfc == $node_8_cntnt && $tnlc == $node_7_cntnt;
631                                                         }
632
633                                                         if ($is_mtrx_flg) {
634                                                                 for ($j = 0;$j < $tmp_node->getNumChild();$j++) {
635                                                                         $tmp_c_node =& $tmp_node->getChildByIdx($j);
636                                                                         
637                                                                         if ($tmp_c_node->getContent() == ',') {
638                                                                                 $comma_pos_arr[$i][] = $j;
639                                                                         }
640                                                                 }
641                                                         }       
642                                                         
643                                                         if ($is_mtrx_flg && $i > 1) {
644                                                                 
645                                                                 $cnt_cpan = isset($comma_pos_arr[$i]) ? count($comma_pos_arr[$i]) : NULL;
646                                                                 $cnt_cpap = isset($comma_pos_arr[$i-2]) ? count($comma_pos_arr[$i-2]) : NULL;
647                                                                 $is_mtrx_flg = $cnt_cpan == $cnt_cpap;
648                                                         }
649                                                         
650                                                         $i += 2;
651                                                 }
652                                                 
653                                                 // If the node passes the matrix tests
654                                                 if ($is_mtrx_flg) {
655                                                         $tab_node_arr = array();
656                                                         
657                                                         for ($i = 0;$i < $node_cnt;$i += 2) {
658                                                                 $tmp_key_node_arr = array_keys($node_arr);
659                                                                 if (!($tmp_node =& $node_arr[$tmp_key_node_arr[0]])) {
660                                                                         break;
661                                                                 }
662                                                                 $num_child = $tmp_node->getNumChild();
663                                                                 $k = 0;
664                                                                 
665                                                                 $tmp_node->removeFirstChild();
666                                                                 
667                                                                 $row_node_arr = array();
668                                                                 $row_frag_node_arr = array();
669                                                                 
670                                                                 for ($j = 1;$j < ($num_child-1);$j++) {
671                                                                         if (isset($comma_pos_arr[$i][$k]) && 
672                                                                                 $j == $comma_pos_arr[$i][$k]) {
673                                                                                 
674                                                                                 $tmp_node->removeFirstChild();
675                                                                                 
676                                                                                 $tmp_c_node =& $this->createNode();
677                                                                                 $tmp_c_node->setName('mtd');
678                                                                                 $tmp_c_node->addChildArr($row_frag_node_arr);
679                                                                                 $row_frag_node_arr = array();
680                                                                                 
681                                                                                 $row_node_arr[$tmp_c_node->getId()] =& $tmp_c_node;
682                                                                                 
683                                                                                 $k++;
684                                                                         } else {
685                                                                                 
686                                                                                 if ($tmp_c_node =& $tmp_node->getFirstChild()) {
687                                                                                         $row_frag_node_arr[$tmp_c_node->getId()] =& $tmp_c_node;
688                                                                                         $tmp_node->removeFirstChild();
689                                                                                 }
690                                                                         }
691                                                                 }
692                                                                 
693                                                                 $tmp_c_node =& $this->createNode();
694                                                                 $tmp_c_node->setName('mtd');
695                                                                 $tmp_c_node->addChildArr($row_frag_node_arr);
696                                                                 
697                                                                 $row_node_arr[$tmp_c_node->getId()] =& $tmp_c_node;
698                                                                 
699                                                                 if (count($node_arr) > 2) {
700                                                                         $tmp_key_node_arr = array_keys($node_arr);
701                                                                         unset($node_arr[$tmp_key_node_arr[0]]);
702                                                                         unset($node_arr[$tmp_key_node_arr[1]]);
703                                                                 }
704                                                                 
705                                                                 $tmp_c_node =& $this->createNode();
706                                                                 $tmp_c_node->setName('mtr');
707                                                                 $tmp_c_node->addChildArr($row_node_arr);
708                                                                 
709                                                                 $tab_node_arr[$tmp_c_node->getId()] =& $tmp_c_node;
710                                                         }
711                                                         
712                                                         $tmp_c_node =& $this->createNode();
713                                                         $tmp_c_node->setName('mtable');
714                                                         $tmp_c_node->addChildArr($tab_node_arr);
715                                                         
716                                                         if (isset($sym['invisible'])) {
717                                                                 $tmp_c_node->setAttr('columnalign','left');
718                                                         }
719                                                         
720                                                         $key_node_arr = array_keys($node_arr);
721                                                         $tmp_c_node->setId($key_node_arr[0]);
722                                                         
723                                                         $node_arr[$tmp_c_node->getId()] =& $tmp_c_node;
724                                                 }
725                                         }
726                                 }
727                         }
728                         
729                         $this->chopExpr($sym['symlen']);
730                         if (!isset($sym['invisible'])) {
731                                 $node_7 =& $this->createNode();
732                                 $node_7->setName('mo');
733                                 $node_7->setContent($sym['output']);
734                                 $node_arr[$node_7->getId()] =& $node_7;
735                         }
736                 }
737                 
738                 return($node_arr);
739         }
740         
741         function & parseSmplExpr()
742         {
743                 $sym = $this->getSymbol();
744                 
745                 if (!$sym || isset($sym['right_bracket'])) {
746                         return(FALSE);
747                 }
748                 
749                 $this->chopExpr($sym['symlen']);
750                 
751                 if (isset($sym['left_bracket'])) {
752                         $node_arr =& $this->parseExpr();
753                         
754                         if (isset($sym['invisible'])) {
755                                 $node_0 =& $this->createNode();
756                                 $node_0->setName('mrow');
757                                 $node_0->addChildArr($node_arr);
758                                 
759                                 return($node_0);
760                         } else {
761                                 $node_0 =& $this->createNode();
762                                 $node_0->setName('mo');
763                                 $node_0->setContent($sym['output']);
764                                 
765                                 $node_1 =& $this->createNode();
766                                 $node_1->setName('mrow');
767                                 $node_1->addChild($node_0);
768                                 $node_1->addChildArr($node_arr);
769                                 
770                                 return($node_1);
771                         }
772                 } elseif (isset($sym['unary'])) {
773                         
774                         if ($sym['input'] == 'sqrt') {
775                                 $node_0 =& $this->parseSmplExpr();
776                                 $node_0->removeBrackets();
777                                 
778                                 $node_1 =& $this->createNode();
779                                 $node_1->setName($sym['tag']);
780                                 $node_1->addChild($node_0);
781                                 
782                                 return($node_1);
783                         } elseif ($sym['input'] == 'text' || $sym['input'] == 'mbox') {
784                                 $expr = ltrim($this->getCurrExpr());
785                                 
786                                 switch($expr{0}) {
787                                         case '(':
788                                                 $end_brckt = ')';
789                                                 break;
790                                         case '[':
791                                                 $end_brckt = ']';
792                                                 break;
793                                         case '{':
794                                                 $end_brckt = '}';
795                                                 break;
796                                         default:
797                                                 $end_brckt = chr(11); // A chracter that will never be matched.
798                                                 break;
799                                 }
800                                 
801                                 $txt = substr($expr,1,strpos($expr,$end_brckt)-1);
802                                 $len = strlen($txt);
803                                 
804                                 $node_0 =& $this->createNode();
805                                 $node_0->setName('mrow');
806                                 
807                                 if ($len > 0) {
808                                         if ($txt{0} == " ") {
809                                                 $node_1 =& $this->createNode();
810                                                 $node_1->setName('mspace');
811                                                 $node_1->setAttr('width','1ex');
812                                                 
813                                                 $node_0->addChild($node_1);
814                                         }
815                                         
816                                         $node_3 =& $this->createNode();
817                                         $node_3->setName($sym['tag']);
818                                         $node_3->setContent(trim($txt));
819                                         
820                                         $node_0->addChild($node_3);
821                                         
822                                         if ($len > 1 && $txt{$len-1} == " ") {
823                                                 $node_2 =& $this->createNode();
824                                                 $node_2->setName('mspace');
825                                                 $node_2->setAttr('width','1ex');
826                                                 
827                                                 $node_0->addChild($node_2);
828                                         }
829                                         
830                                         $this->chopExpr($len+2);
831                                 }
832                                 return($node_0);
833                                 
834                         } elseif (isset($sym['acc'])) {
835                                 $node_0 =& $this->parseSmplExpr();
836                                 $node_0->removeBrackets();
837                                 
838                                 $node_1 =& $this->createNode();
839                                 $node_1->setName($sym['tag']);
840                                 $node_1->addChild($node_0);
841                                 
842                                 $node_2 =& $this->createNode();
843                                 $node_2->setName('mo');
844                                 $node_2->setContent($sym['output']);
845                                 
846                                 $node_1->addChild($node_2);
847                                 return($node_1);
848                         } else {
849                                 // Font change commands -- to complete
850                         }
851                 } elseif (isset($sym['binary'])) {
852                         $node_arr = array();
853                         
854                         $node_0 =& $this->parseSmplExpr();
855                         $node_0->removeBrackets();
856                         
857                         $node_1 =& $this->parseSmplExpr();
858                         $node_1->removeBrackets();
859                         
860                         if ($sym['input'] == 'root') {
861                                 $node_arr[$node_1->getId()] =& $node_1;
862                                 $node_arr[$node_0->getId()] =& $node_0;
863                         } elseif ($sym['input'] == 'frac') {
864                                 $node_arr[$node_0->getId()] =& $node_0;
865                                 $node_arr[$node_1->getId()] =& $node_1;
866                         }
867                         
868                         $node_2 =& $this->createNode();
869                         $node_2->setName($sym['tag']);
870                         $node_2->addChildArr($node_arr);
871                         
872                         return($node_2);
873                 } elseif (isset($sym['infix'])) {
874                         $node_0 =& $this->createNode();
875                         $node_0->setName('mo');
876                         $node_0->setContent($sym['output']);
877                         
878                         return($node_0);
879                 } elseif (isset($sym['space'])) {
880                         $node_0 =& $this->createNode();
881                         $node_0->setName('mrow');
882                         
883                         $node_1 =& $this->createNode();
884                         $node_1->setName('mspace');
885                         $node_1->setAttr('width',$sym['space']);
886                         
887                         $node_2 =& $this->createNode();
888                         $node_2->setName($sym['tag']);
889                         $node_2->setContent($sym['output']);
890                         
891                         $node_3 =& $this->createNode();
892                         $node_3->setName('mspace');
893                         $node_3->setAttr('width',$sym['space']);
894                         
895                         $node_0->addChild($node_1);
896                         $node_0->addChild($node_2);
897                         $node_0->addChild($node_3);
898                         
899                         return($node_0);
900                 } else {
901                         
902                         // A constant
903                         $node_0 =& $this->createNode();
904                         $node_0->setName($sym['tag']);
905                         $node_0->setContent($sym['output']);
906                         return($node_0);
907                 }
908                 
909                 return(FALSE);
910         }
911         
912         function getMathML()
913         {
914                 $root =& $this->_node_arr[0];
915                 return($root->dumpXML());
916         }
917         
918         function getCurrExpr()
919         {
920                 return($this->_curr_expr);
921         }
922         
923         function getExpr()
924         {
925                 return($this->_expr);
926         }
927         
928         function getPrevExpr()
929         {
930                 return($this->_prev_expr);
931         }
932         
933         function & createNode()
934         {
935                 $node =& new MathMLNode($this->_node_cntr);
936                 // $node->setNamespaceAlias('m');
937                 $this->_node_arr[$this->_node_cntr] =& $node;
938                 $this->_node_cntr++;
939                 return($node);
940         }
941         
942         function getSymbol($chop_flg = FALSE)
943         {
944                 $chr_cnt = strlen($this->_curr_expr);
945                 
946                 if ($chr_cnt == 0) {
947                         return(FALSE);
948                 }
949                 
950                 for ($i = 1; $i < $chr_cnt; $i++) {
951                         $sym_0 = substr($this->_curr_expr,0,$i);
952                         $sym_1 = substr($this->_curr_expr,0,$i+1);
953                         
954                         // Reading string for numeric values
955                         if (is_numeric($sym_0)) {
956                                 
957                                 if (!is_numeric($sym_1)) {
958                                         $chop_flg ? $this->chopExpr($i) : 0;
959                                         return(array('input'=>$sym_0, 'tag'=>'mn', 'output'=>$sym_0, 'symlen'=>$i));
960                                 } elseif (is_numeric($sym_1) && $i == ($chr_cnt - 1)) {
961                                         $chop_flg ? $this->chopExpr($i+1) : 0;
962                                         return(array('input'=>$sym_1, 'tag'=>'mn', 'output'=>$sym_1, 'symlen'=>($i+1)));
963                                 }
964                                 
965                         } elseif (isset($this->_symbol_arr[$sym_0]) && !isset($this->_symbol_arr[$sym_1])) {
966                                 
967                                 $chop_flg ? $this->chopExpr($i) : 0;
968                                 $sym_arr = $this->_symbol_arr[$sym_0];
969                                 $sym_arr['symlen'] = $i;
970                                 return($sym_arr);
971                         
972                         } elseif (isset($this->_symbol_arr[$sym_1]) && $i == ($chr_cnt - 1)) {
973                                 
974                                 $chop_flg ? $this->chopExpr($i+1) : 0;
975                                 $sym_arr = $this->_symbol_arr[$sym_1];
976                                 $sym_arr['symlen'] = $i+1;
977                                 return($sym_arr);
978                         }
979                 }
980                 
981                 // Reading string for alphabetic constants and the minus sign
982                 $char = $this->_curr_expr{0};
983                 $len_left = $chop_flg ? $this->chopExpr(1) : strlen($this->_curr_expr)-1;
984                 
985                 // Deals with expressions of length 1
986                 if ($len_left == 0 && isset($this->_symbol_arr[$char])) {
987                         $sym_arr = $this->_symbol_arr[$char];
988                         $sym_arr['symlen'] = 1;
989                         return($sym_arr);
990                 } else {
991                         $tag = preg_match('/[a-z]/i',$char) ? 'mi' : 'mo';
992                         return(array('input'=>$char, 'tag'=>$tag, 'output'=>$char, 'symlen'=>1));
993                 }
994         }
995         
996         function chopExpr($strlen)
997         {
998                 $this->_prev_expr = $this->_curr_expr;
999                 
1000                 if ($strlen == strlen($this->_curr_expr)) {
1001                         $this->_curr_expr = '';
1002                         return(0);
1003                 } else {
1004                         $this->_curr_expr = ltrim(substr($this->_curr_expr,$strlen));
1005                         return(strlen($this->_curr_expr));
1006                 }
1007         }       
1008 }
1009 ?>