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

Generated by: LCOV version 1.10