LCOV - code coverage report
Current view: top level - starmath/source - parse.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 944 1118 84.4 %
Date: 2014-04-11 Functions: 43 46 93.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <stdio.h>
      21             : 
      22             : #include <com/sun/star/i18n/UnicodeType.hpp>
      23             : #include <i18nlangtag/lang.h>
      24             : #include <unotools/charclass.hxx>
      25             : #include <editeng/unolingu.hxx>
      26             : #include <unotools/syslocale.hxx>
      27             : #include <sal/macros.h>
      28             : #include <vcl/settings.hxx>
      29             : #include "parse.hxx"
      30             : #include "starmath.hrc"
      31             : #include "smdll.hxx"
      32             : #include "smmod.hxx"
      33             : #include "config.hxx"
      34             : 
      35             : #include "node.hxx"
      36             : 
      37             : using namespace ::com::sun::star;
      38             : using namespace ::com::sun::star::i18n;
      39             : 
      40             : 
      41             : 
      42             : namespace {
      43             : template < typename T >
      44       17686 : T* lcl_popOrZero( ::std::stack<T*> & rStack )
      45             : {
      46       17686 :     if (rStack.empty())
      47           0 :         return 0;
      48       17686 :     T* pTmp = rStack.top();
      49       17686 :     rStack.pop();
      50       17686 :     return pTmp;
      51             : }
      52             : }
      53             : 
      54        1304 : SmToken::SmToken() :
      55             :     eType       (TUNKNOWN),
      56        1304 :     cMathChar   ('\0')
      57             : {
      58        1304 :     nGroup = nCol = nRow = nLevel = 0;
      59        1304 : }
      60             : 
      61           4 : SmToken::SmToken(SmTokenType eTokenType,
      62             :                  sal_Unicode cMath,
      63             :                  const sal_Char* pText,
      64             :                  sal_uLong nTokenGroup,
      65           4 :                  sal_uInt16 nTokenLevel) {
      66           4 :     eType = eTokenType;
      67           4 :     cMathChar = cMath;
      68           4 :     aText = OUString::createFromAscii(pText);
      69           4 :     nGroup = nTokenGroup;
      70           4 :     nLevel = nTokenLevel;
      71           4 :     nCol = nRow = 0;
      72           4 : }
      73             : 
      74             : 
      75             : 
      76             : 
      77             : static const SmTokenTableEntry aTokenTable[] =
      78             : {
      79             :     { "Im" , TIM, MS_IM, TGSTANDALONE, 5 },
      80             :     { "MZ23", TDEBUG, '\0', TGATTRIBUT, 0 },
      81             :     { "Re" , TRE, MS_RE, TGSTANDALONE, 5 },
      82             :     { "abs", TABS, '\0', TGUNOPER, 13 },
      83             :     { "arcosh", TACOSH, '\0', TGFUNCTION, 5 },
      84             :     { "arcoth", TACOTH, '\0', TGFUNCTION, 5 },
      85             :     { "acute", TACUTE, MS_ACUTE, TGATTRIBUT, 5 },
      86             :     { "aleph" , TALEPH, MS_ALEPH, TGSTANDALONE, 5 },
      87             :     { "alignb", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0},
      88             :     { "alignc", TALIGNC, '\0', TGALIGN, 0},
      89             :     { "alignl", TALIGNL, '\0', TGALIGN, 0},
      90             :     { "alignm", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0},
      91             :     { "alignr", TALIGNR, '\0', TGALIGN, 0},
      92             :     { "alignt", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0},
      93             :     { "and", TAND, MS_AND, TGPRODUCT, 0},
      94             :     { "approx", TAPPROX, MS_APPROX, TGRELATION, 0},
      95             :     { "arccos", TACOS, '\0', TGFUNCTION, 5},
      96             :     { "arccot", TACOT, '\0', TGFUNCTION, 5},
      97             :     { "arcsin", TASIN, '\0', TGFUNCTION, 5},
      98             :     { "arctan", TATAN, '\0', TGFUNCTION, 5},
      99             :     { "arsinh", TASINH, '\0', TGFUNCTION, 5},
     100             :     { "artanh", TATANH, '\0', TGFUNCTION, 5},
     101             :     { "backepsilon" , TBACKEPSILON, MS_BACKEPSILON, TGSTANDALONE, 5},
     102             :     { "bar", TBAR, MS_BAR, TGATTRIBUT, 5},
     103             :     { "binom", TBINOM, '\0', 0, 5 },
     104             :     { "black", TBLACK, '\0', TGCOLOR, 0},
     105             :     { "blue", TBLUE, '\0', TGCOLOR, 0},
     106             :     { "bold", TBOLD, '\0', TGFONTATTR, 5},
     107             :     { "boper", TBOPER, '\0', TGPRODUCT, 0},
     108             :     { "breve", TBREVE, MS_BREVE, TGATTRIBUT, 5},
     109             :     { "bslash", TBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 },
     110             :     { "cdot", TCDOT, MS_CDOT, TGPRODUCT, 0},
     111             :     { "check", TCHECK, MS_CHECK, TGATTRIBUT, 5},
     112             :     { "circ" , TCIRC, MS_CIRC, TGSTANDALONE, 5},
     113             :     { "circle", TCIRCLE, MS_CIRCLE, TGATTRIBUT, 5},
     114             :     { "color", TCOLOR, '\0', TGFONTATTR, 5},
     115             :     { "coprod", TCOPROD, MS_COPROD, TGOPER, 5},
     116             :     { "cos", TCOS, '\0', TGFUNCTION, 5},
     117             :     { "cosh", TCOSH, '\0', TGFUNCTION, 5},
     118             :     { "cot", TCOT, '\0', TGFUNCTION, 5},
     119             :     { "coth", TCOTH, '\0', TGFUNCTION, 5},
     120             :     { "csub", TCSUB, '\0', TGPOWER, 0},
     121             :     { "csup", TCSUP, '\0', TGPOWER, 0},
     122             :     { "cyan", TCYAN, '\0', TGCOLOR, 0},
     123             :     { "dddot", TDDDOT, MS_DDDOT, TGATTRIBUT, 5},
     124             :     { "ddot", TDDOT, MS_DDOT, TGATTRIBUT, 5},
     125             :     { "def", TDEF, MS_DEF, TGRELATION, 0},
     126             :     { "div", TDIV, MS_DIV, TGPRODUCT, 0},
     127             :     { "divides", TDIVIDES, MS_LINE, TGRELATION, 0},
     128             :     { "dlarrow" , TDLARROW, MS_DLARROW, TGSTANDALONE, 5},
     129             :     { "dlrarrow" , TDLRARROW, MS_DLRARROW, TGSTANDALONE, 5},
     130             :     { "dot", TDOT, MS_DOT, TGATTRIBUT, 5},
     131             :     { "dotsaxis", TDOTSAXIS, MS_DOTSAXIS, TGSTANDALONE, 5}, // 5 to continue expression
     132             :     { "dotsdiag", TDOTSDIAG, MS_DOTSUP, TGSTANDALONE, 5},
     133             :     { "dotsdown", TDOTSDOWN, MS_DOTSDOWN, TGSTANDALONE, 5},
     134             :     { "dotslow", TDOTSLOW, MS_DOTSLOW, TGSTANDALONE, 5},
     135             :     { "dotsup", TDOTSUP, MS_DOTSUP, TGSTANDALONE, 5},
     136             :     { "dotsvert", TDOTSVERT, MS_DOTSVERT, TGSTANDALONE, 5},
     137             :     { "downarrow" , TDOWNARROW, MS_DOWNARROW, TGSTANDALONE, 5},
     138             :     { "drarrow" , TDRARROW, MS_DRARROW, TGSTANDALONE, 5},
     139             :     { "emptyset" , TEMPTYSET, MS_EMPTYSET, TGSTANDALONE, 5},
     140             :     { "equiv", TEQUIV, MS_EQUIV, TGRELATION, 0},
     141             :     { "exists", TEXISTS, MS_EXISTS, TGSTANDALONE, 5},
     142             :     { "notexists", TNOTEXISTS, MS_NOTEXISTS, TGSTANDALONE, 5},
     143             :     { "exp", TEXP, '\0', TGFUNCTION, 5},
     144             :     { "fact", TFACT, MS_FACT, TGUNOPER, 5},
     145             :     { "fixed", TFIXED, '\0', TGFONT, 0},
     146             :     { "font", TFONT, '\0', TGFONTATTR, 5},
     147             :     { "forall", TFORALL, MS_FORALL, TGSTANDALONE, 5},
     148             :     { "from", TFROM, '\0', TGLIMIT, 0},
     149             :     { "func", TFUNC, '\0', TGFUNCTION, 5},
     150             :     { "ge", TGE, MS_GE, TGRELATION, 0},
     151             :     { "geslant", TGESLANT, MS_GESLANT, TGRELATION, 0 },
     152             :     { "gg", TGG, MS_GG, TGRELATION, 0},
     153             :     { "grave", TGRAVE, MS_GRAVE, TGATTRIBUT, 5},
     154             :     { "green", TGREEN, '\0', TGCOLOR, 0},
     155             :     { "gt", TGT, MS_GT, TGRELATION, 0},
     156             :     { "hat", THAT, MS_HAT, TGATTRIBUT, 5},
     157             :     { "hbar" , THBAR, MS_HBAR, TGSTANDALONE, 5},
     158             :     { "iiint", TIIINT, MS_IIINT, TGOPER, 5},
     159             :     { "iint", TIINT, MS_IINT, TGOPER, 5},
     160             :     { "in", TIN, MS_IN, TGRELATION, 0},
     161             :     { "infinity" , TINFINITY, MS_INFINITY, TGSTANDALONE, 5},
     162             :     { "infty" , TINFINITY, MS_INFINITY, TGSTANDALONE, 5},
     163             :     { "int", TINT, MS_INT, TGOPER, 5},
     164             :     { "intd", TINTD, MS_INT, TGUNOPER, 5},
     165             :     { "intersection", TINTERSECT, MS_INTERSECT, TGPRODUCT, 0},
     166             :     { "ital", TITALIC, '\0', TGFONTATTR, 5},
     167             :     { "italic", TITALIC, '\0', TGFONTATTR, 5},
     168             :     { "lambdabar" , TLAMBDABAR, MS_LAMBDABAR, TGSTANDALONE, 5},
     169             :     { "langle", TLANGLE, MS_LMATHANGLE, TGLBRACES, 5},
     170             :     { "lbrace", TLBRACE, MS_LBRACE, TGLBRACES, 5},
     171             :     { "lceil", TLCEIL, MS_LCEIL, TGLBRACES, 5},
     172             :     { "ldbracket", TLDBRACKET, MS_LDBRACKET, TGLBRACES, 5},
     173             :     { "ldline", TLDLINE, MS_DVERTLINE, TGLBRACES, 5},
     174             :     { "le", TLE, MS_LE, TGRELATION, 0},
     175             :     { "left", TLEFT, '\0', 0, 5},
     176             :     { "leftarrow" , TLEFTARROW, MS_LEFTARROW, TGSTANDALONE, 5},
     177             :     { "leslant", TLESLANT, MS_LESLANT, TGRELATION, 0 },
     178             :     { "lfloor", TLFLOOR, MS_LFLOOR, TGLBRACES, 5},
     179             :     { "lim", TLIM, '\0', TGOPER, 5},
     180             :     { "liminf", TLIMINF, '\0', TGOPER, 5},
     181             :     { "limsup", TLIMSUP, '\0', TGOPER, 5},
     182             :     { "lint", TLINT, MS_LINT, TGOPER, 5},
     183             :     { "ll", TLL, MS_LL, TGRELATION, 0},
     184             :     { "lline", TLLINE, MS_VERTLINE, TGLBRACES, 5},
     185             :     { "llint", TLLINT, MS_LLINT, TGOPER, 5},
     186             :     { "lllint", TLLLINT, MS_LLLINT, TGOPER, 5},
     187             :     { "ln", TLN, '\0', TGFUNCTION, 5},
     188             :     { "log", TLOG, '\0', TGFUNCTION, 5},
     189             :     { "lsub", TLSUB, '\0', TGPOWER, 0},
     190             :     { "lsup", TLSUP, '\0', TGPOWER, 0},
     191             :     { "lt", TLT, MS_LT, TGRELATION, 0},
     192             :     { "magenta", TMAGENTA, '\0', TGCOLOR, 0},
     193             :     { "matrix", TMATRIX, '\0', 0, 5},
     194             :     { "minusplus", TMINUSPLUS, MS_MINUSPLUS, TGUNOPER | TGSUM, 5},
     195             :     { "mline", TMLINE, MS_VERTLINE, 0, 0},      //! not in TGRBRACES, Level 0
     196             :     { "nabla", TNABLA, MS_NABLA, TGSTANDALONE, 5},
     197             :     { "nbold", TNBOLD, '\0', TGFONTATTR, 5},
     198             :     { "ndivides", TNDIVIDES, MS_NDIVIDES, TGRELATION, 0},
     199             :     { "neg", TNEG, MS_NEG, TGUNOPER, 5 },
     200             :     { "neq", TNEQ, MS_NEQ, TGRELATION, 0},
     201             :     { "newline", TNEWLINE, '\0', 0, 0},
     202             :     { "ni", TNI, MS_NI, TGRELATION, 0},
     203             :     { "nitalic", TNITALIC, '\0', TGFONTATTR, 5},
     204             :     { "none", TNONE, '\0', TGLBRACES | TGRBRACES, 0},
     205             :     { "nospace", TNOSPACE, '\0', TGSTANDALONE, 5},
     206             :     { "notin", TNOTIN, MS_NOTIN, TGRELATION, 0},
     207             :     { "nroot", TNROOT, MS_SQRT, TGUNOPER, 5},
     208             :     { "nsubset", TNSUBSET, MS_NSUBSET, TGRELATION, 0 },
     209             :     { "nsupset", TNSUPSET, MS_NSUPSET, TGRELATION, 0 },
     210             :     { "nsubseteq", TNSUBSETEQ, MS_NSUBSETEQ, TGRELATION, 0 },
     211             :     { "nsupseteq", TNSUPSETEQ, MS_NSUPSETEQ, TGRELATION, 0 },
     212             :     { "odivide", TODIVIDE, MS_ODIVIDE, TGPRODUCT, 0},
     213             :     { "odot", TODOT, MS_ODOT, TGPRODUCT, 0},
     214             :     { "ominus", TOMINUS, MS_OMINUS, TGSUM, 0},
     215             :     { "oper", TOPER, '\0', TGOPER, 5},
     216             :     { "oplus", TOPLUS, MS_OPLUS, TGSUM, 0},
     217             :     { "or", TOR, MS_OR, TGSUM, 0},
     218             :     { "ortho", TORTHO, MS_ORTHO, TGRELATION, 0},
     219             :     { "otimes", TOTIMES, MS_OTIMES, TGPRODUCT, 0},
     220             :     { "over", TOVER, '\0', TGPRODUCT, 0},
     221             :     { "overbrace", TOVERBRACE, MS_OVERBRACE, TGPRODUCT, 5},
     222             :     { "overline", TOVERLINE, '\0', TGATTRIBUT, 5},
     223             :     { "overstrike", TOVERSTRIKE, '\0', TGATTRIBUT, 5},
     224             :     { "owns", TNI, MS_NI, TGRELATION, 0},
     225             :     { "parallel", TPARALLEL, MS_DLINE, TGRELATION, 0},
     226             :     { "partial", TPARTIAL, MS_PARTIAL, TGSTANDALONE, 5 },
     227             :     { "phantom", TPHANTOM, '\0', TGFONTATTR, 5},
     228             :     { "plusminus", TPLUSMINUS, MS_PLUSMINUS, TGUNOPER | TGSUM, 5},
     229             :     { "prec", TPRECEDES, MS_PRECEDES, TGRELATION, 0 },
     230             :     { "preccurlyeq", TPRECEDESEQUAL, MS_PRECEDESEQUAL, TGRELATION, 0 },
     231             :     { "precsim", TPRECEDESEQUIV, MS_PRECEDESEQUIV, TGRELATION, 0 },
     232             :     { "nprec", TNOTPRECEDES, MS_NOTPRECEDES, TGRELATION, 0 },
     233             :     { "prod", TPROD, MS_PROD, TGOPER, 5},
     234             :     { "prop", TPROP, MS_PROP, TGRELATION, 0},
     235             :     { "rangle", TRANGLE, MS_RMATHANGLE, TGRBRACES, 0},  //! 0 to terminate expression
     236             :     { "rbrace", TRBRACE, MS_RBRACE, TGRBRACES, 0},
     237             :     { "rceil", TRCEIL, MS_RCEIL, TGRBRACES, 0},
     238             :     { "rdbracket", TRDBRACKET, MS_RDBRACKET, TGRBRACES, 0},
     239             :     { "rdline", TRDLINE, MS_DVERTLINE, TGRBRACES, 0},
     240             :     { "red", TRED, '\0', TGCOLOR, 0},
     241             :     { "rfloor", TRFLOOR, MS_RFLOOR, TGRBRACES, 0},  //! 0 to terminate expression
     242             :     { "right", TRIGHT, '\0', 0, 0},
     243             :     { "rightarrow" , TRIGHTARROW, MS_RIGHTARROW, TGSTANDALONE, 5},
     244             :     { "rline", TRLINE, MS_VERTLINE, TGRBRACES, 0},  //! 0 to terminate expression
     245             :     { "rsub", TRSUB, '\0', TGPOWER, 0},
     246             :     { "rsup", TRSUP, '\0', TGPOWER, 0},
     247             :     { "sans", TSANS, '\0', TGFONT, 0},
     248             :     { "serif", TSERIF, '\0', TGFONT, 0},
     249             :     { "setC" , TSETC, MS_SETC, TGSTANDALONE, 5},
     250             :     { "setN" , TSETN, MS_SETN, TGSTANDALONE, 5},
     251             :     { "setQ" , TSETQ, MS_SETQ, TGSTANDALONE, 5},
     252             :     { "setR" , TSETR, MS_SETR, TGSTANDALONE, 5},
     253             :     { "setZ" , TSETZ, MS_SETZ, TGSTANDALONE, 5},
     254             :     { "setminus", TBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 },
     255             :     { "sim", TSIM, MS_SIM, TGRELATION, 0},
     256             :     { "simeq", TSIMEQ, MS_SIMEQ, TGRELATION, 0},
     257             :     { "sin", TSIN, '\0', TGFUNCTION, 5},
     258             :     { "sinh", TSINH, '\0', TGFUNCTION, 5},
     259             :     { "size", TSIZE, '\0', TGFONTATTR, 5},
     260             :     { "slash", TSLASH, MS_SLASH, TGPRODUCT, 0 },
     261             :     { "sqrt", TSQRT, MS_SQRT, TGUNOPER, 5},
     262             :     { "stack", TSTACK, '\0', 0, 5},
     263             :     { "sub", TRSUB, '\0', TGPOWER, 0},
     264             :     { "subset", TSUBSET, MS_SUBSET, TGRELATION, 0},
     265             :     { "succ", TSUCCEEDS, MS_SUCCEEDS, TGRELATION, 0 },
     266             :     { "succcurlyeq", TSUCCEEDSEQUAL, MS_SUCCEEDSEQUAL, TGRELATION, 0 },
     267             :     { "succsim", TSUCCEEDSEQUIV, MS_SUCCEEDSEQUIV, TGRELATION, 0 },
     268             :     { "nsucc", TNOTSUCCEEDS, MS_NOTSUCCEEDS, TGRELATION, 0 },
     269             :     { "subseteq", TSUBSETEQ, MS_SUBSETEQ, TGRELATION, 0},
     270             :     { "sum", TSUM, MS_SUM, TGOPER, 5},
     271             :     { "sup", TRSUP, '\0', TGPOWER, 0},
     272             :     { "supset", TSUPSET, MS_SUPSET, TGRELATION, 0},
     273             :     { "supseteq", TSUPSETEQ, MS_SUPSETEQ, TGRELATION, 0},
     274             :     { "tan", TTAN, '\0', TGFUNCTION, 5},
     275             :     { "tanh", TTANH, '\0', TGFUNCTION, 5},
     276             :     { "tilde", TTILDE, MS_TILDE, TGATTRIBUT, 5},
     277             :     { "times", TTIMES, MS_TIMES, TGPRODUCT, 0},
     278             :     { "to", TTO, '\0', TGLIMIT, 0},
     279             :     { "toward", TTOWARD, MS_RIGHTARROW, TGRELATION, 0},
     280             :     { "transl", TTRANSL, MS_TRANSL, TGRELATION, 0},
     281             :     { "transr", TTRANSR, MS_TRANSR, TGRELATION, 0},
     282             :     { "underbrace", TUNDERBRACE, MS_UNDERBRACE, TGPRODUCT, 5},
     283             :     { "underline", TUNDERLINE, '\0', TGATTRIBUT, 5},
     284             :     { "union", TUNION, MS_UNION, TGSUM, 0},
     285             :     { "uoper", TUOPER, '\0', TGUNOPER, 5},
     286             :     { "uparrow" , TUPARROW, MS_UPARROW, TGSTANDALONE, 5},
     287             :     { "vec", TVEC, MS_VEC, TGATTRIBUT, 5},
     288             :     { "white", TWHITE, '\0', TGCOLOR, 0},
     289             :     { "widebslash", TWIDEBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 },
     290             :     { "widehat", TWIDEHAT, MS_HAT, TGATTRIBUT, 5},
     291             :     { "widetilde", TWIDETILDE, MS_TILDE, TGATTRIBUT, 5},
     292             :     { "wideslash", TWIDESLASH, MS_SLASH, TGPRODUCT, 0 },
     293             :     { "widevec", TWIDEVEC, MS_VEC, TGATTRIBUT, 5},
     294             :     { "wp" , TWP, MS_WP, TGSTANDALONE, 5},
     295             :     { "yellow", TYELLOW, '\0', TGCOLOR, 0},
     296             :     { "", TEND, '\0', 0, 0}
     297             : };
     298             : 
     299        6460 : const SmTokenTableEntry * SmParser::GetTokenTableEntry( const OUString &rName )
     300             : {
     301        6460 :     const SmTokenTableEntry * pRes = 0;
     302        6460 :     if (!rName.isEmpty())
     303             :     {
     304     1105849 :         for (size_t i = 0; i < SAL_N_ELEMENTS(aTokenTable); ++i)
     305             :         {
     306     1102865 :             if (rName.equalsIgnoreAsciiCase( OUString::createFromAscii(aTokenTable[i].pIdent) ))
     307             :             {
     308        3476 :                 pRes = &aTokenTable[i];
     309        3476 :                 break;
     310             :             }
     311             :         }
     312             :     }
     313             : 
     314        6460 :     return pRes;
     315             : }
     316             : 
     317             : 
     318             : 
     319             : 
     320             : #if OSL_DEBUG_LEVEL > 1
     321             : 
     322             : static const sal_Unicode aDelimiterTable[] =
     323             : {
     324             :     ' ',    '\t',   '\n',   '\r',   '+',    '-',    '*',    '/',    '=',    '#',
     325             :     '%',    '\\',   '"',    '~',    '`',    '>',    '<',    '&',    '|',    '(',
     326             :     ')',    '{',    '}',    '[',    ']',    '^',    '_',
     327             :     '\0'    // end of list symbol
     328             : };
     329             : 
     330             : bool SmParser::IsDelimiter( const OUString &rTxt, sal_Int32 nPos )
     331             :     // returns 'true' iff cChar is '\0' or a delimiter
     332             : {
     333             :     assert(nPos <= rTxt.getLength()); //index out of range
     334             : 
     335             :     if (nPos == rTxt.getLength())
     336             :         return true;
     337             : 
     338             :     sal_Unicode cChar = rTxt[nPos];
     339             : 
     340             :     // check if 'cChar' is in the delimiter table
     341             :     const sal_Unicode *pDelim = &aDelimiterTable[0];
     342             :     for ( ;  *pDelim != 0;  pDelim++)
     343             :         if (*pDelim == cChar)
     344             :             break;
     345             : 
     346             : 
     347             :     sal_Int16 nTypJp = SM_MOD()->GetSysLocale().GetCharClass().getType( rTxt, nPos );
     348             :     bool bIsDelim = (*pDelim != 0 ||
     349             :             nTypJp == com::sun::star::i18n::UnicodeType::SPACE_SEPARATOR ||
     350             :             nTypJp == com::sun::star::i18n::UnicodeType::CONTROL);
     351             : 
     352             :     return bIsDelim;
     353             : }
     354             : 
     355             : #endif
     356             : 
     357           0 : void SmParser::Replace( sal_Int32 nPos, sal_Int32 nLen, const OUString &rText )
     358             : {
     359             :     OSL_ENSURE( nPos + nLen <= m_aBufferString.getLength(), "argument mismatch" );
     360             : 
     361           0 :     m_aBufferString = m_aBufferString.replaceAt( nPos, nLen, rText );
     362           0 :     sal_Int32 nChg = rText.getLength() - nLen;
     363           0 :     m_nBufferIndex = m_nBufferIndex + nChg;
     364           0 :     m_nTokenIndex = m_nTokenIndex + nChg;
     365           0 : }
     366             : 
     367             : 
     368             : // First character may be any alphabetic
     369             : const sal_Int32 coStartFlags =
     370             :         KParseTokens::ANY_LETTER |
     371             :         KParseTokens::IGNORE_LEADING_WS;
     372             : 
     373             : // Continuing characters may be any alphabetic
     374             : const sal_Int32 coContFlags =
     375             :     (coStartFlags & ~KParseTokens::IGNORE_LEADING_WS)
     376             :     | KParseTokens::TWO_DOUBLE_QUOTES_BREAK_STRING;
     377             : 
     378             : // First character for numbers, may be any numeric or dot
     379             : const sal_Int32 coNumStartFlags =
     380             :         KParseTokens::ASC_DIGIT |
     381             :         KParseTokens::ASC_DOT |
     382             :         KParseTokens::IGNORE_LEADING_WS;
     383             : // Continuing characters for numbers, may be any numeric or dot.
     384             : const sal_Int32 coNumContFlags =
     385             :     coNumStartFlags & ~KParseTokens::IGNORE_LEADING_WS;
     386             : 
     387       18871 : void SmParser::NextToken()
     388             : {
     389       18871 :     static const OUString aEmptyStr;
     390             : 
     391       18871 :     sal_Int32   nBufLen = m_aBufferString.getLength();
     392       18871 :     ParseResult aRes;
     393             :     sal_Int32   nRealStart;
     394             :     bool        bCont;
     395       37742 :     CharClass   aCC(SM_MOD()->GetSysLocale().GetLanguageTag());
     396       18871 :     do
     397             :     {
     398             :         // skip white spaces
     399       47287 :         while (UnicodeType::SPACE_SEPARATOR ==
     400       28416 :                         aCC.getType( m_aBufferString, m_nBufferIndex ))
     401        9545 :            ++m_nBufferIndex;
     402             : 
     403             :         // Try to parse a number. This should be independent from the locale
     404             :         // setting, so temporarily set the language to English.
     405             :         // See https://issues.apache.org/ooo/show_bug.cgi?id=45779
     406       18871 :         LanguageTag aOldLoc(aCC.getLanguageTag());
     407       18871 :         aCC.setLanguageTag(LanguageTag(m_aDotLoc));
     408       37742 :         aRes = aCC.parsePredefinedToken(KParseType::ASC_NUMBER,
     409             :                                         m_aBufferString, m_nBufferIndex,
     410             :                                         coNumStartFlags, aEmptyStr,
     411       18871 :                                         coNumContFlags, aEmptyStr);
     412       18871 :         aCC.setLanguageTag(aOldLoc);
     413             : 
     414       18871 :         if (aRes.TokenType == 0)
     415             :         {
     416             :             // Try again with the default token parsing.
     417       35218 :             aRes = aCC.parseAnyToken(m_aBufferString, m_nBufferIndex,
     418             :                                      coStartFlags, aEmptyStr,
     419       17609 :                                      coContFlags, aEmptyStr);
     420             :         }
     421             : 
     422       18871 :         nRealStart = m_nBufferIndex + aRes.LeadingWhiteSpace;
     423       18871 :         m_nBufferIndex = nRealStart;
     424             : 
     425       18871 :         bCont = false;
     426       39787 :         if ( aRes.TokenType == 0  &&
     427       19161 :                 nRealStart < nBufLen &&
     428         290 :                 '\n' == m_aBufferString[ nRealStart ] )
     429             :         {
     430             :             // keep data needed for tokens row and col entry up to date
     431           0 :             ++m_Row;
     432           0 :             m_nBufferIndex = m_nColOff = nRealStart + 1;
     433           0 :             bCont = true;
     434             :         }
     435       18871 :         else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR)
     436             :         {
     437        8341 :             if (nRealStart + 2 <= nBufLen && m_aBufferString.match("%%", nRealStart))
     438             :             {
     439             :                 //SkipComment
     440           0 :                 m_nBufferIndex = nRealStart + 2;
     441           0 :                 while (m_nBufferIndex < nBufLen  &&
     442           0 :                     '\n' != m_aBufferString[ m_nBufferIndex ])
     443           0 :                     ++m_nBufferIndex;
     444           0 :                 bCont = true;
     445             :             }
     446       18871 :         }
     447             : 
     448             :     } while (bCont);
     449             : 
     450             :     // set index of current token
     451       18871 :     m_nTokenIndex = m_nBufferIndex;
     452             : 
     453       18871 :     m_aCurToken.nRow   = m_Row;
     454       18871 :     m_aCurToken.nCol   = nRealStart - m_nColOff + 1;
     455             : 
     456       18871 :     bool bHandled = true;
     457       18871 :     if (nRealStart >= nBufLen)
     458             :     {
     459        1755 :         m_aCurToken.eType    = TEND;
     460        1755 :         m_aCurToken.cMathChar = '\0';
     461        1755 :         m_aCurToken.nGroup       = 0;
     462        1755 :         m_aCurToken.nLevel       = 0;
     463        1755 :         m_aCurToken.aText = "";
     464             :     }
     465       17116 :     else if (aRes.TokenType & KParseType::ANY_NUMBER)
     466             :     {
     467        1262 :         sal_Int32 n = aRes.EndPos - nRealStart;
     468             :         OSL_ENSURE( n >= 0, "length < 0" );
     469        1262 :         m_aCurToken.eType      = TNUMBER;
     470        1262 :         m_aCurToken.cMathChar  = '\0';
     471        1262 :         m_aCurToken.nGroup     = 0;
     472        1262 :         m_aCurToken.nLevel     = 5;
     473        1262 :         m_aCurToken.aText      = m_aBufferString.copy( nRealStart, n );
     474             : 
     475             : #if OSL_DEBUG_LEVEL > 1
     476             :         if (!IsDelimiter( m_aBufferString, aRes.EndPos ))
     477             :             SAL_WARN( "starmath", "identifier really finished? (compatibility!)" );
     478             : #endif
     479             :     }
     480       15854 :     else if (aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING)
     481             :     {
     482          72 :         m_aCurToken.eType      = TTEXT;
     483          72 :         m_aCurToken.cMathChar  = '\0';
     484          72 :         m_aCurToken.nGroup     = 0;
     485          72 :         m_aCurToken.nLevel     = 5;
     486          72 :         m_aCurToken.aText     = aRes.DequotedNameOrString;
     487          72 :         m_aCurToken.nRow       = m_Row;
     488          72 :         m_aCurToken.nCol       = nRealStart - m_nColOff + 2;
     489             :     }
     490       15782 :     else if (aRes.TokenType & KParseType::IDENTNAME)
     491             :     {
     492        6447 :         sal_Int32 n = aRes.EndPos - nRealStart;
     493             :         OSL_ENSURE( n >= 0, "length < 0" );
     494        6447 :         OUString aName( m_aBufferString.copy( nRealStart, n ) );
     495        6447 :         const SmTokenTableEntry *pEntry = GetTokenTableEntry( aName );
     496             : 
     497        6447 :         if (pEntry)
     498             :         {
     499        3476 :             m_aCurToken.eType      = pEntry->eType;
     500        3476 :             m_aCurToken.cMathChar  = pEntry->cMathChar;
     501        3476 :             m_aCurToken.nGroup     = pEntry->nGroup;
     502        3476 :             m_aCurToken.nLevel     = pEntry->nLevel;
     503        3476 :             m_aCurToken.aText      = OUString::createFromAscii( pEntry->pIdent );
     504             :         }
     505             :         else
     506             :         {
     507        2971 :             m_aCurToken.eType      = TIDENT;
     508        2971 :             m_aCurToken.cMathChar  = '\0';
     509        2971 :             m_aCurToken.nGroup     = 0;
     510        2971 :             m_aCurToken.nLevel     = 5;
     511        2971 :             m_aCurToken.aText      = aName;
     512             : 
     513             : #if OSL_DEBUG_LEVEL > 1
     514             :             if (!IsDelimiter( m_aBufferString, aRes.EndPos ))
     515             :                 SAL_WARN( "starmath", "identifier really finished? (compatibility!)" );
     516             : #endif
     517        6447 :         }
     518             :     }
     519        9335 :     else if (aRes.TokenType == 0  &&  '_' == m_aBufferString[ nRealStart ])
     520             :     {
     521           4 :         m_aCurToken.eType    = TRSUB;
     522           4 :         m_aCurToken.cMathChar = '\0';
     523           4 :         m_aCurToken.nGroup       = TGPOWER;
     524           4 :         m_aCurToken.nLevel       = 0;
     525           4 :         m_aCurToken.aText = "_";
     526             : 
     527           4 :         aRes.EndPos = nRealStart + 1;
     528             :     }
     529        9331 :     else if (aRes.TokenType & KParseType::BOOLEAN)
     530             :     {
     531         704 :         sal_Int32   &rnEndPos = aRes.EndPos;
     532         704 :         if (rnEndPos - nRealStart <= 2)
     533             :         {
     534         704 :             sal_Unicode ch = m_aBufferString[ nRealStart ];
     535         704 :             switch (ch)
     536             :             {
     537             :                 case '<':
     538             :                     {
     539         676 :                         if (m_aBufferString.match("<<", nRealStart))
     540             :                         {
     541           0 :                             m_aCurToken.eType    = TLL;
     542           0 :                             m_aCurToken.cMathChar = MS_LL;
     543           0 :                             m_aCurToken.nGroup       = TGRELATION;
     544           0 :                             m_aCurToken.nLevel       = 0;
     545           0 :                             m_aCurToken.aText = "<<";
     546             : 
     547           0 :                             rnEndPos = nRealStart + 2;
     548             :                         }
     549         676 :                         else if (m_aBufferString.match("<=", nRealStart))
     550             :                         {
     551           2 :                             m_aCurToken.eType    = TLE;
     552           2 :                             m_aCurToken.cMathChar = MS_LE;
     553           2 :                             m_aCurToken.nGroup       = TGRELATION;
     554           2 :                             m_aCurToken.nLevel       = 0;
     555           2 :                             m_aCurToken.aText = "<=";
     556             : 
     557           2 :                             rnEndPos = nRealStart + 2;
     558             :                         }
     559         674 :                         else if (m_aBufferString.match("<>", nRealStart))
     560             :                         {
     561           4 :                             m_aCurToken.eType    = TNEQ;
     562           4 :                             m_aCurToken.cMathChar = MS_NEQ;
     563           4 :                             m_aCurToken.nGroup       = TGRELATION;
     564           4 :                             m_aCurToken.nLevel       = 0;
     565           4 :                             m_aCurToken.aText = "<>";
     566             : 
     567           4 :                             rnEndPos = nRealStart + 2;
     568             :                         }
     569         670 :                         else if (m_aBufferString.match("<?>", nRealStart))
     570             :                         {
     571         620 :                             m_aCurToken.eType    = TPLACE;
     572         620 :                             m_aCurToken.cMathChar = MS_PLACE;
     573         620 :                             m_aCurToken.nGroup       = 0;
     574         620 :                             m_aCurToken.nLevel       = 5;
     575         620 :                             m_aCurToken.aText = "<?>";
     576             : 
     577         620 :                             rnEndPos = nRealStart + 3;
     578             :                         }
     579             :                         else
     580             :                         {
     581          50 :                             m_aCurToken.eType    = TLT;
     582          50 :                             m_aCurToken.cMathChar = MS_LT;
     583          50 :                             m_aCurToken.nGroup       = TGRELATION;
     584          50 :                             m_aCurToken.nLevel       = 0;
     585          50 :                             m_aCurToken.aText = "<";
     586             :                         }
     587             :                     }
     588         676 :                     break;
     589             :                 case '>':
     590             :                     {
     591          28 :                         if (m_aBufferString.match(">=", nRealStart))
     592             :                         {
     593           2 :                             m_aCurToken.eType    = TGE;
     594           2 :                             m_aCurToken.cMathChar = MS_GE;
     595           2 :                             m_aCurToken.nGroup       = TGRELATION;
     596           2 :                             m_aCurToken.nLevel       = 0;
     597           2 :                             m_aCurToken.aText = ">=";
     598             : 
     599           2 :                             rnEndPos = nRealStart + 2;
     600             :                         }
     601          26 :                         else if (m_aBufferString.match(">>", nRealStart))
     602             :                         {
     603           0 :                             m_aCurToken.eType    = TGG;
     604           0 :                             m_aCurToken.cMathChar = MS_GG;
     605           0 :                             m_aCurToken.nGroup       = TGRELATION;
     606           0 :                             m_aCurToken.nLevel       = 0;
     607           0 :                             m_aCurToken.aText = ">>";
     608             : 
     609           0 :                             rnEndPos = nRealStart + 2;
     610             :                         }
     611             :                         else
     612             :                         {
     613          26 :                             m_aCurToken.eType    = TGT;
     614          26 :                             m_aCurToken.cMathChar = MS_GT;
     615          26 :                             m_aCurToken.nGroup       = TGRELATION;
     616          26 :                             m_aCurToken.nLevel       = 0;
     617          26 :                             m_aCurToken.aText = ">";
     618             :                         }
     619             :                     }
     620          28 :                     break;
     621             :                 default:
     622           0 :                     bHandled = false;
     623             :             }
     624             :         }
     625             :     }
     626        8627 :     else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR)
     627             :     {
     628        8341 :         sal_Int32   &rnEndPos = aRes.EndPos;
     629        8341 :         if (rnEndPos - nRealStart == 1)
     630             :         {
     631        8341 :             sal_Unicode ch = m_aBufferString[ nRealStart ];
     632        8341 :             switch (ch)
     633             :             {
     634             :                 case '%':
     635             :                     {
     636             :                         //! modifies aRes.EndPos
     637             : 
     638             :                         OSL_ENSURE( rnEndPos >= nBufLen  ||
     639             :                                     '%' != m_aBufferString[ rnEndPos ],
     640             :                                 "unexpected comment start" );
     641             : 
     642             :                         // get identifier of user-defined character
     643             :                         ParseResult aTmpRes = aCC.parseAnyToken(
     644             :                                 m_aBufferString, rnEndPos,
     645             :                                 KParseTokens::ANY_LETTER,
     646             :                                 aEmptyStr,
     647             :                                 coContFlags,
     648         136 :                                 aEmptyStr );
     649             : 
     650         136 :                         sal_Int32 nTmpStart = rnEndPos + aTmpRes.LeadingWhiteSpace;
     651             : 
     652             :                         // default setting for the case that no identifier
     653             :                         // i.e. a valid symbol-name is following the '%'
     654             :                         // character
     655         136 :                         m_aCurToken.eType      = TTEXT;
     656         136 :                         m_aCurToken.cMathChar  = '\0';
     657         136 :                         m_aCurToken.nGroup     = 0;
     658         136 :                         m_aCurToken.nLevel     = 5;
     659         136 :                         m_aCurToken.aText      = OUString();
     660         136 :                         m_aCurToken.nRow       = m_Row;
     661         136 :                         m_aCurToken.nCol       = nTmpStart - m_nColOff;
     662             : 
     663         136 :                         if (aTmpRes.TokenType & KParseType::IDENTNAME)
     664             :                         {
     665             : 
     666         130 :                             sal_Int32 n = aTmpRes.EndPos - nTmpStart;
     667         130 :                             m_aCurToken.eType      = TSPECIAL;
     668         130 :                             m_aCurToken.aText      = m_aBufferString.copy( nTmpStart-1, n+1 );
     669             : 
     670             :                             OSL_ENSURE( aTmpRes.EndPos > rnEndPos,
     671             :                                     "empty identifier" );
     672         130 :                             if (aTmpRes.EndPos > rnEndPos)
     673         130 :                                 rnEndPos = aTmpRes.EndPos;
     674             :                             else
     675           0 :                                 ++rnEndPos;
     676         136 :                         }
     677             : 
     678             :                         // if no symbol-name was found we start-over with
     679             :                         // finding the next token right afer the '%' sign.
     680             :                         // I.e. we leave rnEndPos unmodified.
     681             :                     }
     682         136 :                     break;
     683             :                 case '[':
     684             :                     {
     685          61 :                         m_aCurToken.eType    = TLBRACKET;
     686          61 :                         m_aCurToken.cMathChar = MS_LBRACKET;
     687          61 :                         m_aCurToken.nGroup       = TGLBRACES;
     688          61 :                         m_aCurToken.nLevel       = 5;
     689          61 :                         m_aCurToken.aText = "[";
     690             :                     }
     691          61 :                     break;
     692             :                 case '\\':
     693             :                     {
     694          30 :                         m_aCurToken.eType    = TESCAPE;
     695          30 :                         m_aCurToken.cMathChar = '\0';
     696          30 :                         m_aCurToken.nGroup       = 0;
     697          30 :                         m_aCurToken.nLevel       = 5;
     698          30 :                         m_aCurToken.aText = "\\";
     699             :                     }
     700          30 :                     break;
     701             :                 case ']':
     702             :                     {
     703          61 :                         m_aCurToken.eType    = TRBRACKET;
     704          61 :                         m_aCurToken.cMathChar = MS_RBRACKET;
     705          61 :                         m_aCurToken.nGroup       = TGRBRACES;
     706          61 :                         m_aCurToken.nLevel       = 0;
     707          61 :                         m_aCurToken.aText = "]";
     708             :                     }
     709          61 :                     break;
     710             :                 case '^':
     711             :                     {
     712         337 :                         m_aCurToken.eType    = TRSUP;
     713         337 :                         m_aCurToken.cMathChar = '\0';
     714         337 :                         m_aCurToken.nGroup       = TGPOWER;
     715         337 :                         m_aCurToken.nLevel       = 0;
     716         337 :                         m_aCurToken.aText = "^";
     717             :                     }
     718         337 :                     break;
     719             :                 case '`':
     720             :                     {
     721           2 :                         m_aCurToken.eType    = TSBLANK;
     722           2 :                         m_aCurToken.cMathChar = '\0';
     723           2 :                         m_aCurToken.nGroup       = TGBLANK;
     724           2 :                         m_aCurToken.nLevel       = 5;
     725           2 :                         m_aCurToken.aText = "`";
     726             :                     }
     727           2 :                     break;
     728             :                 case '{':
     729             :                     {
     730        2995 :                         m_aCurToken.eType    = TLGROUP;
     731        2995 :                         m_aCurToken.cMathChar = MS_LBRACE;
     732        2995 :                         m_aCurToken.nGroup       = 0;
     733        2995 :                         m_aCurToken.nLevel       = 5;
     734        2995 :                         m_aCurToken.aText = "{";
     735             :                     }
     736        2995 :                     break;
     737             :                 case '|':
     738             :                     {
     739           0 :                         m_aCurToken.eType    = TOR;
     740           0 :                         m_aCurToken.cMathChar = MS_OR;
     741           0 :                         m_aCurToken.nGroup       = TGSUM;
     742           0 :                         m_aCurToken.nLevel       = 0;
     743           0 :                         m_aCurToken.aText = "|";
     744             :                     }
     745           0 :                     break;
     746             :                 case '}':
     747             :                     {
     748        2989 :                         m_aCurToken.eType    = TRGROUP;
     749        2989 :                         m_aCurToken.cMathChar = MS_RBRACE;
     750        2989 :                         m_aCurToken.nGroup       = 0;
     751        2989 :                         m_aCurToken.nLevel       = 0;
     752        2989 :                         m_aCurToken.aText = "}";
     753             :                     }
     754        2989 :                     break;
     755             :                 case '~':
     756             :                     {
     757           2 :                         m_aCurToken.eType    = TBLANK;
     758           2 :                         m_aCurToken.cMathChar = '\0';
     759           2 :                         m_aCurToken.nGroup       = TGBLANK;
     760           2 :                         m_aCurToken.nLevel       = 5;
     761           2 :                         m_aCurToken.aText = "~";
     762             :                     }
     763           2 :                     break;
     764             :                 case '#':
     765             :                     {
     766         141 :                         if (m_aBufferString.match("##", nRealStart))
     767             :                         {
     768          22 :                             m_aCurToken.eType    = TDPOUND;
     769          22 :                             m_aCurToken.cMathChar = '\0';
     770          22 :                             m_aCurToken.nGroup       = 0;
     771          22 :                             m_aCurToken.nLevel       = 0;
     772          22 :                             m_aCurToken.aText = "##";
     773             : 
     774          22 :                             rnEndPos = nRealStart + 2;
     775             :                         }
     776             :                         else
     777             :                         {
     778         119 :                             m_aCurToken.eType    = TPOUND;
     779         119 :                             m_aCurToken.cMathChar = '\0';
     780         119 :                             m_aCurToken.nGroup       = 0;
     781         119 :                             m_aCurToken.nLevel       = 0;
     782         119 :                             m_aCurToken.aText = "#";
     783             :                         }
     784             :                     }
     785         141 :                     break;
     786             :                 case '&':
     787             :                     {
     788           0 :                         m_aCurToken.eType    = TAND;
     789           0 :                         m_aCurToken.cMathChar = MS_AND;
     790           0 :                         m_aCurToken.nGroup       = TGPRODUCT;
     791           0 :                         m_aCurToken.nLevel       = 0;
     792           0 :                         m_aCurToken.aText = "&";
     793             :                     }
     794           0 :                     break;
     795             :                 case '(':
     796             :                     {
     797         317 :                         m_aCurToken.eType    = TLPARENT;
     798         317 :                         m_aCurToken.cMathChar = MS_LPARENT;
     799         317 :                         m_aCurToken.nGroup       = TGLBRACES;
     800         317 :                         m_aCurToken.nLevel       = 5;     //! 0 to continue expression
     801         317 :                         m_aCurToken.aText = "(";
     802             :                     }
     803         317 :                     break;
     804             :                 case ')':
     805             :                     {
     806         317 :                         m_aCurToken.eType    = TRPARENT;
     807         317 :                         m_aCurToken.cMathChar = MS_RPARENT;
     808         317 :                         m_aCurToken.nGroup       = TGRBRACES;
     809         317 :                         m_aCurToken.nLevel       = 0;     //! 0 to terminate expression
     810         317 :                         m_aCurToken.aText = ")";
     811             :                     }
     812         317 :                     break;
     813             :                 case '*':
     814             :                     {
     815          19 :                         m_aCurToken.eType    = TMULTIPLY;
     816          19 :                         m_aCurToken.cMathChar = MS_MULTIPLY;
     817          19 :                         m_aCurToken.nGroup       = TGPRODUCT;
     818          19 :                         m_aCurToken.nLevel       = 0;
     819          19 :                         m_aCurToken.aText = "*";
     820             :                     }
     821          19 :                     break;
     822             :                 case '+':
     823             :                     {
     824         377 :                         if (m_aBufferString.match("+-", nRealStart))
     825             :                         {
     826          19 :                             m_aCurToken.eType    = TPLUSMINUS;
     827          19 :                             m_aCurToken.cMathChar = MS_PLUSMINUS;
     828          19 :                             m_aCurToken.nGroup       = TGUNOPER | TGSUM;
     829          19 :                             m_aCurToken.nLevel       = 5;
     830          19 :                             m_aCurToken.aText = "+-";
     831             : 
     832          19 :                             rnEndPos = nRealStart + 2;
     833             :                         }
     834             :                         else
     835             :                         {
     836         358 :                             m_aCurToken.eType    = TPLUS;
     837         358 :                             m_aCurToken.cMathChar = MS_PLUS;
     838         358 :                             m_aCurToken.nGroup       = TGUNOPER | TGSUM;
     839         358 :                             m_aCurToken.nLevel       = 5;
     840         358 :                             m_aCurToken.aText = "+";
     841             :                         }
     842             :                     }
     843         377 :                     break;
     844             :                 case '-':
     845             :                     {
     846         164 :                         if (m_aBufferString.match("-+", nRealStart))
     847             :                         {
     848          19 :                             m_aCurToken.eType    = TMINUSPLUS;
     849          19 :                             m_aCurToken.cMathChar = MS_MINUSPLUS;
     850          19 :                             m_aCurToken.nGroup       = TGUNOPER | TGSUM;
     851          19 :                             m_aCurToken.nLevel       = 5;
     852          19 :                             m_aCurToken.aText = "-+";
     853             : 
     854          19 :                             rnEndPos = nRealStart + 2;
     855             :                         }
     856             :                         else
     857             :                         {
     858         145 :                             m_aCurToken.eType    = TMINUS;
     859         145 :                             m_aCurToken.cMathChar = MS_MINUS;
     860         145 :                             m_aCurToken.nGroup       = TGUNOPER | TGSUM;
     861         145 :                             m_aCurToken.nLevel       = 5;
     862         145 :                             m_aCurToken.aText = "-";
     863             :                         }
     864             :                     }
     865         164 :                     break;
     866             :                 case '.':
     867             :                     {
     868             :                         // Only one character? Then it can't be a number.
     869           3 :                         if (m_nBufferIndex < m_aBufferString.getLength() - 1)
     870             :                         {
     871             :                             // for compatibility with SO5.2
     872             :                             // texts like .34 ...56 ... h ...78..90
     873             :                             // will be treated as numbers
     874           0 :                             m_aCurToken.eType     = TNUMBER;
     875           0 :                             m_aCurToken.cMathChar = '\0';
     876           0 :                             m_aCurToken.nGroup       = 0;
     877           0 :                             m_aCurToken.nLevel    = 5;
     878             : 
     879           0 :                             sal_Int32 nTxtStart = m_nBufferIndex;
     880             :                             sal_Unicode cChar;
     881           0 :                             do
     882             :                             {
     883           0 :                                 cChar = m_aBufferString[ ++m_nBufferIndex ];
     884             :                             }
     885           0 :                             while ( cChar == '.' || rtl::isAsciiDigit( cChar ) );
     886             : 
     887           0 :                             m_aCurToken.aText = m_aBufferString.copy( nTxtStart, m_nBufferIndex - nTxtStart );
     888           0 :                             aRes.EndPos = m_nBufferIndex;
     889             :                         }
     890             :                         else
     891           3 :                             bHandled = false;
     892             :                     }
     893           3 :                     break;
     894             :                 case '/':
     895             :                     {
     896          35 :                         m_aCurToken.eType    = TDIVIDEBY;
     897          35 :                         m_aCurToken.cMathChar = MS_SLASH;
     898          35 :                         m_aCurToken.nGroup       = TGPRODUCT;
     899          35 :                         m_aCurToken.nLevel       = 0;
     900          35 :                         m_aCurToken.aText = "/";
     901             :                     }
     902          35 :                     break;
     903             :                 case '=':
     904             :                     {
     905         232 :                         m_aCurToken.eType    = TASSIGN;
     906         232 :                         m_aCurToken.cMathChar = MS_ASSIGN;
     907         232 :                         m_aCurToken.nGroup       = TGRELATION;
     908         232 :                         m_aCurToken.nLevel       = 0;
     909         232 :                         m_aCurToken.aText = "=";
     910             :                     }
     911         232 :                     break;
     912             :                 default:
     913         123 :                     bHandled = false;
     914             :             }
     915             :         }
     916             :     }
     917             :     else
     918         286 :         bHandled = false;
     919             : 
     920       18871 :     if (!bHandled)
     921             :     {
     922         412 :         m_aCurToken.eType      = TCHARACTER;
     923         412 :         m_aCurToken.cMathChar  = '\0';
     924         412 :         m_aCurToken.nGroup     = 0;
     925         412 :         m_aCurToken.nLevel     = 5;
     926         412 :         m_aCurToken.aText      = m_aBufferString.copy( nRealStart, 1 );
     927             : 
     928         412 :         aRes.EndPos = nRealStart + 1;
     929             :     }
     930             : 
     931       18871 :     if (TEND != m_aCurToken.eType)
     932       35987 :         m_nBufferIndex = aRes.EndPos;
     933       18871 : }
     934             : 
     935             : 
     936             : 
     937             : // grammar
     938             : 
     939             : 
     940             : 
     941         886 : void SmParser::Table()
     942             : {
     943         886 :     SmNodeArray  LineArray;
     944             : 
     945         886 :     Line();
     946        1772 :     while (m_aCurToken.eType == TNEWLINE)
     947             :     {
     948           0 :         NextToken();
     949           0 :         Line();
     950             :     }
     951             : 
     952         886 :     if (m_aCurToken.eType != TEND)
     953           0 :         Error(PE_UNEXPECTED_CHAR);
     954             : 
     955         886 :     sal_uLong n = m_aNodeStack.size();
     956             : 
     957         886 :     LineArray.resize(n);
     958             : 
     959        1774 :     for (sal_uLong i = 0; i < n; i++)
     960             :     {
     961         888 :         LineArray[n - (i + 1)] = m_aNodeStack.top();
     962         888 :         m_aNodeStack.pop();
     963             :     }
     964             : 
     965         886 :     SmStructureNode *pSNode = new SmTableNode(m_aCurToken);
     966         886 :     pSNode->SetSubNodes(LineArray);
     967         886 :     m_aNodeStack.push(pSNode);
     968         886 : }
     969             : 
     970             : 
     971        4485 : void SmParser::Align()
     972             :     // parse alignment info (if any), then go on with rest of expression
     973             : {
     974        4485 :     SmStructureNode *pSNode = 0;
     975             : 
     976        4485 :     if (TokenInGroup(TGALIGN))
     977             :     {
     978          14 :         pSNode = new SmAlignNode(m_aCurToken);
     979             : 
     980          14 :         NextToken();
     981             : 
     982             :         // allow for just one align statement in 5.0
     983          14 :         if (TokenInGroup(TGALIGN))
     984             :         {
     985           0 :             Error(PE_DOUBLE_ALIGN);
     986           0 :             delete pSNode;
     987        4485 :             return;
     988             :         }
     989             :     }
     990             : 
     991        4485 :     Expression();
     992             : 
     993        4485 :     if (pSNode)
     994             :     {
     995          14 :         pSNode->SetSubNodes(lcl_popOrZero(m_aNodeStack), 0);
     996          14 :         m_aNodeStack.push(pSNode);
     997             :     }
     998             : }
     999             : 
    1000             : 
    1001         886 : void SmParser::Line()
    1002             : {
    1003         886 :     sal_uInt16  n = 0;
    1004         886 :     SmNodeArray  ExpressionArray;
    1005             : 
    1006         886 :     ExpressionArray.resize(n);
    1007             : 
    1008             :     // start with single expression that may have an alignment statement
    1009             :     // (and go on with expressions that must not have alignment
    1010             :     // statements in 'while' loop below. See also 'Expression()'.)
    1011         886 :     if (m_aCurToken.eType != TEND  &&  m_aCurToken.eType != TNEWLINE)
    1012         856 :     {   Align();
    1013         856 :         ExpressionArray.resize(++n);
    1014         856 :         ExpressionArray[n - 1] = lcl_popOrZero(m_aNodeStack);
    1015             :     }
    1016             : 
    1017        1772 :     while (m_aCurToken.eType != TEND  &&  m_aCurToken.eType != TNEWLINE)
    1018             :     {
    1019           0 :         Expression();
    1020           0 :         ExpressionArray.resize(++n);
    1021           0 :         ExpressionArray[n - 1] = lcl_popOrZero(m_aNodeStack);
    1022             :     }
    1023             : 
    1024             :     //If there's no expression, add an empty one.
    1025             :     //this is to avoid a formula tree without any caret
    1026             :     //positions, in visual formula editor.
    1027         886 :     if(ExpressionArray.empty())
    1028             :     {
    1029          30 :         SmToken aTok = SmToken();
    1030          30 :         aTok.eType = TNEWLINE;
    1031          30 :         ExpressionArray.push_back(new SmExpressionNode(aTok));
    1032             :     }
    1033             : 
    1034         886 :     SmStructureNode *pSNode = new SmLineNode(m_aCurToken);
    1035         886 :     pSNode->SetSubNodes(ExpressionArray);
    1036         886 :     m_aNodeStack.push(pSNode);
    1037         886 : }
    1038             : 
    1039             : 
    1040        5330 : void SmParser::Expression()
    1041             : {
    1042        5330 :     bool bUseExtraSpaces = true;
    1043        5330 :     if (!m_aNodeStack.empty())
    1044             :     {
    1045         284 :         SmNode *pNode = m_aNodeStack.top();
    1046         284 :         m_aNodeStack.pop();
    1047         284 :         if (pNode->GetToken().eType == TNOSPACE)
    1048           0 :             bUseExtraSpaces = false;
    1049             :         else
    1050         284 :             m_aNodeStack.push(pNode);  // push the node from above again (now to be used as argument to this current 'nospace' node)
    1051             :     }
    1052             : 
    1053        5330 :     sal_uInt16       n = 0;
    1054        5330 :     SmNodeArray  RelationArray;
    1055             : 
    1056        5330 :     RelationArray.resize(n);
    1057             : 
    1058        5330 :     Relation();
    1059        5330 :     RelationArray.resize(++n);
    1060        5330 :     RelationArray[n - 1] = lcl_popOrZero(m_aNodeStack);
    1061             : 
    1062       12197 :     while (m_aCurToken.nLevel >= 4)
    1063        1537 :     {   Relation();
    1064        1537 :         RelationArray.resize(++n);
    1065        1537 :         RelationArray[n - 1] = lcl_popOrZero(m_aNodeStack);
    1066             :     }
    1067             : 
    1068        5330 :     if (n > 1)
    1069             :     {
    1070         702 :         SmExpressionNode *pSNode = new SmExpressionNode(m_aCurToken);
    1071         702 :         pSNode->SetSubNodes(RelationArray);
    1072         702 :         pSNode->SetUseExtraSpaces(bUseExtraSpaces);
    1073         702 :         m_aNodeStack.push(pSNode);
    1074             :     }
    1075             :     else
    1076             :     {
    1077             :         // This expression has only one node so just push this node.
    1078        4628 :         m_aNodeStack.push(RelationArray[0]);
    1079        5330 :     }
    1080        5330 : }
    1081             : 
    1082             : 
    1083        7146 : void SmParser::Relation()
    1084             : {
    1085        7146 :     Sum();
    1086       14654 :     while (TokenInGroup(TGRELATION))
    1087             :     {
    1088         362 :         SmStructureNode *pSNode  = new SmBinHorNode(m_aCurToken);
    1089         362 :         SmNode *pFirst = lcl_popOrZero(m_aNodeStack);
    1090             : 
    1091         362 :         OpSubSup();
    1092         362 :         SmNode *pSecond = lcl_popOrZero(m_aNodeStack);
    1093             : 
    1094         362 :         Sum();
    1095             : 
    1096         362 :         pSNode->SetSubNodes(pFirst, pSecond, lcl_popOrZero(m_aNodeStack));
    1097         362 :         m_aNodeStack.push(pSNode);
    1098             :     }
    1099        7146 : }
    1100             : 
    1101             : 
    1102        7604 : void SmParser::Sum()
    1103             : {
    1104        7604 :     Product();
    1105       15619 :     while (TokenInGroup(TGSUM))
    1106             :     {
    1107         411 :         SmStructureNode *pSNode  = new SmBinHorNode(m_aCurToken);
    1108         411 :         SmNode *pFirst = lcl_popOrZero(m_aNodeStack);
    1109             : 
    1110         411 :         OpSubSup();
    1111         411 :         SmNode *pSecond = lcl_popOrZero(m_aNodeStack);
    1112             : 
    1113         411 :         Product();
    1114             : 
    1115         411 :         pSNode->SetSubNodes(pFirst, pSecond, lcl_popOrZero(m_aNodeStack));
    1116         411 :         m_aNodeStack.push(pSNode);
    1117             :     }
    1118        7604 : }
    1119             : 
    1120             : 
    1121        8015 : void SmParser::Product()
    1122             : {
    1123        8015 :     Power();
    1124             : 
    1125       16492 :     while (TokenInGroup(TGPRODUCT))
    1126             :     {   SmStructureNode *pSNode;
    1127         462 :         SmNode *pFirst = lcl_popOrZero(m_aNodeStack),
    1128             :                *pOper;
    1129         462 :         bool bSwitchArgs = false;
    1130             : 
    1131         462 :         SmTokenType eType = m_aCurToken.eType;
    1132         462 :         switch (eType)
    1133             :         {
    1134             :             case TOVER:
    1135         251 :                 pSNode = new SmBinVerNode(m_aCurToken);
    1136         251 :                 pOper = new SmRectangleNode(m_aCurToken);
    1137         251 :                 NextToken();
    1138         251 :                 break;
    1139             : 
    1140             :             case TBOPER:
    1141           0 :                 pSNode = new SmBinHorNode(m_aCurToken);
    1142             : 
    1143           0 :                 NextToken();
    1144             : 
    1145             :                 //Let the glyph node know it's a binary operation
    1146           0 :                 m_aCurToken.eType = TBOPER;
    1147           0 :                 m_aCurToken.nGroup = TGPRODUCT;
    1148             : 
    1149           0 :                 GlyphSpecial();
    1150           0 :                 pOper = lcl_popOrZero(m_aNodeStack);
    1151           0 :                 break;
    1152             : 
    1153             :             case TOVERBRACE :
    1154             :             case TUNDERBRACE :
    1155          40 :                 pSNode = new SmVerticalBraceNode(m_aCurToken);
    1156          40 :                 pOper = new SmMathSymbolNode(m_aCurToken);
    1157             : 
    1158          40 :                 NextToken();
    1159          40 :                 break;
    1160             : 
    1161             :             case TWIDEBACKSLASH:
    1162             :             case TWIDESLASH:
    1163             :             {
    1164          34 :                 SmBinDiagonalNode *pSTmp = new SmBinDiagonalNode(m_aCurToken);
    1165          34 :                 pSTmp->SetAscending(eType == TWIDESLASH);
    1166          34 :                 pSNode = pSTmp;
    1167             : 
    1168          34 :                 pOper = new SmPolyLineNode(m_aCurToken);
    1169          34 :                 NextToken();
    1170             : 
    1171          34 :                 bSwitchArgs = true;
    1172          34 :                 break;
    1173             :             }
    1174             : 
    1175             :             default:
    1176         137 :                 pSNode = new SmBinHorNode(m_aCurToken);
    1177             : 
    1178         137 :                 OpSubSup();
    1179         137 :                 pOper = lcl_popOrZero(m_aNodeStack);
    1180             :         }
    1181             : 
    1182         462 :         Power();
    1183             : 
    1184         462 :         if (bSwitchArgs)
    1185             :         {
    1186             :             //! vgl siehe SmBinDiagonalNode::Arrange
    1187          34 :             pSNode->SetSubNodes(pFirst, lcl_popOrZero(m_aNodeStack), pOper);
    1188             :         }
    1189             :         else
    1190             :         {
    1191         428 :             pSNode->SetSubNodes(pFirst, pOper, lcl_popOrZero(m_aNodeStack));
    1192             :         }
    1193         462 :         m_aNodeStack.push(pSNode);
    1194             :     }
    1195        8015 : }
    1196             : 
    1197             : 
    1198        9486 : void SmParser::SubSup(sal_uLong nActiveGroup)
    1199             : {
    1200             :     OSL_ENSURE(nActiveGroup == TGPOWER  ||  nActiveGroup == TGLIMIT,
    1201             :                "Sm: wrong token group");
    1202             : 
    1203        9486 :     if (!TokenInGroup(nActiveGroup))
    1204             :         // already finish
    1205       18198 :         return;
    1206             : 
    1207         774 :     SmSubSupNode *pNode = new SmSubSupNode(m_aCurToken);
    1208             :     //! Of course 'm_aCurToken' is just the first sub-/supscript token.
    1209             :     //! It should be of no further interest. The positions of the
    1210             :     //! sub-/supscripts will be identified by the corresponding subnodes
    1211             :     //! index in the 'aSubNodes' array (enum value from 'SmSubSup').
    1212             : 
    1213         774 :     pNode->SetUseLimits(nActiveGroup == TGLIMIT);
    1214             : 
    1215             :     // initialize subnodes array
    1216         774 :     SmNodeArray  aSubNodes;
    1217         774 :     aSubNodes.resize(1 + SUBSUP_NUM_ENTRIES);
    1218         774 :     aSubNodes[0] = lcl_popOrZero(m_aNodeStack);
    1219        5418 :     for (sal_uInt16 i = 1;  i < aSubNodes.size();  i++)
    1220        4644 :         aSubNodes[i] = NULL;
    1221             : 
    1222             :     // process all sub-/supscripts
    1223         774 :     int  nIndex = 0;
    1224        2580 :     while (TokenInGroup(nActiveGroup))
    1225        1032 :     {   SmTokenType  eType (m_aCurToken.eType);
    1226             : 
    1227             :         // skip sub-/supscript token
    1228        1032 :         NextToken();
    1229             : 
    1230             :         // get sub-/supscript node on top of stack
    1231        1032 :         if (eType == TFROM  ||  eType == TTO)
    1232             :         {
    1233             :             // parse limits in old 4.0 and 5.0 style
    1234         279 :             Relation();
    1235             :         }
    1236             :         else
    1237         753 :             Term(true);
    1238             : 
    1239        1032 :         switch (eType)
    1240         212 :         {   case TRSUB :    nIndex = (int) RSUB;    break;
    1241         425 :             case TRSUP :    nIndex = (int) RSUP;    break;
    1242             :             case TFROM :
    1243         168 :             case TCSUB :    nIndex = (int) CSUB;    break;
    1244             :             case TTO :
    1245         151 :             case TCSUP :    nIndex = (int) CSUP;    break;
    1246          38 :             case TLSUB :    nIndex = (int) LSUB;    break;
    1247          38 :             case TLSUP :    nIndex = (int) LSUP;    break;
    1248             :             default :
    1249             :                 SAL_WARN( "starmath", "unknown case");
    1250             :         }
    1251        1032 :         nIndex++;
    1252             :         OSL_ENSURE(1 <= nIndex  &&  nIndex <= 1 + SUBSUP_NUM_ENTRIES,
    1253             :                    "SmParser::Power() : sub-/supscript index falsch");
    1254             : 
    1255             :         // set sub-/supscript if not already done
    1256        1032 :         if (aSubNodes[nIndex] != NULL)
    1257           0 :             Error(PE_DOUBLE_SUBSUPSCRIPT);
    1258        1032 :         aSubNodes[nIndex] = lcl_popOrZero(m_aNodeStack);
    1259             :     }
    1260             : 
    1261         774 :     pNode->SetSubNodes(aSubNodes);
    1262         774 :     m_aNodeStack.push(pNode);
    1263             : }
    1264             : 
    1265             : 
    1266        1082 : void SmParser::OpSubSup()
    1267             : {
    1268             :     // push operator symbol
    1269        1082 :     m_aNodeStack.push(new SmMathSymbolNode(m_aCurToken));
    1270             :     // skip operator token
    1271        1082 :     NextToken();
    1272             :     // get sub- supscripts if any
    1273        1082 :     if (TokenInGroup(TGPOWER))
    1274           0 :         SubSup(TGPOWER);
    1275        1082 : }
    1276             : 
    1277             : 
    1278        9323 : void SmParser::Power()
    1279             : {
    1280             :     // get body for sub- supscripts on top of stack
    1281        9323 :     Term(false);
    1282             : 
    1283        9323 :     SubSup(TGPOWER);
    1284        9323 : }
    1285             : 
    1286             : 
    1287           4 : void SmParser::Blank()
    1288             : {
    1289             :     OSL_ENSURE(TokenInGroup(TGBLANK), "Sm : wrong token");
    1290           4 :     SmBlankNode *pBlankNode = new SmBlankNode(m_aCurToken);
    1291             : 
    1292          12 :     while (TokenInGroup(TGBLANK))
    1293             :     {
    1294           4 :         pBlankNode->IncreaseBy(m_aCurToken);
    1295           4 :         NextToken();
    1296             :     }
    1297             : 
    1298             :     // Blanks am Zeilenende ignorieren wenn die entsprechende Option gesetzt ist
    1299           8 :     if ( m_aCurToken.eType == TNEWLINE ||
    1300           4 :              (m_aCurToken.eType == TEND && SM_MOD()->GetConfig()->IsIgnoreSpacesRight()) )
    1301             :     {
    1302           0 :         pBlankNode->Clear();
    1303             :     }
    1304             : 
    1305           4 :     m_aNodeStack.push(pBlankNode);
    1306           4 : }
    1307             : 
    1308             : 
    1309       10076 : void SmParser::Term(bool bGroupNumberIdent)
    1310             : {
    1311       10076 :     switch (m_aCurToken.eType)
    1312             :     {
    1313             :         case TESCAPE :
    1314          30 :             Escape();
    1315          30 :             break;
    1316             : 
    1317             :         case TNOSPACE :
    1318             :         case TLGROUP :
    1319             :         {
    1320        2894 :             bool bNoSpace = m_aCurToken.eType == TNOSPACE;
    1321        2894 :             if (bNoSpace)   // push 'no space' node and continue to parse expression
    1322             :             {
    1323           0 :                 m_aNodeStack.push(new SmExpressionNode(m_aCurToken));
    1324           0 :                 NextToken();
    1325             :             }
    1326        2894 :             if (m_aCurToken.eType != TLGROUP)
    1327             :             {
    1328           0 :                 m_aNodeStack.pop();    // get rid of the 'no space' node pushed above
    1329           0 :                 Term(false);
    1330             :             }
    1331             :             else
    1332             :             {
    1333        2894 :                 NextToken();
    1334             : 
    1335             :                 // allow for empty group
    1336        2894 :                 if (m_aCurToken.eType == TRGROUP)
    1337             :                 {
    1338          32 :                     if (bNoSpace)   // get rid of the 'no space' node pushed above
    1339           0 :                         m_aNodeStack.pop();
    1340          32 :                     SmStructureNode *pSNode = new SmExpressionNode(m_aCurToken);
    1341          32 :                     pSNode->SetSubNodes(NULL, NULL);
    1342          32 :                     m_aNodeStack.push(pSNode);
    1343             : 
    1344          32 :                     NextToken();
    1345             :                 }
    1346             :                 else    // go as usual
    1347             :                 {
    1348        2862 :                     Align();
    1349        2862 :                     if (m_aCurToken.eType != TRGROUP)
    1350           1 :                         Error(PE_RGROUP_EXPECTED);
    1351             :                     else
    1352        2861 :                         NextToken();
    1353             :                 }
    1354             :             }
    1355             :         }
    1356        2894 :         break;
    1357             : 
    1358             :         case TLEFT :
    1359         444 :             Brace();
    1360         444 :             break;
    1361             : 
    1362             :         case TBLANK :
    1363             :         case TSBLANK :
    1364           4 :             Blank();
    1365           4 :             break;
    1366             : 
    1367             :         case TTEXT :
    1368          78 :             m_aNodeStack.push(new SmTextNode(m_aCurToken, FNT_TEXT));
    1369          78 :             NextToken();
    1370          78 :             break;
    1371             :         case TCHARACTER :
    1372         412 :             m_aNodeStack.push(new SmTextNode(m_aCurToken, FNT_VARIABLE));
    1373         412 :             NextToken();
    1374         412 :             break;
    1375             :         case TIDENT :
    1376             :         case TNUMBER :
    1377             :         {
    1378             :             m_aNodeStack.push(new SmTextNode(m_aCurToken,
    1379        4167 :                                              m_aCurToken.eType == TNUMBER ?
    1380             :                                              FNT_NUMBER :
    1381        8334 :                                              FNT_VARIABLE));
    1382        4167 :             if (!bGroupNumberIdent)
    1383             :             {
    1384        4155 :                 NextToken();
    1385             :             }
    1386             :             else
    1387             :             {
    1388             :                 // Some people want to be able to write "x_2n" for "x_{2n}"
    1389             :                 // although e.g. LaTeX or AsciiMath interpret that as "x_2 n".
    1390             :                 // The tokenizer skips whitespaces so we need some additional
    1391             :                 // work to distinguish from "x_2 n".
    1392             :                 // See https://issues.apache.org/ooo/show_bug.cgi?id=11752 and
    1393             :                 // https://www.libreoffice.org/bugzilla/show_bug.cgi?id=55853
    1394          12 :                 sal_Int32 nBufLen = m_aBufferString.getLength();
    1395          12 :                 CharClass aCC(SM_MOD()->GetSysLocale().GetLanguageTag());
    1396          12 :                 sal_Int32 nTokens = 1;
    1397             : 
    1398             :                 // We need to be careful to call NextToken() only after having
    1399             :                 // tested for a whitespace separator (otherwise it will be
    1400             :                 // skipped!)
    1401          12 :                 bool moveToNextToken = true;
    1402          36 :                 while (m_nBufferIndex < nBufLen &&
    1403          10 :                        aCC.getType(m_aBufferString, m_nBufferIndex) !=
    1404             :                        UnicodeType::SPACE_SEPARATOR)
    1405             :                 {
    1406           2 :                     NextToken();
    1407           4 :                     if (m_aCurToken.eType != TNUMBER &&
    1408           2 :                         m_aCurToken.eType != TIDENT)
    1409             :                     {
    1410             :                         // Neither a number nor an indentifier. We just moved to
    1411             :                         // the next token, so no need to do that again.
    1412           0 :                         moveToNextToken = false;
    1413           0 :                         break;
    1414             :                     }
    1415             :                     m_aNodeStack.push(new SmTextNode(m_aCurToken,
    1416           2 :                                                      m_aCurToken.eType ==
    1417             :                                                      TNUMBER ?
    1418             :                                                      FNT_NUMBER :
    1419           4 :                                                      FNT_VARIABLE));
    1420           2 :                     nTokens++;
    1421             :                 }
    1422          12 :                 if (moveToNextToken) NextToken();
    1423          12 :                 if (nTokens > 1)
    1424             :                 {
    1425             :                     // We have several concatenated identifiers and numbers.
    1426             :                     // Let's group them into one SmExpressionNode.
    1427           2 :                     SmNodeArray nodeArray;
    1428           2 :                     nodeArray.resize(nTokens);
    1429           8 :                     while (nTokens > 0)
    1430             :                     {
    1431           4 :                         nodeArray[nTokens-1] = lcl_popOrZero(m_aNodeStack);
    1432           4 :                         nTokens--;
    1433             :                     }
    1434           2 :                     SmExpressionNode* pNode = new SmExpressionNode(SmToken());
    1435           2 :                     pNode->SetSubNodes(nodeArray);
    1436           2 :                     m_aNodeStack.push(pNode);
    1437          12 :                 }
    1438             :             }
    1439        4167 :             break;
    1440             :         }
    1441             :         case TLEFTARROW :
    1442             :         case TRIGHTARROW :
    1443             :         case TUPARROW :
    1444             :         case TDOWNARROW :
    1445             :         case TCIRC :
    1446             :         case TDRARROW :
    1447             :         case TDLARROW :
    1448             :         case TDLRARROW :
    1449             :         case TEXISTS :
    1450             :         case TNOTEXISTS :
    1451             :         case TFORALL :
    1452             :         case TPARTIAL :
    1453             :         case TNABLA :
    1454             :         case TTOWARD :
    1455             :         case TDOTSAXIS :
    1456             :         case TDOTSDIAG :
    1457             :         case TDOTSDOWN :
    1458             :         case TDOTSLOW :
    1459             :         case TDOTSUP :
    1460             :         case TDOTSVERT :
    1461          53 :             m_aNodeStack.push(new SmMathSymbolNode(m_aCurToken));
    1462          53 :             NextToken();
    1463          53 :             break;
    1464             : 
    1465             :         case TSETN :
    1466             :         case TSETZ :
    1467             :         case TSETQ :
    1468             :         case TSETR :
    1469             :         case TSETC :
    1470             :         case THBAR :
    1471             :         case TLAMBDABAR :
    1472             :         case TBACKEPSILON :
    1473             :         case TALEPH :
    1474             :         case TIM :
    1475             :         case TRE :
    1476             :         case TWP :
    1477             :         case TEMPTYSET :
    1478             :         case TINFINITY :
    1479          26 :             m_aNodeStack.push(new SmMathIdentifierNode(m_aCurToken));
    1480          26 :             NextToken();
    1481          26 :             break;
    1482             : 
    1483             :         case TPLACE:
    1484         620 :             m_aNodeStack.push(new SmPlaceNode(m_aCurToken));
    1485         620 :             NextToken();
    1486         620 :             break;
    1487             : 
    1488             :         case TSPECIAL:
    1489         130 :             Special();
    1490         130 :             break;
    1491             : 
    1492             :         case TBINOM:
    1493          48 :             Binom();
    1494          48 :             break;
    1495             : 
    1496             :         case TSTACK:
    1497          61 :             Stack();
    1498          61 :             break;
    1499             : 
    1500             :         case TMATRIX:
    1501          22 :             Matrix();
    1502          22 :             break;
    1503             : 
    1504             :         default:
    1505        1087 :             if (TokenInGroup(TGLBRACES))
    1506          74 :             {   Brace();
    1507             :             }
    1508        1013 :             else if (TokenInGroup(TGOPER))
    1509         186 :             {   Operator();
    1510             :             }
    1511         827 :             else if (TokenInGroup(TGUNOPER))
    1512         258 :             {   UnOper();
    1513             :             }
    1514        1138 :             else if (    TokenInGroup(TGATTRIBUT)
    1515         569 :                      ||  TokenInGroup(TGFONTATTR))
    1516         385 :             {   SmStructureNodeArray  aArray;
    1517             : 
    1518             :                 bool    bIsAttr;
    1519         385 :                 sal_uInt16  n = 0;
    1520        1155 :                 while (true == (bIsAttr = TokenInGroup(TGATTRIBUT))
    1521         770 :                        ||  TokenInGroup(TGFONTATTR))
    1522         385 :                 {   aArray.resize(n + 1);
    1523             : 
    1524         385 :                     if (bIsAttr)
    1525         290 :                         Attribut();
    1526             :                     else
    1527          95 :                         FontAttribut();
    1528             : 
    1529         385 :                     SmNode* pTmp = lcl_popOrZero(m_aNodeStack);
    1530             : 
    1531             :                     // check if casting in following line is ok
    1532             :                     OSL_ENSURE(pTmp && !pTmp->IsVisible(), "Sm : Ooops...");
    1533             : 
    1534         385 :                     aArray[n] = (SmStructureNode *) pTmp;
    1535         385 :                     n++;
    1536             :                 }
    1537             : 
    1538         385 :                 Power();
    1539             : 
    1540         385 :                 SmNode *pFirstNode = lcl_popOrZero(m_aNodeStack);
    1541        1155 :                 while (n > 0)
    1542         385 :                 {   aArray[n - 1]->SetSubNodes(0, pFirstNode);
    1543         385 :                     pFirstNode = aArray[n - 1];
    1544         385 :                     n--;
    1545             :                 }
    1546         385 :                 m_aNodeStack.push(pFirstNode);
    1547             :             }
    1548         184 :             else if (TokenInGroup(TGFUNCTION))
    1549             :             {
    1550         159 :                 Function();
    1551             :             }
    1552             :             else
    1553          25 :                 Error(PE_UNEXPECTED_CHAR);
    1554             :     }
    1555       10076 : }
    1556             : 
    1557             : 
    1558          30 : void SmParser::Escape()
    1559             : {
    1560          30 :     NextToken();
    1561             : 
    1562          30 :     switch (m_aCurToken.eType)
    1563             :     {
    1564             :         case TLPARENT :
    1565             :         case TRPARENT :
    1566             :         case TLBRACKET :
    1567             :         case TRBRACKET :
    1568             :         case TLDBRACKET :
    1569             :         case TRDBRACKET :
    1570             :         case TLBRACE :
    1571             :         case TLGROUP :
    1572             :         case TRBRACE :
    1573             :         case TRGROUP :
    1574             :         case TLANGLE :
    1575             :         case TRANGLE :
    1576             :         case TLCEIL :
    1577             :         case TRCEIL :
    1578             :         case TLFLOOR :
    1579             :         case TRFLOOR :
    1580             :         case TLLINE :
    1581             :         case TRLINE :
    1582             :         case TLDLINE :
    1583             :         case TRDLINE :
    1584          30 :             break;
    1585             :         default:
    1586           0 :             Error(PE_UNEXPECTED_TOKEN);
    1587             :     }
    1588             : 
    1589          30 :     SmNode *pNode = new SmMathSymbolNode(m_aCurToken);
    1590          30 :     m_aNodeStack.push(pNode);
    1591             : 
    1592          30 :     NextToken();
    1593          30 : }
    1594             : 
    1595             : 
    1596         186 : void SmParser::Operator()
    1597             : {
    1598         186 :     if (TokenInGroup(TGOPER))
    1599         186 :     {   SmStructureNode *pSNode = new SmOperNode(m_aCurToken);
    1600             : 
    1601             :         // put operator on top of stack
    1602         186 :         Oper();
    1603             : 
    1604         186 :         if (TokenInGroup(TGLIMIT) || TokenInGroup(TGPOWER))
    1605         163 :             SubSup(m_aCurToken.nGroup);
    1606         186 :         SmNode *pOperator = lcl_popOrZero(m_aNodeStack);
    1607             : 
    1608             :         // get argument
    1609         186 :         Power();
    1610             : 
    1611         186 :         pSNode->SetSubNodes(pOperator, lcl_popOrZero(m_aNodeStack));
    1612         186 :         m_aNodeStack.push(pSNode);
    1613             :     }
    1614         186 : }
    1615             : 
    1616             : 
    1617         186 : void SmParser::Oper()
    1618             : {
    1619         186 :     SmTokenType  eType (m_aCurToken.eType);
    1620         186 :     SmNode      *pNode = NULL;
    1621             : 
    1622         186 :     switch (eType)
    1623             :     {
    1624             :         case TSUM :
    1625             :         case TPROD :
    1626             :         case TCOPROD :
    1627             :         case TINT :
    1628             :         case TIINT :
    1629             :         case TIIINT :
    1630             :         case TLINT :
    1631             :         case TLLINT :
    1632             :         case TLLLINT :
    1633         169 :             pNode = new SmMathSymbolNode(m_aCurToken);
    1634         169 :             break;
    1635             : 
    1636             :         case TLIM :
    1637             :         case TLIMSUP :
    1638             :         case TLIMINF :
    1639             :             {
    1640          17 :                 const sal_Char* pLim = 0;
    1641          17 :                 switch (eType)
    1642             :                 {
    1643          17 :                     case TLIM :     pLim = "lim";       break;
    1644           0 :                     case TLIMSUP :  pLim = "lim sup";   break;
    1645           0 :                     case TLIMINF :  pLim = "lim inf";   break;
    1646             :                     default:
    1647           0 :                         break;
    1648             :                 }
    1649          17 :                 if( pLim )
    1650          17 :                     m_aCurToken.aText = OUString::createFromAscii(pLim);
    1651          17 :                 pNode = new SmTextNode(m_aCurToken, FNT_TEXT);
    1652             :             }
    1653          17 :             break;
    1654             : 
    1655             :         case TOVERBRACE :
    1656             :         case TUNDERBRACE :
    1657           0 :                 pNode = new SmMathSymbolNode(m_aCurToken);
    1658           0 :             break;
    1659             : 
    1660             :         case TOPER :
    1661           0 :             NextToken();
    1662             : 
    1663             :             OSL_ENSURE(m_aCurToken.eType == TSPECIAL, "Sm: wrong token");
    1664           0 :             pNode = new SmGlyphSpecialNode(m_aCurToken);
    1665           0 :             break;
    1666             : 
    1667             :         default :
    1668             :             SAL_WARN("starmath", "unknown case");
    1669             :     }
    1670         186 :     m_aNodeStack.push(pNode);
    1671             : 
    1672         186 :     NextToken();
    1673         186 : }
    1674             : 
    1675             : 
    1676         258 : void SmParser::UnOper()
    1677             : {
    1678             :     OSL_ENSURE(TokenInGroup(TGUNOPER), "Sm: wrong token");
    1679             : 
    1680         258 :     SmToken      aNodeToken = m_aCurToken;
    1681         258 :     SmTokenType  eType      = m_aCurToken.eType;
    1682         258 :     bool         bIsPostfix = eType == TFACT;
    1683             : 
    1684             :     SmStructureNode *pSNode;
    1685         258 :     SmNode *pOper   = 0,
    1686         258 :            *pExtra  = 0,
    1687             :            *pArg;
    1688             : 
    1689         258 :     switch (eType)
    1690             :     {
    1691             :         case TABS :
    1692             :         case TSQRT :
    1693             :            /* Dynamic integrals are handled as unary operators so we can wrap
    1694             :              the symbol together with the body in a upper level node and make
    1695             :              proper graphic arrangements */
    1696             :         case TINTD:
    1697          69 :             NextToken();
    1698          69 :             break;
    1699             : 
    1700             :         case TNROOT :
    1701          17 :             NextToken();
    1702          17 :             Power();
    1703          17 :             pExtra = lcl_popOrZero(m_aNodeStack);
    1704          17 :             break;
    1705             : 
    1706             :         case TUOPER :
    1707           0 :             NextToken();
    1708             :             //Let the glyph know what it is...
    1709           0 :             m_aCurToken.eType = TUOPER;
    1710           0 :             m_aCurToken.nGroup = TGUNOPER;
    1711           0 :             GlyphSpecial();
    1712           0 :             pOper = lcl_popOrZero(m_aNodeStack);
    1713           0 :             break;
    1714             : 
    1715             :         case TPLUS :
    1716             :         case TMINUS :
    1717             :         case TPLUSMINUS :
    1718             :         case TMINUSPLUS :
    1719             :         case TNEG :
    1720             :         case TFACT :
    1721         172 :             OpSubSup();
    1722         172 :             pOper = lcl_popOrZero(m_aNodeStack);
    1723         172 :             break;
    1724             : 
    1725             :         default :
    1726           0 :             Error(PE_UNOPER_EXPECTED);
    1727             :     }
    1728             : 
    1729             :     // get argument
    1730         258 :     Power();
    1731         258 :     pArg = lcl_popOrZero(m_aNodeStack);
    1732             : 
    1733         258 :     if (eType == TABS)
    1734           4 :     {   pSNode = new SmBraceNode(aNodeToken);
    1735           4 :         pSNode->SetScaleMode(SCALE_HEIGHT);
    1736             : 
    1737             :         // build nodes for left & right lines
    1738             :         // (text, group, level of the used token are of no interrest here)
    1739             :         // we'll use row & column of the keyword for abs
    1740           4 :         aNodeToken.eType = TABS;
    1741             : 
    1742           4 :         aNodeToken.cMathChar = MS_VERTLINE;
    1743           4 :         SmNode* pLeft = new SmMathSymbolNode(aNodeToken);
    1744             : 
    1745           4 :         aNodeToken.cMathChar = MS_VERTLINE;
    1746           4 :         SmNode* pRight = new SmMathSymbolNode(aNodeToken);
    1747             : 
    1748           4 :         pSNode->SetSubNodes(pLeft, pArg, pRight);
    1749             :     }
    1750         254 :     else if (eType == TSQRT  ||  eType == TNROOT)
    1751          82 :     {  pSNode = new SmRootNode(aNodeToken);
    1752          82 :         pOper = new SmRootSymbolNode(aNodeToken);
    1753          82 :         pSNode->SetSubNodes(pExtra, pOper, pArg);
    1754             :     }
    1755         172 :     else if(eType == TINTD)
    1756           0 :     {  pSNode = new SmDynIntegralNode(aNodeToken);
    1757           0 :         pOper = new SmDynIntegralSymbolNode(aNodeToken);
    1758           0 :         pSNode->SetSubNodes(pOper, pArg);
    1759             :     }
    1760             :     else
    1761         172 :     {   pSNode = new SmUnHorNode(aNodeToken);
    1762             : 
    1763         172 :         if (bIsPostfix)
    1764           2 :             pSNode->SetSubNodes(pArg, pOper);
    1765             :         else
    1766             :             // prefix operator
    1767         170 :             pSNode->SetSubNodes(pOper, pArg);
    1768             :     }
    1769             : 
    1770         258 :     m_aNodeStack.push(pSNode);
    1771         258 : }
    1772             : 
    1773             : 
    1774         290 : void SmParser::Attribut()
    1775             : {
    1776             :     OSL_ENSURE(TokenInGroup(TGATTRIBUT), "Sm: wrong token group");
    1777             : 
    1778         290 :     SmStructureNode *pSNode = new SmAttributNode(m_aCurToken);
    1779             :     SmNode      *pAttr;
    1780         290 :     SmScaleMode  eScaleMode = SCALE_NONE;
    1781             : 
    1782             :     // get appropriate node for the attribut itself
    1783         290 :     switch (m_aCurToken.eType)
    1784             :     {   case TUNDERLINE :
    1785             :         case TOVERLINE :
    1786             :         case TOVERSTRIKE :
    1787          42 :             pAttr = new SmRectangleNode(m_aCurToken);
    1788          42 :             eScaleMode = SCALE_WIDTH;
    1789          42 :             break;
    1790             : 
    1791             :         case TWIDEVEC :
    1792             :         case TWIDEHAT :
    1793             :         case TWIDETILDE :
    1794         114 :             pAttr = new SmMathSymbolNode(m_aCurToken);
    1795         114 :             eScaleMode = SCALE_WIDTH;
    1796         114 :             break;
    1797             : 
    1798             :         default :
    1799         134 :             pAttr = new SmMathSymbolNode(m_aCurToken);
    1800             :     }
    1801             : 
    1802         290 :     NextToken();
    1803             : 
    1804         290 :     pSNode->SetSubNodes(pAttr, 0);
    1805         290 :     pSNode->SetScaleMode(eScaleMode);
    1806         290 :     m_aNodeStack.push(pSNode);
    1807         290 : }
    1808             : 
    1809             : 
    1810          95 : void SmParser::FontAttribut()
    1811             : {
    1812             :     OSL_ENSURE(TokenInGroup(TGFONTATTR), "Sm: wrong token group");
    1813             : 
    1814          95 :     switch (m_aCurToken.eType)
    1815             :     {
    1816             :         case TITALIC :
    1817             :         case TNITALIC :
    1818             :         case TBOLD :
    1819             :         case TNBOLD :
    1820             :         case TPHANTOM :
    1821          10 :             m_aNodeStack.push(new SmFontNode(m_aCurToken));
    1822          10 :             NextToken();
    1823          10 :             break;
    1824             : 
    1825             :         case TSIZE :
    1826          62 :             FontSize();
    1827          62 :             break;
    1828             : 
    1829             :         case TFONT :
    1830           6 :             Font();
    1831           6 :             break;
    1832             : 
    1833             :         case TCOLOR :
    1834          17 :             Color();
    1835          17 :             break;
    1836             : 
    1837             :         default :
    1838             :             SAL_WARN("starmath", "unknown case");
    1839             :     }
    1840          95 : }
    1841             : 
    1842             : 
    1843          17 : void SmParser::Color()
    1844             : {
    1845             :     OSL_ENSURE(m_aCurToken.eType == TCOLOR, "Sm : Ooops...");
    1846             : 
    1847             :     // last color rules, get that one
    1848          17 :     SmToken  aToken;
    1849          17 :     do
    1850          17 :     {   NextToken();
    1851             : 
    1852          17 :         if (TokenInGroup(TGCOLOR))
    1853          16 :         {   aToken = m_aCurToken;
    1854          16 :             NextToken();
    1855             :         }
    1856             :         else
    1857           1 :             Error(PE_COLOR_EXPECTED);
    1858          17 :     } while (m_aCurToken.eType == TCOLOR);
    1859             : 
    1860          17 :     m_aNodeStack.push(new SmFontNode(aToken));
    1861          17 : }
    1862             : 
    1863             : 
    1864           6 : void SmParser::Font()
    1865             : {
    1866             :     OSL_ENSURE(m_aCurToken.eType == TFONT, "Sm : Ooops...");
    1867             : 
    1868             :     // last font rules, get that one
    1869           6 :     SmToken  aToken;
    1870           6 :     do
    1871           6 :     {   NextToken();
    1872             : 
    1873           6 :         if (TokenInGroup(TGFONT))
    1874           6 :         {   aToken = m_aCurToken;
    1875           6 :             NextToken();
    1876             :         }
    1877             :         else
    1878           0 :             Error(PE_FONT_EXPECTED);
    1879           6 :     } while (m_aCurToken.eType == TFONT);
    1880             : 
    1881           6 :     m_aNodeStack.push(new SmFontNode(aToken));
    1882           6 : }
    1883             : 
    1884             : 
    1885             : // gets number used as arguments in Math formulas (e.g. 'size' command)
    1886             : // Format: no negative numbers, must start with a digit, no exponent notation, ...
    1887          62 : static bool lcl_IsNumber(const OUString& rText)
    1888             : {
    1889          62 :     bool bPoint = false;
    1890          62 :     const sal_Unicode* pBuffer = rText.getStr();
    1891         156 :     for(sal_Int32 nPos = 0; nPos < rText.getLength(); nPos++, pBuffer++)
    1892             :     {
    1893          94 :         const sal_Unicode cChar = *pBuffer;
    1894          94 :         if(cChar == '.')
    1895             :         {
    1896           0 :             if(bPoint)
    1897           0 :                 return false;
    1898             :             else
    1899           0 :                 bPoint = true;
    1900             :         }
    1901          94 :         else if ( !rtl::isAsciiDigit( cChar ) )
    1902           0 :             return false;
    1903             :     }
    1904          62 :     return true;
    1905             : }
    1906             : 
    1907          62 : void SmParser::FontSize()
    1908             : {
    1909             :     OSL_ENSURE(m_aCurToken.eType == TSIZE, "Sm : Ooops...");
    1910             : 
    1911             :     sal_uInt16   Type;
    1912          62 :     SmFontNode *pFontNode = new SmFontNode(m_aCurToken);
    1913             : 
    1914          62 :     NextToken();
    1915             : 
    1916          62 :     switch (m_aCurToken.eType)
    1917             :     {
    1918          62 :         case TNUMBER:   Type = FNTSIZ_ABSOLUT;  break;
    1919           0 :         case TPLUS:     Type = FNTSIZ_PLUS;     break;
    1920           0 :         case TMINUS:    Type = FNTSIZ_MINUS;    break;
    1921           0 :         case TMULTIPLY: Type = FNTSIZ_MULTIPLY; break;
    1922           0 :         case TDIVIDEBY: Type = FNTSIZ_DIVIDE;   break;
    1923             : 
    1924             :         default:
    1925           0 :             delete pFontNode;
    1926           0 :             Error(PE_SIZE_EXPECTED);
    1927           0 :             return;
    1928             :     }
    1929             : 
    1930          62 :     if (Type != FNTSIZ_ABSOLUT)
    1931             :     {
    1932           0 :         NextToken();
    1933           0 :         if (m_aCurToken.eType != TNUMBER)
    1934             :         {
    1935           0 :             delete pFontNode;
    1936           0 :             Error(PE_SIZE_EXPECTED);
    1937           0 :             return;
    1938             :         }
    1939             :     }
    1940             : 
    1941             :     // get number argument
    1942          62 :     Fraction  aValue( 1L );
    1943          62 :     if (lcl_IsNumber( m_aCurToken.aText ))
    1944             :     {
    1945          62 :         double fTmp = OUString(m_aCurToken.aText).toDouble();
    1946          62 :         if (fTmp != 0.0)
    1947             :         {
    1948          62 :             aValue = fTmp;
    1949             : 
    1950             :             //!! keep the numerator and denominator from being to large
    1951             :             //!! otherwise ongoing multiplications may result in overflows
    1952             :             //!! (for example in SmNode::SetFontSize the font size calculated
    1953             :             //!! may become 0 because of this!!! Happens e.g. for ftmp = 2.9 with Linux
    1954             :             //!! or ftmp = 1.11111111111111111... (11/9) on every platform.)
    1955          62 :             if (aValue.GetDenominator() > 1000)
    1956             :             {
    1957           0 :                 long nNum   = aValue.GetNumerator();
    1958           0 :                 long nDenom = aValue.GetDenominator();
    1959           0 :                 while (nDenom > 1000)
    1960             :                 {
    1961           0 :                     nNum    /= 10;
    1962           0 :                     nDenom  /= 10;
    1963             :                 }
    1964           0 :                 aValue = Fraction( nNum, nDenom );
    1965             :             }
    1966             :         }
    1967             :     }
    1968             : 
    1969          62 :     NextToken();
    1970             : 
    1971          62 :     pFontNode->SetSizeParameter(aValue, Type);
    1972          62 :     m_aNodeStack.push(pFontNode);
    1973             : }
    1974             : 
    1975             : 
    1976         518 : void SmParser::Brace()
    1977             : {
    1978             :     OSL_ENSURE(m_aCurToken.eType == TLEFT  ||  TokenInGroup(TGLBRACES),
    1979             :         "Sm: kein Klammer Ausdruck");
    1980             : 
    1981         518 :     SmStructureNode *pSNode  = new SmBraceNode(m_aCurToken);
    1982         518 :     SmNode *pBody   = 0,
    1983         518 :            *pLeft   = 0,
    1984         518 :            *pRight  = 0;
    1985         518 :     SmScaleMode   eScaleMode = SCALE_NONE;
    1986         518 :     SmParseError  eError     = PE_NONE;
    1987             : 
    1988         518 :     if (m_aCurToken.eType == TLEFT)
    1989         444 :     {   NextToken();
    1990             : 
    1991         444 :         eScaleMode = SCALE_HEIGHT;
    1992             : 
    1993             :         // check for left bracket
    1994         444 :         if (TokenInGroup(TGLBRACES) || TokenInGroup(TGRBRACES))
    1995             :         {
    1996         444 :             pLeft = new SmMathSymbolNode(m_aCurToken);
    1997             : 
    1998         444 :             NextToken();
    1999         444 :             Bracebody(true);
    2000         444 :             pBody = lcl_popOrZero(m_aNodeStack);
    2001             : 
    2002         444 :             if (m_aCurToken.eType == TRIGHT)
    2003         444 :             {   NextToken();
    2004             : 
    2005             :                 // check for right bracket
    2006         444 :                 if (TokenInGroup(TGLBRACES) || TokenInGroup(TGRBRACES))
    2007             :                 {
    2008         444 :                     pRight = new SmMathSymbolNode(m_aCurToken);
    2009         444 :                     NextToken();
    2010             :                 }
    2011             :                 else
    2012           0 :                     eError = PE_RBRACE_EXPECTED;
    2013             :             }
    2014             :             else
    2015           0 :                 eError = PE_RIGHT_EXPECTED;
    2016             :         }
    2017             :         else
    2018           0 :             eError = PE_LBRACE_EXPECTED;
    2019             :     }
    2020             :     else
    2021             :     {
    2022          74 :         if (TokenInGroup(TGLBRACES))
    2023             :         {
    2024          74 :             pLeft = new SmMathSymbolNode(m_aCurToken);
    2025             : 
    2026          74 :             NextToken();
    2027          74 :             Bracebody(false);
    2028          74 :             pBody = lcl_popOrZero(m_aNodeStack);
    2029             : 
    2030          74 :             SmTokenType  eExpectedType = TUNKNOWN;
    2031          74 :             switch (pLeft->GetToken().eType)
    2032          54 :             {   case TLPARENT :     eExpectedType = TRPARENT;   break;
    2033           8 :                 case TLBRACKET :    eExpectedType = TRBRACKET;  break;
    2034           2 :                 case TLBRACE :      eExpectedType = TRBRACE;    break;
    2035           2 :                 case TLDBRACKET :   eExpectedType = TRDBRACKET; break;
    2036           2 :                 case TLLINE :       eExpectedType = TRLINE;     break;
    2037           2 :                 case TLDLINE :      eExpectedType = TRDLINE;    break;
    2038           4 :                 case TLANGLE :      eExpectedType = TRANGLE;    break;
    2039           0 :                 case TLFLOOR :      eExpectedType = TRFLOOR;    break;
    2040           0 :                 case TLCEIL :       eExpectedType = TRCEIL;     break;
    2041             :                 default :
    2042             :                     SAL_WARN("starmath", "unknown case");
    2043             :             }
    2044             : 
    2045          74 :             if (m_aCurToken.eType == eExpectedType)
    2046             :             {
    2047          74 :                 pRight = new SmMathSymbolNode(m_aCurToken);
    2048          74 :                 NextToken();
    2049             :             }
    2050             :             else
    2051           0 :                 eError = PE_PARENT_MISMATCH;
    2052             :         }
    2053             :         else
    2054           0 :             eError = PE_LBRACE_EXPECTED;
    2055             :     }
    2056             : 
    2057         518 :     if (eError == PE_NONE)
    2058             :     {   OSL_ENSURE(pLeft,  "Sm: NULL pointer");
    2059             :         OSL_ENSURE(pRight, "Sm: NULL pointer");
    2060         518 :         pSNode->SetSubNodes(pLeft, pBody, pRight);
    2061         518 :         pSNode->SetScaleMode(eScaleMode);
    2062         518 :         m_aNodeStack.push(pSNode);
    2063             :     }
    2064             :     else
    2065           0 :     {   delete pSNode;
    2066           0 :         delete pBody;
    2067           0 :         delete pLeft;
    2068           0 :         delete pRight;
    2069             : 
    2070           0 :         Error(eError);
    2071             :     }
    2072         518 : }
    2073             : 
    2074             : 
    2075         518 : void SmParser::Bracebody(bool bIsLeftRight)
    2076             : {
    2077         518 :     SmStructureNode *pBody = new SmBracebodyNode(m_aCurToken);
    2078         518 :     SmNodeArray      aNodes;
    2079         518 :     sal_uInt16           nNum = 0;
    2080             : 
    2081             :     // get body if any
    2082         518 :     if (bIsLeftRight)
    2083             :     {
    2084         556 :         do
    2085             :         {
    2086         556 :             if (m_aCurToken.eType == TMLINE)
    2087             :             {
    2088          56 :                 m_aNodeStack.push(new SmMathSymbolNode(m_aCurToken));
    2089          56 :                 NextToken();
    2090          56 :                 nNum++;
    2091             :             }
    2092         500 :             else if (m_aCurToken.eType != TRIGHT)
    2093         479 :             {   Align();
    2094         479 :                 nNum++;
    2095             : 
    2096         479 :                 if (m_aCurToken.eType != TMLINE  &&  m_aCurToken.eType != TRIGHT)
    2097           0 :                     Error(PE_RIGHT_EXPECTED);
    2098             :             }
    2099        1112 :         } while (m_aCurToken.eType != TEND  &&  m_aCurToken.eType != TRIGHT);
    2100             :     }
    2101             :     else
    2102             :     {
    2103          78 :         do
    2104             :         {
    2105          78 :             if (m_aCurToken.eType == TMLINE)
    2106             :             {
    2107           2 :                 m_aNodeStack.push(new SmMathSymbolNode(m_aCurToken));
    2108           2 :                 NextToken();
    2109           2 :                 nNum++;
    2110             :             }
    2111          76 :             else if (!TokenInGroup(TGRBRACES))
    2112          64 :             {   Align();
    2113          64 :                 nNum++;
    2114             : 
    2115          64 :                 if (m_aCurToken.eType != TMLINE  &&  !TokenInGroup(TGRBRACES))
    2116           0 :                     Error(PE_RBRACE_EXPECTED);
    2117             :             }
    2118          78 :         } while (m_aCurToken.eType != TEND  &&  !TokenInGroup(TGRBRACES));
    2119             :     }
    2120             : 
    2121             :     // build argument vector in parsing order
    2122         518 :     aNodes.resize(nNum);
    2123        1119 :     for (sal_uInt16 i = 0;  i < nNum;  i++)
    2124             :     {
    2125         601 :         aNodes[nNum - 1 - i] = lcl_popOrZero(m_aNodeStack);
    2126             :     }
    2127             : 
    2128         518 :     pBody->SetSubNodes(aNodes);
    2129         518 :     pBody->SetScaleMode(bIsLeftRight ? SCALE_HEIGHT : SCALE_NONE);
    2130         518 :     m_aNodeStack.push(pBody);
    2131         518 : }
    2132             : 
    2133             : 
    2134         159 : void SmParser::Function()
    2135             : {
    2136         159 :     switch (m_aCurToken.eType)
    2137             :     {
    2138             :         case TFUNC:
    2139           1 :             NextToken();    // skip "FUNC"-statement
    2140             :             // fall through
    2141             : 
    2142             :         case TSIN :
    2143             :         case TCOS :
    2144             :         case TTAN :
    2145             :         case TCOT :
    2146             :         case TASIN :
    2147             :         case TACOS :
    2148             :         case TATAN :
    2149             :         case TACOT :
    2150             :         case TSINH :
    2151             :         case TCOSH :
    2152             :         case TTANH :
    2153             :         case TCOTH :
    2154             :         case TASINH :
    2155             :         case TACOSH :
    2156             :         case TATANH :
    2157             :         case TACOTH :
    2158             :         case TLN :
    2159             :         case TLOG :
    2160             :         case TEXP :
    2161         159 :             m_aNodeStack.push(new SmTextNode(m_aCurToken, FNT_FUNCTION));
    2162         159 :             NextToken();
    2163         159 :             break;
    2164             : 
    2165             :         default:
    2166           0 :             Error(PE_FUNC_EXPECTED);
    2167             :     }
    2168         159 : }
    2169             : 
    2170             : 
    2171          48 : void SmParser::Binom()
    2172             : {
    2173          48 :     SmNodeArray  ExpressionArray;
    2174          48 :     SmStructureNode *pSNode = new SmTableNode(m_aCurToken);
    2175             : 
    2176          48 :     NextToken();
    2177             : 
    2178          48 :     Sum();
    2179          48 :     Sum();
    2180             : 
    2181          48 :     ExpressionArray.resize(2);
    2182             : 
    2183         144 :     for (int i = 0;  i < 2;  i++)
    2184             :     {
    2185          96 :         ExpressionArray[2 - (i + 1)] = lcl_popOrZero(m_aNodeStack);
    2186             :     }
    2187             : 
    2188          48 :     pSNode->SetSubNodes(ExpressionArray);
    2189          48 :     m_aNodeStack.push(pSNode);
    2190          48 : }
    2191             : 
    2192             : 
    2193          61 : void SmParser::Stack()
    2194             : {
    2195          61 :     SmNodeArray  ExpressionArray;
    2196          61 :     NextToken();
    2197          61 :     if (m_aCurToken.eType == TLGROUP)
    2198             :     {
    2199          61 :         sal_uInt16 n = 0;
    2200             : 
    2201         132 :         do
    2202             :         {
    2203         132 :             NextToken();
    2204         132 :             Align();
    2205         132 :             n++;
    2206             :         }
    2207         132 :         while (m_aCurToken.eType == TPOUND);
    2208             : 
    2209          61 :         ExpressionArray.resize(n);
    2210             : 
    2211         193 :         for (sal_uInt16 i = 0; i < n; i++)
    2212             :         {
    2213         132 :             ExpressionArray[n - (i + 1)] = lcl_popOrZero(m_aNodeStack);
    2214             :         }
    2215             : 
    2216          61 :         if (m_aCurToken.eType != TRGROUP)
    2217           0 :             Error(PE_RGROUP_EXPECTED);
    2218             : 
    2219          61 :         NextToken();
    2220             : 
    2221             :         //We need to let the table node know it context
    2222             :         //it's used in SmNodeToTextVisitor
    2223          61 :         SmToken aTok = m_aCurToken;
    2224          61 :         aTok.eType = TSTACK;
    2225          61 :         SmStructureNode *pSNode = new SmTableNode(aTok);
    2226          61 :         pSNode->SetSubNodes(ExpressionArray);
    2227          61 :         m_aNodeStack.push(pSNode);
    2228             :     }
    2229             :     else
    2230           0 :         Error(PE_LGROUP_EXPECTED);
    2231          61 : }
    2232             : 
    2233             : 
    2234          22 : void SmParser::Matrix()
    2235             : {
    2236          22 :     SmNodeArray  ExpressionArray;
    2237             : 
    2238          22 :     NextToken();
    2239          22 :     if (m_aCurToken.eType == TLGROUP)
    2240             :     {
    2241          22 :         sal_uInt16 c = 0;
    2242             : 
    2243          46 :         do
    2244             :         {
    2245          46 :             NextToken();
    2246          46 :             Align();
    2247          46 :             c++;
    2248             :         }
    2249          46 :         while (m_aCurToken.eType == TPOUND);
    2250             : 
    2251          22 :         sal_uInt16 r = 1;
    2252             : 
    2253          66 :         while (m_aCurToken.eType == TDPOUND)
    2254             :         {
    2255          22 :             NextToken();
    2256          68 :             for (sal_uInt16 i = 0; i < c; i++)
    2257             :             {
    2258          46 :                 Align();
    2259          46 :                 if (i < (c - 1))
    2260             :                 {
    2261          24 :                     if (m_aCurToken.eType == TPOUND)
    2262             :                     {
    2263          24 :                         NextToken();
    2264             :                     }
    2265             :                     else
    2266           0 :                         Error(PE_POUND_EXPECTED);
    2267             :                 }
    2268             :             }
    2269             : 
    2270          22 :             r++;
    2271             :         }
    2272             : 
    2273          22 :         long nRC = r * c;
    2274             : 
    2275          22 :         ExpressionArray.resize(nRC);
    2276             : 
    2277         114 :         for (sal_uInt16 i = 0; i < (nRC); i++)
    2278             :         {
    2279          92 :             ExpressionArray[(nRC) - (i + 1)] = lcl_popOrZero(m_aNodeStack);
    2280             :         }
    2281             : 
    2282          22 :         if (m_aCurToken.eType != TRGROUP)
    2283           0 :             Error(PE_RGROUP_EXPECTED);
    2284             : 
    2285          22 :         NextToken();
    2286             : 
    2287          22 :         SmMatrixNode *pMNode = new SmMatrixNode(m_aCurToken);
    2288          22 :         pMNode->SetSubNodes(ExpressionArray);
    2289          22 :         pMNode->SetRowCol(r, c);
    2290          22 :         m_aNodeStack.push(pMNode);
    2291             :     }
    2292             :     else
    2293           0 :         Error(PE_LGROUP_EXPECTED);
    2294          22 : }
    2295             : 
    2296             : 
    2297         130 : void SmParser::Special()
    2298             : {
    2299         130 :     bool bReplace = false;
    2300         130 :     OUString &rName = m_aCurToken.aText;
    2301         130 :     OUString aNewName;
    2302             : 
    2303             :     // conversion of symbol names for 6.0 (XML) file format
    2304             :     // (name change on import / export.
    2305             :     // UI uses localized names XML file format does not.)
    2306         130 :     if( rName.startsWith("%") )
    2307             :     {
    2308         130 :         if (IsImportSymbolNames())
    2309             :         {
    2310           0 :             const SmLocalizedSymbolData &rLSD = SM_MOD()->GetLocSymbolData();
    2311           0 :             aNewName = rLSD.GetUiSymbolName(rName.copy(1));
    2312           0 :             bReplace = true;
    2313             :         }
    2314         130 :         else if (IsExportSymbolNames())
    2315             :         {
    2316           0 :             const SmLocalizedSymbolData &rLSD = SM_MOD()->GetLocSymbolData();
    2317           0 :             aNewName = rLSD.GetExportSymbolName(rName.copy(1));
    2318           0 :             bReplace = true;
    2319             :         }
    2320             :     }
    2321         130 :     if (!aNewName.isEmpty())
    2322           0 :         aNewName = "%" + aNewName;
    2323             : 
    2324             : 
    2325         130 :     if (bReplace && !aNewName.isEmpty() && rName != aNewName)
    2326             :     {
    2327           0 :         Replace(GetTokenIndex(), rName.getLength(), aNewName);
    2328           0 :         rName = aNewName;
    2329             :     }
    2330             : 
    2331             :     // add symbol name to list of used symbols
    2332         260 :     const OUString aSymbolName(m_aCurToken.aText.copy(1));
    2333         130 :     if (!aSymbolName.isEmpty())
    2334         130 :         AddToUsedSymbols( aSymbolName );
    2335             : 
    2336         130 :     m_aNodeStack.push(new SmSpecialNode(m_aCurToken));
    2337         260 :     NextToken();
    2338         130 : }
    2339             : 
    2340             : 
    2341           0 : void SmParser::GlyphSpecial()
    2342             : {
    2343           0 :     m_aNodeStack.push(new SmGlyphSpecialNode(m_aCurToken));
    2344           0 :     NextToken();
    2345           0 : }
    2346             : 
    2347             : 
    2348          27 : void SmParser::Error(SmParseError eError)
    2349             : {
    2350          27 :     SmStructureNode *pSNode = new SmExpressionNode(m_aCurToken);
    2351          27 :     SmErrorNode     *pErr   = new SmErrorNode(eError, m_aCurToken);
    2352          27 :     pSNode->SetSubNodes(pErr, 0);
    2353             : 
    2354             :     //! put a structure node on the stack (instead of the error node itself)
    2355             :     //! because sometimes such a node is expected in order to attach some
    2356             :     //! subnodes
    2357          27 :     m_aNodeStack.push(pSNode);
    2358             : 
    2359          27 :     AddError(eError, pSNode);
    2360             : 
    2361          27 :     NextToken();
    2362          27 : }
    2363             : 
    2364             : 
    2365             : // end gramar
    2366             : 
    2367             : 
    2368        1182 : SmParser::SmParser()
    2369             :     : m_nCurError( 0 )
    2370             :     , m_nBufferIndex( 0 )
    2371             :     , m_nTokenIndex( 0 )
    2372             :     , m_Row( 0 )
    2373             :     , m_nColOff( 0 )
    2374        1182 :     , m_aDotLoc( LanguageTag::convertToLocale( LANGUAGE_ENGLISH_US ) )
    2375             : {
    2376        1182 :     bImportSymNames = m_bExportSymNames = false;
    2377        1182 :     m_nLang = Application::GetSettings().GetUILanguageTag().getLanguageType();
    2378        1182 : }
    2379             : 
    2380         886 : SmNode *SmParser::Parse(const OUString &rBuffer)
    2381             : {
    2382         886 :     ClearUsedSymbols();
    2383             : 
    2384         886 :     m_aBufferString = convertLineEnd(rBuffer, LINEEND_LF);
    2385         886 :     m_nBufferIndex  = 0;
    2386         886 :     m_nTokenIndex   = 0;
    2387         886 :     m_Row           = 1;
    2388         886 :     m_nColOff       = 0;
    2389         886 :     m_nCurError     = -1;
    2390             : 
    2391         902 :     for ( size_t i = 0, n = m_aErrDescList.size(); i < n; ++i )
    2392          16 :         delete m_aErrDescList[ i ];
    2393         886 :     m_aErrDescList.clear();
    2394             : 
    2395        1772 :     while ( !m_aNodeStack.empty() )
    2396           0 :         m_aNodeStack.pop();
    2397             : 
    2398         886 :     SetLanguage( Application::GetSettings().GetUILanguageTag().getLanguageType() );
    2399         886 :     NextToken();
    2400         886 :     Table();
    2401             : 
    2402         886 :     SmNode* result = lcl_popOrZero(m_aNodeStack);
    2403         886 :     return result;
    2404             : }
    2405             : 
    2406         845 : SmNode *SmParser::ParseExpression(const OUString &rBuffer)
    2407             : {
    2408         845 :     m_aBufferString = convertLineEnd(rBuffer, LINEEND_LF);
    2409         845 :     m_nBufferIndex  = 0;
    2410         845 :     m_nTokenIndex   = 0;
    2411         845 :     m_Row           = 1;
    2412         845 :     m_nColOff       = 0;
    2413         845 :     m_nCurError     = -1;
    2414             : 
    2415         845 :     for ( size_t i = 0, n = m_aErrDescList.size(); i < n; ++i )
    2416           0 :         delete m_aErrDescList[ i ];
    2417         845 :     m_aErrDescList.clear();
    2418             : 
    2419        1690 :     while ( !m_aNodeStack.empty() )
    2420           0 :         m_aNodeStack.pop();
    2421             : 
    2422         845 :     SetLanguage( Application::GetSettings().GetUILanguageTag().getLanguageType() );
    2423         845 :     NextToken();
    2424         845 :     Expression();
    2425             : 
    2426         845 :     SmNode* result = lcl_popOrZero(m_aNodeStack);
    2427         845 :     return result;
    2428             : }
    2429             : 
    2430             : 
    2431          27 : size_t SmParser::AddError(SmParseError Type, SmNode *pNode)
    2432             : {
    2433          27 :     SmErrorDesc *pErrDesc = new SmErrorDesc;
    2434             : 
    2435          27 :     pErrDesc->Type  = Type;
    2436          27 :     pErrDesc->pNode = pNode;
    2437          27 :     pErrDesc->Text  = SM_RESSTR(RID_ERR_IDENT);
    2438             : 
    2439             :     sal_uInt16  nRID;
    2440          27 :     switch (Type)
    2441             :     {
    2442          25 :         case PE_UNEXPECTED_CHAR:     nRID = RID_ERR_UNEXPECTEDCHARACTER;    break;
    2443           0 :         case PE_LGROUP_EXPECTED:     nRID = RID_ERR_LGROUPEXPECTED;         break;
    2444           1 :         case PE_RGROUP_EXPECTED:     nRID = RID_ERR_RGROUPEXPECTED;         break;
    2445           0 :         case PE_LBRACE_EXPECTED:     nRID = RID_ERR_LBRACEEXPECTED;         break;
    2446           0 :         case PE_RBRACE_EXPECTED:     nRID = RID_ERR_RBRACEEXPECTED;         break;
    2447           0 :         case PE_FUNC_EXPECTED:       nRID = RID_ERR_FUNCEXPECTED;           break;
    2448           0 :         case PE_UNOPER_EXPECTED:     nRID = RID_ERR_UNOPEREXPECTED;         break;
    2449           0 :         case PE_BINOPER_EXPECTED:    nRID = RID_ERR_BINOPEREXPECTED;        break;
    2450           0 :         case PE_SYMBOL_EXPECTED:     nRID = RID_ERR_SYMBOLEXPECTED;         break;
    2451           0 :         case PE_IDENTIFIER_EXPECTED: nRID = RID_ERR_IDENTEXPECTED;          break;
    2452           0 :         case PE_POUND_EXPECTED:      nRID = RID_ERR_POUNDEXPECTED;          break;
    2453           1 :         case PE_COLOR_EXPECTED:      nRID = RID_ERR_COLOREXPECTED;          break;
    2454           0 :         case PE_RIGHT_EXPECTED:      nRID = RID_ERR_RIGHTEXPECTED;          break;
    2455             : 
    2456             :         default:
    2457           0 :             nRID = RID_ERR_UNKNOWN;
    2458             :     }
    2459          27 :     pErrDesc->Text += SM_RESSTR(nRID);
    2460             : 
    2461          27 :     m_aErrDescList.push_back( pErrDesc );
    2462             : 
    2463          27 :     return m_aErrDescList.size()-1;
    2464             : }
    2465             : 
    2466             : 
    2467           1 : const SmErrorDesc *SmParser::NextError()
    2468             : {
    2469           1 :     if ( !m_aErrDescList.empty() )
    2470           1 :         if (m_nCurError > 0) return m_aErrDescList[ --m_nCurError ];
    2471             :         else
    2472             :         {
    2473           1 :             m_nCurError = 0;
    2474           1 :             return m_aErrDescList[ m_nCurError ];
    2475             :         }
    2476           0 :     else return NULL;
    2477             : }
    2478             : 
    2479             : 
    2480           3 : const SmErrorDesc *SmParser::PrevError()
    2481             : {
    2482           3 :     if ( !m_aErrDescList.empty() )
    2483           3 :         if (m_nCurError < (int) (m_aErrDescList.size() - 1)) return m_aErrDescList[ ++m_nCurError ];
    2484             :         else
    2485             :         {
    2486           1 :             m_nCurError = (int) (m_aErrDescList.size() - 1);
    2487           1 :             return m_aErrDescList[ m_nCurError ];
    2488             :         }
    2489           0 :     else return NULL;
    2490             : }
    2491             : 
    2492             : 
    2493           0 : const SmErrorDesc *SmParser::GetError(size_t i)
    2494             : {
    2495           0 :     if ( i < m_aErrDescList.size() )
    2496           0 :         return m_aErrDescList[ i ];
    2497             : 
    2498           0 :     if ( (size_t)m_nCurError < m_aErrDescList.size() )
    2499           0 :         return m_aErrDescList[ m_nCurError ];
    2500             : 
    2501           0 :     return NULL;
    2502          27 : }
    2503             : 
    2504             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10