Evaluate command: tdf#109338

Adds evaluate command.
It's visible from UI as a bracket.
Example: evaluate { {1} over {%sigma sqrt{2%pi} }func e^-{{(x-%mu)^2} over {2%sigma^2}} } from { -infinity } to { +infinity } = 0

In order to make the mathml part, several changes had to be mad:
 - Allow mathml to correctly identify the math token for opperators
 - Allow mathml to correctly identify the math token for fences
   - Since improvements where made on token recognision, visitors to string can now be lighter ( removing long long switch )
 - Improving the import / export to mathm
 - LO says it mathml 2, but actually is something between 2 and 3
   - Allowing mfenced ( mathml 2.0 ) to stayl 3 adding the missing data ( prefix and postfix )
     - Be able to know if we are opening or closing brackets
   - lrline and lrdline commands hidden on UI.
     - They are they own open close
     - If prefix and postfix are missing meaning of the expression may change, however that's the user problem.
     - The problem resides in the fact that MS_VERTLINE is uses for lline and rline.
     - The problem resides in the fact that MS_DVERTLINE is uses for ldline and rdline.
 - Changing frac priority from 0 to 5, if not { frac 1 2 frac 1 2 } fails ( found while testing )
 - The mathml testing was made with highter standars than qa tests, however there are no guarantees.
 - Added xml tokens needed for math
 - Added starmathdatabase. Will grow in the future.
   The point is avoiding long lists and swtches inside code.

Added it command for hidden or implicit product ( like ⁢ in mathml ). Oppens path for tdf#66200. Note that about this issue there is only one line on the parser. The mathml implementation will be made later when LO will allow chars with &charname;.

Change-Id: If24b40c2420d39498693944f13a02985f997dd23
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/105267
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/compilerplugins/clang/sequentialassign.cxx b/compilerplugins/clang/sequentialassign.cxx
index 33b1afa..a89afea 100644
--- a/compilerplugins/clang/sequentialassign.cxx
+++ b/compilerplugins/clang/sequentialassign.cxx
@@ -118,6 +118,7 @@ public:
            || fn == SRCDIR "/starmath/source/cfgitem.cxx"
            || fn == SRCDIR "/ucb/source/ucp/ftp/ftpurl.cxx"
            || fn == SRCDIR "/starmath/source/node.cxx"
            || fn == SRCDIR "/starmath/source/starmathdatabase.cxx"
            || fn == SRCDIR "/ucb/source/ucp/cmis/certvalidation_handler.cxx"
            || fn == SRCDIR "/reportdesign/source/ui/inspection/GeometryHandler.cxx"
            || fn == SRCDIR "/reportdesign/source/core/api/ReportDefinition.cxx"
diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index 99b94be..6b2fed0 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -1477,6 +1477,8 @@ namespace xmloff::token {
        XML_POWER,
        XML_PRECISION_AS_SHOWN,
        XML_PREFIX,
        XML_INFIX,
        XML_POSTFIX,
        XML_PRESENTATION,
        XML_PRESENTATION_ORGCHART,
        XML_PRESENTATION_OUTLINE,
diff --git a/starmath/Library_sm.mk b/starmath/Library_sm.mk
index 5d75c87e..a63b506 100644
--- a/starmath/Library_sm.mk
+++ b/starmath/Library_sm.mk
@@ -98,6 +98,7 @@ $(eval $(call gb_Library_add_exception_objects,sm,\
        starmath/source/view \
        starmath/source/visitors \
        starmath/source/wordexportbase \
        starmath/source/starmathdatabase \
))


diff --git a/starmath/inc/parse.hxx b/starmath/inc/parse.hxx
index f078383..020d22f 100644
--- a/starmath/inc/parse.hxx
+++ b/starmath/inc/parse.hxx
@@ -104,6 +104,7 @@ class SmParser
    std::unique_ptr<SmNode> DoSum();
    std::unique_ptr<SmNode> DoProduct();
    std::unique_ptr<SmNode> DoSubSup(TG nActiveGroup, SmNode *pGivenNode);
    std::unique_ptr<SmNode> DoSubSupEvaluate(SmNode *pGivenNode);
    std::unique_ptr<SmNode> DoOpSubSup();
    std::unique_ptr<SmNode> DoPower();
    std::unique_ptr<SmBlankNode> DoBlank();
@@ -120,6 +121,7 @@ class SmParser
    std::unique_ptr<SmStructureNode> DoColor();
    std::unique_ptr<SmStructureNode> DoBrace();
    std::unique_ptr<SmBracebodyNode> DoBracebody(bool bIsLeftRight);
    std::unique_ptr<SmNode> DoEvaluate();
    std::unique_ptr<SmTextNode> DoFunction();
    std::unique_ptr<SmTableNode> DoBinom();
    std::unique_ptr<SmBinVerNode> DoFrac();
diff --git a/starmath/inc/starmathdatabase.hxx b/starmath/inc/starmathdatabase.hxx
new file mode 100644
index 0000000..999b983f
--- /dev/null
+++ b/starmath/inc/starmathdatabase.hxx
@@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "token.hxx"
#include "types.hxx"

namespace starmathdatabase
{
/**
      * Identifies operator chars tokens for importing mathml.
      * Identifies from char cChar
      * @param cChar
      * @return closing fences' token
      */
SmToken Identify_SmXMLOperatorContext_Impl(sal_Unicode cChar, bool bIsStretchy = true);

/**
      * Identifies opening / closing brace tokens for importing mathml.
      * Identifies from char cChar
      * @param cChar
      * @return closing fences' token
      */
SmToken Identify_PrefixPostfix_SmXMLOperatorContext_Impl(sal_Unicode cChar);

/**
      * Identifies opening brace tokens for importing mathml.
      * Identifies from char cChar
      * @param cChar
      * @return closing fences' token
      */
SmToken Identify_Prefix_SmXMLOperatorContext_Impl(sal_Unicode cChar);

/**
      * Identifies closing brace tokens for importing mathml.
      * Identifies from char cChar
      * @param cChar
      * @return closing fences' token
      */
SmToken Identify_Postfix_SmXMLOperatorContext_Impl(sal_Unicode cChar);
}
diff --git a/starmath/inc/strings.hrc b/starmath/inc/strings.hrc
index 09b2b39..fb9fecc 100644
--- a/starmath/inc/strings.hrc
+++ b/starmath/inc/strings.hrc
@@ -229,6 +229,10 @@
#define RID_XEVALUATEDATY_HELP              NC_("RID_XEVALUATEDATY_HELP", "Evaluated At" )
#define RID_XOVERBRACEY_HELP                NC_("RID_XOVERBRACEY_HELP", "Braces Top (Scalable)" )
#define RID_XUNDERBRACEY_HELP               NC_("RID_XUNDERBRACEY_HELP", "Braces Bottom (Scalable)" )
#define RID_EVALUATEX_HELP                  NC_("RID_EVALUATEX_HELP", "Evaluate" )
#define RID_EVALUATE_FROMX_HELP             NC_("RID_EVALUATE_FROMX_HELP", "Evaluate Subscript Bottom" )
#define RID_EVALUATE_TOX_HELP               NC_("RID_EVALUATE_TOX_HELP", "Evaluate Superscript Top" )
#define RID_EVALUATE_FROMTOX_HELP           NC_("RID_EVALUATE_FROMTOX_HELP", "Evaluate Sup/Sub script" )
#define RID_RSUBX_HELP                      NC_("RID_RSUBX_HELP", "Subscript Right" )
#define RID_RSUPX_HELP                      NC_("RID_RSUPX_HELP", "Power" )
#define RID_LSUBX_HELP                      NC_("RID_LSUBX_HELP", "Subscript Left" )
diff --git a/starmath/inc/strings.hxx b/starmath/inc/strings.hxx
index 6f81277..004e55a 100644
--- a/starmath/inc/strings.hxx
+++ b/starmath/inc/strings.hxx
@@ -221,6 +221,10 @@
#define RID_XEVALUATEDATY   "left none {<?>} right rline_{<?>} "
#define RID_XOVERBRACEY     "{<?>} overbrace {<?>} "
#define RID_XUNDERBRACEY    "{<?>} underbrace {<?>} "
#define RID_EVALX           "evaluate <?> "
#define RID_EVAL_FROMX      "evaluate {<?>} from{<?>} "
#define RID_EVAL_TOX        "evaluate {<?>} to{<?>} "
#define RID_EVAL_FROMTOX    "evaluate {<?>} from{<?>} to{<?>} "
#define RID_RSUBX           "<?>_{<?>}"
#define RID_RSUPX           "<?>^{<?>}"
#define RID_LSUBX           "<?> lsub{<?>} "
diff --git a/starmath/inc/token.hxx b/starmath/inc/token.hxx
index caae616..d5f90ab 100644
--- a/starmath/inc/token.hxx
+++ b/starmath/inc/token.hxx
@@ -66,7 +66,7 @@ enum SmTokenType
    TEND,           TSPECIAL,       TNONE,          TESCAPE,        TUNKNOWN,
    TBLANK,         TSBLANK,        TPLACE,         TNOSPACE,       TDOTSDOWN,
    TNEWLINE,       TDOTSAXIS,      TDOTSLOW,       TDOTSVERT,      TBACKEPSILON,
    TDOTSDIAG,      TDOTSUP,        TFRAC,
    TDOTSDIAG,      TDOTSUP,        TERROR,
    // Basic
    TPLUS,          TMINUS,         TMULTIPLY,      TDIVIDEBY,      // +-*/
    TGT,            TLT,            TGE,            TLE,            // > < >= <=
@@ -78,6 +78,7 @@ enum SmTokenType
    TLIM,           TLIMSUP,        TLIMINF,        TTOWARD,        // Limits
    TOVER,          TTIMES,         TCDOT,          TDIV,           // Product type
    TSLASH,         TBACKSLASH,     TWIDESLASH,     TWIDEBACKSLASH, //Slash
    TFRAC,          TIT,                                            // mathml related
    // Structure
    TMATRIX,         TPOUND,        TDPOUND,        TSTACK,         TBINOM,
    // Logic
@@ -119,8 +120,8 @@ enum SmTokenType
    TLBRACKET,      TRBRACKET,      TLDBRACKET,     TRDBRACKET,     // Bracket x1 & x2
    TLCEIL,         TRCEIL,         TLFLOOR,        TRFLOOR,        // Reals -> Wholes
    TLANGLE,        TRANGLE,        TLBRACE,        TRBRACE,        // <x> {x}
    // Brackets Lines
    TLLINE,         TRLINE,         TLDLINE,        TRDLINE,        TMLINE,
    TLLINE,         TRLINE,         TLDLINE,        TRDLINE,        // Lines x1 x2
    TMLINE,         TEVALUATE,      TLRLINE,        TLRDLINE,       // Custom
    // Differential calculus
    TNABLA,         TPARTIAL,       TFOURIER,       TLAPLACE,       // Derivative, Transformation
    TINTD,          TINT,           TIINT,          TIIINT,         // Integral
@@ -156,12 +157,26 @@ struct SmToken
    sal_Int32      nRow; // 1-based
    sal_Int32      nCol; // 1-based

    SmToken();
    SmToken()
        : eType(TUNKNOWN)
        , cMathChar('\0')
        , nGroup(TG::NONE)
        , nLevel(0)
        , nRow(0)
        , nCol(0) {}

    SmToken(SmTokenType eTokenType,
            sal_Unicode cMath,
            const char* pText,
            TG nTokenGroup = TG::NONE,
            sal_uInt16 nTokenLevel = 0);
            sal_uInt16 nTokenLevel = 0)
        : aText(OUString::createFromAscii(pText))
        , eType(eTokenType)
        , cMathChar(cMath)
        , nGroup(nTokenGroup)
        , nLevel(nTokenLevel)
        , nRow(0)
        , nCol(0){}
};

