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

Generated by: LCOV version 1.10