4 * ASCIIMathPHP and associated classes:
6 * -- MathMLNode extends XMLNode
8 * These classes are a PHP port of ASCIIMath(c) Peter Jipsen http://www.chapman.edu/~jipsen
10 * ASCIIMathPHP Version 1.12.1, 06 Jan 2007, (c) Kee-Lin Steven Chan (kc56@cornell.edu)
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or (at
15 * your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License (at http://www.gnu.org/copyleft/gpl.html)
26 * -- Included the missing setCurrExpr() method
29 * -- Added changes that David Lippman <DLippman@pierce.ctc.edu> made to bring ASCIIMathPHP up to
30 * ASCIIMath 1.4.7 functionality.
31 * -- Added parseIntExpr, for intermediate expression parsing rule, allowing x^2/x^3 to render as (x^2)/(x^3)
32 * -- Added quotes as another way of designating text; "hello" is equivalent to text(hello)
33 * -- Added FUNC designator to allow sin, cos, etc to act as functions, so sin(x)/x renders as {sin(x)}/x
36 * -- Fixed bug that stopped script execution for incomplete expressions
37 * -- Changed the algorithm for parsing expressions so that it matches the longest string possible (greedy)
40 * -- Added definition support
41 * -- Added stackrel support
42 * -- Added a bunch of different symbols etc. >>, << and definitions like dx, dy, dz etc.
45 * -- Fixed bug with mbox and text
46 * -- Fixed spacing bug with mbox and text
49 * -- Fixed Bug that did not parse symbols greater than a single character
50 * correctly when appearing at end of expression.
68 function & XMLNode($id = NULL)
70 $this->_id = isset($id) ? $id : md5(uniqid(rand(),1));
73 $this->_mt_elem_flg = FALSE;
74 $this->_attr_arr = array();
75 $this->_child_arr = array();
77 $this->_nmspc_alias = '';
78 $this->_parent_id = FALSE;
79 $this->_parent_node = NULL;
83 function addChild(&$node)
85 $this->_child_arr[$node->getId()] =& $node;
86 $node->setParentId($this->_id);
87 $node->setParentNode($this);
90 function addChildArr(&$node_arr)
92 $key_arr = array_keys($node_arr);
93 $num_key = count($key_arr);
95 for ($i = 0; $i < $num_key; $i++) {
96 $node =& $node_arr[$key_arr[$i]];
97 $this->addChild($node);
101 function insertChildBefore($idx,&$node)
103 $key_arr = array_keys($this->_child_arr);
104 $num_key = count($key_arr);
107 for ($i = 0;$i < $num_key;$i++) {
109 $tmp_arr[$node->getId()] =& $node;
111 $tmp_arr[$key_arr[$i]] =& $this->_child_arr[$key_arr[$i]];
113 $this->_child_arr =& $tmp_arr;
116 function insertChildAfter($idx,&$node)
118 $key_arr = array_keys($this->_child_arr);
119 $num_key = count($key_arr);
122 for ($i = 0;$i < $num_key;$i++) {
123 $tmp_arr[$key_arr[$i]] =& $this->_child_arr[$key_arr[$i]];
125 $tmp_arr[$node->getId()] =& $node;
128 $this->_child_arr =& $tmp_arr;
136 function setName($name)
138 $this->_name = $name;
141 function setNamepace($nmspc)
143 $this->_nmspc = $nmspc;
146 function setNamespaceAlias($nmspc_alias)
148 $this->_nmspc_alias = $nmspc_alias;
151 function setContent($content)
153 $this->_content = $content;
156 function setEmptyElem($mt_elem_flg)
158 $this->_mt_elem_flg = $mt_elem_flg;
161 function setAttr($attr_nm,$attr_val)
163 $this->_attr_arr[$attr_nm] = $attr_val;
166 function setAttrArr($attr_arr)
168 $this->_attr_arr = $attr_arr;
171 function setParentId($id)
173 $this->_parent_id = $id;
176 function setParentNode(&$node)
178 $this->_parent_node =& $node;
188 return($this->_name);
191 function getNamespace()
193 return($this->_nmspc);
196 function getNamespaceAlias()
198 return($this->_nmspc_alias);
201 function getContent()
203 return($this->_content);
206 function getAttr($attr_nm)
208 if (isset($this->_attr_arr[$attr_nm])) {
209 return($this->_attr_arr[$attr_nm]);
215 function getAttrArr()
217 return($this->_attr_arr);
220 function getParentId()
222 return($this->parent_id);
225 function & getParentNode()
227 return($this->_parent_node);
230 function & getChild($id)
232 if (isset($this->_child_arr[$id])) {
233 return($this->_child_arr[$id]);
239 function & getFirstChild()
241 $id_arr = array_keys($this->_child_arr);
242 $num_child = count($id_arr);
244 if ($num_child > 0) {
245 return($this->_child_arr[$id_arr[0]]);
251 function & getLastChild()
253 $id_arr = array_keys($this->_child_arr);
254 $num_child = count($id_arr);
256 if ($num_child > 0) {
257 return($this->_child_arr[$id_arr[$num_child - 1]]);
263 function & getChildByIdx($idx)
265 $id_arr = array_keys($this->_child_arr);
267 if (isset($this->_child_arr[$id_arr[$idx]])) {
268 return($this->_child_arr[$id_arr[$idx]]);
274 function getNumChild()
276 return(count($this->_child_arr));
279 function removeChild($id)
281 unset($this->_child_arr[$id]);
284 function removeChildByIdx($idx)
286 $key_arr = array_keys($this->_child_arr);
287 unset($this->_child_arr[$key_arr[$idx]]);
290 function removeFirstChild()
292 $key_arr = array_keys($this->_child_arr);
293 unset($this->_child_arr[$key_arr[0]]);
296 function removeLastChild()
298 $key_arr = array_keys($this->_child_arr);
299 unset($this->_child_arr[$key_arr[count($key_arr)-1]]);
302 function dumpXML($indent_str = "\t")
304 $attr_txt = $this->_dumpAttr();
305 $name = $this->_dumpName();
306 $xmlns = $this->_dumpXmlns();
307 $lvl = $this->_getCurrentLevel();
308 $indent = str_pad('',$lvl,$indent_str);
310 if ($this->_mt_elem_flg) {
311 $tag = "$indent<$name$xmlns$attr_txt />";
314 $key_arr = array_keys($this->_child_arr);
315 $num_child = count($key_arr);
317 $tag = "$indent<$name$xmlns$attr_txt>$this->_content";
319 for ($i = 0;$i < $num_child;$i++) {
320 $node =& $this->_child_arr[$key_arr[$i]];
322 $child_txt = $node->dumpXML($indent_str);
323 $tag .= "\n$child_txt";
326 $tag .= ($num_child > 0 ? "\n$indent</$name>" : "</$name>");
333 $id_arr = array_keys($this->_attr_arr);
334 $id_arr_cnt = count($id_arr);
337 for($i = 0;$i < $id_arr_cnt;$i++) {
339 $attr_txt .= " $key=\"{$this->_attr_arr[$key]}\"";
347 $alias = $this->getNamespaceAlias();
349 return($this->getName());
351 return("$alias:" . $this->getName());
355 function _dumpXmlns()
357 $nmspc = $this->getNamespace();
358 $alias = $this->getNamespaceAlias();
362 return(" xmlns=\"" . $nmspc . "\"");
364 return(" xmlns:$alias=\"" . $nmspc . "\"");
371 function _getCurrentLevel()
373 if ($this->_parent_id === FALSE) {
376 $node =& $this->getParentNode();
377 $lvl = $node->_getCurrentLevel();
384 class MathMLNode extends XMLNode
386 function & MathMLNode($id = NULL)
388 return parent::XMLNode($id);
391 function removeBrackets()
393 if ($this->_name == 'mrow') {
394 if ($c_node_0 =& $this->getFirstChild()) {
395 $c_node_0->isLeftBracket() ? $this->removeFirstChild() : 0;
398 if ($c_node_0 =& $this->getLastChild()) {
399 $c_node_0->isRightBracket() ? $this->removeLastChild() : 0;
404 function isLeftBracket()
406 switch ($this->_content) {
416 function isRightBracket()
418 switch ($this->_content) {
438 function ASCIIMathPHP($symbol_arr,$expr = NULL)
440 $this->_symbol_arr = $symbol_arr;
442 $this->setExpr($expr);
447 * Returns an empty node (containing a non-breaking space) 26-Apr-2006
449 * Used when an expression is incomplete
455 function & emptyNode()
457 $tmp_node =& $this->createNode();
458 $tmp_node->setName('mn');
459 $tmp_node->setContent('&#' . hexdec('200B') . ';');
463 function pushExpr($prefix) // 2005-06-11 wes
465 $this->_curr_expr = $prefix . $this->_curr_expr;
468 function setExpr($expr)
470 $this->_expr = $expr;
471 $this->_curr_expr = $expr;
472 $this->_prev_expr = $expr;
474 $this->_node_arr = array();
475 $this->_node_cntr = 0;
478 function genMathML($attr_arr = NULL)
481 $node_0 =& $this->createNode();
482 $node_0->setName('math');
483 $node_0->setNamepace('http://www.w3.org/1998/Math/MathML');
486 if (isset($attr_arr)) {
487 $node_1 =& $this->createNode();
488 $node_1->setName('mstyle');
489 $node_1->setAttrArr($attr_arr);
491 $node_arr = $this->parseExpr();
493 $node_1->addChildArr($node_arr);
494 $node_0->addChild($node_1);
496 $node_arr = $this->parseExpr();
497 $node_0->addChildArr($node_arr);
504 function & mergeNodeArr(&$node_arr_0,&$node_arr_1)
506 $key_arr_0 = array_keys($node_arr_0);
507 $key_arr_1 = array_keys($node_arr_1);
509 $num_key_0 = count($key_arr_0);
510 $num_key_1 = count($key_arr_1);
512 $merge_arr = array();
514 for ($i = 0;$i < $num_key_0;$i++) {
515 $merge_arr[$key_arr_0[$i]] =& $node_arr_0[$key_arr_0[$i]];
518 for ($j = 0;$j < $num_key_1;$i++) {
519 $merge_arr[$key_arr_1[$i]] =& $node_arr_1[$key_arr_1[$i]];
526 //Broken out of parseExpr Sept 7, 2006 David Lippman for
527 //ASCIIMathML 1.4.7 compatibility
528 function & parseIntExpr()
530 $sym_0 = $this->getSymbol();
531 $node_0 =& $this->parseSmplExpr();
532 $sym = $this->getSymbol();
534 if (isset($sym['infix']) && $sym['input'] != '/') {
535 $this->chopExpr($sym['symlen']);
536 $node_1 =& $this->parseSmplExpr();
538 if ($node_1 === FALSE) { //show box in place of missing argument
539 $node_1 =& $this->emptyNode();//??
541 $node_1->removeBrackets();
544 // If 'sub' -- subscript
545 if ($sym['input'] == '_') {
547 $sym_1 = $this->getSymbol();
549 // If 'sup' -- superscript
550 if ($sym_1['input'] == '^') {
551 $this->chopExpr($sym_1['symlen']);
552 $node_2 =& $this->parseSmplExpr();
553 $node_2->removeBrackets();
555 $node_3 =& $this->createNode();
556 $node_3->setName(isset($sym_0['underover']) ? 'munderover' : 'msubsup');
557 $node_3->addChild($node_0);
558 $node_3->addChild($node_1);
559 $node_3->addChild($node_2);
561 $node_4 =& $this->createNode();
562 $node_4->setName('mrow');
563 $node_4->addChild($node_3);
567 $node_2 =& $this->createNode();
568 $node_2->setName(isset($sym_0['underover']) ? 'munder' : 'msub');
569 $node_2->addChild($node_0);
570 $node_2->addChild($node_1);
575 $node_2 =& $this->createNode();
576 $node_2->setName($sym['tag']);
577 $node_2->addChild($node_0);
578 $node_2->addChild($node_1);
582 } elseif ($node_0 !== FALSE) {
585 return $this->emptyNode();
592 // Child/Fragment array
595 // Deal whole expressions like 'ax + by + c = 0' etc.
597 $sym_0 = $this->getSymbol();
598 $node_0 =& $this->parseIntExpr();
599 $sym = $this->getSymbol();
602 if (isset($sym['infix']) && $sym['input'] == '/') {
603 $this->chopExpr($sym['symlen']);
604 $node_1 =& $this->parseIntExpr();
606 if ($node_1 === FALSE) { //should show box in place of missing argument
607 $node_1 =& $this->emptyNode();
611 $node_1->removeBrackets();
613 // If 'div' -- divide
614 $node_0->removeBrackets();
615 $node_2 =& $this->createNode();
616 $node_2->setName($sym['tag']);
617 $node_2->addChild($node_0);
618 $node_2->addChild($node_1);
619 $node_arr[$node_2->getId()] =& $node_2;
621 } elseif ($node_0 !== FALSE) {
622 $node_arr[$node_0->getId()] =& $node_0;
624 } while (!isset($sym['right_bracket']) && $sym !== FALSE && $sym['output'] != '');
627 // Possibly to deal with matrices
628 if (isset($sym['right_bracket'])) {
629 $node_cnt = count($node_arr);
630 $key_node_arr = array_keys($node_arr);
633 $node_5 =& $node_arr[$key_node_arr[$node_cnt-1]];
634 $node_6 =& $node_arr[$key_node_arr[$node_cnt-2]];
640 // Dealing with matrices
641 if ($node_5 !== FALSE && $node_6 !== FALSE &&
643 $node_5->getName() == 'mrow' &&
644 $node_6->getName() == 'mo' &&
645 $node_6->getContent() == ',') {
647 // Checking if Node 5 has a LastChild
648 if ($node_7 =& $node_5->getLastChild()) {
649 $node_7_cntnt = $node_7->getContent();
651 $node_7_cntnt = FALSE;
654 // If there is a right bracket
655 if ($node_7 !== FALSE && ($node_7_cntnt == ']' || $node_7_cntnt == ')')) {
657 // Checking if Node 5 has a firstChild
658 if ($node_8 =& $node_5->getFirstChild()) {
659 $node_8_cntnt = $node_8->getContent();
661 $node_8_cntnt = FALSE;
664 // If there is a matching left bracket
665 if ($node_8 !== FALSE &&
666 (($node_8_cntnt == '(' && $node_7_cntnt == ')' && $sym['output'] != '}') ||
667 ($node_8_cntnt == '[' && $node_7_cntnt == ']'))) {
670 $comma_pos_arr = array();
674 while ($i < $node_cnt && $is_mtrx_flg) {
675 $tmp_node =& $node_arr[$key_node_arr[$i]];
677 if($tmp_node_first =& $tmp_node->getFirstChild()) {
678 $tnfc = $tmp_node_first->getContent();
683 if($tmp_node_last =& $tmp_node->getLastChild()) {
684 $tnlc = $tmp_node_last->getContent();
689 if (isset($key_node_arr[$i+1])) {
690 $next_tmp_node =& $node_arr[$key_node_arr[$i+1]];
691 $ntnn = $next_tmp_node->getName();
692 $ntnc = $next_tmp_node->getContent();
698 // Checking each node in node array for matrix criteria
700 $is_mtrx_flg = $tmp_node->getName() == 'mrow' &&
701 ($i == $node_cnt-1 || $ntnn == 'mo' && $ntnc == ',') &&
702 $tnfc == $node_8_cntnt && $tnlc == $node_7_cntnt;
706 for ($j = 0;$j < $tmp_node->getNumChild();$j++) {
707 $tmp_c_node =& $tmp_node->getChildByIdx($j);
709 if ($tmp_c_node->getContent() == ',') {
710 $comma_pos_arr[$i][] = $j;
715 if ($is_mtrx_flg && $i > 1) {
717 $cnt_cpan = isset($comma_pos_arr[$i]) ? count($comma_pos_arr[$i]) : NULL;
718 $cnt_cpap = isset($comma_pos_arr[$i-2]) ? count($comma_pos_arr[$i-2]) : NULL;
719 $is_mtrx_flg = $cnt_cpan == $cnt_cpap;
725 // If the node passes the matrix tests
727 $tab_node_arr = array();
729 for ($i = 0;$i < $node_cnt;$i += 2) {
730 $tmp_key_node_arr = array_keys($node_arr);
731 if (!($tmp_node =& $node_arr[$tmp_key_node_arr[0]])) {
734 $num_child = $tmp_node->getNumChild();
737 $tmp_node->removeFirstChild();
739 $row_node_arr = array();
740 $row_frag_node_arr = array();
742 for ($j = 1;$j < ($num_child-1);$j++) {
743 if (isset($comma_pos_arr[$i][$k]) &&
744 $j == $comma_pos_arr[$i][$k]) {
746 $tmp_node->removeFirstChild();
748 $tmp_c_node =& $this->createNode();
749 $tmp_c_node->setName('mtd');
750 $tmp_c_node->addChildArr($row_frag_node_arr);
751 $row_frag_node_arr = array();
753 $row_node_arr[$tmp_c_node->getId()] =& $tmp_c_node;
758 if ($tmp_c_node =& $tmp_node->getFirstChild()) {
759 $row_frag_node_arr[$tmp_c_node->getId()] =& $tmp_c_node;
760 $tmp_node->removeFirstChild();
765 $tmp_c_node =& $this->createNode();
766 $tmp_c_node->setName('mtd');
767 $tmp_c_node->addChildArr($row_frag_node_arr);
769 $row_node_arr[$tmp_c_node->getId()] =& $tmp_c_node;
771 if (count($node_arr) > 2) {
772 $tmp_key_node_arr = array_keys($node_arr);
773 unset($node_arr[$tmp_key_node_arr[0]]);
774 unset($node_arr[$tmp_key_node_arr[1]]);
777 $tmp_c_node =& $this->createNode();
778 $tmp_c_node->setName('mtr');
779 $tmp_c_node->addChildArr($row_node_arr);
781 $tab_node_arr[$tmp_c_node->getId()] =& $tmp_c_node;
784 $tmp_c_node =& $this->createNode();
785 $tmp_c_node->setName('mtable');
786 $tmp_c_node->addChildArr($tab_node_arr);
788 if (isset($sym['invisible'])) {
789 $tmp_c_node->setAttr('columnalign','left');
792 $key_node_arr = array_keys($node_arr);
793 $tmp_c_node->setId($key_node_arr[0]);
795 $node_arr[$tmp_c_node->getId()] =& $tmp_c_node;
801 $this->chopExpr($sym['symlen']);
802 if (!isset($sym['invisible'])) {
803 $node_7 =& $this->createNode();
804 $node_7->setName('mo');
805 $node_7->setContent($sym['output']);
806 $node_arr[$node_7->getId()] =& $node_7;
813 function & parseSmplExpr()
815 $sym = $this->getSymbol();
817 if (!$sym || isset($sym['right_bracket'])) //return FALSE;
818 return $this->emptyNode();
820 $this->chopExpr($sym['symlen']);
822 // 2005-06-11 wes: add definition type support
823 if(isset($sym['definition'])) {
824 $this->pushExpr($sym['output']);
825 $sym = $this->getSymbol();
826 $this->chopExpr($sym['symlen']);
829 if (isset($sym['left_bracket'])) {
830 $node_arr = $this->parseExpr();
832 if (isset($sym['invisible'])) {
833 $node_0 =& $this->createNode();
834 $node_0->setName('mrow');
835 $node_0->addChildArr($node_arr);
839 $node_0 =& $this->createNode();
840 $node_0->setName('mo');
841 $node_0->setContent($sym['output']);
843 $node_1 =& $this->createNode();
844 $node_1->setName('mrow');
845 $node_1->addChild($node_0);
846 $node_1->addChildArr($node_arr);
850 } elseif (isset($sym['unary'])) {
852 if ($sym['input'] == 'sqrt') {
853 $node_0 =& $this->parseSmplExpr();
854 $node_0->removeBrackets();
856 $node_1 =& $this->createNode();
857 $node_1->setName($sym['tag']);
858 $node_1->addChild($node_0);
861 } elseif (isset($sym['func'])) { //added 2006-9-7 David Lippman
862 $expr = ltrim($this->getCurrExpr());
864 $node_0 =& $this->parseSmplExpr();
865 //$node_0->removeBrackets();
866 if ($st=='^' || $st == '_' || $st=='/' || $st=='|' || $st==',') {
867 $node_1 =& $this->createNode();
868 $node_1->setName($sym['tag']);
869 $node_1->setContent($sym['output']);
870 $this->setCurrExpr($expr);
873 $node_1 =& $this->createNode();
874 $node_1->setName('mrow');
875 $node_2 =& $this->createNode();
876 $node_2->setName($sym['tag']);
877 $node_2->setContent($sym['output']);
878 $node_1->addChild($node_2);
879 $node_1->addChild($node_0);
882 } elseif ($sym['input'] == 'text' || $sym['input'] == 'mbox' || $sym['input'] == '"') {
883 $expr = ltrim($this->getCurrExpr());
884 if ($sym['input']=='"') {
886 $txt = substr($expr,0,strpos($expr,$end_brckt));
899 $end_brckt = chr(11); // A character that will never be matched.
902 $txt = substr($expr,1,strpos($expr,$end_brckt)-1);
905 //$txt = substr($expr,1,strpos($expr,$end_brckt)-1);
908 $node_0 =& $this->createNode();
909 $node_0->setName('mrow');
912 if ($txt{0} == " ") {
913 $node_1 =& $this->createNode();
914 $node_1->setName('mspace');
915 $node_1->setAttr('width','1ex');
917 $node_0->addChild($node_1);
920 $node_3 =& $this->createNode();
921 $node_3->setName($sym['tag']);
922 $node_3->setContent(trim($txt));
924 $node_0->addChild($node_3);
926 if ($len > 1 && $txt{$len-1} == " ") {
927 $node_2 =& $this->createNode();
928 $node_2->setName('mspace');
929 $node_2->setAttr('width','1ex');
931 $node_0->addChild($node_2);
934 $this->chopExpr($len+2);
938 } elseif (isset($sym['acc'])) {
939 $node_0 =& $this->parseSmplExpr();
940 $node_0->removeBrackets();
942 $node_1 =& $this->createNode();
943 $node_1->setName($sym['tag']);
944 $node_1->addChild($node_0);
946 $node_2 =& $this->createNode();
947 $node_2->setName('mo');
948 $node_2->setContent($sym['output']);
950 $node_1->addChild($node_2);
953 // Font change commands -- to complete
955 } elseif (isset($sym['binary'])) {
958 $node_0 =& $this->parseSmplExpr();
959 $node_0->removeBrackets();
961 $node_1 =& $this->parseSmplExpr();
962 $node_1->removeBrackets();
964 /* 2005-06-05 wes: added stackrel */
965 if ($sym['input'] == 'root' || $sym['input'] == 'stackrel') {
966 $node_arr[$node_1->getId()] =& $node_1;
967 $node_arr[$node_0->getId()] =& $node_0;
968 } elseif ($sym['input'] == 'frac') {
969 $node_arr[$node_0->getId()] =& $node_0;
970 $node_arr[$node_1->getId()] =& $node_1;
973 $node_2 =& $this->createNode();
974 $node_2->setName($sym['tag']);
975 $node_2->addChildArr($node_arr);
978 } elseif (isset($sym['infix'])) {
979 $node_0 =& $this->createNode();
980 $node_0->setName('mo');
981 $node_0->setContent($sym['output']);
984 } elseif (isset($sym['space'])) {
985 $node_0 =& $this->createNode();
986 $node_0->setName('mrow');
988 $node_1 =& $this->createNode();
989 $node_1->setName('mspace');
990 $node_1->setAttr('width',$sym['space']);
992 $node_2 =& $this->createNode();
993 $node_2->setName($sym['tag']);
994 $node_2->setContent($sym['output']);
996 $node_3 =& $this->createNode();
997 $node_3->setName('mspace');
998 $node_3->setAttr('width',$sym['space']);
1000 $node_0->addChild($node_1);
1001 $node_0->addChild($node_2);
1002 $node_0->addChild($node_3);
1008 $node_0 =& $this->createNode();
1009 $node_0->setName($sym['tag']);
1010 $node_0->setContent($sym['output']);
1014 // Return an empty node
1015 return $this->emptyNode();
1018 function getMathML()
1020 $root =& $this->_node_arr[0];
1021 return($root->dumpXML());
1024 function getCurrExpr()
1026 return($this->_curr_expr);
1029 function setCurrExpr($str)
1031 $this->_curr_expr = $str;
1036 return($this->_expr);
1039 function getPrevExpr()
1041 return($this->_prev_expr);
1044 function & createNode()
1046 $node =& new MathMLNode($this->_node_cntr);
1047 // $node->setNamespaceAlias('m');
1048 $this->_node_arr[$this->_node_cntr] =& $node;
1049 $this->_node_cntr++;
1054 * Gets the largest symbol in the expression (greedy). Changed from non-greedy 26-Apr-2006
1056 * @parameter boolean[optional] Chop original string?
1062 function getSymbol($chop_flg = FALSE)
1064 // Implemented a reverse symbol matcher.
1065 // Instead of going front to back, it goes back to front. Steven 26-Apr-2006
1066 $chr_cnt = strlen($this->_curr_expr);
1068 if ($chr_cnt == 0) return FALSE;
1070 for ($i = $chr_cnt; $i > 0; $i--) {
1071 $sym_0 = substr($this->_curr_expr,0,$i);
1073 // Reading string for numeric values
1074 if (is_numeric($sym_0)) {
1076 if ($chop_flg) $this->chopExpr($i);
1077 return array('input'=>$sym_0, 'tag'=>'mn', 'output'=>$sym_0, 'symlen'=>$i);
1079 } elseif (isset($this->_symbol_arr[$sym_0])) {
1081 if ($chop_flg) $this->chopExpr($i);
1082 $sym_arr = $this->_symbol_arr[$sym_0];
1083 $sym_arr['symlen'] = $i;
1088 // Reading string for alphabetic constants and the minus sign
1089 $char = $this->_curr_expr{0};
1090 $len_left = $chop_flg ? $this->chopExpr(1) : strlen($this->_curr_expr)-1;
1092 // Deals with expressions of length 1
1093 if ($len_left == 0 && isset($this->_symbol_arr[$char])) {
1094 $sym_arr = $this->_symbol_arr[$char];
1095 $sym_arr['symlen'] = 1;
1098 $tag = preg_match('/[a-z]/i',$char) ? 'mi' : 'mo';
1099 return array('input'=>$char, 'tag'=>$tag, 'output'=>$char, 'symlen'=>1);
1103 function chopExpr($strlen)
1105 $this->_prev_expr = $this->_curr_expr;
1107 if ($strlen == strlen($this->_curr_expr)) {
1108 $this->_curr_expr = '';
1111 $this->_curr_expr = ltrim(substr($this->_curr_expr,$strlen));
1112 return(strlen($this->_curr_expr));