struct SmTokenTableEntry
diff --git a/starmath/inc/types.hxx b/starmath/inc/types.hxx
index d71c872..6efd585 100644
--- a/starmath/inc/types.hxx
+++ b/starmath/inc/types.hxx
@@ -32,6 +32,7 @@ enum SmPrintSize { PRINT_SIZE_NORMAL, PRINT_SIZE_SCALED, PRINT_SIZE_ZOOMED };
//! Note: not listed here does not(!) mean "not used"
//!     (see %alpha ... %gamma for example)

sal_Unicode const MS_NONE = '\0';
sal_Unicode const MS_FACT = 0x0021;
sal_Unicode const MS_INFINITY = 0x221E;
sal_Unicode const MS_SLASH = 0x002F;
diff --git a/starmath/source/ElementsDockingWindow.cxx b/starmath/source/ElementsDockingWindow.cxx
index aa96a1e..ab9d723 100644
--- a/starmath/source/ElementsDockingWindow.cxx
+++ b/starmath/source/ElementsDockingWindow.cxx
@@ -209,9 +209,11 @@ const SmElementDescr SmElementsControl::m_aBracketsList[] =
    {RID_SLRANGLEX, RID_SLRANGLEX_HELP}, {RID_SLMRANGLEXY, RID_SLMRANGLEXY_HELP},
    {RID_SLRCEILX, RID_SLRCEILX_HELP}, {RID_SLRFLOORX, RID_SLRFLOORX_HELP},
    {RID_SLRLINEX, RID_SLRLINEX_HELP}, {RID_SLRDLINEX, RID_SLRDLINEX_HELP},
    {RID_XEVALUATEDATY, RID_XEVALUATEDATY_HELP},
    {nullptr, nullptr},
    {RID_XOVERBRACEY, RID_XOVERBRACEY_HELP}, {RID_XUNDERBRACEY, RID_XUNDERBRACEY_HELP},
    {nullptr, nullptr},
    {RID_EVALX, RID_EVALUATEX_HELP}, {RID_EVAL_FROMX, RID_EVALUATE_FROMX_HELP},
    {RID_EVAL_TOX, RID_EVALUATE_TOX_HELP}, {RID_EVAL_FROMTOX, RID_EVALUATE_FROMTOX_HELP},
};

const SmElementDescr SmElementsControl::m_aFormatsList[] =
diff --git a/starmath/source/mathmlexport.cxx b/starmath/source/mathmlexport.cxx
index 821144a..f570ff5 100644
--- a/starmath/source/mathmlexport.cxx
+++ b/starmath/source/mathmlexport.cxx
@@ -998,6 +998,7 @@ void SmXMLExport::ExportBrace(const SmNode *pNode, int nLevel)
    if (pLeft && (pLeft->GetToken().eType != TNONE))
    {
        AddAttribute(XML_NAMESPACE_MATH, XML_FENCE, XML_TRUE);
        AddAttribute(XML_NAMESPACE_MATH, XML_FORM, XML_PREFIX);
        if (pNode->GetScaleMode() == SmScaleMode::Height)
            AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_TRUE);
        else
@@ -1018,6 +1019,7 @@ void SmXMLExport::ExportBrace(const SmNode *pNode, int nLevel)
    if (pRight && (pRight->GetToken().eType != TNONE))
    {
        AddAttribute(XML_NAMESPACE_MATH, XML_FENCE, XML_TRUE);
        AddAttribute(XML_NAMESPACE_MATH, XML_FORM, XML_POSTFIX);
        if (pNode->GetScaleMode() == SmScaleMode::Height)
            AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_TRUE);
        else
diff --git a/starmath/source/mathmlimport.cxx b/starmath/source/mathmlimport.cxx
index db56d3c..587ba3c 100644
--- a/starmath/source/mathmlimport.cxx
+++ b/starmath/source/mathmlimport.cxx
@@ -72,6 +72,7 @@ one go*/
#include <unomodel.hxx>
#include <utility.hxx>
#include <visitors.hxx>
#include <starmathdatabase.hxx>

using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::container;
@@ -1043,11 +1044,13 @@ class SmXMLFencedContext_Impl : public SmXMLRowContext_Impl
protected:
    sal_Unicode cBegin;
    sal_Unicode cEnd;
    bool bIsStretchy;

public:
    SmXMLFencedContext_Impl(SmXMLImport &rImport)
        : SmXMLRowContext_Impl(rImport),
        cBegin('('), cEnd(')') {}
        : SmXMLRowContext_Impl(rImport)
        , cBegin('('), cEnd(')')
        , bIsStretchy(false) {}

    void SAL_CALL startFastElement(sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList > & xAttrList ) override;
    void SAL_CALL endFastElement(sal_Int32 nElement) override;
