LCOV - code coverage report
Current view: top level - starmath/source - parse.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 955 1119 85.3 %
Date: 2014-11-03 Functions: 43 46 93.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10