| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_starmath.hxx" |
| |
| |
| #include <stdio.h> |
| |
| #define SMDLL 1 |
| |
| #include <com/sun/star/i18n/UnicodeType.hpp> |
| #include <i18npool/lang.h> |
| #include <unotools/charclass.hxx> |
| #include <editeng/unolingu.hxx> |
| #include <unotools/syslocale.hxx> |
| #include "parse.hxx" |
| #ifndef _STARMATH_HRC |
| #include "starmath.hrc" |
| #endif |
| #ifndef _SMDLL_HXX |
| #include "smdll.hxx" |
| #endif |
| #include "smmod.hxx" |
| #include "config.hxx" |
| |
| #include "node.hxx" |
| |
| using namespace ::com::sun::star; |
| using namespace ::com::sun::star::i18n; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| |
| static inline sal_Bool strnccmp(const String &u1, xub_StrLen nIdx, |
| const sal_Char *s2, xub_StrLen nLen) |
| { |
| return u1.EqualsIgnoreCaseAscii( s2, nIdx, nLen ); |
| } |
| |
| static const sal_Unicode aDelimiterTable[] = |
| { |
| ' ', '\t', '\n', '\r', '+', '-', '*', '/', '=', '#', |
| '%', '\\', '"', '~', '`', '>', '<', '&', '|', '(', |
| ')', '{', '}', '[', ']', '^', '_', |
| '\0' // end of list symbol |
| }; |
| |
| |
| static inline sal_Bool IsDigit( sal_Unicode cChar ) |
| { |
| return '0' <= cChar && cChar <= '9'; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| |
| SmToken::SmToken() : |
| eType (TUNKNOWN), |
| cMathChar ('\0') |
| { |
| nGroup = nCol = nRow = nLevel = 0; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| |
| struct SmTokenTableEntry |
| { |
| const sal_Char* pIdent; |
| SmTokenType eType; |
| sal_Unicode cMathChar; |
| sal_uLong nGroup; |
| sal_uInt16 nLevel; |
| }; |
| |
| static const SmTokenTableEntry aTokenTable[] = |
| { |
| // { "#", TPOUND, '\0', 0, 0 }, |
| // { "##", TDPOUND, '\0', 0, 0 }, |
| // { "&", TAND, MS_AND, TGPRODUCT, 0 }, |
| // { "(", TLPARENT, MS_LPARENT, TGLBRACES, 5 }, //! 5 to continue expression |
| // { ")", TRPARENT, MS_RPARENT, TGRBRACES, 0 }, //! 0 to terminate expression |
| // { "*", TMULTIPLY, MS_MULTIPLY, TGPRODUCT, 0 }, |
| // { "+", TPLUS, MS_PLUS, TGUNOPER | TGSUM, 5 }, |
| // { "+-", TPLUSMINUS, MS_PLUSMINUS, TGUNOPER | TGSUM, 5 }, |
| // { "-", TMINUS, MS_MINUS, TGUNOPER | TGSUM, 5 }, |
| // { "-+", TMINUSPLUS, MS_MINUSPLUS, TGUNOPER | TGSUM, 5 }, |
| // { ".", TPOINT, '\0', 0, 0 }, |
| // { "/", TDIVIDEBY, MS_SLASH, TGPRODUCT, 0 }, |
| // { "<", TLT, MS_LT, TGRELATION, 0 }, |
| // { "<<", TLL, MS_LL, TGRELATION, 0 }, |
| // { "<=", TLE, MS_LE, TGRELATION, 0 }, |
| // { "<>", TNEQ, MS_NEQ, TGRELATION, 0}, |
| // { "<?>", TPLACE, MS_PLACE, 0, 5 }, |
| // { "=", TASSIGN, MS_ASSIGN, TGRELATION, 0}, |
| // { ">", TGT, MS_GT, TGRELATION, 0 }, |
| // { ">=", TGE, MS_GE, TGRELATION, 0 }, |
| // { ">>", TGG, MS_GG, TGRELATION, 0 }, |
| { "Im" , TIM, MS_IM, TGSTANDALONE, 5 }, |
| { "MZ23", TDEBUG, '\0', TGATTRIBUT, 0 }, |
| { "Re" , TRE, MS_RE, TGSTANDALONE, 5 }, |
| { "abs", TABS, '\0', TGUNOPER, 13 }, |
| { "arcosh", TACOSH, '\0', TGFUNCTION, 5 }, |
| { "arcoth", TACOTH, '\0', TGFUNCTION, 5 }, |
| { "acute", TACUTE, MS_ACUTE, TGATTRIBUT, 5 }, |
| { "aleph" , TALEPH, MS_ALEPH, TGSTANDALONE, 5 }, |
| { "alignb", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0}, |
| { "alignc", TALIGNC, '\0', TGALIGN, 0}, |
| { "alignl", TALIGNL, '\0', TGALIGN, 0}, |
| { "alignm", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0}, |
| { "alignr", TALIGNR, '\0', TGALIGN, 0}, |
| { "alignt", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0}, |
| { "and", TAND, MS_AND, TGPRODUCT, 0}, |
| { "approx", TAPPROX, MS_APPROX, TGRELATION, 0}, |
| { "arccos", TACOS, '\0', TGFUNCTION, 5}, |
| { "arccot", TACOT, '\0', TGFUNCTION, 5}, |
| { "arcsin", TASIN, '\0', TGFUNCTION, 5}, |
| { "arctan", TATAN, '\0', TGFUNCTION, 5}, |
| { "arsinh", TASINH, '\0', TGFUNCTION, 5}, |
| { "artanh", TATANH, '\0', TGFUNCTION, 5}, |
| { "backepsilon" , TBACKEPSILON, MS_BACKEPSILON, TGSTANDALONE, 5}, |
| { "bar", TBAR, MS_BAR, TGATTRIBUT, 5}, |
| { "binom", TBINOM, '\0', 0, 5 }, |
| { "black", TBLACK, '\0', TGCOLOR, 0}, |
| { "blue", TBLUE, '\0', TGCOLOR, 0}, |
| { "bold", TBOLD, '\0', TGFONTATTR, 5}, |
| { "boper", TBOPER, '\0', TGPRODUCT, 0}, |
| { "breve", TBREVE, MS_BREVE, TGATTRIBUT, 5}, |
| { "bslash", TBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 }, |
| { "cdot", TCDOT, MS_CDOT, TGPRODUCT, 0}, |
| { "check", TCHECK, MS_CHECK, TGATTRIBUT, 5}, |
| { "circ" , TCIRC, MS_CIRC, TGSTANDALONE, 5}, |
| { "circle", TCIRCLE, MS_CIRCLE, TGATTRIBUT, 5}, |
| { "color", TCOLOR, '\0', TGFONTATTR, 5}, |
| { "coprod", TCOPROD, MS_COPROD, TGOPER, 5}, |
| { "cos", TCOS, '\0', TGFUNCTION, 5}, |
| { "cosh", TCOSH, '\0', TGFUNCTION, 5}, |
| { "cot", TCOT, '\0', TGFUNCTION, 5}, |
| { "coth", TCOTH, '\0', TGFUNCTION, 5}, |
| { "csub", TCSUB, '\0', TGPOWER, 0}, |
| { "csup", TCSUP, '\0', TGPOWER, 0}, |
| { "cyan", TCYAN, '\0', TGCOLOR, 0}, |
| { "dddot", TDDDOT, MS_DDDOT, TGATTRIBUT, 5}, |
| { "ddot", TDDOT, MS_DDOT, TGATTRIBUT, 5}, |
| { "def", TDEF, MS_DEF, TGRELATION, 0}, |
| { "div", TDIV, MS_DIV, TGPRODUCT, 0}, |
| { "divides", TDIVIDES, MS_LINE, TGRELATION, 0}, |
| { "dlarrow" , TDLARROW, MS_DLARROW, TGSTANDALONE, 5}, |
| { "dlrarrow" , TDLRARROW, MS_DLRARROW, TGSTANDALONE, 5}, |
| { "dot", TDOT, MS_DOT, TGATTRIBUT, 5}, |
| { "dotsaxis", TDOTSAXIS, MS_DOTSAXIS, TGSTANDALONE, 5}, // 5 to continue expression |
| { "dotsdiag", TDOTSDIAG, MS_DOTSUP, TGSTANDALONE, 5}, // |
| { "dotsdown", TDOTSDOWN, MS_DOTSDOWN, TGSTANDALONE, 5}, // |
| { "dotslow", TDOTSLOW, MS_DOTSLOW, TGSTANDALONE, 5}, // |
| { "dotsup", TDOTSUP, MS_DOTSUP, TGSTANDALONE, 5}, // |
| { "dotsvert", TDOTSVERT, MS_DOTSVERT, TGSTANDALONE, 5}, // |
| { "downarrow" , TDOWNARROW, MS_DOWNARROW, TGSTANDALONE, 5}, |
| { "drarrow" , TDRARROW, MS_DRARROW, TGSTANDALONE, 5}, |
| { "emptyset" , TEMPTYSET, MS_EMPTYSET, TGSTANDALONE, 5}, |
| { "equiv", TEQUIV, MS_EQUIV, TGRELATION, 0}, |
| { "exists", TEXISTS, MS_EXISTS, TGSTANDALONE, 5}, |
| { "exp", TEXP, '\0', TGFUNCTION, 5}, |
| { "fact", TFACT, MS_FACT, TGUNOPER, 5}, |
| { "fixed", TFIXED, '\0', TGFONT, 0}, |
| { "font", TFONT, '\0', TGFONTATTR, 5}, |
| { "forall", TFORALL, MS_FORALL, TGSTANDALONE, 5}, |
| { "from", TFROM, '\0', TGLIMIT, 0}, |
| { "func", TFUNC, '\0', TGFUNCTION, 5}, |
| { "ge", TGE, MS_GE, TGRELATION, 0}, |
| { "geslant", TGESLANT, MS_GESLANT, TGRELATION, 0 }, |
| { "gg", TGG, MS_GG, TGRELATION, 0}, |
| { "grave", TGRAVE, MS_GRAVE, TGATTRIBUT, 5}, |
| { "green", TGREEN, '\0', TGCOLOR, 0}, |
| { "gt", TGT, MS_GT, TGRELATION, 0}, |
| { "hat", THAT, MS_HAT, TGATTRIBUT, 5}, |
| { "hbar" , THBAR, MS_HBAR, TGSTANDALONE, 5}, |
| { "iiint", TIIINT, MS_IIINT, TGOPER, 5}, |
| { "iint", TIINT, MS_IINT, TGOPER, 5}, |
| { "in", TIN, MS_IN, TGRELATION, 0}, |
| { "infinity" , TINFINITY, MS_INFINITY, TGSTANDALONE, 5}, |
| { "infty" , TINFINITY, MS_INFINITY, TGSTANDALONE, 5}, |
| { "int", TINT, MS_INT, TGOPER, 5}, |
| { "intersection", TINTERSECT, MS_INTERSECT, TGPRODUCT, 0}, |
| { "ital", TITALIC, '\0', TGFONTATTR, 5}, |
| { "italic", TITALIC, '\0', TGFONTATTR, 5}, |
| { "lambdabar" , TLAMBDABAR, MS_LAMBDABAR, TGSTANDALONE, 5}, |
| { "langle", TLANGLE, MS_LANGLE, TGLBRACES, 5}, |
| { "lbrace", TLBRACE, MS_LBRACE, TGLBRACES, 5}, |
| { "lceil", TLCEIL, MS_LCEIL, TGLBRACES, 5}, |
| { "ldbracket", TLDBRACKET, MS_LDBRACKET, TGLBRACES, 5}, |
| { "ldline", TLDLINE, MS_DLINE, TGLBRACES, 5}, |
| { "le", TLE, MS_LE, TGRELATION, 0}, |
| { "left", TLEFT, '\0', 0, 5}, |
| { "leftarrow" , TLEFTARROW, MS_LEFTARROW, TGSTANDALONE, 5}, |
| { "leslant", TLESLANT, MS_LESLANT, TGRELATION, 0 }, |
| { "lfloor", TLFLOOR, MS_LFLOOR, TGLBRACES, 5}, |
| { "lim", TLIM, '\0', TGOPER, 5}, |
| { "liminf", TLIMINF, '\0', TGOPER, 5}, |
| { "limsup", TLIMSUP, '\0', TGOPER, 5}, |
| { "lint", TLINT, MS_LINT, TGOPER, 5}, |
| { "ll", TLL, MS_LL, TGRELATION, 0}, |
| { "lline", TLLINE, MS_LINE, TGLBRACES, 5}, |
| { "llint", TLLINT, MS_LLINT, TGOPER, 5}, |
| { "lllint", TLLLINT, MS_LLLINT, TGOPER, 5}, |
| { "ln", TLN, '\0', TGFUNCTION, 5}, |
| { "log", TLOG, '\0', TGFUNCTION, 5}, |
| { "lsub", TLSUB, '\0', TGPOWER, 0}, |
| { "lsup", TLSUP, '\0', TGPOWER, 0}, |
| { "lt", TLT, MS_LT, TGRELATION, 0}, |
| { "magenta", TMAGENTA, '\0', TGCOLOR, 0}, |
| { "matrix", TMATRIX, '\0', 0, 5}, |
| { "minusplus", TMINUSPLUS, MS_MINUSPLUS, TGUNOPER | TGSUM, 5}, |
| { "mline", TMLINE, MS_LINE, 0, 0}, //! nicht in TGRBRACES, Level 0 |
| { "nabla", TNABLA, MS_NABLA, TGSTANDALONE, 5}, |
| { "nbold", TNBOLD, '\0', TGFONTATTR, 5}, |
| { "ndivides", TNDIVIDES, MS_NDIVIDES, TGRELATION, 0}, |
| { "neg", TNEG, MS_NEG, TGUNOPER, 5 }, |
| { "neq", TNEQ, MS_NEQ, TGRELATION, 0}, |
| { "newline", TNEWLINE, '\0', 0, 0}, |
| { "ni", TNI, MS_NI, TGRELATION, 0}, |
| { "nitalic", TNITALIC, '\0', TGFONTATTR, 5}, |
| { "none", TNONE, '\0', TGLBRACES | TGRBRACES, 0}, |
| { "nospace", TNOSPACE, '\0', TGSTANDALONE, 5}, |
| { "notin", TNOTIN, MS_NOTIN, TGRELATION, 0}, |
| { "nroot", TNROOT, MS_SQRT, TGUNOPER, 5}, |
| { "nsubset", TNSUBSET, MS_NSUBSET, TGRELATION, 0 }, |
| { "nsupset", TNSUPSET, MS_NSUPSET, TGRELATION, 0 }, |
| { "nsubseteq", TNSUBSETEQ, MS_NSUBSETEQ, TGRELATION, 0 }, |
| { "nsupseteq", TNSUPSETEQ, MS_NSUPSETEQ, TGRELATION, 0 }, |
| { "odivide", TODIVIDE, MS_ODIVIDE, TGPRODUCT, 0}, |
| { "odot", TODOT, MS_ODOT, TGPRODUCT, 0}, |
| { "ominus", TOMINUS, MS_OMINUS, TGSUM, 0}, |
| { "oper", TOPER, '\0', TGOPER, 5}, |
| { "oplus", TOPLUS, MS_OPLUS, TGSUM, 0}, |
| { "or", TOR, MS_OR, TGSUM, 0}, |
| { "ortho", TORTHO, MS_ORTHO, TGRELATION, 0}, |
| { "otimes", TOTIMES, MS_OTIMES, TGPRODUCT, 0}, |
| { "over", TOVER, '\0', TGPRODUCT, 0}, |
| { "overbrace", TOVERBRACE, MS_OVERBRACE, TGPRODUCT, 5}, |
| { "overline", TOVERLINE, '\0', TGATTRIBUT, 5}, |
| { "overstrike", TOVERSTRIKE, '\0', TGATTRIBUT, 5}, |
| { "owns", TNI, MS_NI, TGRELATION, 0}, |
| { "parallel", TPARALLEL, MS_DLINE, TGRELATION, 0}, |
| { "partial", TPARTIAL, MS_PARTIAL, TGSTANDALONE, 5 }, |
| { "phantom", TPHANTOM, '\0', TGFONTATTR, 5}, |
| { "plusminus", TPLUSMINUS, MS_PLUSMINUS, TGUNOPER | TGSUM, 5}, |
| { "prod", TPROD, MS_PROD, TGOPER, 5}, |
| { "prop", TPROP, MS_PROP, TGRELATION, 0}, |
| { "rangle", TRANGLE, MS_RANGLE, TGRBRACES, 0}, //! 0 to terminate expression |
| { "rbrace", TRBRACE, MS_RBRACE, TGRBRACES, 0}, // |
| { "rceil", TRCEIL, MS_RCEIL, TGRBRACES, 0}, // |
| { "rdbracket", TRDBRACKET, MS_RDBRACKET, TGRBRACES, 0}, // |
| { "rdline", TRDLINE, MS_DLINE, TGRBRACES, 0}, // |
| { "red", TRED, '\0', TGCOLOR, 0}, |
| { "rfloor", TRFLOOR, MS_RFLOOR, TGRBRACES, 0}, //! 0 to terminate expression |
| { "right", TRIGHT, '\0', 0, 0}, |
| { "rightarrow" , TRIGHTARROW, MS_RIGHTARROW, TGSTANDALONE, 5}, |
| { "rline", TRLINE, MS_LINE, TGRBRACES, 0}, //! 0 to terminate expression |
| { "rsub", TRSUB, '\0', TGPOWER, 0}, |
| { "rsup", TRSUP, '\0', TGPOWER, 0}, |
| { "sans", TSANS, '\0', TGFONT, 0}, |
| { "serif", TSERIF, '\0', TGFONT, 0}, |
| { "setC" , TSETC, MS_SETC, TGSTANDALONE, 5}, |
| { "setN" , TSETN, MS_SETN, TGSTANDALONE, 5}, |
| { "setQ" , TSETQ, MS_SETQ, TGSTANDALONE, 5}, |
| { "setR" , TSETR, MS_SETR, TGSTANDALONE, 5}, |
| { "setZ" , TSETZ, MS_SETZ, TGSTANDALONE, 5}, |
| { "setminus", TBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 }, |
| { "sim", TSIM, MS_SIM, TGRELATION, 0}, |
| { "simeq", TSIMEQ, MS_SIMEQ, TGRELATION, 0}, |
| { "sin", TSIN, '\0', TGFUNCTION, 5}, |
| { "sinh", TSINH, '\0', TGFUNCTION, 5}, |
| { "size", TSIZE, '\0', TGFONTATTR, 5}, |
| { "slash", TSLASH, MS_SLASH, TGPRODUCT, 0 }, |
| { "sqrt", TSQRT, MS_SQRT, TGUNOPER, 5}, |
| { "stack", TSTACK, '\0', 0, 5}, |
| { "sub", TRSUB, '\0', TGPOWER, 0}, |
| { "subset", TSUBSET, MS_SUBSET, TGRELATION, 0}, |
| { "subseteq", TSUBSETEQ, MS_SUBSETEQ, TGRELATION, 0}, |
| { "sum", TSUM, MS_SUM, TGOPER, 5}, |
| { "sup", TRSUP, '\0', TGPOWER, 0}, |
| { "supset", TSUPSET, MS_SUPSET, TGRELATION, 0}, |
| { "supseteq", TSUPSETEQ, MS_SUPSETEQ, TGRELATION, 0}, |
| { "tan", TTAN, '\0', TGFUNCTION, 5}, |
| { "tanh", TTANH, '\0', TGFUNCTION, 5}, |
| { "tilde", TTILDE, MS_TILDE, TGATTRIBUT, 5}, |
| { "times", TTIMES, MS_TIMES, TGPRODUCT, 0}, |
| { "to", TTO, '\0', TGLIMIT, 0}, |
| { "toward", TTOWARD, MS_RIGHTARROW, TGRELATION, 0}, |
| { "transl", TTRANSL, MS_TRANSL, TGRELATION, 0}, |
| { "transr", TTRANSR, MS_TRANSR, TGRELATION, 0}, |
| { "underbrace", TUNDERBRACE, MS_UNDERBRACE, TGPRODUCT, 5}, |
| { "underline", TUNDERLINE, '\0', TGATTRIBUT, 5}, |
| { "union", TUNION, MS_UNION, TGSUM, 0}, |
| { "uoper", TUOPER, '\0', TGUNOPER, 5}, |
| { "uparrow" , TUPARROW, MS_UPARROW, TGSTANDALONE, 5}, |
| { "vec", TVEC, MS_VEC, TGATTRIBUT, 5}, |
| { "white", TWHITE, '\0', TGCOLOR, 0}, |
| { "widebslash", TWIDEBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 }, |
| { "widehat", TWIDEHAT, MS_HAT, TGATTRIBUT, 5}, |
| { "widetilde", TWIDETILDE, MS_TILDE, TGATTRIBUT, 5}, |
| { "wideslash", TWIDESLASH, MS_SLASH, TGPRODUCT, 0 }, |
| { "widevec", TWIDEVEC, MS_VEC, TGATTRIBUT, 5}, |
| { "wp" , TWP, MS_WP, TGSTANDALONE, 5}, |
| { "yellow", TYELLOW, '\0', TGCOLOR, 0}, |
| // { "[", TLBRACKET, MS_LBRACKET, TGLBRACES, 5}, //! 5 to continue expression |
| // { "\\", TESCAPE, '\0', 0, 5}, |
| // { "]", TRBRACKET, MS_RBRACKET, TGRBRACES, 0}, //! 0 to terminate expression |
| // { "^", TRSUP, '\0', TGPOWER, 0}, |
| // { "_", TRSUB, '\0', TGPOWER, 0}, |
| // { "`", TSBLANK, '\0', TGBLANK, 5}, |
| // { "{", TLGROUP, MS_LBRACE, 0, 5}, //! 5 to continue expression |
| // { "|", TOR, MS_OR, TGSUM, 0}, |
| // { "}", TRGROUP, MS_RBRACE, 0, 0}, //! 0 to terminate expression |
| // { "~", TBLANK, '\0', TGBLANK, 5}, |
| { "", TEND, '\0', 0, 0} |
| }; |
| |
| |
| static const SmTokenTableEntry * GetTokenTableEntry( const String &rName ) |
| { |
| const SmTokenTableEntry * pRes = 0; |
| if (rName.Len()) |
| { |
| sal_Int32 nEntries = sizeof( aTokenTable ) / sizeof( aTokenTable[0] ); |
| for (sal_Int32 i = 0; i < nEntries; ++i) |
| { |
| if (rName.EqualsIgnoreCaseAscii( aTokenTable[i].pIdent )) |
| { |
| pRes = &aTokenTable[i]; |
| break; |
| } |
| } |
| |
| } |
| |
| return pRes; |
| } |
| |
| |
| /////////////////////////////////////////////////////////////////////////// |
| |
| #if OSL_DEBUG_LEVEL |
| |
| sal_Bool SmParser::IsDelimiter( const String &rTxt, xub_StrLen nPos ) |
| // returns 'sal_True' iff cChar is '\0' or a delimeter |
| { |
| DBG_ASSERT( nPos <= rTxt.Len(), "index out of range" ); |
| |
| sal_Unicode cChar = rTxt.GetChar( nPos ); |
| if(!cChar) |
| return sal_True; |
| |
| // check if 'cChar' is in the delimeter table |
| const sal_Unicode *pDelim = &aDelimiterTable[0]; |
| for ( ; *pDelim != 0; pDelim++) |
| if (*pDelim == cChar) |
| break; |
| |
| sal_Bool bIsDelim = *pDelim != 0; |
| |
| sal_Int16 nTypJp = SM_MOD()->GetSysLocale().GetCharClass().getType( rTxt, nPos ); |
| bIsDelim |= nTypJp == com::sun::star::i18n::UnicodeType::SPACE_SEPARATOR || |
| nTypJp == com::sun::star::i18n::UnicodeType::CONTROL; |
| |
| return bIsDelim; |
| } |
| |
| #endif |
| |
| void SmParser::Insert(const String &rText, sal_uInt16 nPos) |
| { |
| m_aBufferString.Insert(rText, nPos); |
| |
| xub_StrLen nLen = rText.Len(); |
| m_nBufferIndex = m_nBufferIndex + nLen; |
| m_nTokenIndex = m_nTokenIndex + nLen; |
| } |
| |
| |
| void SmParser::Replace( sal_uInt16 nPos, sal_uInt16 nLen, const String &rText ) |
| { |
| DBG_ASSERT( nPos + nLen <= m_aBufferString.Len(), "argument mismatch" ); |
| |
| m_aBufferString.Replace( nPos, nLen, rText ); |
| sal_Int16 nChg = rText.Len() - nLen; |
| m_nBufferIndex = m_nBufferIndex + nChg; |
| m_nTokenIndex = m_nTokenIndex + nChg; |
| } |
| |
| |
| // First character may be any alphabetic |
| const sal_Int32 coStartFlags = |
| KParseTokens::ANY_LETTER_OR_NUMBER | |
| KParseTokens::IGNORE_LEADING_WS; |
| |
| // Continuing characters may be any alphanumeric or dot. |
| const sal_Int32 coContFlags = |
| ((coStartFlags | KParseTokens::ASC_DOT) & ~KParseTokens::IGNORE_LEADING_WS) |
| | KParseTokens::TWO_DOUBLE_QUOTES_BREAK_STRING; |
| |
| // First character for numbers, may be any numeric or dot |
| const sal_Int32 coNumStartFlags = |
| KParseTokens::ASC_DIGIT | |
| KParseTokens::ASC_DOT | |
| KParseTokens::IGNORE_LEADING_WS; |
| // Continuing characters for numbers, may be any numeric or dot. |
| const sal_Int32 coNumContFlags = |
| (coNumStartFlags | KParseTokens::ASC_DOT) & ~KParseTokens::IGNORE_LEADING_WS; |
| |
| void SmParser::NextToken() |
| { |
| static const String aEmptyStr; |
| |
| xub_StrLen nBufLen = m_aBufferString.Len(); |
| ParseResult aRes; |
| xub_StrLen nRealStart; |
| sal_Bool bCont; |
| sal_Bool bNumStart = sal_False; |
| CharClass aCC(SM_MOD()->GetSysLocale().GetCharClass().getLocale()); |
| do |
| { |
| // skip white spaces |
| while (UnicodeType::SPACE_SEPARATOR == |
| aCC.getType( m_aBufferString, m_nBufferIndex )) |
| ++m_nBufferIndex; |
| |
| sal_Int32 nStartFlags = coStartFlags; |
| sal_Int32 nContFlags = coContFlags; |
| sal_Unicode cFirstChar = m_aBufferString.GetChar( m_nBufferIndex ); |
| /* |
| removed because of #i11752# |
| bNumStart = cFirstChar == '.' || ('0' <= cFirstChar && cFirstChar <= '9'); |
| if (bNumStart) |
| { |
| nStartFlags = coNumStartFlags; |
| nContFlags = coNumContFlags; |
| } |
| */ |
| aRes = aCC.parseAnyToken( m_aBufferString, m_nBufferIndex, |
| nStartFlags, aEmptyStr, |
| nContFlags, aEmptyStr ); |
| |
| // #i45779# parse numbers correctly |
| // i.e. independent from the locale setting. |
| // (note that #i11752# remains fixed) |
| if ((aRes.TokenType & KParseType::IDENTNAME) && IsDigit( cFirstChar )) |
| { |
| //! locale where '.' is decimal seperator! |
| static lang::Locale aDotLoc( SvxCreateLocale( LANGUAGE_ENGLISH_US ) ); |
| |
| ParseResult aTmpRes; |
| lang::Locale aOldLoc( aCC.getLocale() ); |
| aCC.setLocale( aDotLoc ); |
| aTmpRes = aCC.parsePredefinedToken( |
| KParseType::ASC_NUMBER, |
| m_aBufferString, m_nBufferIndex, |
| KParseTokens::ASC_DIGIT, aEmptyStr, |
| KParseTokens::ASC_DIGIT | KParseTokens::ASC_DOT, aEmptyStr ); |
| aCC.setLocale( aOldLoc ); |
| if (aTmpRes.TokenType & KParseType::ASC_NUMBER) |
| aRes.TokenType = aTmpRes.TokenType; |
| } |
| |
| nRealStart = m_nBufferIndex + sal::static_int_cast< xub_StrLen >(aRes.LeadingWhiteSpace); |
| m_nBufferIndex = nRealStart; |
| |
| bCont = sal_False; |
| if ( aRes.TokenType == 0 && |
| nRealStart < nBufLen && |
| '\n' == m_aBufferString.GetChar( nRealStart ) ) |
| { |
| // keep data needed for tokens row and col entry up to date |
| ++m_Row; |
| m_nBufferIndex = m_nColOff = nRealStart + 1; |
| bCont = sal_True; |
| } |
| else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR) |
| { |
| String aName( m_aBufferString.Copy( nRealStart, 2 )); |
| if ( aName.EqualsAscii( "%%" )) |
| { |
| //SkipComment |
| m_nBufferIndex = nRealStart + 2; |
| while (m_nBufferIndex < nBufLen && |
| '\n' != m_aBufferString.GetChar( m_nBufferIndex )) |
| ++m_nBufferIndex; |
| bCont = sal_True; |
| } |
| } |
| |
| } while (bCont); |
| |
| // set index of current token |
| m_nTokenIndex = m_nBufferIndex; |
| |
| m_aCurToken.nRow = m_Row; |
| m_aCurToken.nCol = nRealStart - m_nColOff + 1; |
| |
| sal_Bool bHandled = sal_True; |
| if (nRealStart >= nBufLen) |
| { |
| m_aCurToken.eType = TEND; |
| m_aCurToken.cMathChar = '\0'; |
| m_aCurToken.nGroup = 0; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.Erase(); |
| } |
| else if ((aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER)) |
| || (bNumStart && (aRes.TokenType & KParseType::IDENTNAME))) |
| { |
| sal_Int32 n = aRes.EndPos - nRealStart; |
| DBG_ASSERT( n >= 0, "length < 0" ); |
| m_aCurToken.eType = TNUMBER; |
| m_aCurToken.cMathChar = '\0'; |
| m_aCurToken.nGroup = 0; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText = m_aBufferString.Copy( nRealStart, sal::static_int_cast< xub_StrLen >(n) ); |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| if (!IsDelimiter( m_aBufferString, static_cast< xub_StrLen >(aRes.EndPos) )) |
| { |
| DBG_WARNING( "identifier really finished? (compatibility!)" ); |
| } |
| #endif |
| } |
| else if (aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING) |
| { |
| m_aCurToken.eType = TTEXT; |
| m_aCurToken.cMathChar = '\0'; |
| m_aCurToken.nGroup = 0; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText = aRes.DequotedNameOrString; |
| m_aCurToken.nRow = m_Row; |
| m_aCurToken.nCol = nRealStart - m_nColOff + 2; |
| } |
| else if (aRes.TokenType & KParseType::IDENTNAME) |
| { |
| sal_Int32 n = aRes.EndPos - nRealStart; |
| DBG_ASSERT( n >= 0, "length < 0" ); |
| String aName( m_aBufferString.Copy( nRealStart, sal::static_int_cast< xub_StrLen >(n) ) ); |
| const SmTokenTableEntry *pEntry = GetTokenTableEntry( aName ); |
| |
| if (pEntry) |
| { |
| m_aCurToken.eType = pEntry->eType; |
| m_aCurToken.cMathChar = pEntry->cMathChar; |
| m_aCurToken.nGroup = pEntry->nGroup; |
| m_aCurToken.nLevel = pEntry->nLevel; |
| m_aCurToken.aText.AssignAscii( pEntry->pIdent ); |
| } |
| else |
| { |
| m_aCurToken.eType = TIDENT; |
| m_aCurToken.cMathChar = '\0'; |
| m_aCurToken.nGroup = 0; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText = aName; |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| if (!IsDelimiter( m_aBufferString, static_cast< xub_StrLen >(aRes.EndPos) )) |
| { |
| DBG_WARNING( "identifier really finished? (compatibility!)" ); |
| } |
| #endif |
| } |
| } |
| else if (aRes.TokenType == 0 && '_' == m_aBufferString.GetChar( nRealStart )) |
| { |
| m_aCurToken.eType = TRSUB; |
| m_aCurToken.cMathChar = '\0'; |
| m_aCurToken.nGroup = TGPOWER; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "_" ); |
| |
| aRes.EndPos = nRealStart + 1; |
| } |
| else if (aRes.TokenType & KParseType::BOOLEAN) |
| { |
| sal_Int32 &rnEndPos = aRes.EndPos; |
| String aName( m_aBufferString.Copy( nRealStart, |
| sal::static_int_cast< xub_StrLen >(rnEndPos - nRealStart) )); |
| if (2 >= aName.Len()) |
| { |
| sal_Unicode ch = aName.GetChar( 0 ); |
| switch (ch) |
| { |
| case '<': |
| { |
| if (m_aBufferString.Copy( nRealStart, 2 ). |
| EqualsAscii( "<<" )) |
| { |
| m_aCurToken.eType = TLL; |
| m_aCurToken.cMathChar = MS_LL; |
| m_aCurToken.nGroup = TGRELATION; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "<<" ); |
| |
| rnEndPos = nRealStart + 2; |
| } |
| else if (m_aBufferString.Copy( nRealStart, 2 ). |
| EqualsAscii( "<=" )) |
| { |
| m_aCurToken.eType = TLE; |
| m_aCurToken.cMathChar = MS_LE; |
| m_aCurToken.nGroup = TGRELATION; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "<=" ); |
| |
| rnEndPos = nRealStart + 2; |
| } |
| else if (m_aBufferString.Copy( nRealStart, 2 ). |
| EqualsAscii( "<>" )) |
| { |
| m_aCurToken.eType = TNEQ; |
| m_aCurToken.cMathChar = MS_NEQ; |
| m_aCurToken.nGroup = TGRELATION; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "<>" ); |
| |
| rnEndPos = nRealStart + 2; |
| } |
| else if (m_aBufferString.Copy( nRealStart, 3 ). |
| EqualsAscii( "<?>" )) |
| { |
| m_aCurToken.eType = TPLACE; |
| m_aCurToken.cMathChar = MS_PLACE; |
| m_aCurToken.nGroup = 0; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText.AssignAscii( "<?>" ); |
| |
| rnEndPos = nRealStart + 3; |
| } |
| else |
| { |
| m_aCurToken.eType = TLT; |
| m_aCurToken.cMathChar = MS_LT; |
| m_aCurToken.nGroup = TGRELATION; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "<" ); |
| } |
| } |
| break; |
| case '>': |
| { |
| if (m_aBufferString.Copy( nRealStart, 2 ). |
| EqualsAscii( ">=" )) |
| { |
| m_aCurToken.eType = TGE; |
| m_aCurToken.cMathChar = MS_GE; |
| m_aCurToken.nGroup = TGRELATION; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( ">=" ); |
| |
| rnEndPos = nRealStart + 2; |
| } |
| else if (m_aBufferString.Copy( nRealStart, 2 ). |
| EqualsAscii( ">>" )) |
| { |
| m_aCurToken.eType = TGG; |
| m_aCurToken.cMathChar = MS_GG; |
| m_aCurToken.nGroup = TGRELATION; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( ">>" ); |
| |
| rnEndPos = nRealStart + 2; |
| } |
| else |
| { |
| m_aCurToken.eType = TGT; |
| m_aCurToken.cMathChar = MS_GT; |
| m_aCurToken.nGroup = TGRELATION; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( ">" ); |
| } |
| } |
| break; |
| default: |
| bHandled = sal_False; |
| } |
| } |
| } |
| else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR) |
| { |
| sal_Int32 &rnEndPos = aRes.EndPos; |
| String aName( m_aBufferString.Copy( nRealStart, |
| sal::static_int_cast< xub_StrLen >(rnEndPos - nRealStart) ) ); |
| |
| if (1 == aName.Len()) |
| { |
| sal_Unicode ch = aName.GetChar( 0 ); |
| switch (ch) |
| { |
| case '%': |
| { |
| //! modifies aRes.EndPos |
| |
| DBG_ASSERT( rnEndPos >= nBufLen || |
| '%' != m_aBufferString.GetChar( sal::static_int_cast< xub_StrLen >(rnEndPos) ), |
| "unexpected comment start" ); |
| |
| // get identifier of user-defined character |
| ParseResult aTmpRes = aCC.parseAnyToken( |
| m_aBufferString, rnEndPos, |
| KParseTokens::ANY_LETTER, |
| aEmptyStr, |
| coContFlags, |
| aEmptyStr ); |
| |
| xub_StrLen nTmpStart = sal::static_int_cast< xub_StrLen >(rnEndPos + |
| aTmpRes.LeadingWhiteSpace); |
| |
| // default setting for the case that no identifier |
| // i.e. a valid symbol-name is following the '%' |
| // character |
| m_aCurToken.eType = TTEXT; |
| m_aCurToken.cMathChar = '\0'; |
| m_aCurToken.nGroup = 0; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText = String(); |
| m_aCurToken.nRow = sal::static_int_cast< xub_StrLen >(m_Row); |
| m_aCurToken.nCol = nTmpStart - m_nColOff; |
| |
| if (aTmpRes.TokenType & KParseType::IDENTNAME) |
| { |
| |
| xub_StrLen n = sal::static_int_cast< xub_StrLen >(aTmpRes.EndPos - nTmpStart); |
| m_aCurToken.eType = TSPECIAL; |
| m_aCurToken.aText = m_aBufferString.Copy( sal::static_int_cast< xub_StrLen >(nTmpStart-1), n+1 ); |
| |
| DBG_ASSERT( aTmpRes.EndPos > rnEndPos, |
| "empty identifier" ); |
| if (aTmpRes.EndPos > rnEndPos) |
| rnEndPos = aTmpRes.EndPos; |
| else |
| ++rnEndPos; |
| } |
| |
| // if no symbol-name was found we start-over with |
| // finding the next token right afer the '%' sign. |
| // I.e. we leave rnEndPos unmodified. |
| } |
| break; |
| case '[': |
| { |
| m_aCurToken.eType = TLBRACKET; |
| m_aCurToken.cMathChar = MS_LBRACKET; |
| m_aCurToken.nGroup = TGLBRACES; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText.AssignAscii( "[" ); |
| } |
| break; |
| case '\\': |
| { |
| m_aCurToken.eType = TESCAPE; |
| m_aCurToken.cMathChar = '\0'; |
| m_aCurToken.nGroup = 0; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText.AssignAscii( "\\" ); |
| } |
| break; |
| case ']': |
| { |
| m_aCurToken.eType = TRBRACKET; |
| m_aCurToken.cMathChar = MS_RBRACKET; |
| m_aCurToken.nGroup = TGRBRACES; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "]" ); |
| } |
| break; |
| case '^': |
| { |
| m_aCurToken.eType = TRSUP; |
| m_aCurToken.cMathChar = '\0'; |
| m_aCurToken.nGroup = TGPOWER; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "^" ); |
| } |
| break; |
| case '`': |
| { |
| m_aCurToken.eType = TSBLANK; |
| m_aCurToken.cMathChar = '\0'; |
| m_aCurToken.nGroup = TGBLANK; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText.AssignAscii( "`" ); |
| } |
| break; |
| case '{': |
| { |
| m_aCurToken.eType = TLGROUP; |
| m_aCurToken.cMathChar = MS_LBRACE; |
| m_aCurToken.nGroup = 0; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText.AssignAscii( "{" ); |
| } |
| break; |
| case '|': |
| { |
| m_aCurToken.eType = TOR; |
| m_aCurToken.cMathChar = MS_OR; |
| m_aCurToken.nGroup = TGSUM; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "|" ); |
| } |
| break; |
| case '}': |
| { |
| m_aCurToken.eType = TRGROUP; |
| m_aCurToken.cMathChar = MS_RBRACE; |
| m_aCurToken.nGroup = 0; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "}" ); |
| } |
| break; |
| case '~': |
| { |
| m_aCurToken.eType = TBLANK; |
| m_aCurToken.cMathChar = '\0'; |
| m_aCurToken.nGroup = TGBLANK; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText.AssignAscii( "~" ); |
| } |
| break; |
| case '#': |
| { |
| if (m_aBufferString.Copy( nRealStart, 2 ). |
| EqualsAscii( "##" )) |
| { |
| m_aCurToken.eType = TDPOUND; |
| m_aCurToken.cMathChar = '\0'; |
| m_aCurToken.nGroup = 0; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "##" ); |
| |
| rnEndPos = nRealStart + 2; |
| } |
| else |
| { |
| m_aCurToken.eType = TPOUND; |
| m_aCurToken.cMathChar = '\0'; |
| m_aCurToken.nGroup = 0; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "#" ); |
| } |
| } |
| break; |
| case '&': |
| { |
| m_aCurToken.eType = TAND; |
| m_aCurToken.cMathChar = MS_AND; |
| m_aCurToken.nGroup = TGPRODUCT; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "&" ); |
| } |
| break; |
| case '(': |
| { |
| m_aCurToken.eType = TLPARENT; |
| m_aCurToken.cMathChar = MS_LPARENT; |
| m_aCurToken.nGroup = TGLBRACES; |
| m_aCurToken.nLevel = 5; //! 0 to continue expression |
| m_aCurToken.aText.AssignAscii( "(" ); |
| } |
| break; |
| case ')': |
| { |
| m_aCurToken.eType = TRPARENT; |
| m_aCurToken.cMathChar = MS_RPARENT; |
| m_aCurToken.nGroup = TGRBRACES; |
| m_aCurToken.nLevel = 0; //! 0 to terminate expression |
| m_aCurToken.aText.AssignAscii( ")" ); |
| } |
| break; |
| case '*': |
| { |
| m_aCurToken.eType = TMULTIPLY; |
| m_aCurToken.cMathChar = MS_MULTIPLY; |
| m_aCurToken.nGroup = TGPRODUCT; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "*" ); |
| } |
| break; |
| case '+': |
| { |
| if (m_aBufferString.Copy( nRealStart, 2 ). |
| EqualsAscii( "+-" )) |
| { |
| m_aCurToken.eType = TPLUSMINUS; |
| m_aCurToken.cMathChar = MS_PLUSMINUS; |
| m_aCurToken.nGroup = TGUNOPER | TGSUM; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText.AssignAscii( "+-" ); |
| |
| rnEndPos = nRealStart + 2; |
| } |
| else |
| { |
| m_aCurToken.eType = TPLUS; |
| m_aCurToken.cMathChar = MS_PLUS; |
| m_aCurToken.nGroup = TGUNOPER | TGSUM; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText.AssignAscii( "+" ); |
| } |
| } |
| break; |
| case '-': |
| { |
| if (m_aBufferString.Copy( nRealStart, 2 ). |
| EqualsAscii( "-+" )) |
| { |
| m_aCurToken.eType = TMINUSPLUS; |
| m_aCurToken.cMathChar = MS_MINUSPLUS; |
| m_aCurToken.nGroup = TGUNOPER | TGSUM; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText.AssignAscii( "-+" ); |
| |
| rnEndPos = nRealStart + 2; |
| } |
| else |
| { |
| m_aCurToken.eType = TMINUS; |
| m_aCurToken.cMathChar = MS_MINUS; |
| m_aCurToken.nGroup = TGUNOPER | TGSUM; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText.AssignAscii( "-" ); |
| } |
| } |
| break; |
| case '.': |
| { |
| // for compatibility with SO5.2 |
| // texts like .34 ...56 ... h ...78..90 |
| // will be treated as numbers |
| m_aCurToken.eType = TNUMBER; |
| m_aCurToken.cMathChar = '\0'; |
| m_aCurToken.nGroup = 0; |
| m_aCurToken.nLevel = 5; |
| |
| xub_StrLen nTxtStart = m_nBufferIndex; |
| sal_Unicode cChar; |
| do |
| { |
| cChar = m_aBufferString.GetChar( ++m_nBufferIndex ); |
| } |
| while ( cChar == '.' || IsDigit( cChar ) ); |
| |
| m_aCurToken.aText = m_aBufferString.Copy( sal::static_int_cast< xub_StrLen >(nTxtStart), |
| sal::static_int_cast< xub_StrLen >(m_nBufferIndex - nTxtStart) ); |
| aRes.EndPos = m_nBufferIndex; |
| } |
| break; |
| case '/': |
| { |
| m_aCurToken.eType = TDIVIDEBY; |
| m_aCurToken.cMathChar = MS_SLASH; |
| m_aCurToken.nGroup = TGPRODUCT; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "/" ); |
| } |
| break; |
| case '=': |
| { |
| m_aCurToken.eType = TASSIGN; |
| m_aCurToken.cMathChar = MS_ASSIGN; |
| m_aCurToken.nGroup = TGRELATION; |
| m_aCurToken.nLevel = 0; |
| m_aCurToken.aText.AssignAscii( "=" ); |
| } |
| break; |
| default: |
| bHandled = sal_False; |
| } |
| } |
| } |
| else |
| bHandled = sal_False; |
| |
| if (!bHandled) |
| { |
| m_aCurToken.eType = TCHARACTER; |
| m_aCurToken.cMathChar = '\0'; |
| m_aCurToken.nGroup = 0; |
| m_aCurToken.nLevel = 5; |
| m_aCurToken.aText = m_aBufferString.Copy( nRealStart, 1 ); |
| |
| aRes.EndPos = nRealStart + 1; |
| } |
| |
| if (TEND != m_aCurToken.eType) |
| m_nBufferIndex = sal::static_int_cast< xub_StrLen >(aRes.EndPos); |
| } |
| |
| |
| //////////////////////////////////////// |
| // grammar |
| // |
| |
| |
| void SmParser::Table() |
| { |
| SmNodeArray LineArray; |
| |
| Line(); |
| while (m_aCurToken.eType == TNEWLINE) |
| { |
| NextToken(); |
| Line(); |
| } |
| |
| if (m_aCurToken.eType != TEND) |
| Error(PE_UNEXPECTED_CHAR); |
| |
| sal_uLong n = m_aNodeStack.Count(); |
| |
| LineArray.resize(n); |
| |
| for (sal_uLong i = 0; i < n; i++) |
| LineArray[n - (i + 1)] = m_aNodeStack.Pop(); |
| |
| SmStructureNode *pSNode = new SmTableNode(m_aCurToken); |
| pSNode->SetSubNodes(LineArray); |
| m_aNodeStack.Push(pSNode); |
| } |
| |
| |
| void SmParser::Align() |
| // parse alignment info (if any), then go on with rest of expression |
| { |
| SmStructureNode *pSNode = 0; |
| sal_Bool bNeedGroupClose = sal_False; |
| |
| if (TokenInGroup(TGALIGN)) |
| { |
| if (CONVERT_40_TO_50 == GetConversion()) |
| // encapsulate expression to be aligned in group braces |
| // (here group-open brace) |
| { Insert('{', GetTokenIndex()); |
| bNeedGroupClose = sal_True; |
| |
| // get first valid align statement in sequence |
| // (the dominant one in 4.0) and erase all others (especially old |
| // discarded tokens) from command string. |
| while (TokenInGroup(TGALIGN)) |
| { |
| if (TokenInGroup(TGDISCARDED) || pSNode) |
| { |
| m_nBufferIndex = GetTokenIndex(); |
| m_aBufferString.Erase(m_nBufferIndex, m_aCurToken.aText.Len()); |
| } |
| else |
| pSNode = new SmAlignNode(m_aCurToken); |
| |
| NextToken(); |
| } |
| } |
| else |
| { |
| pSNode = new SmAlignNode(m_aCurToken); |
| |
| NextToken(); |
| |
| // allow for just one align statement in 5.0 |
| if (CONVERT_40_TO_50 != GetConversion() && TokenInGroup(TGALIGN)) |
| { Error(PE_DOUBLE_ALIGN); |
| return; |
| } |
| } |
| } |
| |
| Expression(); |
| |
| if (bNeedGroupClose) |
| Insert('}', GetTokenIndex()); |
| |
| if (pSNode) |
| { pSNode->SetSubNodes(m_aNodeStack.Pop(), 0); |
| m_aNodeStack.Push(pSNode); |
| } |
| } |
| |
| |
| void SmParser::Line() |
| { |
| sal_uInt16 n = 0; |
| SmNodeArray ExpressionArray; |
| |
| ExpressionArray.resize(n); |
| |
| // start with single expression that may have an alignment statement |
| // (and go on with expressions that must not have alignment |
| // statements in 'while' loop below. See also 'Expression()'.) |
| if (m_aCurToken.eType != TEND && m_aCurToken.eType != TNEWLINE) |
| { Align(); |
| ExpressionArray.resize(++n); |
| ExpressionArray[n - 1] = m_aNodeStack.Pop(); |
| } |
| |
| while (m_aCurToken.eType != TEND && m_aCurToken.eType != TNEWLINE) |
| { if (CONVERT_40_TO_50 != GetConversion()) |
| Expression(); |
| else |
| Align(); |
| ExpressionArray.resize(++n); |
| ExpressionArray[n - 1] = m_aNodeStack.Pop(); |
| } |
| |
| SmStructureNode *pSNode = new SmLineNode(m_aCurToken); |
| pSNode->SetSubNodes(ExpressionArray); |
| m_aNodeStack.Push(pSNode); |
| } |
| |
| |
| void SmParser::Expression() |
| { |
| sal_Bool bUseExtraSpaces = sal_True; |
| SmNode *pNode = m_aNodeStack.Pop(); |
| if (pNode) |
| { |
| if (pNode->GetToken().eType == TNOSPACE) |
| bUseExtraSpaces = sal_False; |
| else |
| m_aNodeStack.Push(pNode); // push the node from above again (now to be used as argument to this current 'nospace' node) |
| } |
| |
| sal_uInt16 n = 0; |
| SmNodeArray RelationArray; |
| |
| RelationArray.resize(n); |
| |
| Relation(); |
| RelationArray.resize(++n); |
| RelationArray[n - 1] = m_aNodeStack.Pop(); |
| |
| while (m_aCurToken.nLevel >= 4) |
| { Relation(); |
| RelationArray.resize(++n); |
| RelationArray[n - 1] = m_aNodeStack.Pop(); |
| } |
| |
| SmExpressionNode *pSNode = new SmExpressionNode(m_aCurToken); |
| pSNode->SetSubNodes(RelationArray); |
| pSNode->SetUseExtraSpaces(bUseExtraSpaces); |
| m_aNodeStack.Push(pSNode); |
| } |
| |
| |
| void SmParser::Relation() |
| { |
| Sum(); |
| while (TokenInGroup(TGRELATION)) |
| { |
| SmStructureNode *pSNode = new SmBinHorNode(m_aCurToken); |
| SmNode *pFirst = m_aNodeStack.Pop(); |
| |
| OpSubSup(); |
| SmNode *pSecond = m_aNodeStack.Pop(); |
| |
| Sum(); |
| |
| pSNode->SetSubNodes(pFirst, pSecond, m_aNodeStack.Pop()); |
| m_aNodeStack.Push(pSNode); |
| } |
| } |
| |
| |
| void SmParser::Sum() |
| { |
| Product(); |
| while (TokenInGroup(TGSUM)) |
| { |
| SmStructureNode *pSNode = new SmBinHorNode(m_aCurToken); |
| SmNode *pFirst = m_aNodeStack.Pop(); |
| |
| OpSubSup(); |
| SmNode *pSecond = m_aNodeStack.Pop(); |
| |
| Product(); |
| |
| pSNode->SetSubNodes(pFirst, pSecond, m_aNodeStack.Pop()); |
| m_aNodeStack.Push(pSNode); |
| } |
| } |
| |
| |
| void SmParser::Product() |
| { |
| Power(); |
| |
| while (TokenInGroup(TGPRODUCT)) |
| { SmStructureNode *pSNode; |
| SmNode *pFirst = m_aNodeStack.Pop(), |
| *pOper; |
| sal_Bool bSwitchArgs = sal_False; |
| |
| SmTokenType eType = m_aCurToken.eType; |
| switch (eType) |
| { |
| case TOVER: |
| pSNode = new SmBinVerNode(m_aCurToken); |
| pOper = new SmRectangleNode(m_aCurToken); |
| NextToken(); |
| break; |
| |
| case TBOPER: |
| pSNode = new SmBinHorNode(m_aCurToken); |
| |
| NextToken(); |
| |
| GlyphSpecial(); |
| pOper = m_aNodeStack.Pop(); |
| break; |
| |
| case TOVERBRACE : |
| case TUNDERBRACE : |
| pSNode = new SmVerticalBraceNode(m_aCurToken); |
| pOper = new SmMathSymbolNode(m_aCurToken); |
| |
| NextToken(); |
| break; |
| |
| case TWIDEBACKSLASH: |
| case TWIDESLASH: |
| { |
| SmBinDiagonalNode *pSTmp = new SmBinDiagonalNode(m_aCurToken); |
| pSTmp->SetAscending(eType == TWIDESLASH); |
| pSNode = pSTmp; |
| |
| pOper = new SmPolyLineNode(m_aCurToken); |
| NextToken(); |
| |
| bSwitchArgs =sal_True; |
| break; |
| } |
| |
| default: |
| pSNode = new SmBinHorNode(m_aCurToken); |
| |
| OpSubSup(); |
| pOper = m_aNodeStack.Pop(); |
| } |
| |
| Power(); |
| |
| if (bSwitchArgs) |
| //! vgl siehe SmBinDiagonalNode::Arrange |
| pSNode->SetSubNodes(pFirst, m_aNodeStack.Pop(), pOper); |
| else |
| pSNode->SetSubNodes(pFirst, pOper, m_aNodeStack.Pop()); |
| m_aNodeStack.Push(pSNode); |
| } |
| } |
| |
| |
| void SmParser::SubSup(sal_uLong nActiveGroup) |
| { |
| DBG_ASSERT(nActiveGroup == TGPOWER || nActiveGroup == TGLIMIT, |
| "Sm: falsche Tokengruppe"); |
| |
| if (!TokenInGroup(nActiveGroup)) |
| // already finish |
| return; |
| |
| SmSubSupNode *pNode = new SmSubSupNode(m_aCurToken); |
| //! Of course 'm_aCurToken' is just the first sub-/supscript token. |
| //! It should be of no further interest. The positions of the |
| //! sub-/supscripts will be identified by the corresponding subnodes |
| //! index in the 'aSubNodes' array (enum value from 'SmSubSup'). |
| |
| pNode->SetUseLimits(nActiveGroup == TGLIMIT); |
| |
| // initialize subnodes array |
| SmNodeArray aSubNodes; |
| aSubNodes.resize(1 + SUBSUP_NUM_ENTRIES); |
| aSubNodes[0] = m_aNodeStack.Pop(); |
| for (sal_uInt16 i = 1; i < aSubNodes.size(); i++) |
| aSubNodes[i] = NULL; |
| |
| // process all sub-/supscripts |
| int nIndex = 0; |
| while (TokenInGroup(nActiveGroup)) |
| { SmTokenType eType (m_aCurToken.eType); |
| |
| // skip sub-/supscript token |
| NextToken(); |
| |
| // get sub-/supscript node on top of stack |
| if (eType == TFROM || eType == TTO) |
| { |
| // parse limits in old 4.0 and 5.0 style |
| Relation(); |
| } |
| else |
| Term(); |
| |
| switch (eType) |
| { case TRSUB : nIndex = (int) RSUB; break; |
| case TRSUP : nIndex = (int) RSUP; break; |
| case TFROM : |
| case TCSUB : nIndex = (int) CSUB; break; |
| case TTO : |
| case TCSUP : nIndex = (int) CSUP; break; |
| case TLSUB : nIndex = (int) LSUB; break; |
| case TLSUP : nIndex = (int) LSUP; break; |
| default : |
| DBG_ASSERT(sal_False, "Sm: unbekannter Fall"); |
| } |
| nIndex++; |
| DBG_ASSERT(1 <= nIndex && nIndex <= 1 + SUBSUP_NUM_ENTRIES, |
| "SmParser::Power() : sub-/supscript index falsch"); |
| |
| // set sub-/supscript if not already done |
| if (aSubNodes[nIndex] != NULL) |
| Error(PE_DOUBLE_SUBSUPSCRIPT); |
| aSubNodes[nIndex] = m_aNodeStack.Pop(); |
| } |
| |
| pNode->SetSubNodes(aSubNodes); |
| m_aNodeStack.Push(pNode); |
| } |
| |
| |
| void SmParser::OpSubSup() |
| { |
| // push operator symbol |
| m_aNodeStack.Push(new SmMathSymbolNode(m_aCurToken)); |
| // skip operator token |
| NextToken(); |
| // get sub- supscripts if any |
| if (TokenInGroup(TGPOWER)) |
| SubSup(TGPOWER); |
| } |
| |
| |
| void SmParser::Power() |
| { |
| // get body for sub- supscripts on top of stack |
| Term(); |
| |
| SubSup(TGPOWER); |
| } |
| |
| |
| void SmParser::Blank() |
| { |
| DBG_ASSERT(TokenInGroup(TGBLANK), "Sm : falsches Token"); |
| SmBlankNode *pBlankNode = new SmBlankNode(m_aCurToken); |
| |
| while (TokenInGroup(TGBLANK)) |
| { |
| pBlankNode->IncreaseBy(m_aCurToken); |
| NextToken(); |
| } |
| |
| // Blanks am Zeilenende ignorieren wenn die entsprechende Option gesetzt ist |
| if ( m_aCurToken.eType == TNEWLINE || |
| (m_aCurToken.eType == TEND && SM_MOD()->GetConfig()->IsIgnoreSpacesRight()) ) |
| { |
| pBlankNode->Clear(); |
| } |
| |
| m_aNodeStack.Push(pBlankNode); |
| } |
| |
| |
| void SmParser::Term() |
| { |
| switch (m_aCurToken.eType) |
| { |
| case TESCAPE : |
| Escape(); |
| break; |
| |
| case TNOSPACE : |
| case TLGROUP : |
| { |
| bool bNoSpace = m_aCurToken.eType == TNOSPACE; |
| if (bNoSpace) // push 'no space' node and continue to parse expression |
| { |
| m_aNodeStack.Push(new SmExpressionNode(m_aCurToken)); |
| NextToken(); |
| } |
| if (m_aCurToken.eType != TLGROUP) |
| { |
| m_aNodeStack.Pop(); // get rid of the 'no space' node pushed above |
| Term(); |
| } |
| else |
| { |
| NextToken(); |
| |
| // allow for empty group |
| if (m_aCurToken.eType == TRGROUP) |
| { |
| if (bNoSpace) // get rid of the 'no space' node pushed above |
| m_aNodeStack.Pop(); |
| SmStructureNode *pSNode = new SmExpressionNode(m_aCurToken); |
| pSNode->SetSubNodes(NULL, NULL); |
| m_aNodeStack.Push(pSNode); |
| |
| NextToken(); |
| } |
| else // go as usual |
| { |
| Align(); |
| if (m_aCurToken.eType != TRGROUP) |
| Error(PE_RGROUP_EXPECTED); |
| else |
| NextToken(); |
| } |
| } |
| } |
| break; |
| |
| case TLEFT : |
| Brace(); |
| break; |
| |
| case TBLANK : |
| case TSBLANK : |
| Blank(); |
| break; |
| |
| case TTEXT : |
| m_aNodeStack.Push(new SmTextNode(m_aCurToken, FNT_TEXT)); |
| NextToken(); |
| break; |
| case TIDENT : |
| case TCHARACTER : |
| m_aNodeStack.Push(new SmTextNode(m_aCurToken, FNT_VARIABLE)); |
| NextToken(); |
| break; |
| case TNUMBER : |
| m_aNodeStack.Push(new SmTextNode(m_aCurToken, FNT_NUMBER)); |
| NextToken(); |
| break; |
| |
| case TLEFTARROW : |
| case TRIGHTARROW : |
| case TUPARROW : |
| case TDOWNARROW : |
| case TSETN : |
| case TSETZ : |
| case TSETQ : |
| case TSETR : |
| case TSETC : |
| case THBAR : |
| case TLAMBDABAR : |
| case TCIRC : |
| case TDRARROW : |
| case TDLARROW : |
| case TDLRARROW : |
| case TBACKEPSILON : |
| case TALEPH : |
| case TIM : |
| case TRE : |
| case TWP : |
| case TEMPTYSET : |
| case TINFINITY : |
| case TEXISTS : |
| case TFORALL : |
| case TPARTIAL : |
| case TNABLA : |
| case TTOWARD : |
| case TDOTSAXIS : |
| case TDOTSDIAG : |
| case TDOTSDOWN : |
| case TDOTSLOW : |
| case TDOTSUP : |
| case TDOTSVERT : |
| m_aNodeStack.Push(new SmMathSymbolNode(m_aCurToken)); |
| NextToken(); |
| break; |
| |
| case TPLACE: |
| m_aNodeStack.Push(new SmPlaceNode(m_aCurToken)); |
| NextToken(); |
| break; |
| |
| case TSPECIAL: |
| Special(); |
| break; |
| |
| case TBINOM: |
| Binom(); |
| break; |
| |
| case TSTACK: |
| Stack(); |
| break; |
| |
| case TMATRIX: |
| Matrix(); |
| break; |
| |
| default: |
| if (TokenInGroup(TGLBRACES)) |
| { Brace(); |
| } |
| else if (TokenInGroup(TGOPER)) |
| { Operator(); |
| } |
| else if (TokenInGroup(TGUNOPER)) |
| { UnOper(); |
| } |
| else if ( TokenInGroup(TGATTRIBUT) |
| || TokenInGroup(TGFONTATTR)) |
| { SmStructureNodeArray aArray; |
| |
| sal_Bool bIsAttr; |
| sal_uInt16 n = 0; |
| while (sal_True == (bIsAttr = TokenInGroup(TGATTRIBUT)) |
| || TokenInGroup(TGFONTATTR)) |
| { aArray.resize(n + 1); |
| |
| if (bIsAttr) |
| Attribut(); |
| else |
| FontAttribut(); |
| |
| // check if casting in following line is ok |
| DBG_ASSERT(!m_aNodeStack.Top()->IsVisible(), "Sm : Ooops..."); |
| |
| aArray[n] = (SmStructureNode *) m_aNodeStack.Pop(); |
| n++; |
| } |
| |
| Power(); |
| |
| SmNode *pFirstNode = m_aNodeStack.Pop(); |
| while (n > 0) |
| { aArray[n - 1]->SetSubNodes(0, pFirstNode); |
| pFirstNode = aArray[n - 1]; |
| n--; |
| } |
| m_aNodeStack.Push(pFirstNode); |
| } |
| else if (TokenInGroup(TGFUNCTION)) |
| { if (CONVERT_40_TO_50 != GetConversion()) |
| { Function(); |
| } |
| else // encapsulate old 4.0 style parsing in braces |
| { |
| // insert opening brace |
| Insert('{', GetTokenIndex()); |
| |
| // |
| // parse in 4.0 style |
| // |
| Function(); |
| |
| SmNode *pFunc = m_aNodeStack.Pop(); |
| |
| if (m_aCurToken.eType == TLPARENT) |
| { Term(); |
| } |
| else |
| { Align(); |
| } |
| |
| // insert closing brace |
| Insert('}', GetTokenIndex()); |
| |
| SmStructureNode *pSNode = new SmExpressionNode(pFunc->GetToken()); |
| pSNode->SetSubNodes(pFunc, m_aNodeStack.Pop()); |
| m_aNodeStack.Push(pSNode); |
| } |
| } |
| else |
| Error(PE_UNEXPECTED_CHAR); |
| } |
| } |
| |
| |
| void SmParser::Escape() |
| { |
| NextToken(); |
| |
| sal_Unicode cChar; |
| switch (m_aCurToken.eType) |
| { case TLPARENT : cChar = MS_LPARENT; break; |
| case TRPARENT : cChar = MS_RPARENT; break; |
| case TLBRACKET : cChar = MS_LBRACKET; break; |
| case TRBRACKET : cChar = MS_RBRACKET; break; |
| case TLDBRACKET : cChar = MS_LDBRACKET; break; |
| case TRDBRACKET : cChar = MS_RDBRACKET; break; |
| case TLBRACE : |
| case TLGROUP : cChar = MS_LBRACE; break; |
| case TRBRACE : |
| case TRGROUP : cChar = MS_RBRACE; break; |
| case TLANGLE : cChar = MS_LANGLE; break; |
| case TRANGLE : cChar = MS_RANGLE; break; |
| case TLCEIL : cChar = MS_LCEIL; break; |
| case TRCEIL : cChar = MS_RCEIL; break; |
| case TLFLOOR : cChar = MS_LFLOOR; break; |
| case TRFLOOR : cChar = MS_RFLOOR; break; |
| case TLLINE : |
| case TRLINE : cChar = MS_LINE; break; |
| case TLDLINE : |
| case TRDLINE : cChar = MS_DLINE; break; |
| default: |
| Error(PE_UNEXPECTED_TOKEN); |
| } |
| |
| SmNode *pNode = new SmMathSymbolNode(m_aCurToken); |
| m_aNodeStack.Push(pNode); |
| |
| NextToken(); |
| } |
| |
| |
| void SmParser::Operator() |
| { |
| if (TokenInGroup(TGOPER)) |
| { SmStructureNode *pSNode = new SmOperNode(m_aCurToken); |
| |
| // put operator on top of stack |
| Oper(); |
| |
| if (TokenInGroup(TGLIMIT) || TokenInGroup(TGPOWER)) |
| SubSup(m_aCurToken.nGroup); |
| SmNode *pOperator = m_aNodeStack.Pop(); |
| |
| // get argument |
| Power(); |
| |
| pSNode->SetSubNodes(pOperator, m_aNodeStack.Pop()); |
| m_aNodeStack.Push(pSNode); |
| } |
| } |
| |
| |
| void SmParser::Oper() |
| { |
| SmTokenType eType (m_aCurToken.eType); |
| SmNode *pNode = NULL; |
| |
| switch (eType) |
| { |
| case TSUM : |
| case TPROD : |
| case TCOPROD : |
| case TINT : |
| case TIINT : |
| case TIIINT : |
| case TLINT : |
| case TLLINT : |
| case TLLLINT : |
| pNode = new SmMathSymbolNode(m_aCurToken); |
| break; |
| |
| case TLIM : |
| case TLIMSUP : |
| case TLIMINF : |
| { |
| const sal_Char* pLim = 0; |
| switch (eType) |
| { |
| case TLIM : pLim = "lim"; break; |
| case TLIMSUP : pLim = "lim sup"; break; |
| case TLIMINF : pLim = "lim inf"; break; |
| default: |
| break; |
| } |
| if( pLim ) |
| m_aCurToken.aText.AssignAscii( pLim ); |
| pNode = new SmTextNode(m_aCurToken, FNT_TEXT); |
| } |
| break; |
| |
| case TOVERBRACE : |
| case TUNDERBRACE : |
| pNode = new SmMathSymbolNode(m_aCurToken); |
| break; |
| |
| case TOPER : |
| NextToken(); |
| |
| DBG_ASSERT(m_aCurToken.eType == TSPECIAL, "Sm: falsches Token"); |
| pNode = new SmGlyphSpecialNode(m_aCurToken); |
| break; |
| |
| default : |
| DBG_ASSERT(0, "Sm: unbekannter Fall"); |
| } |
| m_aNodeStack.Push(pNode); |
| |
| NextToken(); |
| } |
| |
| |
| void SmParser::UnOper() |
| { |
| DBG_ASSERT(TokenInGroup(TGUNOPER), "Sm: falsches Token"); |
| |
| SmToken aNodeToken = m_aCurToken; |
| SmTokenType eType = m_aCurToken.eType; |
| sal_Bool bIsPostfix = eType == TFACT; |
| |
| SmStructureNode *pSNode; |
| SmNode *pOper = 0, |
| *pExtra = 0, |
| *pArg; |
| |
| switch (eType) |
| { |
| case TABS : |
| case TSQRT : |
| NextToken(); |
| break; |
| |
| case TNROOT : |
| NextToken(); |
| Power(); |
| pExtra = m_aNodeStack.Pop(); |
| break; |
| |
| case TUOPER : |
| NextToken(); |
| GlyphSpecial(); |
| pOper = m_aNodeStack.Pop(); |
| break; |
| |
| case TPLUS : |
| case TMINUS : |
| case TPLUSMINUS : |
| case TMINUSPLUS : |
| case TNEG : |
| case TFACT : |
| OpSubSup(); |
| pOper = m_aNodeStack.Pop(); |
| break; |
| |
| default : |
| Error(PE_UNOPER_EXPECTED); |
| } |
| |
| // get argument |
| Power(); |
| pArg = m_aNodeStack.Pop(); |
| |
| if (eType == TABS) |
| { pSNode = new SmBraceNode(aNodeToken); |
| pSNode->SetScaleMode(SCALE_HEIGHT); |
| |
| // build nodes for left & right lines |
| // (text, group, level of the used token are of no interrest here) |
| // we'll use row & column of the keyword for abs |
| aNodeToken.eType = TABS; |
| // |
| aNodeToken.cMathChar = MS_LINE; |
| SmNode* pLeft = new SmMathSymbolNode(aNodeToken); |
| // |
| aNodeToken.cMathChar = MS_LINE; |
| SmNode* pRight = new SmMathSymbolNode(aNodeToken); |
| |
| pSNode->SetSubNodes(pLeft, pArg, pRight); |
| } |
| else if (eType == TSQRT || eType == TNROOT) |
| { pSNode = new SmRootNode(aNodeToken); |
| pOper = new SmRootSymbolNode(aNodeToken); |
| pSNode->SetSubNodes(pExtra, pOper, pArg); |
| } |
| else |
| { pSNode = new SmUnHorNode(aNodeToken); |
| |
| if (bIsPostfix) |
| pSNode->SetSubNodes(pArg, pOper); |
| else |
| // prefix operator |
| pSNode->SetSubNodes(pOper, pArg); |
| } |
| |
| m_aNodeStack.Push(pSNode); |
| } |
| |
| |
| void SmParser::Attribut() |
| { |
| DBG_ASSERT(TokenInGroup(TGATTRIBUT), "Sm: falsche Tokengruppe"); |
| |
| SmStructureNode *pSNode = new SmAttributNode(m_aCurToken); |
| SmNode *pAttr; |
| SmScaleMode eScaleMode = SCALE_NONE; |
| |
| // get appropriate node for the attribut itself |
| switch (m_aCurToken.eType) |
| { case TUNDERLINE : |
| case TOVERLINE : |
| case TOVERSTRIKE : |
| pAttr = new SmRectangleNode(m_aCurToken); |
| eScaleMode = SCALE_WIDTH; |
| break; |
| |
| case TWIDEVEC : |
| case TWIDEHAT : |
| case TWIDETILDE : |
| pAttr = new SmMathSymbolNode(m_aCurToken); |
| eScaleMode = SCALE_WIDTH; |
| break; |
| |
| default : |
| pAttr = new SmMathSymbolNode(m_aCurToken); |
| } |
| |
| NextToken(); |
| |
| pSNode->SetSubNodes(pAttr, 0); |
| pSNode->SetScaleMode(eScaleMode); |
| m_aNodeStack.Push(pSNode); |
| } |
| |
| |
| void SmParser::FontAttribut() |
| { |
| DBG_ASSERT(TokenInGroup(TGFONTATTR), "Sm: falsche Tokengruppe"); |
| |
| switch (m_aCurToken.eType) |
| { |
| case TITALIC : |
| case TNITALIC : |
| case TBOLD : |
| case TNBOLD : |
| case TPHANTOM : |
| m_aNodeStack.Push(new SmFontNode(m_aCurToken)); |
| NextToken(); |
| break; |
| |
| case TSIZE : |
| FontSize(); |
| break; |
| |
| case TFONT : |
| Font(); |
| break; |
| |
| case TCOLOR : |
| Color(); |
| break; |
| |
| default : |
| DBG_ASSERT(0, "Sm: unbekannter Fall"); |
| } |
| } |
| |
| |
| void SmParser::Color() |
| { |
| DBG_ASSERT(m_aCurToken.eType == TCOLOR, "Sm : Ooops..."); |
| |
| // last color rules, get that one |
| SmToken aToken; |
| do |
| { NextToken(); |
| |
| if (TokenInGroup(TGCOLOR)) |
| { aToken = m_aCurToken; |
| NextToken(); |
| } |
| else |
| Error(PE_COLOR_EXPECTED); |
| } while (m_aCurToken.eType == TCOLOR); |
| |
| m_aNodeStack.Push(new SmFontNode(aToken)); |
| } |
| |
| |
| void SmParser::Font() |
| { |
| DBG_ASSERT(m_aCurToken.eType == TFONT, "Sm : Ooops..."); |
| |
| // last font rules, get that one |
| SmToken aToken; |
| do |
| { NextToken(); |
| |
| if (TokenInGroup(TGFONT)) |
| { aToken = m_aCurToken; |
| NextToken(); |
| } |
| else |
| Error(PE_FONT_EXPECTED); |
| } while (m_aCurToken.eType == TFONT); |
| |
| m_aNodeStack.Push(new SmFontNode(aToken)); |
| } |
| |
| |
| // gets number used as arguments in Math formulas (e.g. 'size' command) |
| // Format: no negative numbers, must start with a digit, no exponent notation, ... |
| sal_Bool lcl_IsNumber(const UniString& rText) |
| { |
| sal_Bool bPoint = sal_False; |
| const sal_Unicode* pBuffer = rText.GetBuffer(); |
| for(xub_StrLen nPos = 0; nPos < rText.Len(); nPos++, pBuffer++) |
| { |
| const sal_Unicode cChar = *pBuffer; |
| if(cChar == '.') |
| { |
| if(bPoint) |
| return sal_False; |
| else |
| bPoint = sal_True; |
| } |
| else if ( !IsDigit( cChar ) ) |
| return sal_False; |
| } |
| return sal_True; |
| } |
| |
| void SmParser::FontSize() |
| { |
| DBG_ASSERT(m_aCurToken.eType == TSIZE, "Sm : Ooops..."); |
| |
| sal_uInt16 Type; |
| SmFontNode *pFontNode = new SmFontNode(m_aCurToken); |
| |
| NextToken(); |
| |
| switch (m_aCurToken.eType) |
| { |
| case TNUMBER: Type = FNTSIZ_ABSOLUT; break; |
| case TPLUS: Type = FNTSIZ_PLUS; break; |
| case TMINUS: Type = FNTSIZ_MINUS; break; |
| case TMULTIPLY: Type = FNTSIZ_MULTIPLY; break; |
| case TDIVIDEBY: Type = FNTSIZ_DIVIDE; break; |
| |
| default: |
| delete pFontNode; |
| Error(PE_SIZE_EXPECTED); |
| return; |
| } |
| |
| if (Type != FNTSIZ_ABSOLUT) |
| { |
| NextToken(); |
| if (m_aCurToken.eType != TNUMBER) |
| { |
| delete pFontNode; |
| Error(PE_SIZE_EXPECTED); |
| return; |
| } |
| } |
| |
| // get number argument |
| Fraction aValue( 1L ); |
| if (lcl_IsNumber( m_aCurToken.aText )) |
| { |
| double fTmp; |
| if ((fTmp = m_aCurToken.aText.ToDouble()) != 0.0) |
| { |
| aValue = fTmp; |
| |
| //!! keep the numerator and denominator from being to large |
| //!! otherwise ongoing multiplications may result in overflows |
| //!! (for example in SmNode::SetFontSize the font size calculated |
| //!! may become 0 because of this!!! Happens e.g. for ftmp = 2.9 with Linux |
| //!! or ftmp = 1.11111111111111111... (11/9) on every platform.) |
| if (aValue.GetDenominator() > 1000) |
| { |
| long nNum = aValue.GetNumerator(); |
| long nDenom = aValue.GetDenominator(); |
| while (nDenom > 1000) |
| { |
| nNum /= 10; |
| nDenom /= 10; |
| } |
| aValue = Fraction( nNum, nDenom ); |
| } |
| } |
| } |
| |
| NextToken(); |
| |
| pFontNode->SetSizeParameter(aValue, Type); |
| m_aNodeStack.Push(pFontNode); |
| } |
| |
| |
| void SmParser::Brace() |
| { |
| DBG_ASSERT(m_aCurToken.eType == TLEFT || TokenInGroup(TGLBRACES), |
| "Sm: kein Klammer Ausdruck"); |
| |
| SmStructureNode *pSNode = new SmBraceNode(m_aCurToken); |
| SmNode *pBody = 0, |
| *pLeft = 0, |
| *pRight = 0; |
| SmScaleMode eScaleMode = SCALE_NONE; |
| SmParseError eError = PE_NONE; |
| |
| if (m_aCurToken.eType == TLEFT) |
| { NextToken(); |
| |
| eScaleMode = SCALE_HEIGHT; |
| |
| // check for left bracket |
| if (TokenInGroup(TGLBRACES) || TokenInGroup(TGRBRACES)) |
| { |
| pLeft = new SmMathSymbolNode(m_aCurToken); |
| |
| NextToken(); |
| Bracebody(sal_True); |
| pBody = m_aNodeStack.Pop(); |
| |
| if (m_aCurToken.eType == TRIGHT) |
| { NextToken(); |
| |
| // check for right bracket |
| if (TokenInGroup(TGLBRACES) || TokenInGroup(TGRBRACES)) |
| { |
| pRight = new SmMathSymbolNode(m_aCurToken); |
| NextToken(); |
| } |
| else |
| eError = PE_RBRACE_EXPECTED; |
| } |
| else |
| eError = PE_RIGHT_EXPECTED; |
| } |
| else |
| eError = PE_LBRACE_EXPECTED; |
| } |
| else |
| { |
| if (TokenInGroup(TGLBRACES)) |
| { |
| pLeft = new SmMathSymbolNode(m_aCurToken); |
| |
| NextToken(); |
| Bracebody(sal_False); |
| pBody = m_aNodeStack.Pop(); |
| |
| SmTokenType eExpectedType = TUNKNOWN; |
| switch (pLeft->GetToken().eType) |
| { case TLPARENT : eExpectedType = TRPARENT; break; |
| case TLBRACKET : eExpectedType = TRBRACKET; break; |
| case TLBRACE : eExpectedType = TRBRACE; break; |
| case TLDBRACKET : eExpectedType = TRDBRACKET; break; |
| case TLLINE : eExpectedType = TRLINE; break; |
| case TLDLINE : eExpectedType = TRDLINE; break; |
| case TLANGLE : eExpectedType = TRANGLE; break; |
| case TLFLOOR : eExpectedType = TRFLOOR; break; |
| case TLCEIL : eExpectedType = TRCEIL; break; |
| default : |
| DBG_ASSERT(0, "Sm: unbekannter Fall"); |
| } |
| |
| if (m_aCurToken.eType == eExpectedType) |
| { |
| pRight = new SmMathSymbolNode(m_aCurToken); |
| NextToken(); |
| } |
| else |
| eError = PE_PARENT_MISMATCH; |
| } |
| else |
| eError = PE_LBRACE_EXPECTED; |
| } |
| |
| if (eError == PE_NONE) |
| { DBG_ASSERT(pLeft, "Sm: NULL pointer"); |
| DBG_ASSERT(pRight, "Sm: NULL pointer"); |
| pSNode->SetSubNodes(pLeft, pBody, pRight); |
| pSNode->SetScaleMode(eScaleMode); |
| m_aNodeStack.Push(pSNode); |
| } |
| else |
| { delete pSNode; |
| delete pBody; |
| delete pLeft; |
| delete pRight; |
| |
| Error(eError); |
| } |
| } |
| |
| |
| void SmParser::Bracebody(sal_Bool bIsLeftRight) |
| { |
| SmStructureNode *pBody = new SmBracebodyNode(m_aCurToken); |
| SmNodeArray aNodes; |
| sal_uInt16 nNum = 0; |
| |
| // get body if any |
| if (bIsLeftRight) |
| { |
| do |
| { |
| if (m_aCurToken.eType == TMLINE) |
| { |
| m_aNodeStack.Push(new SmMathSymbolNode(m_aCurToken)); |
| NextToken(); |
| nNum++; |
| } |
| else if (m_aCurToken.eType != TRIGHT) |
| { Align(); |
| nNum++; |
| |
| if (m_aCurToken.eType != TMLINE && m_aCurToken.eType != TRIGHT) |
| Error(PE_RIGHT_EXPECTED); |
| } |
| } while (m_aCurToken.eType != TEND && m_aCurToken.eType != TRIGHT); |
| } |
| else |
| { |
| do |
| { |
| if (m_aCurToken.eType == TMLINE) |
| { |
| m_aNodeStack.Push(new SmMathSymbolNode(m_aCurToken)); |
| NextToken(); |
| nNum++; |
| } |
| else if (!TokenInGroup(TGRBRACES)) |
| { Align(); |
| nNum++; |
| |
| if (m_aCurToken.eType != TMLINE && !TokenInGroup(TGRBRACES)) |
| Error(PE_RBRACE_EXPECTED); |
| } |
| } while (m_aCurToken.eType != TEND && !TokenInGroup(TGRBRACES)); |
| } |
| |
| // build argument vector in parsing order |
| aNodes.resize(nNum); |
| for (sal_uInt16 i = 0; i < nNum; i++) |
| aNodes[nNum - 1 - i] = m_aNodeStack.Pop(); |
| |
| pBody->SetSubNodes(aNodes); |
| pBody->SetScaleMode(bIsLeftRight ? SCALE_HEIGHT : SCALE_NONE); |
| m_aNodeStack.Push(pBody); |
| } |
| |
| |
| void SmParser::Function() |
| { |
| switch (m_aCurToken.eType) |
| { |
| case TFUNC: |
| NextToken(); // skip "FUNC"-statement |
| // fall through |
| |
| case TSIN : |
| case TCOS : |
| case TTAN : |
| case TCOT : |
| case TASIN : |
| case TACOS : |
| case TATAN : |
| case TACOT : |
| case TSINH : |
| case TCOSH : |
| case TTANH : |
| case TCOTH : |
| case TASINH : |
| case TACOSH : |
| case TATANH : |
| case TACOTH : |
| case TLN : |
| case TLOG : |
| case TEXP : |
| m_aNodeStack.Push(new SmTextNode(m_aCurToken, FNT_FUNCTION)); |
| NextToken(); |
| break; |
| |
| default: |
| Error(PE_FUNC_EXPECTED); |
| } |
| } |
| |
| |
| void SmParser::Binom() |
| { |
| SmNodeArray ExpressionArray; |
| SmStructureNode *pSNode = new SmTableNode(m_aCurToken); |
| |
| NextToken(); |
| |
| Sum(); |
| Sum(); |
| |
| ExpressionArray.resize(2); |
| |
| for (int i = 0; i < 2; i++) |
| ExpressionArray[2 - (i + 1)] = m_aNodeStack.Pop(); |
| |
| pSNode->SetSubNodes(ExpressionArray); |
| m_aNodeStack.Push(pSNode); |
| } |
| |
| |
| void SmParser::Stack() |
| { |
| SmNodeArray ExpressionArray; |
| NextToken(); |
| if (m_aCurToken.eType == TLGROUP) |
| { |
| sal_uInt16 n = 0; |
| |
| do |
| { |
| NextToken(); |
| Align(); |
| n++; |
| } |
| while (m_aCurToken.eType == TPOUND); |
| |
| ExpressionArray.resize(n); |
| |
| for (sal_uInt16 i = 0; i < n; i++) |
| ExpressionArray[n - (i + 1)] = m_aNodeStack.Pop(); |
| |
| if (m_aCurToken.eType != TRGROUP) |
| Error(PE_RGROUP_EXPECTED); |
| |
| NextToken(); |
| |
| SmStructureNode *pSNode = new SmTableNode(m_aCurToken); |
| pSNode->SetSubNodes(ExpressionArray); |
| m_aNodeStack.Push(pSNode); |
| } |
| else |
| Error(PE_LGROUP_EXPECTED); |
| } |
| |
| |
| void SmParser::Matrix() |
| { |
| SmNodeArray ExpressionArray; |
| |
| NextToken(); |
| if (m_aCurToken.eType == TLGROUP) |
| { |
| sal_uInt16 c = 0; |
| |
| do |
| { |
| NextToken(); |
| Align(); |
| c++; |
| } |
| while (m_aCurToken.eType == TPOUND); |
| |
| sal_uInt16 r = 1; |
| |
| while (m_aCurToken.eType == TDPOUND) |
| { |
| NextToken(); |
| for (sal_uInt16 i = 0; i < c; i++) |
| { |
| Align(); |
| if (i < (c - 1)) |
| { |
| if (m_aCurToken.eType == TPOUND) |
| { |
| NextToken(); |
| } |
| else |
| Error(PE_POUND_EXPECTED); |
| } |
| } |
| |
| r++; |
| } |
| |
| long nRC = r * c; |
| |
| ExpressionArray.resize(nRC); |
| |
| for (sal_uInt16 i = 0; i < (nRC); i++) |
| ExpressionArray[(nRC) - (i + 1)] = m_aNodeStack.Pop(); |
| |
| if (m_aCurToken.eType != TRGROUP) |
| Error(PE_RGROUP_EXPECTED); |
| |
| NextToken(); |
| |
| SmMatrixNode *pMNode = new SmMatrixNode(m_aCurToken); |
| pMNode->SetSubNodes(ExpressionArray); |
| pMNode->SetRowCol(r, c); |
| m_aNodeStack.Push(pMNode); |
| } |
| else |
| Error(PE_LGROUP_EXPECTED); |
| } |
| |
| |
| void SmParser::Special() |
| { |
| sal_Bool bReplace = sal_False; |
| String &rName = m_aCurToken.aText; |
| String aNewName; |
| |
| if (CONVERT_NONE == GetConversion()) |
| { |
| // conversion of symbol names for 6.0 (XML) file format |
| // (name change on import / export. |
| // UI uses localized names XML file format does not.) |
| if( rName.Len() && rName.GetChar( 0 ) == sal_Unicode( '%' ) ) |
| { |
| if (IsImportSymbolNames()) |
| { |
| const SmLocalizedSymbolData &rLSD = SM_MOD()->GetLocSymbolData(); |
| aNewName = rLSD.GetUiSymbolName( rName.Copy( 1 ) ); |
| bReplace = sal_True; |
| } |
| else if (IsExportSymbolNames()) |
| { |
| const SmLocalizedSymbolData &rLSD = SM_MOD()->GetLocSymbolData(); |
| aNewName = rLSD.GetExportSymbolName( rName.Copy( 1 ) ); |
| bReplace = sal_True; |
| } |
| } |
| if( aNewName.Len() ) |
| aNewName.Insert( '%', 0 ); |
| } |
| else // 5.0 <-> 6.0 formula text (symbol name) conversion |
| { |
| LanguageType nLanguage = GetLanguage(); |
| SmLocalizedSymbolData &rData = SM_MOD()->GetLocSymbolData(); |
| const ResStringArray *pFrom = 0; |
| const ResStringArray *pTo = 0; |
| if (CONVERT_50_TO_60 == GetConversion()) |
| { |
| pFrom = rData.Get50NamesArray( nLanguage ); |
| pTo = rData.Get60NamesArray( nLanguage ); |
| } |
| else if (CONVERT_60_TO_50 == GetConversion()) |
| { |
| pFrom = rData.Get60NamesArray( nLanguage ); |
| pTo = rData.Get50NamesArray( nLanguage ); |
| } |
| if (pFrom && pTo) |
| { |
| DBG_ASSERT( pFrom->Count() == pTo->Count(), |
| "array length mismatch" ); |
| sal_uInt16 nCount = sal::static_int_cast< sal_uInt16 >(pFrom->Count()); |
| for (sal_uInt16 i = 0; i < nCount; ++i) |
| { |
| if (pFrom->GetString(i) == rName) |
| { |
| aNewName = pTo->GetString(i); |
| bReplace = sal_True; |
| } |
| } |
| } |
| // else: |
| // conversion arrays not found or (usually) |
| // conversion not necessary |
| } |
| |
| if (bReplace && aNewName.Len() && rName != aNewName) |
| { |
| Replace( GetTokenIndex(), rName.Len(), aNewName ); |
| rName = aNewName; |
| } |
| |
| // add symbol name to list of used symbols |
| const String aSymbolName( m_aCurToken.aText.Copy( 1 ) ); |
| if (aSymbolName.Len() > 0 ) |
| AddToUsedSymbols( aSymbolName ); |
| |
| m_aNodeStack.Push(new SmSpecialNode(m_aCurToken)); |
| NextToken(); |
| } |
| |
| |
| void SmParser::GlyphSpecial() |
| { |
| m_aNodeStack.Push(new SmGlyphSpecialNode(m_aCurToken)); |
| NextToken(); |
| } |
| |
| |
| void SmParser::Error(SmParseError eError) |
| { |
| SmStructureNode *pSNode = new SmExpressionNode(m_aCurToken); |
| SmErrorNode *pErr = new SmErrorNode(eError, m_aCurToken); |
| pSNode->SetSubNodes(pErr, 0); |
| |
| //! put a structure node on the stack (instead of the error node itself) |
| //! because sometimes such a node is expected in order to attach some |
| //! subnodes |
| m_aNodeStack.Push(pSNode); |
| |
| AddError(eError, pSNode); |
| |
| NextToken(); |
| } |
| |
| |
| // end gramar |
| |
| |
| SmParser::SmParser() |
| { |
| m_eConversion = CONVERT_NONE; |
| m_bImportSymNames = m_bExportSymNames = sal_False; |
| m_nLang = Application::GetSettings().GetUILanguage(); |
| } |
| |
| |
| SmNode *SmParser::Parse(const String &rBuffer) |
| { |
| ClearUsedSymbols(); |
| |
| m_aBufferString = rBuffer; |
| m_aBufferString.ConvertLineEnd( LINEEND_LF ); |
| m_nBufferIndex = |
| m_nTokenIndex = 0; |
| m_Row = 1; |
| m_nColOff = 0; |
| m_nCurError = -1; |
| |
| for (sal_uInt16 i = 0; i < m_aErrDescList.Count(); i++) |
| delete m_aErrDescList.Remove(i); |
| |
| m_aErrDescList.Clear(); |
| |
| m_aNodeStack.Clear(); |
| |
| SetLanguage( Application::GetSettings().GetUILanguage() ); |
| NextToken(); |
| Table(); |
| |
| return m_aNodeStack.Pop(); |
| } |
| |
| |
| sal_uInt16 SmParser::AddError(SmParseError Type, SmNode *pNode) |
| { |
| SmErrorDesc *pErrDesc = new SmErrorDesc; |
| |
| pErrDesc->Type = Type; |
| pErrDesc->pNode = pNode; |
| pErrDesc->Text = String(SmResId(RID_ERR_IDENT)); |
| |
| sal_uInt16 nRID; |
| switch (Type) |
| { |
| case PE_UNEXPECTED_CHAR: nRID = RID_ERR_UNEXPECTEDCHARACTER; break; |
| case PE_LGROUP_EXPECTED: nRID = RID_ERR_LGROUPEXPECTED; break; |
| case PE_RGROUP_EXPECTED: nRID = RID_ERR_RGROUPEXPECTED; break; |
| case PE_LBRACE_EXPECTED: nRID = RID_ERR_LBRACEEXPECTED; break; |
| case PE_RBRACE_EXPECTED: nRID = RID_ERR_RBRACEEXPECTED; break; |
| case PE_FUNC_EXPECTED: nRID = RID_ERR_FUNCEXPECTED; break; |
| case PE_UNOPER_EXPECTED: nRID = RID_ERR_UNOPEREXPECTED; break; |
| case PE_BINOPER_EXPECTED: nRID = RID_ERR_BINOPEREXPECTED; break; |
| case PE_SYMBOL_EXPECTED: nRID = RID_ERR_SYMBOLEXPECTED; break; |
| case PE_IDENTIFIER_EXPECTED: nRID = RID_ERR_IDENTEXPECTED; break; |
| case PE_POUND_EXPECTED: nRID = RID_ERR_POUNDEXPECTED; break; |
| case PE_COLOR_EXPECTED: nRID = RID_ERR_COLOREXPECTED; break; |
| case PE_RIGHT_EXPECTED: nRID = RID_ERR_RIGHTEXPECTED; break; |
| |
| default: |
| nRID = RID_ERR_UNKOWN; |
| } |
| pErrDesc->Text += SmResId(nRID); |
| |
| m_aErrDescList.Insert(pErrDesc); |
| |
| return (sal_uInt16) m_aErrDescList.GetPos(pErrDesc); |
| } |
| |
| |
| const SmErrorDesc *SmParser::NextError() |
| { |
| if (m_aErrDescList.Count()) |
| if (m_nCurError > 0) return m_aErrDescList.Seek(--m_nCurError); |
| else |
| { |
| m_nCurError = 0; |
| return m_aErrDescList.Seek(m_nCurError); |
| } |
| else return 0; |
| } |
| |
| |
| const SmErrorDesc *SmParser::PrevError() |
| { |
| if (m_aErrDescList.Count()) |
| if (m_nCurError < (int) (m_aErrDescList.Count() - 1)) return m_aErrDescList.Seek(++m_nCurError); |
| else |
| { |
| m_nCurError = (int) (m_aErrDescList.Count() - 1); |
| return m_aErrDescList.Seek(m_nCurError); |
| } |
| else return 0; |
| } |
| |
| |
| const SmErrorDesc *SmParser::GetError(sal_uInt16 i) |
| { |
| return (/*i >= 0 &&*/ i < m_aErrDescList.Count()) |
| ? m_aErrDescList.Seek(i) |
| : m_aErrDescList.Seek(m_nCurError); |
| } |
| |
| |