@@ -1070,6 +1073,9 @@ void SmXMLFencedContext_Impl::startFastElement(sal_Int32 /*nElement*/, const uno
            case XML_CLOSE:
                cEnd = sValue[0];
                break;
            case XML_STRETCHY:
                bIsStretchy = sValue == GetXMLToken(XML_TRUE);
                break;
            default:
                XMLOFF_WARN_UNKNOWN("starmath", aIter);
                /*Go to superclass*/
@@ -1086,18 +1092,18 @@ void SmXMLFencedContext_Impl::endFastElement(sal_Int32 /*nElement*/)
    aToken.aText = ",";
    aToken.nLevel = 5;

    aToken.eType = TLPARENT;
    aToken.cMathChar = cBegin;
    std::unique_ptr<SmStructureNode> pSNode(new SmBraceNode(aToken));
    if( bIsStretchy ) aToken = starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl( cBegin );
    else aToken = starmathdatabase::Identify_Prefix_SmXMLOperatorContext_Impl( cBegin );
    if( aToken.eType == TERROR  ) aToken = SmToken( TLPARENT, MS_LPARENT, "(", TG::LBrace, 5 );
    std::unique_ptr<SmNode> pLeft(new SmMathSymbolNode(aToken));

    aToken.cMathChar = cEnd;
    aToken.eType = TRPARENT;
    if( bIsStretchy ) aToken = starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl( cEnd );
    else aToken = starmathdatabase::Identify_Postfix_SmXMLOperatorContext_Impl( cEnd );
    if( aToken.eType == TERROR  ) aToken = SmToken( TRPARENT, MS_RPARENT, ")", TG::LBrace, 5 );
    std::unique_ptr<SmNode> pRight(new SmMathSymbolNode(aToken));

    SmNodeArray aRelationArray;
    SmNodeStack &rNodeStack = GetSmImport().GetNodeStack();

    aToken.cMathChar = '\0';
    aToken.eType = TIDENT;

@@ -1120,6 +1126,8 @@ void SmXMLFencedContext_Impl::endFastElement(sal_Int32 /*nElement*/)


    pSNode->SetSubNodes(std::move(pLeft), std::move(pBody), std::move(pRight));
    // mfenced is always scalable. Stretchy keyword is not official, but in case of been in there
    // can be used as a hint.
    pSNode->SetScaleMode(SmScaleMode::Height);
    GetSmImport().GetNodeStack().push_front(std::move(pSNode));
}
@@ -1375,6 +1383,10 @@ class SmXMLOperatorContext_Impl : public SmXMLImportContext
{
    SmXMLTokenAttrHelper maTokenAttrHelper;
    bool bIsStretchy;
    bool bIsFenced;
    bool isPrefix;
    bool isInfix;
    bool isPostfix;
    SmToken aToken;

public:
@@ -1382,6 +1394,10 @@ public:
        : SmXMLImportContext(rImport)
        , maTokenAttrHelper(*this)
        , bIsStretchy(false)
        , bIsFenced(false)
        , isPrefix(false)
        , isInfix(false)
        , isPostfix(false)
    {
        aToken.eType = TSPECIAL;
        aToken.nLevel = 5;
@@ -1397,6 +1413,25 @@ public:
void SmXMLOperatorContext_Impl::TCharacters(const OUString &rChars)
{
    aToken.cMathChar = rChars[0];
    SmToken bToken;
    if( bIsFenced ){
        if( bIsStretchy )
        {
            if( isPrefix ) bToken = starmathdatabase::Identify_Prefix_SmXMLOperatorContext_Impl( aToken.cMathChar );
            else if( isInfix ) bToken = SmToken( TMLINE, MS_VERTLINE, "mline", TG::NONE, 0 );
            else if( isPostfix ) bToken = starmathdatabase::Identify_Postfix_SmXMLOperatorContext_Impl( aToken.cMathChar );
            else bToken = starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl( aToken.cMathChar );
        }
        else
        {
            if( isPrefix ) bToken = starmathdatabase::Identify_Prefix_SmXMLOperatorContext_Impl( aToken.cMathChar );
            else if( isInfix ) bToken = SmToken( TMLINE, MS_VERTLINE, "mline", TG::NONE, 0 );
            else if( isPostfix ) bToken = starmathdatabase::Identify_Postfix_SmXMLOperatorContext_Impl( aToken.cMathChar );
            else bToken = starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl( aToken.cMathChar );
        }
    }
    else bToken = starmathdatabase::Identify_SmXMLOperatorContext_Impl( aToken.cMathChar, bIsStretchy );
    if( bToken.eType != TERROR ) aToken = bToken;
}

void SmXMLOperatorContext_Impl::endFastElement(sal_Int32 )
@@ -1428,6 +1463,14 @@ void SmXMLOperatorContext_Impl::startFastElement(sal_Int32 /*nElement*/, const u
            case XML_STRETCHY:
                bIsStretchy = sValue == GetXMLToken(XML_TRUE);
                break;
            case XML_FENCE:
                bIsFenced   = sValue == GetXMLToken(XML_TRUE);
                break;
            case XML_FORM:
                isPrefix    = sValue == GetXMLToken(XML_PREFIX);    // <
                isInfix     = sValue == GetXMLToken(XML_INFIX);     // |
                isPostfix   = sValue == GetXMLToken(XML_POSTFIX);   // >
                break;
            default:
                XMLOFF_WARN_UNKNOWN("starmath", aIter);
                break;
@@ -2229,12 +2272,14 @@ void SmXMLRowContext_Impl::endFastElement(sal_Int32 )
        aToken.cMathChar = MS_LBRACE;
        aToken.nLevel = 5;
        aToken.eType = TLGROUP;
        aToken.nGroup = TG::NONE;
        aToken.aText = "{";
        aRelationArray[0] = new SmLineNode(aToken);

        aToken.cMathChar = MS_RBRACE;
        aToken.nLevel = 0;
        aToken.eType = TRGROUP;
        aToken.nGroup = TG::NONE;
        aToken.aText = "}";
        aRelationArray[1] = new SmLineNode(aToken);
    }
diff --git a/starmath/source/parse.cxx b/starmath/source/parse.cxx
index 598ec12..803f974 100644
--- a/starmath/source/parse.cxx
+++ b/starmath/source/parse.cxx
@@ -38,32 +38,6 @@

using namespace ::com::sun::star::i18n;


SmToken::SmToken()
    : eType(TUNKNOWN)
    , cMathChar('\0')
    , nGroup(TG::NONE)
    , nLevel(0)
    , nRow(0)
    , nCol(0)
{
}

SmToken::SmToken(SmTokenType eTokenType,
                 sal_Unicode cMath,
                 const char* pText,
                 TG nTokenGroup,
                 sal_uInt16 nTokenLevel)
    : aText(OUString::createFromAscii(pText))
    , eType(eTokenType)
    , cMathChar(cMath)
    , nGroup(nTokenGroup)
    , nLevel(nTokenLevel)
    , nRow(0)
    , nCol(0)
{
}

//Definition of math keywords
const SmTokenTableEntry aTokenTable[] =
{
@@ -123,6 +97,7 @@ const SmTokenTableEntry aTokenTable[] =
    { "drarrow" , TDRARROW, MS_DRARROW, TG::Standalone, 5},
    { "emptyset" , TEMPTYSET, MS_EMPTYSET, TG::Standalone, 5},
    { "equiv", TEQUIV, MS_EQUIV, TG::Relation, 0},
    { "evaluate", TEVALUATE, '\0', TG::NONE, 0},
    { "exists", TEXISTS, MS_EXISTS, TG::Standalone, 5},
    { "exp", TEXP, '\0', TG::Function, 5},
    { "fact", TFACT, MS_FACT, TG::UnOper, 5},
@@ -130,7 +105,7 @@ const SmTokenTableEntry aTokenTable[] =
    { "font", TFONT, '\0', TG::FontAttr, 5},
    { "forall", TFORALL, MS_FORALL, TG::Standalone, 5},
    { "fourier", TFOURIER, MS_FOURIER, TG::Standalone, 5},
    { "frac", TFRAC, '\0', TG::NONE, 0},
    { "frac", TFRAC, '\0', TG::NONE, 5},
    { "from", TFROM, '\0', TG::Limit, 0},
    { "func", TFUNC, '\0', TG::Function, 5},
    { "ge", TGE, MS_GE, TG::Relation, 0},
@@ -150,6 +125,7 @@ const SmTokenTableEntry aTokenTable[] =
    { "int", TINT, MS_INT, TG::Oper, 5},
    { "intd", TINTD, MS_INT, TG::Oper, 5},
    { "intersection", TINTERSECT, MS_INTERSECT, TG::Product, 0},
    { "it", TIT, '\0', TG::Product, 0},
    { "ital", TITALIC, '\0', TG::FontAttr, 5},
    { "italic", TITALIC, '\0', TG::FontAttr, 5},
    { "lambdabar" , TLAMBDABAR, MS_LAMBDABAR, TG::Standalone, 5},
@@ -174,6 +150,8 @@ const SmTokenTableEntry aTokenTable[] =
    { "lllint", TLLLINT, MS_LLLINT, TG::Oper, 5},
    { "ln", TLN, '\0', TG::Function, 5},
    { "log", TLOG, '\0', TG::Function, 5},
    { "lrline", TLRLINE, MS_VERTLINE, TG::LBrace | TG::RBrace, 5},
    { "lrdline", TLRDLINE, MS_VERTLINE, TG::LBrace | TG::RBrace, 5},
    { "lsub", TLSUB, '\0', TG::Power, 0},
    { "lsup", TLSUP, '\0', TG::Power, 0},
    { "lt", TLT, MS_LT, TG::Relation, 0},
@@ -1513,6 +1491,55 @@ std::unique_ptr<SmNode> SmParser::DoSubSup(TG nActiveGroup, SmNode *pGivenNode)
    return pNode;
}

std::unique_ptr<SmNode> SmParser::DoSubSupEvaluate(SmNode *pGivenNode)
{
    std::unique_ptr<SmNode> xGivenNode(pGivenNode);
    DepthProtect aDepthGuard(m_nParseDepth);
    if (aDepthGuard.TooDeep()) throw std::range_error("parser depth limit");

    std::unique_ptr<SmSubSupNode> pNode(new SmSubSupNode(m_aCurToken));
    pNode->SetUseLimits(true);

    // initialize subnodes array
    std::vector<std::unique_ptr<SmNode>> aSubNodes(1 + SUBSUP_NUM_ENTRIES);
    aSubNodes[0] = std::move(xGivenNode);

    // process all sub-/supscripts
    int  nIndex = 0;
    while (TokenInGroup(TG::Limit))
    {
        SmTokenType  eType (m_aCurToken.eType);

        switch (eType)
        {
            case TFROM :    nIndex = static_cast<int>(RSUB);    break;
            case TTO   :    nIndex = static_cast<int>(RSUP);    break;
            default :
                SAL_WARN( "starmath", "unknown case");
        }
        nIndex++;
        assert(1 <= nIndex  &&  nIndex <= SUBSUP_NUM_ENTRIES);

        std::unique_ptr<SmNode> xENode;
        if (aSubNodes[nIndex]) // if already occupied at earlier iteration
        {
            // forget the earlier one, remember an error instead
            aSubNodes[nIndex].reset();
            xENode = DoError(SmParseError::DoubleSubsupscript); // this also skips current token.
        }
        else NextToken(); // skip sub-/supscript token

        // get sub-/supscript node
        std::unique_ptr<SmNode> xSNode;
        xSNode = DoTerm(true);

        aSubNodes[nIndex] = std::move(xENode ? xENode : xSNode);
    }

    pNode->SetSubNodes(buildNodeArray(aSubNodes));
    return pNode;
}

std::unique_ptr<SmNode> SmParser::DoOpSubSup()
{
    DepthProtect aDepthGuard(m_nParseDepth);
@@ -1613,6 +1640,8 @@ std::unique_ptr<SmNode> SmParser::DoTerm(bool bGroupNumberIdent)

        case TLEFT :
            return DoBrace();
                   case TEVALUATE:
            return DoEvaluate();

        case TBLANK :
        case TSBLANK :
@@ -2302,6 +2331,8 @@ std::unique_ptr<SmStructureNode> SmParser::DoBrace()
            case TLANGLE :      eExpectedType = TRANGLE;    break;
            case TLFLOOR :      eExpectedType = TRFLOOR;    break;
            case TLCEIL :       eExpectedType = TRCEIL;     break;
            case TLRLINE :      eExpectedType = TLRLINE;    break;
            case TLRDLINE :     eExpectedType = TLRDLINE;   break;
            default :
                SAL_WARN("starmath", "unknown case");
            }
@@ -2376,6 +2407,43 @@ std::unique_ptr<SmBracebodyNode> SmParser::DoBracebody(bool bIsLeftRight)
    return pBody;
}

std::unique_ptr<SmNode> SmParser::DoEvaluate()
{

    // Checkout depth and create node
    DepthProtect aDepthGuard(m_nParseDepth);
    if (aDepthGuard.TooDeep()) throw std::range_error("parser depth limit");
    std::unique_ptr<SmStructureNode> xSNode(new SmBraceNode(m_aCurToken));
    SmToken aToken( TRLINE, MS_VERTLINE, "evaluate", TG::RBrace, 5);
    aToken.nRow = m_aCurToken.nRow;
    aToken.nCol = m_aCurToken.nCol;

    // Parse body && left none
    NextToken();
    std::unique_ptr<SmNode> pBody = DoPower();
    SmToken bToken( TNONE, '\0', "", TG::LBrace, 5);
    std::unique_ptr<SmNode> pLeft;
    pLeft.reset(new SmMathSymbolNode(bToken));

    // Mount nodes
    std::unique_ptr<SmNode> pRight;
    pRight.reset(new SmMathSymbolNode(aToken));
    xSNode->SetSubNodes(std::move(pLeft), std::move(pBody), std::move(pRight));
    xSNode->SetScaleMode(SmScaleMode::Height); // scalable line

    // Parse from to
    if ( m_aCurToken.nGroup == TG::Limit )
    {
        std::unique_ptr<SmNode> rSNode;
        rSNode = DoSubSupEvaluate(xSNode.release());
        rSNode->GetToken().eType = TEVALUATE;
        return rSNode;
    }

    return xSNode;

}

std::unique_ptr<SmTextNode> SmParser::DoFunction()
{
    DepthProtect aDepthGuard(m_nParseDepth);
diff --git a/starmath/source/starmathdatabase.cxx b/starmath/source/starmathdatabase.cxx
new file mode 100644
index 0000000..9b1dd65
--- /dev/null
+++ b/starmath/source/starmathdatabase.cxx
@@ -0,0 +1,358 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <starmathdatabase.hxx>

SmToken starmathdatabase::Identify_SmXMLOperatorContext_Impl(sal_Unicode cChar, bool bIsStretchy)
{
    switch (cChar)
    {
        case MS_COPROD:
            return SmToken(TCOPROD, MS_COPROD, "coprod", TG::Oper, 5);
        case MS_IIINT:
            return SmToken(TIIINT, MS_IIINT, "iiint", TG::Oper, 5);
        case MS_IINT:
            return SmToken(TIINT, MS_IINT, "iint", TG::Oper, 5);
        case MS_INT:
            if (bIsStretchy)
                return SmToken(TINTD, MS_INT, "intd", TG::Oper, 5);
            else
                return SmToken(TINT, MS_INT, "int", TG::Oper, 5);
        case MS_LINT:
            return SmToken(TLINT, MS_LINT, "lint", TG::Oper, 5);
        case MS_LLINT:
            return SmToken(TLLINT, MS_LLINT, "llint", TG::Oper, 5);
        case MS_LLLINT:
            return SmToken(TLLLINT, MS_LLLINT, "lllint", TG::Oper, 5);
        case MS_PROD:
            return SmToken(TPROD, MS_PROD, "prod", TG::Oper, 5);
        case MS_SUM:
            return SmToken(TSUM, MS_SUM, "sum", TG::Oper, 5);
        case MS_FACT:
            return SmToken(TFACT, MS_FACT, "!", TG::UnOper, 5);
        case MS_NEG:
            return SmToken(TNEG, MS_NEG, "neg", TG::UnOper, 5);
        case MS_OMINUS:
            return SmToken(TOMINUS, MS_OMINUS, "ominus", TG::Sum, 0);
        case MS_OPLUS:
            return SmToken(TOPLUS, MS_OPLUS, "oplus", TG::Sum, 0);
        case MS_UNION:
            return SmToken(TUNION, MS_UNION, "union", TG::Sum, 0);
        case MS_OR:
            return SmToken(TOR, MS_OR, "|", TG::Sum, 5);
        case MS_PLUSMINUS:
            return SmToken(TPLUSMINUS, MS_PLUSMINUS, "+-", TG::Sum | TG::UnOper, 5);
        case MS_MINUSPLUS:
            return SmToken(TMINUSPLUS, MS_MINUSPLUS, "-+", TG::Sum | TG::UnOper, 5);
        case 0xe083:
        case MS_PLUS:
            return SmToken(TPLUS, MS_PLUS, "+", TG::Sum | TG::UnOper, 5);
        case MS_MINUS:
            return SmToken(TMINUS, MS_MINUS, "-", TG::Sum | TG::UnOper, 5);
        case 0x2022:
        case MS_CDOT:
            return SmToken(TCDOT, MS_CDOT, "cdot", TG::Product, 0);
        case MS_DIV:
            return SmToken(TDIV, MS_DIV, "div", TG::Product, 0);
        case MS_TIMES:
            return SmToken(TTIMES, MS_TIMES, "times", TG::Product, 0);
        case MS_INTERSECT:
            return SmToken(TINTERSECT, MS_INTERSECT, "intersection", TG::Product, 0);
        case MS_ODIVIDE:
            return SmToken(TODIVIDE, MS_ODIVIDE, "odivide", TG::Product, 0);
        case MS_ODOT:
            return SmToken(TODOT, MS_ODOT, "odot", TG::Product, 0);
        case MS_OTIMES:
            return SmToken(TOTIMES, MS_OTIMES, "otimes", TG::Product, 0);
        case MS_AND:
            return SmToken(TAND, MS_AND, "&", TG::Product, 0);
        case MS_MULTIPLY:
            return SmToken(TMULTIPLY, MS_MULTIPLY, "*", TG::Product, 0);
        case MS_SLASH:
            if (bIsStretchy)
                return SmToken(TWIDESLASH, MS_SLASH, "wideslash", TG::Product, 0);
            else
                return SmToken(TSLASH, MS_SLASH, "slash", TG::Product, 0);
        case MS_BACKSLASH:
            if (bIsStretchy)
                return SmToken(TWIDEBACKSLASH, MS_BACKSLASH, "bslash", TG::Product, 0);
            else
                return SmToken(TBACKSLASH, MS_BACKSLASH, "slash", TG::Product, 0);
        case MS_DEF:
            return SmToken(TDEF, MS_DEF, "def", TG::Relation, 0);
        case MS_LINE:
            return SmToken(TDIVIDES, MS_LINE, "divides", TG::Relation, 0);
        case MS_EQUIV:
            return SmToken(TEQUIV, MS_EQUIV, "equiv", TG::Relation, 0);
        case MS_GE:
            return SmToken(TGE, MS_GE, ">=", TG::Relation, 0);
        case MS_GESLANT:
            return SmToken(TGESLANT, MS_GESLANT, "geslant", TG::Relation, 0);
        case MS_GG:
            return SmToken(TGG, MS_GG, ">>", TG::Relation, 0);
        case MS_GT:
            return SmToken(TGT, MS_GT, ">", TG::Relation, 0);
        case MS_IN:
            return SmToken(TIN, MS_IN, "in", TG::Relation, 0);
        case MS_LE:
            return SmToken(TLE, MS_LE, "<=", TG::Relation, 0);
        case MS_LESLANT:
            return SmToken(TLESLANT, MS_LESLANT, "leslant", TG::Relation, 0);
        case MS_LL:
            return SmToken(TLL, MS_LL, "<<", TG::Relation, 0);
        case MS_LT:
            return SmToken(TLT, MS_LT, "<", TG::Relation, 0);
        case MS_NDIVIDES:
            return SmToken(TNDIVIDES, MS_NDIVIDES, "ndivides", TG::Relation, 0);
        case MS_NEQ:
            return SmToken(TNEQ, MS_NEQ, "<>", TG::Relation, 0);
        case MS_NOTIN:
            return SmToken(TNOTIN, MS_NOTIN, "notin", TG::Relation, 0);
        case MS_NOTPRECEDES:
            return SmToken(TNOTPRECEDES, MS_NOTPRECEDES, "nprec", TG::Relation, 0);
        case MS_NSUBSET:
            return SmToken(TNSUBSET, MS_NSUBSET, "nsubset", TG::Relation, 0);
        case MS_NSUBSETEQ:
            return SmToken(TNSUBSETEQ, MS_NSUBSETEQ, "nsubseteq", TG::Relation, 0);
        case MS_NOTSUCCEEDS:
            return SmToken(TNOTSUCCEEDS, MS_NOTSUCCEEDS, "nsucc", TG::Relation, 0);
        case MS_NSUPSET:
            return SmToken(TNSUPSET, MS_NSUPSET, "nsupset", TG::Relation, 0);
        case MS_NSUPSETEQ:
            return SmToken(TNSUPSETEQ, MS_NSUPSETEQ, "nsupseteq", TG::Relation, 0);
        case MS_ORTHO:
            return SmToken(TORTHO, MS_ORTHO, "ortho", TG::Relation, 0);
        case MS_NI:
            return SmToken(TNI, MS_NI, "owns", TG::Relation, 0);
        case MS_DLINE:
            return SmToken(TPARALLEL, MS_DLINE, "parallel", TG::Relation, 0);
        case MS_PRECEDES:
            return SmToken(TPRECEDES, MS_PRECEDES, "prec", TG::Relation, 0);
        case MS_PRECEDESEQUAL:
            return SmToken(TPRECEDESEQUAL, MS_PRECEDESEQUAL, "preccurlyeq", TG::Relation, 0);
        case MS_PRECEDESEQUIV:
            return SmToken(TPRECEDESEQUIV, MS_PRECEDESEQUIV, "precsim", TG::Relation, 0);
        case MS_PROP:
            return SmToken(TPROP, MS_PROP, "prop", TG::Relation, 0);
        case MS_SIM:
            return SmToken(TSIM, MS_SIM, "sim", TG::Relation, 0);
        case 0x2245:
        case MS_SIMEQ:
            return SmToken(TSIMEQ, MS_SIMEQ, "simeq", TG::Relation, 0);
        case MS_SUBSET:
            return SmToken(TSUBSET, MS_SUBSET, "subset", TG::Relation, 0);
        case MS_SUBSETEQ:
            return SmToken(TSUBSETEQ, MS_SUBSETEQ, "subseteq", TG::Relation, 0);
        case MS_SUCCEEDS:
            return SmToken(TSUCCEEDS, MS_SUCCEEDS, "succ", TG::Relation, 0);
        case MS_SUCCEEDSEQUAL:
            return SmToken(TSUCCEEDSEQUAL, MS_SUCCEEDSEQUAL, "succcurlyeq", TG::Relation, 0);
        case MS_SUCCEEDSEQUIV:
            return SmToken(TSUCCEEDSEQUIV, MS_SUCCEEDSEQUIV, "succsim", TG::Relation, 0);
        case MS_SUPSET:
            return SmToken(TSUPSET, MS_SUPSET, "supset", TG::Relation, 0);
        case MS_SUPSETEQ:
            return SmToken(TSUPSETEQ, MS_SUPSETEQ, "supseteq", TG::Relation, 0);
        case MS_RIGHTARROW:
            return SmToken(TTOWARD, MS_RIGHTARROW, "toward", TG::Relation, 0);
        case MS_TRANSL:
            return SmToken(TTRANSL, MS_TRANSL, "transl", TG::Relation, 0);
        case MS_TRANSR:
            return SmToken(TTRANSR, MS_TRANSR, "transr", TG::Relation, 0);
        case MS_ASSIGN:
            return SmToken(TASSIGN, MS_ASSIGN, "=", TG::Relation, 0);
        case MS_LANGLE:
            return SmToken(TLANGLE, MS_LMATHANGLE, "langle", TG::LBrace, 5);
        case MS_LMATHANGLE:
            return SmToken(TLANGLE, MS_LMATHANGLE, "langle", TG::LBrace, 5);
        case MS_LBRACE:
            return SmToken(TLBRACE, MS_LBRACE, "lbrace", TG::LBrace, 5);
        case MS_LCEIL:
            return SmToken(TLCEIL, MS_LCEIL, "lceil", TG::LBrace, 5);
        case MS_LFLOOR:
            return SmToken(TLFLOOR, MS_LFLOOR, "lfloor", TG::LBrace, 5);
        case MS_LDBRACKET:
            return SmToken(TLDBRACKET, MS_LDBRACKET, "ldbracket", TG::LBrace, 5);
        case MS_LBRACKET:
            return SmToken(TLBRACKET, MS_LBRACKET, "[", TG::LBrace, 5);
        case MS_LPARENT:
            return SmToken(TLPARENT, MS_LPARENT, "(", TG::LBrace, 5);
        case MS_RANGLE:
            return SmToken(TRANGLE, MS_RMATHANGLE, "rangle", TG::RBrace, 5);
        case MS_RMATHANGLE:
            return SmToken(TRANGLE, MS_RMATHANGLE, "rangle", TG::RBrace, 5);
        case MS_RBRACE:
            return SmToken(TRBRACE, MS_RBRACE, "rbrace", TG::RBrace, 5);
        case MS_RCEIL:
            return SmToken(TRCEIL, MS_RCEIL, "rceil", TG::RBrace, 5);
        case MS_RFLOOR:
            return SmToken(TRFLOOR, MS_RFLOOR, "rfloor", TG::RBrace, 5);
        case MS_RDBRACKET:
            return SmToken(TRDBRACKET, MS_RDBRACKET, "rdbracket", TG::RBrace, 5);
        case MS_RBRACKET:
            return SmToken(TRBRACKET, MS_RBRACKET, "]", TG::RBrace, 5);
        case MS_RPARENT:
            return SmToken(TRPARENT, MS_RPARENT, ")", TG::RBrace, 5);
        case MS_NONE:
            return SmToken(TNONE, MS_NONE, "none", TG::RBrace | TG::LBrace, 5);
        default:
            return SmToken(TERROR, MS_NONE, "", TG::NONE, SAL_MAX_UINT16);
    }
}

SmToken starmathdatabase::Identify_Prefix_SmXMLOperatorContext_Impl(sal_Unicode cChar)
{
    switch (cChar)
    {
        case MS_VERTLINE:
            return SmToken(TLLINE, MS_VERTLINE, "lline", TG::LBrace, 5);
        case MS_DVERTLINE:
            return SmToken(TLDLINE, MS_DVERTLINE, "ldline", TG::LBrace, 5);
        case MS_LANGLE:
            return SmToken(TLANGLE, MS_LMATHANGLE, "langle", TG::LBrace, 5);
        case MS_LMATHANGLE:
            return SmToken(TLANGLE, MS_LMATHANGLE, "langle", TG::LBrace, 5);
        case MS_LBRACE:
            return SmToken(TLBRACE, MS_LBRACE, "lbrace", TG::LBrace, 5);
        case MS_LCEIL:
            return SmToken(TLCEIL, MS_LCEIL, "lceil", TG::LBrace, 5);
        case MS_LFLOOR:
            return SmToken(TLFLOOR, MS_LFLOOR, "lfloor", TG::LBrace, 5);
        case MS_LDBRACKET:
            return SmToken(TLDBRACKET, MS_LDBRACKET, "ldbracket", TG::LBrace, 5);
        case MS_LBRACKET:
            return SmToken(TLBRACKET, MS_LBRACKET, "[", TG::LBrace, 5);
        case MS_LPARENT:
            return SmToken(TLPARENT, MS_LPARENT, "(", TG::LBrace, 5);
        case MS_RANGLE:
            return SmToken(TRANGLE, MS_RMATHANGLE, "rangle", TG::RBrace, 5);
        case MS_RMATHANGLE:
            return SmToken(TRANGLE, MS_RMATHANGLE, "rangle", TG::RBrace, 5);
        case MS_RBRACE:
            return SmToken(TRBRACE, MS_RBRACE, "rbrace", TG::RBrace, 5);
        case MS_RCEIL:
            return SmToken(TRCEIL, MS_RCEIL, "rceil", TG::RBrace, 5);
        case MS_RFLOOR:
            return SmToken(TRFLOOR, MS_RFLOOR, "rfloor", TG::RBrace, 5);
        case MS_RDBRACKET:
            return SmToken(TRDBRACKET, MS_RDBRACKET, "rdbracket", TG::RBrace, 5);
        case MS_RBRACKET:
            return SmToken(TRBRACKET, MS_RBRACKET, "]", TG::RBrace, 5);
        case MS_RPARENT:
            return SmToken(TRPARENT, MS_RPARENT, ")", TG::RBrace, 5);
        case MS_NONE:
            return SmToken(TNONE, MS_NONE, "none", TG::LBrace | TG::RBrace, 5);
        default:
            return SmToken(TERROR, MS_NONE, "", TG::NONE, SAL_MAX_UINT16);
    }
}

SmToken starmathdatabase::Identify_Postfix_SmXMLOperatorContext_Impl(sal_Unicode cChar)
{
    switch (cChar)
    {
        case MS_VERTLINE:
            return SmToken(TRLINE, MS_VERTLINE, "rline", TG::RBrace, 5);
        case MS_DVERTLINE:
            return SmToken(TRDLINE, MS_DVERTLINE, "rdline", TG::RBrace, 5);
        case MS_LANGLE:
            return SmToken(TLANGLE, MS_LMATHANGLE, "langle", TG::LBrace, 5);
        case MS_LMATHANGLE:
            return SmToken(TLANGLE, MS_LMATHANGLE, "langle", TG::LBrace, 5);
        case MS_LBRACE:
            return SmToken(TLBRACE, MS_LBRACE, "lbrace", TG::LBrace, 5);
        case MS_LCEIL:
            return SmToken(TLCEIL, MS_LCEIL, "lceil", TG::LBrace, 5);
        case MS_LFLOOR:
            return SmToken(TLFLOOR, MS_LFLOOR, "lfloor", TG::LBrace, 5);
        case MS_LDBRACKET:
            return SmToken(TLDBRACKET, MS_LDBRACKET, "ldbracket", TG::LBrace, 5);
        case MS_LBRACKET:
            return SmToken(TLBRACKET, MS_LBRACKET, "[", TG::LBrace, 5);
        case MS_LPARENT:
            return SmToken(TLPARENT, MS_LPARENT, "(", TG::LBrace, 5);
        case MS_RANGLE:
            return SmToken(TRANGLE, MS_RMATHANGLE, "rangle", TG::RBrace, 5);
        case MS_RMATHANGLE:
            return SmToken(TRANGLE, MS_RMATHANGLE, "rangle", TG::RBrace, 5);
        case MS_RBRACE:
            return SmToken(TRBRACE, MS_RBRACE, "rbrace", TG::RBrace, 5);
        case MS_RCEIL:
            return SmToken(TRCEIL, MS_RCEIL, "rceil", TG::RBrace, 5);
        case MS_RFLOOR:
            return SmToken(TRFLOOR, MS_RFLOOR, "rfloor", TG::RBrace, 5);
        case MS_RDBRACKET:
            return SmToken(TRDBRACKET, MS_RDBRACKET, "rdbracket", TG::RBrace, 5);
        case MS_RBRACKET:
            return SmToken(TRBRACKET, MS_RBRACKET, "]", TG::RBrace, 5);
        case MS_RPARENT:
            return SmToken(TRPARENT, MS_RPARENT, ")", TG::RBrace, 5);
        case MS_NONE:
            return SmToken(TNONE, MS_NONE, "none", TG::LBrace | TG::RBrace, 5);
        default:
            return SmToken(TERROR, MS_NONE, "", TG::NONE, SAL_MAX_UINT16);
    }
}

SmToken starmathdatabase::Identify_PrefixPostfix_SmXMLOperatorContext_Impl(sal_Unicode cChar)
{
    switch (cChar)
    {
        case MS_VERTLINE:
            return SmToken(TLRLINE, MS_VERTLINE, "lrline", TG::LBrace | TG::RBrace, 5);
        case MS_DVERTLINE:
            return SmToken(TLRDLINE, MS_DVERTLINE, "lrdline", TG::LBrace | TG::RBrace, 5);
        case MS_LANGLE:
            return SmToken(TLANGLE, MS_LMATHANGLE, "langle", TG::LBrace, 5);
        case MS_LMATHANGLE:
            return SmToken(TLANGLE, MS_LMATHANGLE, "langle", TG::LBrace, 5);
        case MS_LBRACE:
            return SmToken(TLBRACE, MS_LBRACE, "lbrace", TG::LBrace, 5);
        case MS_LCEIL:
            return SmToken(TLCEIL, MS_LCEIL, "lceil", TG::LBrace, 5);
        case MS_LFLOOR:
            return SmToken(TLFLOOR, MS_LFLOOR, "lfloor", TG::LBrace, 5);
        case MS_LDBRACKET:
            return SmToken(TLDBRACKET, MS_LDBRACKET, "ldbracket", TG::LBrace, 5);
        case MS_LBRACKET:
            return SmToken(TLBRACKET, MS_LBRACKET, "[", TG::LBrace, 5);
        case MS_LPARENT:
            return SmToken(TLPARENT, MS_LPARENT, "(", TG::LBrace, 5);
        case MS_RANGLE:
            return SmToken(TRANGLE, MS_RMATHANGLE, "rangle", TG::RBrace, 5);
        case MS_RMATHANGLE:
            return SmToken(TRANGLE, MS_RMATHANGLE, "rangle", TG::RBrace, 5);
        case MS_RBRACE:
            return SmToken(TRBRACE, MS_RBRACE, "rbrace", TG::RBrace, 5);
        case MS_RCEIL:
            return SmToken(TRCEIL, MS_RCEIL, "rceil", TG::RBrace, 5);
        case MS_RFLOOR:
            return SmToken(TRFLOOR, MS_RFLOOR, "rfloor", TG::RBrace, 5);
        case MS_RDBRACKET:
            return SmToken(TRDBRACKET, MS_RDBRACKET, "rdbracket", TG::RBrace, 5);
        case MS_RBRACKET:
            return SmToken(TRBRACKET, MS_RBRACKET, "]", TG::RBrace, 5);
        case MS_RPARENT:
            return SmToken(TRPARENT, MS_RPARENT, ")", TG::RBrace, 5);
        case MS_NONE:
            return SmToken(TNONE, MS_NONE, "none", TG::LBrace | TG::RBrace, 5);
        default:
            return SmToken(TERROR, MS_NONE, "", TG::NONE, SAL_MAX_UINT16);
    }
}
diff --git a/starmath/source/visitors.cxx b/starmath/source/visitors.cxx
index 9b8ac0d..08f9d33 100644
--- a/starmath/source/visitors.cxx
+++ b/starmath/source/visitors.cxx
@@ -1967,23 +1967,32 @@ void SmNodeToTextVisitor::Visit( SmTableNode* pNode )

void SmNodeToTextVisitor::Visit( SmBraceNode* pNode )
{
    SmNode *pLeftBrace  = pNode->OpeningBrace(),
           *pBody       = pNode->Body(),
           *pRightBrace = pNode->ClosingBrace();
    //Handle special case where it's absolute function
    if( pNode->GetToken( ).eType == TABS ) {
        Append( "abs" );
        LineToText( pBody );
    } else {
        if( pNode->GetScaleMode( ) == SmScaleMode::Height )
            Append( "left " );
        pLeftBrace->Accept( this );
        Separate( );
    if ( pNode->GetToken().eType == TEVALUATE )
    {
        SmNode *pBody = pNode->Body();
        Append( "evaluate { " );
        pBody->Accept( this );
        Separate( );
        if( pNode->GetScaleMode( ) == SmScaleMode::Height )
            Append( "right " );
        pRightBrace->Accept( this );
        Append("} ");
    }
    else{
        SmNode *pLeftBrace  = pNode->OpeningBrace(),
               *pBody       = pNode->Body(),
               *pRightBrace = pNode->ClosingBrace();
        //Handle special case where it's absolute function
        if( pNode->GetToken( ).eType == TABS ) {
            Append( "abs" );
            LineToText( pBody );
        } else {
            if( pNode->GetScaleMode( ) == SmScaleMode::Height )
                Append( "left " );
            pLeftBrace->Accept( this );
            Separate( );
            pBody->Accept( this );
            Separate( );
            if( pNode->GetScaleMode( ) == SmScaleMode::Height )
                Append( "right " );
            pRightBrace->Accept( this );
        }
    }
}

@@ -2313,48 +2322,71 @@ void SmNodeToTextVisitor::Visit( SmBinDiagonalNode* pNode )

void SmNodeToTextVisitor::Visit( SmSubSupNode* pNode )
{
    LineToText( pNode->GetBody( ) );
    SmNode *pChild = pNode->GetSubSup( LSUP );
    if( pChild ) {
        Separate( );
        Append( "lsup " );
        LineToText( pChild );
    if( pNode->GetToken().eType == TEVALUATE )
    {
        Append("evaluate { ");
        pNode->GetSubNode( 0 )->GetSubNode( 1 )->Accept(this);
        Append("} ");
        SmNode* pChild = pNode->GetSubSup( RSUP );
        if( pChild ) {
            Separate( );
            Append( "to { " );
            LineToText( pChild );
            Append( "} " );
        }
        pChild = pNode->GetSubSup( RSUB );
        if( pChild ) {
            Separate( );
            Append( "from { " );
            LineToText( pChild );
            Append( "} " );
        }
    }
    pChild = pNode->GetSubSup( LSUB );
    if( pChild ) {
        Separate( );
        Append( "lsub " );
        LineToText( pChild );
    }
    pChild = pNode->GetSubSup( RSUP );
    if( pChild ) {
        Separate( );
        Append( "^ " );
        LineToText( pChild );
    }
    pChild = pNode->GetSubSup( RSUB );
    if( pChild ) {
        Separate( );
        Append( "_ " );
        LineToText( pChild );
    }
    pChild = pNode->GetSubSup( CSUP );
    if( pChild ) {
        Separate( );
        if (pNode->IsUseLimits())
            Append( "to " );
        else
            Append( "csup " );
        LineToText( pChild );
    }
    pChild = pNode->GetSubSup( CSUB );
    if( pChild ) {
        Separate( );
        if (pNode->IsUseLimits())
            Append( "from " );
        else
            Append( "csub " );
        LineToText( pChild );
    else
    {
        LineToText( pNode->GetBody( ) );
        SmNode *pChild = pNode->GetSubSup( LSUP );
        if( pChild ) {
            Separate( );
            Append( "lsup " );
            LineToText( pChild );
        }
        pChild = pNode->GetSubSup( LSUB );
        if( pChild ) {
            Separate( );
            Append( "lsub " );
            LineToText( pChild );
        }
        pChild = pNode->GetSubSup( RSUP );
        if( pChild ) {
            Separate( );
            Append( "^ " );
            LineToText( pChild );
        }
        pChild = pNode->GetSubSup( RSUB );
        if( pChild ) {
            Separate( );
            Append( "_ " );
            LineToText( pChild );
        }
        pChild = pNode->GetSubSup( CSUP );
        if( pChild ) {
            Separate( );
            if (pNode->IsUseLimits())
                Append( "to " );
            else
                Append( "csup " );
            LineToText( pChild );
        }
        pChild = pNode->GetSubSup( CSUB );
        if( pChild ) {
            Separate( );
            if (pNode->IsUseLimits())
                Append( "from " );
            else
                Append( "csub " );
            LineToText( pChild );
        }
    }
}

@@ -2418,39 +2450,6 @@ void SmNodeToTextVisitor::Visit( SmSpecialNode* pNode )
{
    SmTokenType type = pNode->GetToken().eType;
    switch(type){
        case TINTD:
            Append("intd ");
            break;
        case TINT:
            Append("int ");
            break;
        case TSUM:
            Append("sum ");
            break;
        case TIINT:
            Append("iint ");
            break;
        case TIIINT:
            Append("iiint ");
            break;
        case TLINT:
            Append("lint ");
            break;
        case TLLINT:
            Append("llint ");
            break;
        case TLLLINT:
            Append("lllint ");
            break;
        case TCOPROD:
            Append("coprod ");
            break;
        case TPROD:
            Append("prod ");
            break;
        case TLIM:
            Append("lim ");
            break;
        case TLIMSUP:
            Append("lim sup ");
            break;
@@ -2475,54 +2474,35 @@ void SmNodeToTextVisitor::Visit( SmGlyphSpecialNode* pNode )
//TODO to improve this it is required to improve mathmlimport.
void SmNodeToTextVisitor::Visit( SmMathSymbolNode* pNode )
{
    if (    ( pNode->GetToken().nGroup & TG::LBrace )
         || ( pNode->GetToken().nGroup & TG::RBrace )
         || ( pNode->GetToken().nGroup & TG::Sum )
         || ( pNode->GetToken().nGroup & TG::Product )
         || ( pNode->GetToken().nGroup & TG::Relation )
         || ( pNode->GetToken().nGroup & TG::UnOper )
         || ( pNode->GetToken().nGroup & TG::Oper )
    ) {
        Append( pNode->GetToken().aText );
        return;
    }
    sal_Unicode cChar = pNode->GetToken().cMathChar;
    Separate( );
    switch(cChar){
        case '(':
            Append("(");
            break;
        case '[':
            Append("[");
            break;
        case '{':
            Append("lbrace");
            break;
        case ')':
            Append(")");
            break;
        case ']':
            Append("]");
            break;
        case '}':
            Append("rbrace");
            break;
        case 0x0000:
        case MS_NONE:
            Append("none");
            break;
        case MS_NEG:
            Append("neg");
        case '{':
            Append("{");
            break;
        case MS_PLUSMINUS:
            Append("+-");
            break;
        case MS_FACT:
            Append("fact");
        case '}':
            Append("}");
            break;
        case MS_VERTLINE:
            if( pNode->GetToken().eType == TLLINE ) Append("lline");
            else if( pNode->GetToken().eType == TRLINE ) Append("rline");
            else Append("mline");
            Append("mline");
            break;
        case MS_TILDE:
            Append("\"~\"");
            break;
        case MS_SIM:
            Append("sim");
            break;
        case MS_DVERTLINE:
            if( pNode->GetToken().eType == TLDLINE ) Append("ldline");
            else Append("rdline");
            break;
        case MS_RIGHTARROW:
            if( pNode->GetToken().eType == TTOWARD ) Append("toward");
            else Append("rightarrow");
@@ -2536,30 +2516,12 @@ void SmNodeToTextVisitor::Visit( SmMathSymbolNode* pNode )
        case MS_DOWNARROW:
            Append("downarrow");
            break;
        case MS_NDIVIDES:
            Append("ndivides");
            break;
        case MS_DLINE:
            Append("parallel");
            break;
        case MS_TIMES:
            Append("times");
            break;
        case MS_DIV:
            Append("div");
            break;
        case MS_LAMBDABAR:
            Append("lambdabar");
            break;
        case MS_DOTSLOW:
            Append("dotslow");
            break;
        case 0x2022:
            Append("cdot");
            break;
        case MS_CDOT:
            Append("cdot");
            break;
        case MS_SETC:
            Append("setC");
            break;
@@ -2623,157 +2585,15 @@ void SmNodeToTextVisitor::Visit( SmMathSymbolNode* pNode )
        case MS_NABLA:
            Append("nabla");
            break;
        case MS_IN:
            Append("in");
            break;
        case MS_NI:
            Append("owns");
            break;
        case MS_NOTIN:
            Append("notin");
            break;
        case MS_BACKEPSILON:
            Append("backepsilon");
            break;
        case MS_PROD:
            Append("prod");
            break;
        case MS_COPROD:
            Append("coprod");
            break;
        case MS_SUM:
            Append("sum");
            break;
        case MS_MINUS:
            Append("-");
            break;
        case MS_MINUSPLUS:
            Append("-+");
            break;
        case MS_MULTIPLY:
            Append("*");
            break;
        case MS_CIRC:
            Append("circ");
            break;
        case MS_PROP:
            Append("prop");
            break;
        case MS_INFINITY:
            Append("infinity");
            break;
        case MS_AND:
            Append("and");
            break;
        case MS_OR:
            Append("or");
            break;
        case MS_INTERSECT:
            Append("intersection");
            break;
        case MS_UNION:
            Append("union");
            break;
        case MS_LINE:
            Append("divides");
            break;
        case MS_INT:
            if (pNode->GetScaleMode() == SmScaleMode::Height) Append("intd");
            else Append("int");
            break;
        case MS_IINT:
            Append("iint");
            break;
        case MS_IIINT:
            Append("iiint");
            break;
        case MS_LINT:
            Append("lint");
            break;
        case MS_LLINT:
            Append("llint");
            break;
        case MS_LLLINT:
            Append("lllint");
            break;
        case 0x2245:
            Append("simeq");
            break;
        case MS_SIMEQ:
            Append("simeq");
            break;
        case MS_BACKSLASH:
            Append("setminus");
            break;
        case MS_APPROX:
            Append("approx");
            break;
        case MS_NEQ:
            Append("<>");
            break;
        case MS_EQUIV:
            Append("equiv");
            break;
        case MS_LE:
            Append("<=");
            break;
        case MS_GE:
            Append(">=");
            break;
        case MS_LESLANT:
            Append("leslant");
            break;
        case MS_GESLANT:
            Append("geslant");
            break;
        case MS_PRECEDES:
            Append("prec");
            break;
        case MS_SUCCEEDS:
            Append("succ");
            break;
        case MS_PRECEDESEQUAL:
            Append("preccurlyeq");
            break;
        case MS_SUCCEEDSEQUAL:
            Append("succcurlyeq");
            break;
        case MS_PRECEDESEQUIV:
            Append("precsim");
            break;
        case MS_SUCCEEDSEQUIV:
            Append("succsim");
            break;
        case MS_NOTPRECEDES:
            Append("nprec");
            break;
        case MS_NOTSUCCEEDS:
            Append("nsucc");
            break;
        case MS_SUBSET:
            Append("subset");
            break;
        case MS_SUPSET:
            Append("supset");
            break;
        case MS_NSUBSET:
            Append("nsubset");
            break;
        case MS_NSUPSET:
            Append("nsupset");
            break;
        case MS_SUBSETEQ:
            Append("subseteq");
            break;
        case MS_SUPSETEQ:
            Append("supseteq");
            break;
        case MS_NSUBSETEQ:
            Append("nsubseteq");
            break;
        case MS_NSUPSETEQ:
            Append("nsupseteq");
            break;
        case 0x22b2: // NORMAL SUBGROUP OF
            Append(OUStringChar(cChar));
            break;
@@ -2795,32 +2615,6 @@ void SmNodeToTextVisitor::Visit( SmMathSymbolNode* pNode )
        case MS_DOTSDOWN:
            Append("dotsdown");
            break;
        case MS_LANGLE:
        case MS_LMATHANGLE:
            Append("langle");
            break;
        case MS_RANGLE:
        case MS_RMATHANGLE:
            Append("rangle");
            break;
        case 0x301a:
            Append("ldbracket");
            break;
        case 0x301b:
            Append("rdbracket");
            break;
        case MS_LDBRACKET:
            Append("ldbracket");
            break;
        case MS_RDBRACKET:
            Append("rdbracket");
            break;
        case 0xe083:
            Append("+");
            break;
        case MS_PLUS:
            Append("+");
            break;
        case '^':
            Append("^");
            break;
@@ -2833,12 +2627,6 @@ void SmNodeToTextVisitor::Visit( SmMathSymbolNode* pNode )
        case 0xe098:
            Append("widevec");
            break;
        case 0xE421:
            Append("geslant");
            break;
        case 0xE425:
            Append("leslant");
            break;
        case 0xeb01:    //no space
        case 0xeb08:    //normal space
            break;
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index 23186f6..f8cd9c9 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -1483,6 +1483,8 @@ namespace xmloff::token {
        TOKEN( "power",                           XML_POWER ),
        TOKEN( "precision-as-shown",              XML_PRECISION_AS_SHOWN ),
        TOKEN( "prefix",                          XML_PREFIX ),
        TOKEN( "infix",                           XML_INFIX ),
        TOKEN( "postfix",                         XML_POSTFIX ),
        TOKEN( "presentation",                    XML_PRESENTATION ),
        TOKEN( "orgchart",                        XML_PRESENTATION_ORGCHART ),
        TOKEN( "outline",                         XML_PRESENTATION_OUTLINE ),
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index a0019db..c3dcca0 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -1393,6 +1393,8 @@ oblique
power
precision-as-shown
prefix
infix
postfix
presentation
orgchart
outline