public void ConvertFracXYPlus2ReturnsFracXYPlus2InMML()
        {
            String latexExpression = @"$\frac{x}{y}+2$";
            String latexToConvert = begin + latexExpression + end;
            latex2MathMLConverter = new LatexMathToMathMLConverter();
            latex2MathMLConverter.BeforeXmlFormat += ConvertFracXYPlus2ReturnsFracXYPlus2InMMLEventListener;
            latex2MathMLConverter.Convert(latexToConvert);
            String expected = @"<math xmlns=""http://www.w3.org/1998/Math/MathML"" alttext=""\frac{x}{y}+2"" display=""inline"" class=""normalsize"">
            <mstyle displaystyle=""true"" /><mrow>
            <mfrac>
            <mrow>
            <mi>x</mi>
            </mrow>
            <mrow>
            <mi>y</mi>
            </mrow>
            </mfrac>
            <mo>+</mo>
            <mn>2</mn>
            </mrow>
            </math>";
            Thread.Sleep(400);

            NUnit.Framework.Assert.That(result, Is.EqualTo(expected));
        }
        public static string ConvertLatextToMathMl(string latexExp)
        {
            LatexMathToMathMLConverter lmm;

            //For demo Try with following Expression
            //String latexExpression = @"$\frac{\mathrm d}{\mathrm d x} \big( k g(x \big)$";
            lmm = new LatexMathToMathMLConverter();
            return(lmm.ConvertToMathMLTree(latexExpression: latexExp));
        }
 public void Convert()
 {
     String latexExpression = @"\begin{document} $\frac{\mathrm d}{\mathrm d x} \big( k g(x \big)$ \end{document}";
     lmm = new LatexMathToMathMLConverter();
     lmm.ValidateResult = true;
     lmm.BeforeXmlFormat += MyEventListener;
     lmm.ExceptionEvent += ExceptionListener;
     lmm.Convert(latexExpression);
 }
 /// <summary>
 /// Appends the opening MathML &lt;math&gt; tag to the specified StringBuilder instance.
 /// </summary>
 /// <param name="bld">The StringBuilder instance.</param>
 /// <param name="altText">The alternative text.</param>
 /// <param name="inline">Indicates whether the math block is inline.</param>
 public static void AppendMathProlog(StringBuilder bld, string altText,
     bool inline, LatexMathToMathMLConverter customization)
 {
     bld.Append("<math xmlns=\"http://www.w3.org/1998/Math/MathML\" alttext=\"");
     bld.Append(altText);
     bld.Append("\" ");
     bld.Append(inline ? "display=\"inline\"" : "display=\"block\"");
     bld.Append(" class=\"" + "normalsize" + "\"");
     bld.Append(">\n<mstyle displaystyle=\"true\" />");
 }
