/// <summary> /// Searches in a predefined conversion table and returns the converted result or null. /// </summary> /// <param name="table">The conversion table to search in.</param> /// <param name="expr">The expression to convert.</param> /// <returns>The converted result or null.</returns> private static string SearchInTables(IDictionary <string, string> table, LatexExpression expr) { string constant; if (table.TryGetValue(expr.Name, out constant)) { string children = ""; if (expr.Expressions != null && expr.Options != null && expr.Options.AsExpressions != null) { for (int i = 0; i < expr.Options.AsExpressions.Count; i++) { children += expr.Options.AsExpressions[i].Convert(); } } if (expr.Expressions != null) { for (int i = 0; i < expr.Expressions.Count; i++) { for (int j = 0; j < expr.Expressions[i].Count; j++) { children += expr.Expressions[i][j].Convert(); } } } return(constant + children); } return(null); }
public string ConvertToMathMLTree(string latexExpression) { //string prefixLatex = @"\begin{document}"; //string postfixLatex = @"\end{document}"; //string resultLatexExpression = string.Format("{0}{1}{2}", prefixLatex, latexExpression, postfixLatex); string resultLatexExpression = latexExpression; var parser = new LatexParser(resultLatexExpression, this); try { LatexExpression root = parser.Root; CallEventHandler(AfterDocumentWasParsed); String linkToMMLDDT = "<!DOCTYPE math SYSTEM 'http://www.w3.org/Math/DTD/mathml1/mathml.dtd'>"; StringBuilder sb = new StringBuilder(linkToMMLDDT); Output = root.Convert(); return(Output); } catch (Exception exp) { return(exp.Message); } }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { if (expr.Expressions == null) { return(""); } GetParameters(); var bld = new StringBuilder(); if (_mathMode) { bld.Append("<mover accent=\"true\">\n"); if (!_stretchy) { bld.Append(expr.Expressions[0][0].Convert()); } else { bld.Append(SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization)); } bld.Append("<mo stretchy=\"true\">" + _value + "</mo>\n</mover>\n"); } else { MathConverter.AppendMathProlog(bld, "accent", true, expr.Customization); bld.Append("<mrow>"); bld.Append("<mover accent=\"true\">\n"); bld.Append(expr.Expressions[0][0].Convert()); bld.Append("<mo>" + _value + "</mo>\n</mover>\n"); bld.Append("</mrow>\n"); MathConverter.AppendMathEpilog(bld); } return(bld.ToString()); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var bld = new StringBuilder("<"); var tag = _tag; if (CommandConverter.MathFunctionsScriptCommandConstants.ContainsKey(expr.Expressions[0][0].Name)) { tag = (_tag == "msup") ? "mover" : "munder"; } bld.Append(tag); bld.Append(">\n<mrow>\n"); var first = expr.Expressions[0][0].Convert(); if (first != "</mrow>\n</mfenced>\n") { bld.Append(first); } bld.Append("</mrow>\n<mrow>\n"); bld.Append(expr.Expressions[0][1].Convert()); bld.Append("</mrow>\n</"); bld.Append(tag); bld.Append(">\n"); if (first != "</mrow>\n</mfenced>\n") { return(bld.ToString()); } return(first + bld); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var bodyBuilder = new StringBuilder(); // Convert the {document} block LatexExpression documentExpression = expr.FindDocument(); if (documentExpression != null) { try { bodyBuilder.Append(documentExpression.Convert()); } // ReSharper disable RedundantCatchClause #pragma warning disable 168 catch (Exception e) #pragma warning restore 168 { #if DEBUG throw; #else Log.Error("Failed to convert the document block", e); #endif } // ReSharper restore RedundantCatchClause // ReSharper restore RedundantCatchClause } return(bodyBuilder.ToString()); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { if (expr.Expressions == null) return ""; var url = expr.Expressions[0][0].Name; var text = SequenceConverter.ConvertOutline(expr.Expressions[1], expr.Customization); return "<a href=\"" + url + "\">" + text + "</a>"; }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { if (expr.Expressions == null) return ""; GetParameters(); var bld = new StringBuilder(); if (_mathMode) { bld.Append("<mover accent=\"true\">\n"); if (!_stretchy) { bld.Append(expr.Expressions[0][0].Convert()); } else { bld.Append(SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization)); } bld.Append("<mo stretchy=\"true\">" + _value + "</mo>\n</mover>\n"); } else { MathConverter.AppendMathProlog(bld, "accent", true, expr.Customization); bld.Append("<mrow>"); bld.Append("<mover accent=\"true\">\n"); bld.Append(expr.Expressions[0][0].Convert()); bld.Append("<mo>" + _value + "</mo>\n</mover>\n"); bld.Append("</mrow>\n"); MathConverter.AppendMathEpilog(bld); } return bld.ToString(); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { if (expr.Expressions == null) return ""; var alg = "<code class=\"algorithm\">"; alg += SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization); return alg + "</code>\n"; }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { if (!expr.MathMode) { var formatDiv = "<span class=\"" + "normalsize" + "\">"; formatDiv += LatexStringToXmlString(expr.Name); return(formatDiv + "</span>"); } if (expr.Name == "InvisibleTimes") { return("<mo>⁢<!-- ⁢ --></mo>\n"); } if (char.IsLetter(expr.Name[0])) { return("<mi>" + expr.Name + "</mi>\n"); } if (char.IsDigit(expr.Name[0])) { return("<mn>" + expr.Name + "</mn>\n"); } string str; if (MathConstants.TryGetValue(expr.Name, out str)) { return(str); } return("<mo>" + LatexStringToXmlString(expr.Name.Trim()) + "</mo>\n"); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var bld = new StringBuilder("<"); var tag = _tag; bool reverse = false; if (CommandConverter.MathFunctionsScriptCommandConstants.ContainsKey(expr.Expressions[0][0].Name)) { tag = (_tag == "msupsub") ? "moverunder" : "munderover"; } else { tag = "msubsup"; reverse = _tag != tag; } bld.Append(tag); bld.Append(">\n<mrow>\n"); var first = expr.Expressions[0][0].Convert(); if (first != "</mrow>\n</mfenced>\n") { bld.Append(first); } bld.Append("</mrow>\n<mrow>\n"); bld.Append(expr.Expressions[0][reverse? 2 : 1].Convert()); bld.Append("</mrow>\n<mrow>\n"); bld.Append(expr.Expressions[0][reverse? 1 : 2].Convert()); bld.Append("</mrow>\n</"); bld.Append(tag); bld.Append(">\n"); if (first != "</mrow>\n</mfenced>\n") { return bld.ToString(); } return first + bld; }
/// <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> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var bodyBuilder = new StringBuilder(); // Convert the {document} block LatexExpression documentExpression = expr.FindDocument(); if (documentExpression != null) { try { bodyBuilder.Append(documentExpression.Convert()); } // ReSharper disable RedundantCatchClause #pragma warning disable 168 catch (Exception e) #pragma warning restore 168 { #if DEBUG throw; #else Log.Error("Failed to convert the document block", e); #endif } // ReSharper restore RedundantCatchClause // ReSharper restore RedundantCatchClause } return bodyBuilder.ToString(); }
/// <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> /// Recursively incapsulates tree fragments between \begin and \end. /// </summary> /// <param name="outline">The outline of a LatexExpression instance.</param> private static void IncapsulateCommands(List <LatexExpression> outline) { for (int i = 0; i < outline.Count; i++) { if (outline[i].ExprType == ExpressionType.Command && outline[i].Name == "begin") { var cmdValue = outline[i].Expressions[0][0].Name; int j; for (j = i; outline[j].Name != "end" || outline[j].Expressions == null || outline[j].Expressions[0][0].Name != cmdValue; j++) { } int length = j - i - 1; var subOutline = new LatexExpression[length]; // Cut the right chunk outline.CopyTo(i + 1, subOutline, 0, length); outline.RemoveRange(i + 1, length + 1); // Update outline[i] outline[i].Name = cmdValue; outline[i].ExprType = ExpressionType.Block; outline[i].Expressions.RemoveAt(0); for (int k = 0; k < outline[i].Expressions.Count; k++) { foreach (var expr in outline[i].Expressions[k]) { expr.ParentChildNumber--; } } // Update outline for (int k = i + 1; k < outline.Count; k++) { outline[k].IndexInParentChild -= length + 1; } // Update subOutline int parentChildNumber = outline[i].Expressions.Count; for (int k = 0; k < subOutline.Length; k++) { subOutline[k].Parent = outline[i]; subOutline[k].ParentChildNumber = parentChildNumber; subOutline[k].IndexInParentChild = k; } // Link subOutline outline[i].Expressions.Add(new List <LatexExpression>(subOutline)); IncapsulateCommands(outline[i].Expressions[parentChildNumber]); } } for (int i = 0; i < outline.Count; i++) { if (outline[i].Expressions != null) { foreach (var subTree in outline[i].Expressions) { IncapsulateCommands(subTree); } } } }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { expr.ExprType = ExpressionType.BlockMath; expr.Expressions.Add(new List <LatexExpression> { new LatexExpression("equation", expr, 1, 0, expr.Customization) }); return(expr.Convert()); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var bld = new StringBuilder("<p style=\"text-align:"); bld.Append(_alignment); bld.Append(";\">\n"); bld.Append(SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization)); bld.Append("</p>\n"); return bld.ToString(); }
/// <summary> /// Recursively replaces all occurences of src in all subtrees with the specified sequence of expressions. /// </summary> /// <param name="src">The string to search and replace.</param> /// <param name="repl">The replacesment sequence of expressions.</param> public void RecursiveReplace(string src, List <LatexExpression> repl) { if (Expressions != null) { foreach (var childOutline in Expressions) { for (int i = 0; i < childOutline.Count; i++) { childOutline[i].RecursiveReplace(src, repl); } } } if (ExprType == ExpressionType.PlainText) { int pos = Name.IndexOf(src); if (pos > -1) { if (pos > 0) { var beg = Name.Substring(0, pos); bool verbatimMode = false; int index = IndexInParentChild; Parent.Expressions[ParentChildNumber].Insert(IndexInParentChild, new LatexExpression(Parent, ParentChildNumber, ref index, ref verbatimMode, ExpressionType.PlainText, MathMode, Customization, beg, null, null)); IndexInParentChild++; } Parent.Expressions[ParentChildNumber].RemoveAt(IndexInParentChild); for (int i = IndexInParentChild; i < Parent.Expressions[ParentChildNumber].Count; i++) { Parent.Expressions[ParentChildNumber][i].IndexInParentChild = i + repl.Count; } var localRepl = new LatexExpression[repl.Count]; repl.CopyTo(localRepl); for (int i = 0; i < repl.Count; i++) { var expr = localRepl[i]; expr.Parent = Parent; expr.ParentChildNumber = ParentChildNumber; expr.IndexInParentChild = i + IndexInParentChild; } Parent.Expressions[ParentChildNumber].InsertRange(IndexInParentChild, localRepl); var end = Name.Substring(src.Length); if (end != "") { bool verbatimMode2 = false; int index2 = IndexInParentChild + repl.Count; Parent.Expressions[ParentChildNumber].Insert(index2, new LatexExpression(Parent, ParentChildNumber, ref index2, ref verbatimMode2, ExpressionType.PlainText, MathMode, Customization, end, null, null)); } } } }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { BlockConverter converter; if (BlockConverters.TryGetValue(expr.Name, out converter)) { return(converter.Convert(expr)); } return((new UnknownBlockConverter()).Convert(expr)); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var bld = new StringBuilder(); bld.Append("<mfrac>\n<mrow>\n"); bld.Append(SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization)); bld.Append("</mrow>\n<mrow>\n"); bld.Append(SequenceConverter.ConvertOutline(expr.Expressions[1], expr.Customization)); bld.Append("</mrow>\n</mfrac>\n"); return bld.ToString(); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { if (expr.Expressions == null) { return(""); } var url = expr.Expressions[0][0].Name; return("<a href=\"" + url + "\">" + url + "</a>"); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var bld = new StringBuilder("<p style=\"text-align:"); bld.Append(_alignment); bld.Append(";\">\n"); bld.Append(SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization)); bld.Append("</p>\n"); return(bld.ToString()); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var bld = new StringBuilder(); bld.Append("<mfrac>\n<mrow>\n"); bld.Append(SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization)); bld.Append("</mrow>\n<mrow>\n"); bld.Append(SequenceConverter.ConvertOutline(expr.Expressions[1], expr.Customization)); bld.Append("</mrow>\n</mfrac>\n"); return(bld.ToString()); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { if (expr.Expressions == null) { return(""); } var url = expr.Expressions[0][0].Name; var text = SequenceConverter.ConvertOutline(expr.Expressions[1], expr.Customization); return("<a href=\"" + url + "\">" + text + "</a>"); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { if (expr.Expressions == null) { return(""); } var alg = "<code class=\"algorithm\">"; alg += SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization); return(alg + "</code>\n"); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var tag = (int[])expr.Tag; var result = "<br />"; if (tag != null) { result += new string(' ', tag[1]); } return(result); }
/// <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> /// 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> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { if (expr.Expressions == null) return ""; if (expr.Parent.ExprType == ExpressionType.Block && expr.Parent.Name.IndexOf("script") > -1) { return SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization); } var bld = new StringBuilder(); string tag; tag = expr.Name == "^" ? "sup" : "sub"; bld.Append("<" + tag + ">\n"); bld.Append(SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization)); bld.Append("</" + tag + ">"); return bld.ToString(); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { if (expr.Expressions == null) { return(""); } var letter = expr.Expressions[0][0].Name[0]; string converted; if (!ConversionTable.TryGetValue(letter, out converted)) { converted = "" + letter; } return(converted); }
/// <summary> /// Checks for the beginning or the ending of a future block that must be parsed in math mode. /// </summary> /// <param name="expr">The suspected expression.</param> /// <param name="mathMode">The math mode flag.</param> private static void CheckMathMode(LatexExpression expr, ref bool mathMode) { if (!mathMode && expr.ExprType == ExpressionType.Command && expr.Expressions != null && expr.Name == "begin") { mathMode = BlockConverter.ImpliesMathMode(expr.Expressions[0][0].Name); } if (mathMode && expr.ExprType == ExpressionType.Command && expr.Expressions != null && expr.Name == "end") { if (BlockConverter.ImpliesMathMode(expr.Expressions[0][0].Name)) { mathMode = false; } } }
/// <summary> /// Initializes a new instance of the LatexExpression class and copies the specified expression data to it. /// </summary> /// <param name="expression">The expression to clone.</param> public LatexExpression(LatexExpression expression) { Parent = expression.Parent; Name = expression.Name; ExprType = expression.ExprType; MathMode = expression.MathMode; Customization = expression.Customization; if (expression.Options != null) { Options = new ExpressionOptions(); } if (expression.Expressions != null) { Expressions = new List <List <LatexExpression> >(expression.Expressions); } }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { CommandConverter converter; if (CommandConverters.TryGetValue(expr.GetCommandConverterHashCode(), out converter)) { if (converter.ExpectedBranchesCount > 0 && (expr.Expressions == null || expr.Expressions.Count < converter.ExpectedBranchesCount)) { throw new FormatException(@"Unexpected format in command \\" + converter.Name); //return "<!-- Unexpected format in command \\" + converter.Name + " -->"; } var result = converter.Convert(expr); // Make sure that {} blocks which were attached to the command by mistake will be converted, too. // Goddamn ancient Latex if (expr.Expressions != null && expr.Expressions.Count > converter.ExpectedBranchesCount) { for (int i = converter.ExpectedBranchesCount; i < expr.Expressions.Count; i++) { result += SequenceConverter.ConvertOutline(expr.Expressions[i], expr.Customization); } } return(result); } string constant; if (CommandConstants.TryGetValue(expr.Name, out constant)) { if (expr.MathMode) { return("<mi>" + constant + "</mi>"); } return(constant); } if ((constant = SearchInTables(MathCommandConstants, expr)) != null) { return(constant); } if ((constant = SearchInTables(MathFunctionsCommandConstants, expr)) != null) { return(constant); } if ((constant = SearchInTables(MathFunctionsScriptCommandConstants, expr)) != null) { return(constant); } return("<!-- \\" + LatexStringToXmlString(expr.Name) + " -->\n"); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var bld = new StringBuilder(); if (expr.Options == null) { bld.Append("<msqrt>\n<mrow>\n"); bld.Append(SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization)); bld.Append("</mrow>\n</msqrt>\n"); return bld.ToString(); } bld.Append("<mroot>\n<mrow>\n"); bld.Append(SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization)); bld.Append("</mrow>\n<mrow>\n"); bld.Append(SequenceConverter.ConvertOutline(expr.Options.AsExpressions, expr.Customization)); bld.Append("</mrow>\n</mroot>\n"); return bld.ToString(); }
/// <summary> /// Performs the conversion procedure (comments the expression). /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var bld = new StringBuilder(); int parentChildNumber = expr.Expressions.Count == 1 ? 0 : 1; var rows = expr.Expressions[parentChildNumber]; var alignments = parentChildNumber > 0 ? expr.Expressions[0][0].Name : ""; alignments = alignments.Replace("|", ""); bld.Append("<mtable>\n"); for (int i = 0; i < rows.Count; i++) { bld.Append("<mtr>\n"); for (int j = 0; j < rows[i].Expressions[0].Count; j++) { #region Determine the alignment var alignment = "center"; if (j < alignments.Length) { switch (alignments[j]) { case 'c': alignment = "center"; break; case 'l': alignment = "left"; break; case 'r': alignment = "right"; break; } } #endregion bld.Append("<mtd columnalign=\""); bld.Append(alignment); bld.Append("\">\n<mrow>\n"); bld.Append(SequenceConverter.ConvertOutline(rows[i].Expressions[0][j].Expressions[0], expr.Customization)); bld.Append("</mrow>\n</mtd>\n"); } bld.Append("</mtr>\n"); } bld.Append("</mtable>\n"); return(bld.ToString()); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var bld = new StringBuilder(); if (expr.Options == null) { bld.Append("<msqrt>\n<mrow>\n"); bld.Append(SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization)); bld.Append("</mrow>\n</msqrt>\n"); return(bld.ToString()); } bld.Append("<mroot>\n<mrow>\n"); bld.Append(SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization)); bld.Append("</mrow>\n<mrow>\n"); bld.Append(SequenceConverter.ConvertOutline(expr.Options.AsExpressions, expr.Customization)); bld.Append("</mrow>\n</mroot>\n"); return(bld.ToString()); }
/// <summary> /// Find the document block in children (valid only for the root expression). /// </summary> /// <returns></returns> public LatexExpression FindDocument() { if (ExprType != ExpressionType.Root) { return(null); } LatexExpression documentExpression = null; foreach (var child in Expressions[0]) { if (child.ExprType == ExpressionType.Block && child.Name == "document") { documentExpression = child; break; } } return(documentExpression); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { if (expr.Expressions == null) { return(""); } if (expr.Parent.ExprType == ExpressionType.Block && expr.Parent.Name.IndexOf("script") > -1) { return(SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization)); } var bld = new StringBuilder(); string tag; tag = expr.Name == "^" ? "sup" : "sub"; bld.Append("<" + tag + ">\n"); bld.Append(SequenceConverter.ConvertOutline(expr.Expressions[0], expr.Customization)); bld.Append("</" + tag + ">"); return(bld.ToString()); }
/// <summary> /// Performs the conversion procedure (comments the expression). /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var bld = new StringBuilder(); int parentChildNumber = expr.Expressions.Count == 1 ? 0 : 1; var rows = expr.Expressions[parentChildNumber]; var alignments = parentChildNumber > 0 ? expr.Expressions[0][0].Name : ""; alignments = alignments.Replace("|", ""); bld.Append("<mtable>\n"); for (int i = 0; i < rows.Count; i++) { bld.Append("<mtr>\n"); for (int j = 0; j < rows[i].Expressions[0].Count; j++) { #region Determine the alignment var alignment = "center"; if (j < alignments.Length) { switch (alignments[j]) { case 'c': alignment = "center"; break; case 'l': alignment = "left"; break; case 'r': alignment = "right"; break; } } #endregion bld.Append("<mtd columnalign=\""); bld.Append(alignment); bld.Append("\">\n<mrow>\n"); bld.Append(SequenceConverter.ConvertOutline(rows[i].Expressions[0][j].Expressions[0], expr.Customization)); bld.Append("</mrow>\n</mtd>\n"); } bld.Append("</mtr>\n"); } bld.Append("</mtable>\n"); return bld.ToString(); }
/// <summary> /// Performs the conversion procedure (comments the expression). /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var bld = new StringBuilder(); MathConverter.AppendMathProlog(bld, "eqnarray", false, expr.Customization); var rows = expr.Expressions[0]; bld.Append("<mtable>\n"); for (int i = 0; i < rows.Count; i++) { bld.Append("<mtr>\n"); for (int j = 0; j < rows[i].Expressions[0].Count; j++) { bld.Append("<mtd columnalign=\"left\">\n<mrow>\n"); bld.Append(SequenceConverter.ConvertOutline(rows[i].Expressions[0][j].Expressions[0], expr.Customization)); bld.Append("</mrow>\n</mtd>\n"); } bld.Append("</mtr>\n"); } bld.Append("</mtable>\n"); MathConverter.AppendMathEpilog(bld); return bld.ToString(); }
/// <summary> /// Performs the conversion procedure (comments the expression). /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { var bld = new StringBuilder(); MathConverter.AppendMathProlog(bld, "eqnarray", false, expr.Customization); var rows = expr.Expressions[0]; bld.Append("<mtable>\n"); for (int i = 0; i < rows.Count; i++) { bld.Append("<mtr>\n"); for (int j = 0; j < rows[i].Expressions[0].Count; j++) { bld.Append("<mtd columnalign=\"left\">\n<mrow>\n"); bld.Append(SequenceConverter.ConvertOutline(rows[i].Expressions[0][j].Expressions[0], expr.Customization)); bld.Append("</mrow>\n</mtd>\n"); } bld.Append("</mtr>\n"); } bld.Append("</mtable>\n"); MathConverter.AppendMathEpilog(bld); return(bld.ToString()); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { return CommonConvert(expr.Expressions[0], LatexStringToXmlString(expr.Expressions[1][0].Name), expr.ExprType == ExpressionType.InlineMath, expr.Customization); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { expr.ExprType = ExpressionType.BlockMath; expr.Expressions.Add(new List<LatexExpression> {new LatexExpression("equation", expr, 1, 0, expr.Customization)}); return expr.Convert(); }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { BlockConverter converter; if (BlockConverters.TryGetValue(expr.Name, out converter)) { return converter.Convert(expr); } return (new UnknownBlockConverter()).Convert(expr); }
/// <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> /// 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> /// Searches in a predefined conversion table and returns the converted result or null. /// </summary> /// <param name="table">The conversion table to search in.</param> /// <param name="expr">The expression to convert.</param> /// <returns>The converted result or null.</returns> private static string SearchInTables(IDictionary<string, string> table, LatexExpression expr) { string constant; if (table.TryGetValue(expr.Name, out constant)) { string children = ""; if (expr.Expressions != null && expr.Options != null && expr.Options.AsExpressions != null) { for (int i = 0; i < expr.Options.AsExpressions.Count; i++) { children += expr.Options.AsExpressions[i].Convert(); } } if (expr.Expressions != null) { for (int i = 0; i < expr.Expressions.Count; i++) { for (int j = 0; j < expr.Expressions[i].Count; j++) { children += expr.Expressions[i][j].Convert(); } } } return constant + children; } return null; }
/// <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> /// 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> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { return "<br /><span class=\"algorithm_token\">end procedure</span>"; }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { if (expr.Expressions == null) return ""; var url = expr.Expressions[0][0].Name; return "<a href=\"" + url + "\">" + url + "</a>"; }
/// <summary> /// Recursively incapsulates tree fragments between \begin and \end. /// </summary> /// <param name="outline">The outline of a LatexExpression instance.</param> private static void IncapsulateCommands(List<LatexExpression> outline) { for (int i = 0; i < outline.Count; i++) { if (outline[i].ExprType == ExpressionType.Command && outline[i].Name == "begin") { var cmdValue = outline[i].Expressions[0][0].Name; int j; for (j = i; outline[j].Name != "end" || outline[j].Expressions == null || outline[j].Expressions[0][0].Name != cmdValue; j++) { } int length = j - i - 1; var subOutline = new LatexExpression[length]; // Cut the right chunk outline.CopyTo(i + 1, subOutline, 0, length); outline.RemoveRange(i + 1, length + 1); // Update outline[i] outline[i].Name = cmdValue; outline[i].ExprType = ExpressionType.Block; outline[i].Expressions.RemoveAt(0); for (int k = 0; k < outline[i].Expressions.Count; k++) { foreach (var expr in outline[i].Expressions[k]) { expr.ParentChildNumber--; } } // Update outline for (int k = i + 1; k < outline.Count; k++) { outline[k].IndexInParentChild -= length + 1; } // Update subOutline int parentChildNumber = outline[i].Expressions.Count; for (int k = 0; k < subOutline.Length; k++) { subOutline[k].Parent = outline[i]; subOutline[k].ParentChildNumber = parentChildNumber; subOutline[k].IndexInParentChild = k; } // Link subOutline outline[i].Expressions.Add(new List<LatexExpression>(subOutline)); IncapsulateCommands(outline[i].Expressions[parentChildNumber]); } } for (int i = 0; i < outline.Count; i++) { if (outline[i].Expressions != null) { foreach (var subTree in outline[i].Expressions) { IncapsulateCommands(subTree); } } } }
/// <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 } } }
/// <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. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { if (expr.Expressions == null) return ""; var letter = expr.Expressions[0][0].Name[0]; string converted; if (!ConversionTable.TryGetValue(letter, out converted)) { converted = "" + letter; } return converted; }
/// <summary> /// Recursively replaces all occurences of src in all subtrees with the specified sequence of expressions. /// </summary> /// <param name="src">The string to search and replace.</param> /// <param name="repl">The replacesment sequence of expressions.</param> public void RecursiveReplace(string src, List<LatexExpression> repl) { if (Expressions != null) { foreach (var childOutline in Expressions) { for (int i = 0; i < childOutline.Count; i++ ) { childOutline[i].RecursiveReplace(src, repl); } } } if (ExprType == ExpressionType.PlainText) { int pos = Name.IndexOf(src); if (pos > -1) { if (pos > 0) { var beg = Name.Substring(0, pos); bool verbatimMode = false; int index = IndexInParentChild; Parent.Expressions[ParentChildNumber].Insert(IndexInParentChild, new LatexExpression(Parent, ParentChildNumber, ref index, ref verbatimMode, ExpressionType.PlainText, MathMode, Customization, beg, null, null)); IndexInParentChild++; } Parent.Expressions[ParentChildNumber].RemoveAt(IndexInParentChild); for (int i = IndexInParentChild; i < Parent.Expressions[ParentChildNumber].Count; i++) { Parent.Expressions[ParentChildNumber][i].IndexInParentChild = i + repl.Count; } var localRepl = new LatexExpression[repl.Count]; repl.CopyTo(localRepl); for (int i = 0; i < repl.Count; i++) { var expr = localRepl[i]; expr.Parent = Parent; expr.ParentChildNumber = ParentChildNumber; expr.IndexInParentChild = i + IndexInParentChild; } Parent.Expressions[ParentChildNumber].InsertRange(IndexInParentChild, localRepl); var end = Name.Substring(src.Length); if (end != "") { bool verbatimMode2 = false; int index2 = IndexInParentChild + repl.Count; Parent.Expressions[ParentChildNumber].Insert(index2, new LatexExpression(Parent, ParentChildNumber, ref index2, ref verbatimMode2, ExpressionType.PlainText, MathMode, Customization, end, null, null)); } } } }
/// <summary> /// Initializes a new instance of the LatexExpression class and copies the specified expression data to it. /// </summary> /// <param name="expression">The expression to clone.</param> public LatexExpression(LatexExpression expression) { Parent = expression.Parent; Name = expression.Name; ExprType = expression.ExprType; MathMode = expression.MathMode; Customization = expression.Customization; if (expression.Options != null) { Options = new ExpressionOptions(); } if (expression.Expressions != null) { Expressions = new List<List<LatexExpression>>(expression.Expressions); } }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { CommandConverter converter; if (CommandConverters.TryGetValue(expr.GetCommandConverterHashCode(), out converter)) { if (converter.ExpectedBranchesCount > 0 && (expr.Expressions == null || expr.Expressions.Count < converter.ExpectedBranchesCount)) { throw new FormatException(@"Unexpected format in command \\" + converter.Name); //return "<!-- Unexpected format in command \\" + converter.Name + " -->"; } var result = converter.Convert(expr); // Make sure that {} blocks which were attached to the command by mistake will be converted, too. // Goddamn ancient Latex if (expr.Expressions != null && expr.Expressions.Count > converter.ExpectedBranchesCount) { for (int i = converter.ExpectedBranchesCount; i < expr.Expressions.Count; i++) { result += SequenceConverter.ConvertOutline(expr.Expressions[i], expr.Customization); } } return result; } string constant; if (CommandConstants.TryGetValue(expr.Name, out constant)) { if (expr.MathMode) { return "<mi>" + constant + "</mi>"; } return constant; } if ((constant = SearchInTables(MathCommandConstants, expr)) != null) { return constant; } if ((constant = SearchInTables(MathFunctionsCommandConstants, expr)) != null) { return constant; } if ((constant = SearchInTables(MathFunctionsScriptCommandConstants, expr)) != null) { return constant; } return "<!-- \\" + LatexStringToXmlString(expr.Name) + " -->\n"; }
/// <summary> /// Performs the conversion procedure. /// </summary> /// <param name="expr">The expression to convert.</param> /// <returns>The conversion result.</returns> public override string Convert(LatexExpression expr) { return(ConvertOutline(expr.Expressions[0], expr.Customization)); }
/// <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>()}; }