示例#5
0
		public void Convert() {
			String latexExpression = @"\begin{document}
                                        $\frac{\mathrm d}{\mathrm d x} \big( k g(x \big)$
                                        \end{document}";
			lmm = new LatexMathToMathMLConverter();
			lmm.ValidateResult = true;
			lmm.BeforeXmlFormat += MyEventListener;
			lmm.ExceptionEvent += ExceptionListener;
			lmm.Convert(latexExpression); 

		}
 public static string ConvertOutline(IList<LatexExpression> outline, LatexMathToMathMLConverter customization)
 {
     var bld = new StringBuilder();
     var backupTextSize = customization.CurrentTextSize;
     var backupTextStyle = customization.CurrentTextStyle;
     foreach (var child in outline)
     {
         bld.Append(child.Convert());
     }
     customization.CurrentTextSize = backupTextSize;
     customization.CurrentTextStyle = backupTextStyle;
     return bld.ToString();
 }
        public void ConvertOperatorsDotsReturnsCorrectMML()
        {
            String latexExpression = @"$\dots \dotsm \vdots \ddots$";
            String latexToConvert = begin + latexExpression + end;
            latex2MathMLConverter = new LatexMathToMathMLConverter();
            latex2MathMLConverter.BeforeXmlFormat += ConvertOperatorsDotsReturnsCorrectMMLListener;
            latex2MathMLConverter.Convert(latexToConvert);

            String expected = @"<math xmlns=""http://www.w3.org/1998/Math/MathML"" alttext=""\dots \dotsm \vdots \ddots"" display=""inline"" class=""normalsize"">
            <mstyle displaystyle=""true"" /><mrow>
            <mo>&hellip;</mo>
            <mo>&ctdot;</mo>
            <mo>&dtdot;</mo>
            <mo>&vellip;</mo>
            </mrow>
            </math>";
            Thread.Sleep(400);

            NUnit.Framework.Assert.That(result, Is.EqualTo(expected));
        }
        public void ConvertOperatorsBinaryOperators()
        {
            String latexExpression = @"$\pm \mp \times \div \ast \star \dagger \ddagger \cap \cup \uplus \sqcap \sqcup \vee \wedge \cdot \diamond \bigtriangleup \bigtriangledown \triangleleft \triangledown \bigcirc \bullet \wr \oplus \ominus \otimes \oslash \odot \circ \setminus \amalg$";
            String latexToConvert = begin + latexExpression + end;
            latex2MathMLConverter = new LatexMathToMathMLConverter();
            latex2MathMLConverter.BeforeXmlFormat += ConvertOperatorsBinaryOperatorsListener;
            latex2MathMLConverter.Convert(latexToConvert);

            String expected = @"<math xmlns=""http://www.w3.org/1998/Math/MathML"" alttext=""\dots \dotsm \vdots \ddots"" display=""inline"" class=""normalsize"">
            <mstyle displaystyle=""true"" /><mrow>
            <mo>&hellip;</mo>
            <mo>&ctdot;</mo>
            <mo>&dtdot;</mo>
            <mo>&vellip;</mo>
            </mrow>
            </math>";
            Thread.Sleep(400);

            NUnit.Framework.Assert.That(result, Is.EqualTo(expected));
        }
 /// <summary>
 /// Builds a new LatexExpression instance (front).
 /// </summary>
 /// <param name="parent">The parent of the builded expression.</param>
 /// <param name="parentChildNumber">Index of the parent child outline.</param>
 /// <param name="indexInParentChild">Index in the parent child outline.</param>
 /// <param name="verbatimMode">True if verbatim mode is on; otherwise, false.</param>
 /// <param name="beginning">The beginning string.</param>
 /// <param name="rdr">The reader to read ahead.</param>
 /// <param name="end">The stub of the unparsed part.</param>
 /// <param name="mathMode">The math mode switch.</param>
 /// <param name="whitespaceBefore">Indicates whether there was at least one whitespace char before the returned result.</param>
 /// <param name="customization">The LatexMathToMathMLConverter class instance to customize the conversion result.</param>
 /// <returns></returns>
 private static LatexExpression ReadFromTextReader(LatexExpression parent, int parentChildNumber, 
     ref int indexInParentChild, ref bool verbatimMode, bool mathMode, LatexMathToMathMLConverter customization,
     string beginning, TextReader rdr, out string end, ref bool whitespaceBefore)
 {
     if (beginning == null && rdr == null)
     {
         end = null;
         return null;
     }
     return ReadFromTextReaderInner(parent, parentChildNumber, ref indexInParentChild, ref verbatimMode,
         mathMode, customization, beginning ?? rdr.ReadLine(), rdr, out end, ref whitespaceBefore);
 }
 /// <summary>
 /// Parses the document and builds the document object tree.
 /// </summary>
 /// <param name="rdr">The reader to read the document from.</param>
 /// <param name="customization">The LatexMathToMathMLConverter class instance to customize the conversion result.</param>
 /// <returns>The root of the document object tree.</returns>
 public static LatexExpression CreateRoot(TextReader rdr, LatexMathToMathMLConverter customization)
 {
     bool verbatimMode = false;
     int rootIndex = 0;
     var root = new LatexExpression(null, 0, ref rootIndex, ref verbatimMode,
         ExpressionType.Root, false, customization, null, null, null)
     {
         Expressions = new List<List<LatexExpression>>(1)
     };
     var children = new List<LatexExpression>();
     string beginning = null;
     string end;
     LatexExpression cmd;
     rootIndex = 0;
     bool mathMode = false;
     bool whitespaceBefore = false;
     while ((cmd = ReadFromTextReader(root, 0, ref rootIndex, ref verbatimMode,
         mathMode, customization, beginning, rdr, out end, ref whitespaceBefore)) != null)
     {
         CheckMathMode(cmd, ref mathMode);
         beginning = end;
         children.Add(cmd);
     }
     root.Expressions.Add(children);
     return root;
 }
        /// <summary>
        /// Initializes a new instance of the LatexExpression class.
        /// </summary>
        /// <param name="parent">The parent of the builded expression.</param>
        /// <param name="parentChildNumber">Index of the parent child outline.</param>
        /// <param name="indexInParentChild">Index in the parent child outline.</param>
        /// <param name="verbatimMode">True if verbatim mode is on; otherwise, false.</param>
        /// <param name="type">The expression type.</param>
        /// <param name="mathMode">The math mode switch.</param>
        /// <param name="name">The expression name.</param>
        /// <param name="options">The options of the expression.</param>
        /// <param name="customization">The LatexMathToMathMLConverter class instance to customize the conversion result.</param>
        /// <param name="values">The child outlines of the expression.</param>
        private LatexExpression(LatexExpression parent, int parentChildNumber, ref int indexInParentChild,
            ref bool verbatimMode, ExpressionType type, bool mathMode, LatexMathToMathMLConverter customization,
            string name, string options, params string[] values)
        {
            Parent = parent;
            ParentChildNumber = parentChildNumber;
            IndexInParentChild = indexInParentChild++;
            Customization = customization;
            Name = name;
            ExprType = type;
            MathMode = mathMode;
            #region Switch verbatim mode on/off
            if (type == ExpressionType.Verbatim)
            {
                verbatimMode = false;
            }
            if (Expressions != null && Name == "begin" &&
                Expressions[0][0].Name == "verbatim" && Expressions.Count == 1)
            {
                verbatimMode = true;
            }
            #endregion
            ParseOptions(options);
            if (values != null)
            {
                ParseExpressions(values);
            }
            #region If a math block, add the alternative text
            if (type == ExpressionType.InlineMath || type == ExpressionType.BlockMath)
            {
                // ReSharper disable PossibleNullReferenceException
                Expressions.Add(new List<LatexExpression>());
                int index = 0;
                Expressions[1].Add(new LatexExpression(this, 1, ref index, ref verbatimMode,
                    ExpressionType.PlainText, false, Customization, values[0], null, null));
                // ReSharper restore PossibleNullReferenceException
            }
            #endregion
            #region Post-parse plain text if in math mode
            if (ExprType == ExpressionType.PlainText && mathMode && Name.Length > 1 &&
                (Parent.ExprType != ExpressionType.Block || Parent.Name != "PlainText") &&
                (Parent.ExprType != ExpressionType.Command || Parent.Name != "begin" && Parent.Name != "end"))
            {
                ExprType = ExpressionType.Block;
                Name = "PlainText";
                #region Parse
                var list = new List<string>();
                var buf = "" + name[0];
                for (int pos = 1; pos < name.Length; pos++)
                {
                    var chrPre = name[pos - 1];
                    var chr = name[pos];
                    if (char.IsWhiteSpace(chr))
                    {
                        list.Add(buf);
                        buf = "";
                        continue;
                    }
                    if (char.IsDigit(chr))
                    {
                        #region Digit
                        if (char.IsDigit(chrPre))
                        {
                            buf += chr;
                            continue;
                        }
                        if (char.IsLetter(chr) || chr == '(')
                        {
                            list.Add("InvisibleTimes");
                        }
                        list.Add(buf);
                        buf = "" + chr;
                        continue;

                        #endregion
                    }
                    if (char.IsLetter(chr))
                    {
                        #region Letter
                        if (char.IsLetter(chrPre))
                        {
                            buf += chr;
                            continue;
                        }
                        if (char.IsDigit(chr) || chr == '(')
                        {
                            list.Add("InvisibleTimes");
                        }
                        list.Add(buf);
                        buf = "" + chr;
                        continue;

                        #endregion
                    }
                    #region >=, <=
                    if (chr == '=')
                    {
                        if (chrPre == '>' || chrPre == '<')
                        {
                            buf += chr;
                        }
                    }
                    #endregion
                    list.Add(buf);
                    buf = "" + chr;
                }
                list.Add(buf);
                #endregion
                Expressions = new List<List<LatexExpression>>(list.Count) {new List<LatexExpression>()};
                int i;
                for (i = 0; i < list.Count;)
                {
                    if (list[i].Trim() != "")
                    {
                        Expressions[0].Add(new LatexExpression(this, 0, ref i, ref verbatimMode,
                            ExpressionType.PlainText, true, customization, list[i].Trim(), null, null));
                    }
                    else
                    {
                        i++;
                    }
                }
            }
            #endregion
        }
 /// <summary>
 /// Initializes a new instance of the LatexExpression class of type ExpressionType.Block.
 /// </summary>
 /// <param name="name">The name of the block.</param>
 /// <param name="parent">The parent of the builded expression.</param>
 /// <param name="parentChildNumber">Index of the parent child outline.</param>
 /// <param name="indexInParentChild">Index in the parent child outline.</param>
 /// <param name="customization">The LatexMathToMathMLConverter class instance to customize the conversion result.</param>
 public LatexExpression(string name, LatexExpression parent, int parentChildNumber, int indexInParentChild, LatexMathToMathMLConverter customization)
 {
     Name = name;
     Customization = customization;
     ExprType = ExpressionType.Block;
     MathMode = parent.MathMode |
         parent.ExprType == ExpressionType.BlockMath | parent.ExprType == ExpressionType.InlineMath;
     Parent = parent;
     ParentChildNumber = parentChildNumber;
     IndexInParentChild = indexInParentChild;
     Expressions = new List<List<LatexExpression>> {new List<LatexExpression>()};
 }
 /// <summary>
 /// Initializes a new instance of the LatexParser class.
 /// </summary>
 /// <param name="source">The source string to build the tree from.</param>
 /// <param name="customization">The LatexMathToMathMLConverter class instance to customize the conversion result.</param>
 public LatexParser(string source, LatexMathToMathMLConverter customization)
 {
     if (String.IsNullOrEmpty(source))
     {
         throw new ArgumentException("The parameter can not be null or empty.", "source");
     }
     _source = source;
     _customization = customization;
 }
 /// <summary>
 /// Post-parses arrays.
 /// </summary>
 /// <param name="outline">The outline of a LatexExpression instance.</param>
 /// <param name="customization">The LatexMathToMathMLConverter class instance to customize the conversion result.</param>
 private static void PostParseArrays(IList<LatexExpression> outline, LatexMathToMathMLConverter customization)
 {
     for (int i = 0; i < outline.Count; i++)
     {
         if (outline[i].ExprType == ExpressionType.Block &&
             (ArrayLikeBlockNames.Contains(outline[i].Name)))
         {
             int parentChildNumber = outline[i].Expressions.Count == 1? 0 : 1;
             var main = outline[i].Expressions[parentChildNumber];
             var latex_array = new List<List<List<LatexExpression>>>(3) {new List<List<LatexExpression>>(3)};
             #region Build array
             int rowIndex = 0;
             for (int j = 0; ; j++)
             {
                 var cell = new List<LatexExpression>(2);
                 for (; j < main.Count &&
                     !(main[j].Name == "\\" && main[j].ExprType == ExpressionType.Command) &&
                     !(main[j].Name == "&" && main[j].ExprType == ExpressionType.PlainText)
                     ; j++)
                 {
                     // \hline won't do the same in XHTML
                     if (main[j].ExprType == ExpressionType.Command && main[j].Name == "hline") continue;
                     if (main[j].ExprType == ExpressionType.Comment) continue;
                     cell.Add(main[j]);
                 }
                 if (cell.Count > 0)
                 {
                     latex_array[rowIndex].Add(cell);
                 }
                 if (j == main.Count)
                 {
                     break;
                 }
                 if (main[j].Name == "\\")
                 {
                     rowIndex++;
                     latex_array.Add(new List<List<LatexExpression>>(3));
                 }
             }
             if (latex_array[rowIndex].Count == 0)
             {
                 latex_array.RemoveAt(rowIndex);
             }
             #endregion
             #region Link array
             main = new List<LatexExpression>(latex_array.Count);
             for (int j = 0; j < latex_array.Count; j++)
             {
                 // Add row
                 main.Add(new LatexExpression("", outline[i], parentChildNumber, j, customization));
                 for (int k = 0; k < latex_array[j].Count; k++)
                 {
                     // Add column cell
                     main[j].Expressions[0].Add(new LatexExpression("", main[j], 0, k, customization));
                     for (int m = 0; m < latex_array[j][k].Count; m++)
                     {
                         latex_array[j][k][m].Parent = main[j].Expressions[0][k];
                         latex_array[j][k][m].ParentChildNumber = 0;
                         latex_array[j][k][m].IndexInParentChild = m;
                         // Add cell atom
                         main[j].Expressions[0][k].Expressions[0].Add(latex_array[j][k][m]);
                     }
                 }
             }
             outline[i].Expressions[parentChildNumber] = main;
             #endregion
         }
     }
     for (int i = 0; i < outline.Count; i++)
     {
         if (outline[i].Expressions != null)
         {
             foreach (var subTree in outline[i].Expressions)
             {
                 PostParseArrays(subTree, customization);
             }
         }
     }
 }
        public void ConvertOperatorsWhitespacesReturnsMMLWithCorrectSpacing()
        {
            String latexExpression = @"$A,\qquad B, \quad C, \; D, \: E, \, F, \! G $";
            String latexToConvert = begin + latexExpression + end;
            latex2MathMLConverter = new LatexMathToMathMLConverter();
            latex2MathMLConverter.BeforeXmlFormat += ConvertOperatorsWhitespacesReturnsMMLWithCorrectSpacingListener;
            latex2MathMLConverter.Convert(latexToConvert);

            String expected = @"<math xmlns=""http://www.w3.org/1998/Math/MathML"" alttext=""A,\qquad B, \quad C, \; D, \: E, \, F, \! G "" display=""inline"" class=""normalsize"">
            <mstyle displaystyle=""true"" /><mrow>
            <mi>A</mi>
            <mo>,</mo>
            <mspace width=""4em""/><mi>B</mi>
            <mo>,</mo>
            <mspace width=""2em""/><mi>C</mi>
            <mo>,</mo>
            <mspace width=""1.1em""/><mi>D</mi>
            <mo>,</mo>
            <mspace width=""0.9em""/><mi>E</mi>
            <mo>,</mo>
            <mspace width=""0.7em""/><mi>F</mi>
            <mo>,</mo>
            <mspace width=""0.3em""/><mi>G</mi>
            </mrow>
            </math>";
            Thread.Sleep(400);

            NUnit.Framework.Assert.That(result, Is.EqualTo(expected));
        }
        /// <summary>
        /// Builds the document object tree.
        /// </summary>
        /// <param name="customization">The LatexMathToMathMLConverter class instance to customize the conversion result.</param>
        /// <remarks>The parsing procedure consists of stand-alone passes, so that it resembles a compiler pipeline.</remarks>
        public void Parse(LatexMathToMathMLConverter customization)
        {
            foreach (var rule in PreformatRules)
            {
                _source = _source.Replace(rule[0], rule[1]);
            }
            var rdr = new StringReader(_source);
            const byte PASS_COUNT = 14;
            byte step = 1;

            // Build the tree
            LogInfo("CreateRoot");
            _root = LatexExpression.CreateRoot(rdr, customization);
            OnProgressEvent(step++, PASS_COUNT);

            //TODO Go through the usage of _customCommands
            // Rebuild tree with custom commands
            _customCommands = new Dictionary<string, LatexExpression>();
            LogInfo("RecursiveParseCustomCommands");

            // Incapsulate fragments between \begin and \end
            LogInfo("IncapsulateCommands");
            IncapsulateCommands(Root.Expressions[0]);
            OnProgressEvent(step++, PASS_COUNT);

            // Post-parse arrays
            LogInfo("PostParseArrays");
            PostParseArrays(Root.Expressions[0], customization);
            OnProgressEvent(step++, PASS_COUNT);

            // Build super- and subscripts
            LogInfo("BuildScripts");
            BuildScripts(Root.Expressions[0], customization);
            OnProgressEvent(step++, PASS_COUNT);

            // Simplify math blocks that begin with baseless scripts
            LogInfo("SimplifyScripts");
            SimplifyBaselessScripts(Root.Expressions[0]);
            OnProgressEvent(step++, PASS_COUNT);

            // Numerate blocks (needed for the next step)
            LogInfo("NumerateBlocks");
            NumerateBlocks(Root.FindDocument().Expressions[0]);
            Root.Customization.Counters.Add("document", 0);
            OnProgressEvent(step++, PASS_COUNT);

            // Simplify math blocks that begin with baseless scripts
            LogInfo("PreProcessLabels");
            PreprocessLabels(Root.FindDocument().Expressions[0]);
            Root.Customization.Counters.Clear();
            OnProgressEvent(step++, PASS_COUNT);

            // Deal with algorithmic blocks
            LogInfo("PreprocessAlgorithms");
            PreprocessAlgorithms(Root.FindDocument().Expressions[0]);
            OnProgressEvent(step++, PASS_COUNT);

            LogInfo("Finished");
        }
 /// <summary>
 /// Performs the conversion procedure of math blocks.
 /// </summary>
 /// <param name="outline">The sequence of expressions to convert.</param>
 /// <param name="altText">The alternative text.</param>
 /// <param name="inline">Indicates whether the math block is inline.</param>
 /// <returns>The converted XML string.</returns>
 private static string CommonConvert(IList<LatexExpression> outline, string altText,
     bool inline, LatexMathToMathMLConverter customization)
 {
     if (outline.Count == 0) return "";
     var bld = new StringBuilder();
     AppendMathProlog(bld, altText, inline, customization);
     bld.Append("<mrow>\n");
     bld.Append(SequenceConverter.ConvertOutline(outline, customization));
     bld.Append("</mrow>\n");
     AppendMathEpilog(bld);
     return bld.ToString();
 }
        public void ConvertXSquaredReturnXSquaredInMML()
        {
            String latexExpression = "$x^2$";
            String latexToConvert = begin + latexExpression + end;
            latex2MathMLConverter= new LatexMathToMathMLConverter();
            latex2MathMLConverter.BeforeXmlFormat += ConvertXSquaredReturnXSquaredInMMLEventListener;
            latex2MathMLConverter.Convert(latexToConvert);

            String expected = @"<math xmlns=""http://www.w3.org/1998/Math/MathML"" alttext=""x^2"" display=""inline"" class=""normalsize"">
            <mstyle displaystyle=""true"" /><mrow>
            <msup>
            <mrow>
            <mi>x</mi>
            </mrow>
            <mrow>
            <mn>2</mn>
            </mrow>
            </msup>
            </mrow>
            </math>";
            Thread.Sleep(400);
            Console.WriteLine(result);
            Console.WriteLine(expected);
            NUnit.Framework.Assert.That(result, Is.EqualTo(expected));
        }
        public void ConvertSymbolsGreekLettersReturnsCorrectMML()
        {
            String latexExpression = @"$A, \alpha, B, \beta, \Gamma, \gamma, \Delta, \delta, E, \epsilon, \varepsilon, Z, \zeta, H, \eta, \Theta, \theta, \vartheta, I, \iota, K, \kappa, \varkappa, \Lambda, \lambda, M, \mu, N, \nu, \Xi, \xi, O, o, \Pi, \pi, \varpi, P, \rho, \varrho, \Sigma, \sigma, \varsigma, T, \tau, \Upsilon, \upsilon, \Phi, \phi, \varphi, X, \chi, \Psi, \psi, \Omega, \omega$";
            String latexToConvert = begin + latexExpression + end;
            latex2MathMLConverter = new LatexMathToMathMLConverter();
            latex2MathMLConverter.BeforeXmlFormat += ConvertSymbolsGreekLettersReturnsCorrectMMLListener;
            latex2MathMLConverter.Convert(latexToConvert);

            String expected = @"<math xmlns=""http://www.w3.org/1998/Math/MathML"" alttext=""A, \alpha, B, \beta, \Gamma, \gamma, \Delta, \delta, E, \epsilon, \varepsilon, Z, \zeta, H, \eta, \Theta, \theta, \vartheta, I, \iota, K, \kappa, \varkappa, \Lambda, \lambda, M, \mu, N, \nu, \Xi, \xi, O, o, \Pi, \pi, \varpi, P, \rho, \varrho, \Sigma, \sigma, \varsigma, T, \tau, \Upsilon, \upsilon, \Phi, \phi, \varphi, X, \chi, \Psi, \psi, \Omega, \omega"" display=""inline"" class=""normalsize"">
            <mstyle displaystyle=""true"" /><mrow>
            <mi>A</mi>
            <mo>,</mo>
            <mi>&#x3B1;<!-- &alpha; --></mi><mo>,</mo>
            <mi>B</mi>
            <mo>,</mo>
            <mi>&#x3B2;<!-- &beta; --></mi><mo>,</mo>
            <mi>&#x393;<!-- &Gamma; --></mi><mo>,</mo>
            <mi>&#x3B3;<!-- &gamma; --></mi><mo>,</mo>
            <mi>&#x394;<!-- &Delta; --></mi><mo>,</mo>
            <mi>&#x3B4;<!-- &delta; --></mi><mo>,</mo>
            <mi>E</mi>
            <mo>,</mo>
            <mi>&#x3B5;<!-- &epsilon; --></mi><mo>,</mo>
            <mi>&#x3B5;<!-- &epsilon; --></mi><mo>,</mo>
            <mi>Z</mi>
            <mo>,</mo>
            <mi>&#x3B6;<!-- &zeta; --></mi><mo>,</mo>
            <mi>H</mi>
            <mo>,</mo>
            <mi>&#x3B7;<!-- &eta; --></mi><mo>,</mo>
            <mi>&#x398;<!-- &Theta; --></mi><mo>,</mo>
            <mi>&#x3B8;<!-- &theta; --></mi><mo>,</mo>
            <mi>&#x03D1;<!-- &theta --></mi><mo>,</mo>
            <mi>I</mi>
            <mo>,</mo>
            <mi>&#x3B9;<!-- &iota; --></mi><mo>,</mo>
            <mi>K</mi>
            <mo>,</mo>
            <mi>&#x3BA;<!-- &kappa; --></mi><mo>,</mo>
            <mi>&#x03F0;<!-- &kappav; --></mi><mo>,</mo>
            <mi>&#x39b;<!-- &Lambda; --></mi><mo>,</mo>
            <mi>&#x3BB;<!-- &lambda; --></mi><mo>,</mo>
            <mi>M</mi>
            <mo>,</mo>
            <mi>&#x3BC;<!-- &mu; --></mi><mo>,</mo>
            <mi>N</mi>
            <mo>,</mo>
            <mi>&#x3BD;<!-- &nu; --></mi><mo>,</mo>
            <mi>&#x39e;<!-- &Xi; --></mi><mo>,</mo>
            <mi>&#x3BE;<!-- &xi; --></mi><mo>,</mo>
            <mi>O</mi>
            <mo>,</mo>
            <mi>o</mi>
            <mo>,</mo>
            <mi>&#x3a0;<!-- &Pi; --></mi><mo>,</mo>
            <mi>&#x3C0;<!-- &pi; --></mi><mo>,</mo>
            <mi>&#x03D6;<!-- &piv; --></mi><mo>,</mo>
            <mi>P</mi>
            <mo>,</mo>
            <mi>&#x3C1;<!-- &rho; --></mi><mo>,</mo>
            <mi>&#x03F1;<!--&rhov --></mi><mo>,</mo>
            <mi>&#x3a3;<!--&Sigma --></mi><mo>,</mo>
            <mi>&#x3C3;<!-- &sigma; --></mi><mo>,</mo>
            <mi>&#x03C2;<!--&sigmav; --></mi><mo>,</mo>
            <mi>T</mi>
            <mo>,</mo>
            <mi>&#x3C4;<!-- &tau; --></mi><mo>,</mo>
            <mi>&#x3a5;<!-- &Upsilon; --></mi><mo>,</mo>
            <mi>&#x3C5;<!-- &upsilon; --></mi><mo>,</mo>
            <mi>&#x3a6;<!-- &Phi; --></mi><mo>,</mo>
            <mi>&#x3c6;<!-- &phi; --></mi><mo>,</mo>
            <mi>&#x03D5;<!-- &phiv; --></mi><mo>,</mo>
            <mi>X</mi>
            <mo>,</mo>
            <mi>&#x3C7;<!-- &chi; --></mi><mo>,</mo>
            <mi>&#x3a8;<!-- &Psi; --></mi><mo>,</mo>
            <mi>&#x3C8;<!-- &psi; --></mi><mo>,</mo>
            <mi>&#x3a9;<!-- &Omega; --></mi><mo>,</mo>
            <mi>&#x3C9;<!-- &omega; --></mi></mrow>
            </math>";
            Thread.Sleep(400);

            NUnit.Framework.Assert.That(result, Is.EqualTo(expected));
        }
        public void ConvertSymbolsForAllInQuadExistsLeqEpsilonLeGeqGeReturnsCorrectMML()
        {
            String latexExpression = @"$\forall x \in X, \quad \exists y \leq \epsilon \le \geq \ge$";
            String latexToConvert = begin + latexExpression + end;
            latex2MathMLConverter = new LatexMathToMathMLConverter();
            latex2MathMLConverter.BeforeXmlFormat += ConvertSymbolsForAllInQuadExistsLeqEpsilonReturnsCorrectMMLListener;
            latex2MathMLConverter.Convert(latexToConvert);

            String expected = @"<math xmlns=""http://www.w3.org/1998/Math/MathML"" alttext=""\forall x \in X, \quad \exists y \leq \epsilon \le \geq \ge"" display=""inline"" class=""normalsize"">
            <mstyle displaystyle=""true"" /><mrow>
            <mo>&#x2200;<!-- &forall; --></mo>
            <mi>x</mi>
            <mo>&#x2208;<!-- &isin; --></mo>
            <mi>X</mi>
            <mo>,</mo>
            <mspace width=""2em""/><mo>&#x2203;<!-- &exist; --></mo>
            <mi>y</mi>
            <mo>&#8804; <!-- leq --> </mo>
            <mi>&#x3B5;<!-- &epsilon; --></mi><mo>&#8804; <!-- le --> </mo>
            <mo>&#8805; <!-- geq --> </mo>
            <mo>&#8805; <!-- ge --> </mo>
            </mrow>
            </math>";
            Thread.Sleep(400);

            NUnit.Framework.Assert.That(result, Is.EqualTo(expected));
        }
        public void ConvertOperatorsRelationShipOperatorsReturnsCorrectMML()
        {
            String latexExpression = @"$< <= \leq \ll \subset \subseteq \nsubseteq \sqsubset \sqsubseteq \preceq > >=\geq \gg \supset \supseteq \nsupseteq \sqsupset \sqsupseteq \succeq = \doteq \equiv \approx \cong \simeq \sim \propto \neq \parallel \asymp \vdash \in \smile \models \perp \prec \sphericalangle$";
            String latexToConvert = begin + latexExpression + end;
            latex2MathMLConverter = new LatexMathToMathMLConverter();
            latex2MathMLConverter.BeforeXmlFormat += ConvertOperatorsRelationShipOperatorsReturnsCorrectMMLListener;
            latex2MathMLConverter.Convert(latexToConvert);

            String expected = @"<math xmlns=""http://www.w3.org/1998/Math/MathML"" alttext=""&amp;lt; &amp;lt;= \leq \ll \subset \subseteq \nsubseteq \sqsubset \sqsubseteq \preceq &amp;gt; &amp;gt;=\geq \gg \supset \supseteq \nsupseteq \sqsupset \sqsupseteq \succeq = \doteq \equiv \approx \cong \simeq \sim \propto \neq \parallel \asymp \vdash \in \smile \models \perp \prec \sphericalangle"" display=""inline"" class=""normalsize"">
            <mstyle displaystyle=""true"" /><mrow>
            <mo>&lt;</mo>
            <mo>&le;</mo>
            <mo>=</mo>
            <mo>&#8804; <!-- leq --> </mo>
            <mo>&#x226A;<!-- &Lt; --></mo>
            <mo>&#x2282;<!-- &sub; --></mo>
            <mo>&#x2286;<!-- &sube; --></mo>
            <mo>&#x2288;<!-- &nsube; --></mo>
            <mo>&#x228F;<!-- &sqsub; --></mo>
            <mo>&#x2291;<!-- &sqsube; --></mo>
            <mo>&#x227C;<!-- &cupre; --></mo>
            <mo>&gt;</mo>
            <mo>&ge;</mo>
            <mo>=</mo>
            <mo>&#8805; <!-- geq --> </mo>
            <mo>&#x226B;<!-- &Gt; --></mo>
            <mo>&#x2283;<!-- &sup; --></mo>
            <mo>&#x2287;<!-- &supe; --></mo>
            <mo>&#x2289;<!-- &nsupe; --></mo>
            <mo>&#x2290;<!-- &sqsup; --></mo>
            <mo>&#x2292;<!-- &sqsupe; --></mo>
            <mo>&#x227D;<!-- &sccue; --></mo>
            <mo>=</mo>
            <mo>&#x2250;<!-- &esdot; --></mo>
            <mo>&#x2261;<!-- equiv --></mo>
            <mo>&#x2248;<!-- &asymp; --></mo>
            <mo>&#x2245;<!-- &cong; --></mo>
            <mo>&#x2243;<!-- &sime; --></mo>
            <mo>&#x223C;<!-- &sim; --></mo>
            <mo>&#x221D;<!-- &vprop; --></mo>
            <mo>&#x2260;<!-- &ne; --></mo>
            <mo>&#x20E6;</mo>
            <mo>&#x224d;<!-- &asymp; --></mo>
            <mo>&#x22A2;<!-- &vdash; --></mo>
            <mo>&#x2208;<!-- &isin; --></mo>
            <mo>&#x23DD;</mo>
            <mo>&#x22A7;<!-- &models; --></mo>
            <mo>&#x22A5;<!-- &bottom; --></mo>
            <mo>&#x227A;<!-- &pr; --></mo>
            <mo>&#x2222;<!-- &angsph; --></mo>
            </mrow>
            </math>";
            Thread.Sleep(400);

            NUnit.Framework.Assert.That(result, Is.EqualTo(expected));
        }
        /// <summary>
        /// Builds a new LatexExpression instance (main).
        /// </summary>
        /// <param name="parent">The parent of the builded expression.</param>
        /// <param name="parentChildNumber">Index of the parent child outline.</param>
        /// <param name="indexInParentChild">Index in the parent child outline.</param>
        /// <param name="verbatimMode">True if verbatim mode is on; otherwise, false.</param>
        /// <param name="beginning">The beginning string.</param>
        /// <param name="rdr">The reader to read ahead.</param>
        /// <param name="mathMode">The math mode switch.</param>
        /// <param name="end">The stub of the unparsed part.</param>
        /// <param name="whitespaceBefore">Indicates whether there was at least one whitespace char before the returned result.</param>
        /// <param name="customization">The LatexMathToMathMLConverter class instance to customize the conversion result.</param>
        /// <returns>The parsed LatexExpression instance.</returns>
        private static LatexExpression ReadFromTextReaderInner(LatexExpression parent, int parentChildNumber,
            ref int indexInParentChild, ref bool verbatimMode, bool mathMode, LatexMathToMathMLConverter customization,
            string beginning, TextReader rdr, out string end, ref bool whitespaceBefore)
        {
            string name;

            #region Verbatim
            if (verbatimMode)
            {
                name = ReadToVerbatimEnd(beginning, rdr, out end);
                return new LatexExpression(parent, parentChildNumber, ref indexInParentChild,
                    ref verbatimMode, ExpressionType.Verbatim, false, customization, name, null, null);
            }
            #endregion

            bool whitespaceBeforeGuard;
            string str = ReadToNotEmptyString(beginning, rdr, out whitespaceBeforeGuard);
            whitespaceBefore |= whitespaceBeforeGuard;
            if (str == null)
            {
                end = null;
                return null;
            }
            string value;
            switch (str[0])
            {
                case '\\':
                    #region Command
                    string options;
                    string[] values;
                    name = Regex.Match(str.Substring(1), @"^[a-zA-Z]+\*?").Value;
                    if (String.IsNullOrEmpty(name))
                    {
                        name = "" + str[1];
                        options = null;
                        if (name != "[")
                        {
                            values = null;
                            end = str.Substring(2);
                        }
                        else // Math
                        {
                            value = ParseBraces(ref str, rdr, "\\[", "\\]", out whitespaceBefore);
                            end = str;
                            return new LatexExpression(parent, parentChildNumber, ref indexInParentChild,
                                ref verbatimMode, ExpressionType.BlockMath, mathMode, customization,
                                name, null, value);
                        }
                    }
                    else
                    {
                        ParseCommandOptionsAndValues(
                            str.Substring(name.Length + 1), rdr, out end,
                            out options, out values, out whitespaceBefore);
                    }
                    return new LatexExpression(parent, parentChildNumber, ref indexInParentChild, ref verbatimMode,
                        ExpressionType.Command, mathMode, customization, name, options, values);
                    #endregion
                case '$':
                    #region Math
                    ExpressionType type;
                    if (str[1] == '$')
                    {
                        name = "$$";
                        value = ParseBraces(ref str, rdr, "$$", "$$", out whitespaceBefore);
                        type = ExpressionType.BlockMath;
                    }
                    else
                    {
                        name = "$";
                        value = ParseBraces(ref str, rdr, "$", "$", out whitespaceBefore);
                        type = ExpressionType.InlineMath;
                    }
                    end = str;
                    return new LatexExpression(parent, parentChildNumber, ref indexInParentChild,
                        ref verbatimMode, type, false, customization, name, null, value);
                    #endregion
                case '%':
                    #region Comment
                    end = null;
                    return new LatexExpression(parent, parentChildNumber, ref indexInParentChild, ref verbatimMode,
                        ExpressionType.Comment, false, customization, str.Substring(1), null, null);
                    #endregion
                case '{':
                    #region Block
                    value = ParseBraces(ref str, rdr, "{", "}", out whitespaceBefore);
                    end = str;
                    return new LatexExpression(parent, parentChildNumber, ref indexInParentChild,
                        ref verbatimMode, ExpressionType.Block, mathMode, customization, "{}", null, value);
                    #endregion
                case '&':
                    #region Table cell
                    end = str.Substring(1);
                    return new LatexExpression(parent, parentChildNumber, ref indexInParentChild, ref verbatimMode,
                        ExpressionType.PlainText, mathMode, customization, "&", null, null);
                    #endregion
                case '^':
                case '_':
                    #region Block for sub and sup
                    if (mathMode)
                    {
                        name = "" + str[0];
                        str = ReadToNotEmptyString(str.Substring(1), rdr, out whitespaceBefore);
                        switch (str[0])
                        {
                            case '{':
                                value = ParseBraces(ref str, rdr, "{", "}", out whitespaceBefore);
                                end = str;
                                break;
                            case '\\':
                                var cmdName = Regex.Match(str.Substring(1), @"^[a-zA-Z]+\*?").Value;
                                ParseCommandOptionsAndValues(
                                    str.Substring(cmdName.Length + 1), rdr, out end,
                                    out options, out values, out whitespaceBefore);
                                value = "\\" + cmdName + options;
                                if (values != null)
                                {
                                    for (int i = 0; i < values.Length; i++)
                                    {
                                        value += "{" + values[i] + "}";
                                    }
                                }
                                break;
                            default:
                                value = "" + str[0];
                                if (char.IsDigit(str[0]))
                                {
                                    value = Regex.Match(str, @"\d+").Value;
                                }
                                if (char.IsLetter(str[0]))
                                {
                                    value = Regex.Match(str, @"[a-zA-Z]+").Value;
                                }
                                end = str.Substring(value.Length);
                                break;
                        }
                        return new LatexExpression(parent, parentChildNumber, ref indexInParentChild,
                            ref verbatimMode, ExpressionType.Block, true, customization, name, null, value);
                    }
                    goto default;
                    #endregion
                default:
                    #region Plain text block
                    name = "";
                    var stopChars = mathMode ? new[] { '\\', '$', '{', '%', '&', '^', '_' } :
                        new[] { '\\', '$', '{', '%', '&' };
                    int stopPos;
                    while ((stopPos = GetStopPos(str, stopChars)) == -1)
                    {
                        if (rdr != null)
                        {
                            name += str + " ";
                            str = rdr.ReadLine();
                            if (str == null) // End of the document
                            {
                                name = name.Substring(0, name.Length - 1);
                                break;
                            }
                            if (str.Trim() == "")
                            {
                                str = "\\paragraph";
                                stopPos = 0;
                                break;
                            }
                        }
                        else
                        {
                            stopPos = str.Length;
                            break;
                        }
                    }
                    if (str == null) // End of the document?
                    {
                        end = null;
                    }
                    else
                    {
                        name += str.Substring(0, stopPos);
                        if (stopPos < str.Length && (str[stopPos] == '^' || str[stopPos] == '_'))
                        {
                            var match = Regex.Match(name, @"[a-zA-Z]+\s*\Z");
                            var chunk = match.Value;
                            if (chunk.Trim() == "")
                            {
                                match = Regex.Match(name, @"\d+\s*\Z");
                                chunk = match.Value;
                                if (chunk.Trim() == "")
                                {
                                    match = Regex.Match(name, @"\S\s*\Z");
                                    chunk = match.Value.Trim();
                                }
                            }
                            if (name != chunk)
                            {
                                end = name.Substring(match.Index) + str.Substring(stopPos);
                                name = name.Substring(0, match.Index);
                            }
                            else
                            {
                                end = str.Substring(stopPos);
                            }
                        }
                        else
                        {
                            end = str.Substring(stopPos);
                        }
                    }
                    return new LatexExpression(parent, parentChildNumber, ref indexInParentChild, ref verbatimMode,
                        ExpressionType.PlainText, mathMode, customization, (whitespaceBefore? " " : "") + SmartTextTrim(name), null, null);
                    #endregion
            }
        }
 /// <summary>
 /// Recursively build scripts (for msup, munder, etc.)
 /// </summary>
 /// <param name="list">The outline of a LatexExpression instance.</param>
 /// <param name="customization">The LatexMathToMathMLConverter class instance to customize the conversion result.</param>
 private static void BuildScripts(List<LatexExpression> list, LatexMathToMathMLConverter customization)
 {
     for (int i = 0; i < list.Count; i++)
     {
         if (list[i].Expressions != null)
         {
             foreach (var subTree in list[i].Expressions)
             {
                 BuildScripts(subTree, customization);
             }
         }
         if (list[i].ExprType == ExpressionType.Block &&
             (list[i].Name == "^" || list[i].Name == "_") && i > 0)
         {
             if (list[i - 1].ExprType == ExpressionType.Command && list[i - 1].Name == "limits")
             {
                 list[i - 1].EraseFromParent();
                 i--;
             }
             #region Place the previous expression to the script block
             if (i < list.Count - 1 && list[i + 1].ExprType == ExpressionType.Block &&
                 (list[i + 1].Name == "^" || list[i + 1].Name == "_"))
             {
                 var block = new LatexExpression("script" + list[i].Name + list[i + 1].Name, list[i].Parent,
                     list[i].ParentChildNumber, i - 1, customization);
                 block.MathMode = list[i].MathMode;
                 block.Expressions[0].Add(new LatexExpression(list[i - 1]));
                 block.Expressions[0].Add(new LatexExpression(list[i]));
                 block.Expressions[0].Add(new LatexExpression(list[i + 1]));
                 block.Expressions[0][0].Parent = block;
                 block.Expressions[0][0].ParentChildNumber = 0;
                 block.Expressions[0][0].IndexInParentChild = 0;
                 block.Expressions[0][0].MathMode = block.MathMode;
                 block.Expressions[0][1].Parent = block;
                 block.Expressions[0][1].ParentChildNumber = 0;
                 block.Expressions[0][1].IndexInParentChild = 1;
                 block.Expressions[0][1].MathMode = block.MathMode;
                 block.Expressions[0][2].Parent = block;
                 block.Expressions[0][2].ParentChildNumber = 0;
                 block.Expressions[0][2].IndexInParentChild = 2;
                 block.Expressions[0][2].MathMode = block.MathMode;
                 list[i - 1] = block;
                 list[i].EraseFromParent();
                 list[i].EraseFromParent();
             }
             else
             {
                 var block = new LatexExpression("script" + list[i].Name, list[i].Parent, list[i].ParentChildNumber, i - 1, customization);
                 block.MathMode = list[i].MathMode;
                 block.Expressions[0].Add(new LatexExpression(list[i - 1]));
                 block.Expressions[0].Add(new LatexExpression(list[i]));
                 block.Expressions[0][0].Parent = block;
                 block.Expressions[0][0].ParentChildNumber = 0;
                 block.Expressions[0][0].IndexInParentChild = 0;
                 block.Expressions[0][0].MathMode = block.MathMode;
                 block.Expressions[0][1].Parent = block;
                 block.Expressions[0][1].ParentChildNumber = 0;
                 block.Expressions[0][1].IndexInParentChild = 1;
                 block.Expressions[0][1].MathMode = block.MathMode;
                 list[i - 1] = block;
                 list[i].EraseFromParent();
             }
             i--;
             #endregion
         }
     }
 }
        public void ConvertOperatorsSinCosReturnsSinCos()
        {
            String latexExpression = @"$\cos (2\theta) = \cos^2 \theta - \sin^2 \theta$";
            String latexToConvert = begin + latexExpression + end;
            latex2MathMLConverter = new LatexMathToMathMLConverter();
            latex2MathMLConverter.BeforeXmlFormat += ConvertFracXYPlus2ReturnsFracXYPlus2InMMLEventListener;
            latex2MathMLConverter.Convert(latexToConvert);

            String expected = @"<math xmlns=""http://www.w3.org/1998/Math/MathML"" alttext=""\cos (2\theta) = \cos^2 \theta - \sin^2 \theta"" display=""inline"" class=""normalsize"">
            <mstyle displaystyle=""true"" /><mrow>
            <mi>cos</mi>
            <mfenced>
            <mrow>
            <mn>2</mn>
            <mi>&#x3B8;<!-- &theta; --></mi></mrow>
            </mfenced>
            <mo>=</mo>
            <msup>
            <mrow>
            <mi>cos</mi>
            </mrow>
            <mrow>
            <mn>2</mn>
            </mrow>
            </msup>
            <mi>&#x3B8;<!-- &theta; --></mi><mo>-</mo>
            <msup>
            <mrow>
            <mi>sin</mi>
            </mrow>
            <mrow>
            <mn>2</mn>
            </mrow>
            </msup>
            <mi>&#x3B8;<!-- &theta; --></mi></mrow>
            </math>";
            Thread.Sleep(400);

            NUnit.Framework.Assert.That(result, Is.EqualTo(expected));
        }