summaryrefslogtreecommitdiff
path: root/starmath/source/parse.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'starmath/source/parse.cxx')
-rw-r--r--starmath/source/parse.cxx2475
1 files changed, 2475 insertions, 0 deletions
diff --git a/starmath/source/parse.cxx b/starmath/source/parse.cxx
new file mode 100644
index 000000000000..1955b0553b62
--- /dev/null
+++ b/starmath/source/parse.cxx
@@ -0,0 +1,2475 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 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 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 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;
+ ULONG nGroup;
+ USHORT 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},
+ { "notin", TNOTIN, MS_NOTIN, TGRELATION, 0},
+ { "nsubset", TNSUBSET, MS_NSUBSET, TGRELATION, 0 },
+ { "nsupset", TNSUPSET, MS_NSUPSET, TGRELATION, 0 },
+ { "nsubseteq", TNSUBSETEQ, MS_NSUBSETEQ, TGRELATION, 0 },
+ { "nsupseteq", TNSUPSETEQ, MS_NSUPSETEQ, TGRELATION, 0 },
+ { "nroot", TNROOT, MS_SQRT, TGUNOPER, 5},
+ { "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())
+ {
+ INT32 nEntries = sizeof( aTokenTable ) / sizeof( aTokenTable[0] );
+ for (INT32 i = 0; i < nEntries; ++i)
+ {
+ if (rName.EqualsIgnoreCaseAscii( aTokenTable[i].pIdent ))
+ {
+ pRes = &aTokenTable[i];
+ break;
+ }
+ }
+
+ }
+
+ return pRes;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+#if OSL_DEBUG_LEVEL
+
+BOOL SmParser::IsDelimiter( const String &rTxt, xub_StrLen nPos )
+ // returns '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 TRUE;
+
+ // check if 'cChar' is in the delimeter table
+ const sal_Unicode *pDelim = &aDelimiterTable[0];
+ for ( ; *pDelim != 0; pDelim++)
+ if (*pDelim == cChar)
+ break;
+
+ BOOL bIsDelim = *pDelim != 0;
+
+ INT16 nTypJp = SM_MOD1()->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, USHORT nPos)
+{
+ BufferString.Insert(rText, nPos);
+
+ xub_StrLen nLen = rText.Len();
+ BufferIndex = BufferIndex + nLen;
+ nTokenIndex = nTokenIndex + nLen;
+}
+
+
+void SmParser::Replace( USHORT nPos, USHORT nLen, const String &rText )
+{
+ DBG_ASSERT( nPos + nLen <= BufferString.Len(), "argument mismatch" );
+
+ BufferString.Replace( nPos, nLen, rText );
+ INT16 nChg = rText.Len() - nLen;
+ BufferIndex = BufferIndex + nChg;
+ nTokenIndex = 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 = BufferString.Len();
+ ParseResult aRes;
+ xub_StrLen nRealStart;
+ BOOL bCont;
+ BOOL bNumStart = FALSE;
+ CharClass aCC(SM_MOD1()->GetSysLocale().GetCharClass().getLocale());
+ do
+ {
+ // skip white spaces
+ while (UnicodeType::SPACE_SEPARATOR ==
+ aCC.getType( BufferString, BufferIndex ))
+ ++BufferIndex;
+
+ sal_Int32 nStartFlags = coStartFlags;
+ sal_Int32 nContFlags = coContFlags;
+ sal_Unicode cFirstChar = BufferString.GetChar( BufferIndex );
+/*
+ removed because of #i11752#
+ bNumStart = cFirstChar == '.' || ('0' <= cFirstChar && cFirstChar <= '9');
+ if (bNumStart)
+ {
+ nStartFlags = coNumStartFlags;
+ nContFlags = coNumContFlags;
+ }
+*/
+ aRes = aCC.parseAnyToken( BufferString, BufferIndex,
+ 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,
+ BufferString, BufferIndex,
+ 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 = BufferIndex + sal::static_int_cast< xub_StrLen >(aRes.LeadingWhiteSpace);
+ BufferIndex = nRealStart;
+
+ bCont = FALSE;
+ if ( aRes.TokenType == 0 &&
+ nRealStart < nBufLen &&
+ '\n' == BufferString.GetChar( nRealStart ) )
+ {
+ // keep data needed for tokens row and col entry up to date
+ ++Row;
+ BufferIndex = ColOff = nRealStart + 1;
+ bCont = TRUE;
+ }
+ else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR)
+ {
+ String aName( BufferString.Copy( nRealStart, 2 ));
+ if ( aName.EqualsAscii( "%%" ))
+ {
+ //SkipComment
+ BufferIndex = nRealStart + 2;
+ while (BufferIndex < nBufLen &&
+ '\n' != BufferString.GetChar( BufferIndex ))
+ ++BufferIndex;
+ bCont = TRUE;
+ }
+ }
+
+ } while (bCont);
+
+ // set index of current token
+ nTokenIndex = BufferIndex;
+
+ CurToken.nRow = Row;
+ CurToken.nCol = nRealStart - ColOff + 1;
+
+ BOOL bHandled = TRUE;
+ if (nRealStart >= nBufLen)
+ {
+ CurToken.eType = TEND;
+ CurToken.cMathChar = '\0';
+ CurToken.nGroup = 0;
+ CurToken.nLevel = 0;
+ CurToken.aText.Erase();
+ }
+ else if ((aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER))
+ || (bNumStart && (aRes.TokenType & KParseType::IDENTNAME)))
+ {
+ INT32 n = aRes.EndPos - nRealStart;
+ DBG_ASSERT( n >= 0, "length < 0" );
+ CurToken.eType = TNUMBER;
+ CurToken.cMathChar = '\0';
+ CurToken.nGroup = 0;
+ CurToken.nLevel = 5;
+ CurToken.aText = BufferString.Copy( nRealStart, sal::static_int_cast< xub_StrLen >(n) );
+
+#if OSL_DEBUG_LEVEL > 1
+ if (!IsDelimiter( BufferString, static_cast< xub_StrLen >(aRes.EndPos) ))
+ {
+ DBG_WARNING( "identifier really finished? (compatibility!)" );
+ }
+#endif
+ }
+ else if (aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING)
+ {
+ CurToken.eType = TTEXT;
+ CurToken.cMathChar = '\0';
+ CurToken.nGroup = 0;
+ CurToken.nLevel = 5;
+ CurToken.aText = aRes.DequotedNameOrString;
+ CurToken.nRow = Row;
+ CurToken.nCol = nRealStart - ColOff + 2;
+ }
+ else if (aRes.TokenType & KParseType::IDENTNAME)
+ {
+ INT32 n = aRes.EndPos - nRealStart;
+ DBG_ASSERT( n >= 0, "length < 0" );
+ String aName( BufferString.Copy( nRealStart, sal::static_int_cast< xub_StrLen >(n) ) );
+ const SmTokenTableEntry *pEntry = GetTokenTableEntry( aName );
+
+ if (pEntry)
+ {
+ CurToken.eType = pEntry->eType;
+ CurToken.cMathChar = pEntry->cMathChar;
+ CurToken.nGroup = pEntry->nGroup;
+ CurToken.nLevel = pEntry->nLevel;
+ CurToken.aText.AssignAscii( pEntry->pIdent );
+ }
+ else
+ {
+ CurToken.eType = TIDENT;
+ CurToken.cMathChar = '\0';
+ CurToken.nGroup = 0;
+ CurToken.nLevel = 5;
+ CurToken.aText = aName;
+
+#if OSL_DEBUG_LEVEL > 1
+ if (!IsDelimiter( BufferString, static_cast< xub_StrLen >(aRes.EndPos) ))
+ {
+ DBG_WARNING( "identifier really finished? (compatibility!)" );
+ }
+#endif
+ }
+ }
+ else if (aRes.TokenType == 0 && '_' == BufferString.GetChar( nRealStart ))
+ {
+ CurToken.eType = TRSUB;
+ CurToken.cMathChar = '\0';
+ CurToken.nGroup = TGPOWER;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "_" );
+
+ aRes.EndPos = nRealStart + 1;
+ }
+ else if (aRes.TokenType & KParseType::BOOLEAN)
+ {
+ sal_Int32 &rnEndPos = aRes.EndPos;
+ String aName( BufferString.Copy( nRealStart,
+ sal::static_int_cast< xub_StrLen >(rnEndPos - nRealStart) ));
+ if (2 >= aName.Len())
+ {
+ sal_Unicode ch = aName.GetChar( 0 );
+ switch (ch)
+ {
+ case '<':
+ {
+ if (BufferString.Copy( nRealStart, 2 ).
+ EqualsAscii( "<<" ))
+ {
+ CurToken.eType = TLL;
+ CurToken.cMathChar = MS_LL;
+ CurToken.nGroup = TGRELATION;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "<<" );
+
+ rnEndPos = nRealStart + 2;
+ }
+ else if (BufferString.Copy( nRealStart, 2 ).
+ EqualsAscii( "<=" ))
+ {
+ CurToken.eType = TLE;
+ CurToken.cMathChar = MS_LE;
+ CurToken.nGroup = TGRELATION;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "<=" );
+
+ rnEndPos = nRealStart + 2;
+ }
+ else if (BufferString.Copy( nRealStart, 2 ).
+ EqualsAscii( "<>" ))
+ {
+ CurToken.eType = TNEQ;
+ CurToken.cMathChar = MS_NEQ;
+ CurToken.nGroup = TGRELATION;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "<>" );
+
+ rnEndPos = nRealStart + 2;
+ }
+ else if (BufferString.Copy( nRealStart, 3 ).
+ EqualsAscii( "<?>" ))
+ {
+ CurToken.eType = TPLACE;
+ CurToken.cMathChar = MS_PLACE;
+ CurToken.nGroup = 0;
+ CurToken.nLevel = 5;
+ CurToken.aText.AssignAscii( "<?>" );
+
+ rnEndPos = nRealStart + 3;
+ }
+ else
+ {
+ CurToken.eType = TLT;
+ CurToken.cMathChar = MS_LT;
+ CurToken.nGroup = TGRELATION;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "<" );
+ }
+ }
+ break;
+ case '>':
+ {
+ if (BufferString.Copy( nRealStart, 2 ).
+ EqualsAscii( ">=" ))
+ {
+ CurToken.eType = TGE;
+ CurToken.cMathChar = MS_GE;
+ CurToken.nGroup = TGRELATION;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( ">=" );
+
+ rnEndPos = nRealStart + 2;
+ }
+ else if (BufferString.Copy( nRealStart, 2 ).
+ EqualsAscii( ">>" ))
+ {
+ CurToken.eType = TGG;
+ CurToken.cMathChar = MS_GG;
+ CurToken.nGroup = TGRELATION;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( ">>" );
+
+ rnEndPos = nRealStart + 2;
+ }
+ else
+ {
+ CurToken.eType = TGT;
+ CurToken.cMathChar = MS_GT;
+ CurToken.nGroup = TGRELATION;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( ">" );
+ }
+ }
+ break;
+ default:
+ bHandled = FALSE;
+ }
+ }
+ }
+ else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR)
+ {
+ sal_Int32 &rnEndPos = aRes.EndPos;
+ String aName( BufferString.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 ||
+ '%' != BufferString.GetChar( sal::static_int_cast< xub_StrLen >(rnEndPos) ),
+ "unexpected comment start" );
+
+ // get identifier of user-defined character
+ ParseResult aTmpRes = aCC.parseAnyToken(
+ BufferString, rnEndPos,
+ KParseTokens::ANY_LETTER,
+ aEmptyStr,
+ coContFlags,
+ aEmptyStr );
+
+ xub_StrLen nTmpStart = sal::static_int_cast< xub_StrLen >(rnEndPos +
+ aTmpRes.LeadingWhiteSpace);
+
+ // default setting fo the case that no identifier
+ // i.e. a valid symbol-name is following the '%'
+ // character
+ CurToken.eType = TTEXT;
+ CurToken.cMathChar = '\0';
+ CurToken.nGroup = 0;
+ CurToken.nLevel = 5;
+ CurToken.aText = String();
+ CurToken.nRow = sal::static_int_cast< xub_StrLen >(Row);
+ CurToken.nCol = nTmpStart - ColOff + 1;
+
+ if (aTmpRes.TokenType & KParseType::IDENTNAME)
+ {
+
+ xub_StrLen n = sal::static_int_cast< xub_StrLen >(aTmpRes.EndPos - nTmpStart);
+ CurToken.eType = TSPECIAL;
+ CurToken.aText = BufferString.Copy( sal::static_int_cast< xub_StrLen >(nTmpStart), n );
+
+ 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 '[':
+ {
+ CurToken.eType = TLBRACKET;
+ CurToken.cMathChar = MS_LBRACKET;
+ CurToken.nGroup = TGLBRACES;
+ CurToken.nLevel = 5;
+ CurToken.aText.AssignAscii( "[" );
+ }
+ break;
+ case '\\':
+ {
+ CurToken.eType = TESCAPE;
+ CurToken.cMathChar = '\0';
+ CurToken.nGroup = 0;
+ CurToken.nLevel = 5;
+ CurToken.aText.AssignAscii( "\\" );
+ }
+ break;
+ case ']':
+ {
+ CurToken.eType = TRBRACKET;
+ CurToken.cMathChar = MS_RBRACKET;
+ CurToken.nGroup = TGRBRACES;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "]" );
+ }
+ break;
+ case '^':
+ {
+ CurToken.eType = TRSUP;
+ CurToken.cMathChar = '\0';
+ CurToken.nGroup = TGPOWER;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "^" );
+ }
+ break;
+ case '`':
+ {
+ CurToken.eType = TSBLANK;
+ CurToken.cMathChar = '\0';
+ CurToken.nGroup = TGBLANK;
+ CurToken.nLevel = 5;
+ CurToken.aText.AssignAscii( "`" );
+ }
+ break;
+ case '{':
+ {
+ CurToken.eType = TLGROUP;
+ CurToken.cMathChar = MS_LBRACE;
+ CurToken.nGroup = 0;
+ CurToken.nLevel = 5;
+ CurToken.aText.AssignAscii( "{" );
+ }
+ break;
+ case '|':
+ {
+ CurToken.eType = TOR;
+ CurToken.cMathChar = MS_OR;
+ CurToken.nGroup = TGSUM;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "|" );
+ }
+ break;
+ case '}':
+ {
+ CurToken.eType = TRGROUP;
+ CurToken.cMathChar = MS_RBRACE;
+ CurToken.nGroup = 0;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "}" );
+ }
+ break;
+ case '~':
+ {
+ CurToken.eType = TBLANK;
+ CurToken.cMathChar = '\0';
+ CurToken.nGroup = TGBLANK;
+ CurToken.nLevel = 5;
+ CurToken.aText.AssignAscii( "~" );
+ }
+ break;
+ case '#':
+ {
+ if (BufferString.Copy( nRealStart, 2 ).
+ EqualsAscii( "##" ))
+ {
+ CurToken.eType = TDPOUND;
+ CurToken.cMathChar = '\0';
+ CurToken.nGroup = 0;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "##" );
+
+ rnEndPos = nRealStart + 2;
+ }
+ else
+ {
+ CurToken.eType = TPOUND;
+ CurToken.cMathChar = '\0';
+ CurToken.nGroup = 0;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "#" );
+ }
+ }
+ break;
+ case '&':
+ {
+ CurToken.eType = TAND;
+ CurToken.cMathChar = MS_AND;
+ CurToken.nGroup = TGPRODUCT;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "&" );
+ }
+ break;
+ case '(':
+ {
+ CurToken.eType = TLPARENT;
+ CurToken.cMathChar = MS_LPARENT;
+ CurToken.nGroup = TGLBRACES;
+ CurToken.nLevel = 5; //! 0 to continue expression
+ CurToken.aText.AssignAscii( "(" );
+ }
+ break;
+ case ')':
+ {
+ CurToken.eType = TRPARENT;
+ CurToken.cMathChar = MS_RPARENT;
+ CurToken.nGroup = TGRBRACES;
+ CurToken.nLevel = 0; //! 0 to terminate expression
+ CurToken.aText.AssignAscii( ")" );
+ }
+ break;
+ case '*':
+ {
+ CurToken.eType = TMULTIPLY;
+ CurToken.cMathChar = MS_MULTIPLY;
+ CurToken.nGroup = TGPRODUCT;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "*" );
+ }
+ break;
+ case '+':
+ {
+ if (BufferString.Copy( nRealStart, 2 ).
+ EqualsAscii( "+-" ))
+ {
+ CurToken.eType = TPLUSMINUS;
+ CurToken.cMathChar = MS_PLUSMINUS;
+ CurToken.nGroup = TGUNOPER | TGSUM;
+ CurToken.nLevel = 5;
+ CurToken.aText.AssignAscii( "+-" );
+
+ rnEndPos = nRealStart + 2;
+ }
+ else
+ {
+ CurToken.eType = TPLUS;
+ CurToken.cMathChar = MS_PLUS;
+ CurToken.nGroup = TGUNOPER | TGSUM;
+ CurToken.nLevel = 5;
+ CurToken.aText.AssignAscii( "+" );
+ }
+ }
+ break;
+ case '-':
+ {
+ if (BufferString.Copy( nRealStart, 2 ).
+ EqualsAscii( "-+" ))
+ {
+ CurToken.eType = TMINUSPLUS;
+ CurToken.cMathChar = MS_MINUSPLUS;
+ CurToken.nGroup = TGUNOPER | TGSUM;
+ CurToken.nLevel = 5;
+ CurToken.aText.AssignAscii( "-+" );
+
+ rnEndPos = nRealStart + 2;
+ }
+ else
+ {
+ CurToken.eType = TMINUS;
+ CurToken.cMathChar = MS_MINUS;
+ CurToken.nGroup = TGUNOPER | TGSUM;
+ CurToken.nLevel = 5;
+ CurToken.aText.AssignAscii( "-" );
+ }
+ }
+ break;
+ case '.':
+ {
+ // for compatibility with SO5.2
+ // texts like .34 ...56 ... h ...78..90
+ // will be treated as numbers
+ CurToken.eType = TNUMBER;
+ CurToken.cMathChar = '\0';
+ CurToken.nGroup = 0;
+ CurToken.nLevel = 5;
+
+ xub_StrLen nTxtStart = BufferIndex;
+ sal_Unicode cChar;
+ do
+ {
+ cChar = BufferString.GetChar( ++BufferIndex );
+ }
+ while ( cChar == '.' || IsDigit( cChar ) );
+
+ CurToken.aText = BufferString.Copy( sal::static_int_cast< xub_StrLen >(nTxtStart),
+ sal::static_int_cast< xub_StrLen >(BufferIndex - nTxtStart) );
+ aRes.EndPos = BufferIndex;
+ }
+ break;
+ case '/':
+ {
+ CurToken.eType = TDIVIDEBY;
+ CurToken.cMathChar = MS_SLASH;
+ CurToken.nGroup = TGPRODUCT;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "/" );
+ }
+ break;
+ case '=':
+ {
+ CurToken.eType = TASSIGN;
+ CurToken.cMathChar = MS_ASSIGN;
+ CurToken.nGroup = TGRELATION;
+ CurToken.nLevel = 0;
+ CurToken.aText.AssignAscii( "=" );
+ }
+ break;
+ default:
+ bHandled = FALSE;
+ }
+ }
+ }
+ else
+ bHandled = FALSE;
+
+ if (!bHandled)
+ {
+ CurToken.eType = TCHARACTER;
+ CurToken.cMathChar = '\0';
+ CurToken.nGroup = 0;
+ CurToken.nLevel = 5;
+ CurToken.aText = BufferString.Copy( nRealStart, 1 );
+
+ aRes.EndPos = nRealStart + 1;
+ }
+
+ if (TEND != CurToken.eType)
+ BufferIndex = sal::static_int_cast< xub_StrLen >(aRes.EndPos);
+}
+
+
+////////////////////////////////////////
+// grammar
+//
+
+
+void SmParser::Table()
+{
+ SmNodeArray LineArray;
+
+ Line();
+ while (CurToken.eType == TNEWLINE)
+ {
+ NextToken();
+ Line();
+ }
+
+ if (CurToken.eType != TEND)
+ Error(PE_UNEXPECTED_CHAR);
+
+ ULONG n = NodeStack.Count();
+
+ LineArray.resize(n);
+
+ for (ULONG i = 0; i < n; i++)
+ LineArray[n - (i + 1)] = NodeStack.Pop();
+
+ SmStructureNode *pSNode = new SmTableNode(CurToken);
+ pSNode->SetSubNodes(LineArray);
+ NodeStack.Push(pSNode);
+}
+
+
+void SmParser::Align()
+ // parse alignment info (if any), then go on with rest of expression
+{
+ SmStructureNode *pSNode = 0;
+ BOOL bNeedGroupClose = 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 = 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)
+ { BufferIndex = GetTokenIndex();
+ BufferString.Erase(BufferIndex, CurToken.aText.Len());
+ }
+ else
+ pSNode = new SmAlignNode(CurToken);
+
+ NextToken();
+ }
+ }
+ else
+ {
+ pSNode = new SmAlignNode(CurToken);
+
+ 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(NodeStack.Pop(), 0);
+ NodeStack.Push(pSNode);
+ }
+}
+
+
+void SmParser::Line()
+{
+ USHORT 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 (CurToken.eType != TEND && CurToken.eType != TNEWLINE)
+ { Align();
+ ExpressionArray.resize(++n);
+ ExpressionArray[n - 1] = NodeStack.Pop();
+ }
+
+ while (CurToken.eType != TEND && CurToken.eType != TNEWLINE)
+ { if (CONVERT_40_TO_50 != GetConversion())
+ Expression();
+ else
+ Align();
+ ExpressionArray.resize(++n);
+ ExpressionArray[n - 1] = NodeStack.Pop();
+ }
+
+ SmStructureNode *pSNode = new SmLineNode(CurToken);
+ pSNode->SetSubNodes(ExpressionArray);
+ NodeStack.Push(pSNode);
+}
+
+
+void SmParser::Expression()
+{
+ USHORT n = 0;
+ SmNodeArray RelationArray;
+
+ RelationArray.resize(n);
+
+ Relation();
+ RelationArray.resize(++n);
+ RelationArray[n - 1] = NodeStack.Pop();
+
+ while (CurToken.nLevel >= 4)
+ { Relation();
+ RelationArray.resize(++n);
+ RelationArray[n - 1] = NodeStack.Pop();
+ }
+
+ SmStructureNode *pSNode = new SmExpressionNode(CurToken);
+ pSNode->SetSubNodes(RelationArray);
+ NodeStack.Push(pSNode);
+}
+
+
+void SmParser::Relation()
+{
+ Sum();
+ while (TokenInGroup(TGRELATION))
+ {
+ SmStructureNode *pSNode = new SmBinHorNode(CurToken);
+ SmNode *pFirst = NodeStack.Pop();
+
+ OpSubSup();
+ SmNode *pSecond = NodeStack.Pop();
+
+ Sum();
+
+ pSNode->SetSubNodes(pFirst, pSecond, NodeStack.Pop());
+ NodeStack.Push(pSNode);
+ }
+}
+
+
+void SmParser::Sum()
+{
+ Product();
+ while (TokenInGroup(TGSUM))
+ {
+ SmStructureNode *pSNode = new SmBinHorNode(CurToken);
+ SmNode *pFirst = NodeStack.Pop();
+
+ OpSubSup();
+ SmNode *pSecond = NodeStack.Pop();
+
+ Product();
+
+ pSNode->SetSubNodes(pFirst, pSecond, NodeStack.Pop());
+ NodeStack.Push(pSNode);
+ }
+}
+
+
+void SmParser::Product()
+{
+ Power();
+
+ while (TokenInGroup(TGPRODUCT))
+ { SmStructureNode *pSNode;
+ SmNode *pFirst = NodeStack.Pop(),
+ *pOper;
+ BOOL bSwitchArgs = FALSE;
+
+ SmTokenType eType = CurToken.eType;
+ switch (eType)
+ {
+ case TOVER:
+ pSNode = new SmBinVerNode(CurToken);
+ pOper = new SmRectangleNode(CurToken);
+ NextToken();
+ break;
+
+ case TBOPER:
+ pSNode = new SmBinHorNode(CurToken);
+
+ NextToken();
+
+ GlyphSpecial();
+ pOper = NodeStack.Pop();
+ break;
+
+ case TOVERBRACE :
+ case TUNDERBRACE :
+ pSNode = new SmVerticalBraceNode(CurToken);
+ pOper = new SmMathSymbolNode(CurToken);
+
+ NextToken();
+ break;
+
+ case TWIDEBACKSLASH:
+ case TWIDESLASH:
+ {
+ SmBinDiagonalNode *pSTmp = new SmBinDiagonalNode(CurToken);
+ pSTmp->SetAscending(eType == TWIDESLASH);
+ pSNode = pSTmp;
+
+ pOper = new SmPolyLineNode(CurToken);
+ NextToken();
+
+ bSwitchArgs =TRUE;
+ break;
+ }
+
+ default:
+ pSNode = new SmBinHorNode(CurToken);
+
+ OpSubSup();
+ pOper = NodeStack.Pop();
+ }
+
+ Power();
+
+ if (bSwitchArgs)
+ //! vgl siehe SmBinDiagonalNode::Arrange
+ pSNode->SetSubNodes(pFirst, NodeStack.Pop(), pOper);
+ else
+ pSNode->SetSubNodes(pFirst, pOper, NodeStack.Pop());
+ NodeStack.Push(pSNode);
+ }
+}
+
+
+void SmParser::SubSup(ULONG nActiveGroup)
+{
+ DBG_ASSERT(nActiveGroup == TGPOWER || nActiveGroup == TGLIMIT,
+ "Sm: falsche Tokengruppe");
+
+ if (!TokenInGroup(nActiveGroup))
+ // already finish
+ return;
+
+ SmSubSupNode *pNode = new SmSubSupNode(CurToken);
+ //! Of course 'CurToken' ist 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] = NodeStack.Pop();
+ for (USHORT i = 1; i < aSubNodes.size(); i++)
+ aSubNodes[i] = NULL;
+
+ // process all sub-/supscripts
+ int nIndex = 0;
+ while (TokenInGroup(nActiveGroup))
+ { SmTokenType eType (CurToken.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(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] = NodeStack.Pop();
+ }
+
+ pNode->SetSubNodes(aSubNodes);
+ NodeStack.Push(pNode);
+}
+
+
+void SmParser::OpSubSup()
+{
+ // push operator symbol
+ NodeStack.Push(new SmMathSymbolNode(CurToken));
+ // 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(CurToken);
+
+ while (TokenInGroup(TGBLANK))
+ {
+ pBlankNode->IncreaseBy(CurToken);
+ NextToken();
+ }
+
+ // Blanks am Zeilenende ignorieren wenn die entsprechende Option gesetzt ist
+ if ( CurToken.eType == TNEWLINE ||
+ (CurToken.eType == TEND && SM_MOD1()->GetConfig()->IsIgnoreSpacesRight()) )
+ {
+ pBlankNode->Clear();
+ }
+
+ NodeStack.Push(pBlankNode);
+}
+
+
+void SmParser::Term()
+{
+ switch (CurToken.eType)
+ { case TESCAPE :
+ Escape();
+ break;
+
+ case TLGROUP :
+ NextToken();
+
+ // allow for empty group
+ if (CurToken.eType == TRGROUP)
+ { SmStructureNode *pSNode = new SmExpressionNode(CurToken);
+ pSNode->SetSubNodes(NULL, NULL);
+ NodeStack.Push(pSNode);
+
+ NextToken();
+ }
+ else // go as usual
+ { Align();
+ if (CurToken.eType != TRGROUP)
+ Error(PE_RGROUP_EXPECTED);
+ else
+ { NextToken();
+ }
+ }
+ break;
+
+ case TLEFT :
+ Brace();
+ break;
+
+ case TBLANK :
+ case TSBLANK :
+ Blank();
+ break;
+
+ case TTEXT :
+ NodeStack.Push(new SmTextNode(CurToken, FNT_TEXT));
+ NextToken();
+ break;
+ case TIDENT :
+ case TCHARACTER :
+ NodeStack.Push(new SmTextNode(CurToken, FNT_VARIABLE));
+ NextToken();
+ break;
+ case TNUMBER :
+ NodeStack.Push(new SmTextNode(CurToken, 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 :
+ NodeStack.Push(new SmMathSymbolNode(CurToken));
+ NextToken();
+ break;
+
+ case TPLACE:
+ NodeStack.Push(new SmPlaceNode(CurToken));
+ 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;
+
+ BOOL bIsAttr;
+ USHORT n = 0;
+ while (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(!NodeStack.Top()->IsVisible(), "Sm : Ooops...");
+
+ aArray[n] = (SmStructureNode *) NodeStack.Pop();
+ n++;
+ }
+
+ Power();
+
+ SmNode *pFirstNode = NodeStack.Pop();
+ while (n > 0)
+ { aArray[n - 1]->SetSubNodes(0, pFirstNode);
+ pFirstNode = aArray[n - 1];
+ n--;
+ }
+ NodeStack.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 = NodeStack.Pop();
+
+ if (CurToken.eType == TLPARENT)
+ { Term();
+ }
+ else
+ { Align();
+ }
+
+ // insert closing brace
+ Insert('}', GetTokenIndex());
+
+ SmStructureNode *pSNode = new SmExpressionNode(pFunc->GetToken());
+ pSNode->SetSubNodes(pFunc, NodeStack.Pop());
+ NodeStack.Push(pSNode);
+ }
+ }
+ else
+ Error(PE_UNEXPECTED_CHAR);
+ }
+}
+
+
+void SmParser::Escape()
+{
+ NextToken();
+
+ sal_Unicode cChar;
+ switch (CurToken.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(CurToken);
+ NodeStack.Push(pNode);
+
+ NextToken();
+}
+
+
+void SmParser::Operator()
+{
+ if (TokenInGroup(TGOPER))
+ { SmStructureNode *pSNode = new SmOperNode(CurToken);
+
+ // put operator on top of stack
+ Oper();
+
+ if (TokenInGroup(TGLIMIT) || TokenInGroup(TGPOWER))
+ SubSup(CurToken.nGroup);
+ SmNode *pOperator = NodeStack.Pop();
+
+ // get argument
+ Power();
+
+ pSNode->SetSubNodes(pOperator, NodeStack.Pop());
+ NodeStack.Push(pSNode);
+ }
+}
+
+
+void SmParser::Oper()
+{
+ SmTokenType eType (CurToken.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(CurToken);
+ 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 )
+ CurToken.aText.AssignAscii( pLim );
+ pNode = new SmTextNode(CurToken, FNT_TEXT);
+ }
+ break;
+
+ case TOVERBRACE :
+ case TUNDERBRACE :
+ pNode = new SmMathSymbolNode(CurToken);
+ break;
+
+ case TOPER :
+ NextToken();
+
+ DBG_ASSERT(CurToken.eType == TSPECIAL, "Sm: falsches Token");
+ pNode = new SmGlyphSpecialNode(CurToken);
+ break;
+
+ default :
+ DBG_ASSERT(0, "Sm: unbekannter Fall");
+ }
+ NodeStack.Push(pNode);
+
+ NextToken();
+}
+
+
+void SmParser::UnOper()
+{
+ DBG_ASSERT(TokenInGroup(TGUNOPER), "Sm: falsches Token");
+
+ SmToken aNodeToken = CurToken;
+ SmTokenType eType = CurToken.eType;
+ 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 = NodeStack.Pop();
+ break;
+
+ case TUOPER :
+ NextToken();
+ GlyphSpecial();
+ pOper = NodeStack.Pop();
+ break;
+
+ case TPLUS :
+ case TMINUS :
+ case TPLUSMINUS :
+ case TMINUSPLUS :
+ case TNEG :
+ case TFACT :
+ OpSubSup();
+ pOper = NodeStack.Pop();
+ break;
+
+ default :
+ Error(PE_UNOPER_EXPECTED);
+ }
+
+ // get argument
+ Power();
+ pArg = NodeStack.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);
+ }
+
+ NodeStack.Push(pSNode);
+}
+
+
+void SmParser::Attribut()
+{
+ DBG_ASSERT(TokenInGroup(TGATTRIBUT), "Sm: falsche Tokengruppe");
+
+ SmStructureNode *pSNode = new SmAttributNode(CurToken);
+ SmNode *pAttr;
+ SmScaleMode eScaleMode = SCALE_NONE;
+
+ // get appropriate node for the attribut itself
+ switch (CurToken.eType)
+ { case TUNDERLINE :
+ case TOVERLINE :
+ case TOVERSTRIKE :
+ pAttr = new SmRectangleNode(CurToken);
+ eScaleMode = SCALE_WIDTH;
+ break;
+
+ case TWIDEVEC :
+ case TWIDEHAT :
+ case TWIDETILDE :
+ pAttr = new SmMathSymbolNode(CurToken);
+ eScaleMode = SCALE_WIDTH;
+ break;
+
+ default :
+ pAttr = new SmMathSymbolNode(CurToken);
+ }
+
+ NextToken();
+
+ pSNode->SetSubNodes(pAttr, 0);
+ pSNode->SetScaleMode(eScaleMode);
+ NodeStack.Push(pSNode);
+}
+
+
+void SmParser::FontAttribut()
+{
+ DBG_ASSERT(TokenInGroup(TGFONTATTR), "Sm: falsche Tokengruppe");
+
+ switch (CurToken.eType)
+ {
+ case TITALIC :
+ case TNITALIC :
+ case TBOLD :
+ case TNBOLD :
+ case TPHANTOM :
+ NodeStack.Push(new SmFontNode(CurToken));
+ 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(CurToken.eType == TCOLOR, "Sm : Ooops...");
+
+ // last color rules, get that one
+ SmToken aToken;
+ do
+ { NextToken();
+
+ if (TokenInGroup(TGCOLOR))
+ { aToken = CurToken;
+ NextToken();
+ }
+ else
+ Error(PE_COLOR_EXPECTED);
+ } while (CurToken.eType == TCOLOR);
+
+ NodeStack.Push(new SmFontNode(aToken));
+}
+
+
+void SmParser::Font()
+{
+ DBG_ASSERT(CurToken.eType == TFONT, "Sm : Ooops...");
+
+ // last font rules, get that one
+ SmToken aToken;
+ do
+ { NextToken();
+
+ if (TokenInGroup(TGFONT))
+ { aToken = CurToken;
+ NextToken();
+ }
+ else
+ Error(PE_FONT_EXPECTED);
+ } while (CurToken.eType == TFONT);
+
+ NodeStack.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, ...
+BOOL lcl_IsNumber(const UniString& rText)
+{
+ BOOL bPoint = 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 FALSE;
+ else
+ bPoint = TRUE;
+ }
+ else if ( !IsDigit( cChar ) )
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void SmParser::FontSize()
+{
+ DBG_ASSERT(CurToken.eType == TSIZE, "Sm : Ooops...");
+
+ USHORT Type;
+ SmFontNode *pFontNode = new SmFontNode(CurToken);
+
+ NextToken();
+
+ switch (CurToken.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 (CurToken.eType != TNUMBER)
+ {
+ delete pFontNode;
+ Error(PE_SIZE_EXPECTED);
+ return;
+ }
+ }
+
+ // get number argument
+ Fraction aValue( 1L );
+ if (lcl_IsNumber( CurToken.aText ))
+ {
+ double fTmp;
+ if ((fTmp = CurToken.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);
+ NodeStack.Push(pFontNode);
+}
+
+
+void SmParser::Brace()
+{
+ DBG_ASSERT(CurToken.eType == TLEFT || TokenInGroup(TGLBRACES),
+ "Sm: kein Klammer Ausdruck");
+
+ SmStructureNode *pSNode = new SmBraceNode(CurToken);
+ SmNode *pBody = 0,
+ *pLeft = 0,
+ *pRight = 0;
+ SmScaleMode eScaleMode = SCALE_NONE;
+ SmParseError eError = PE_NONE;
+
+ if (CurToken.eType == TLEFT)
+ { NextToken();
+
+ eScaleMode = SCALE_HEIGHT;
+
+ // check for left bracket
+ if (TokenInGroup(TGLBRACES) || TokenInGroup(TGRBRACES))
+ {
+ pLeft = new SmMathSymbolNode(CurToken);
+
+ NextToken();
+ Bracebody(TRUE);
+ pBody = NodeStack.Pop();
+
+ if (CurToken.eType == TRIGHT)
+ { NextToken();
+
+ // check for right bracket
+ if (TokenInGroup(TGLBRACES) || TokenInGroup(TGRBRACES))
+ {
+ pRight = new SmMathSymbolNode(CurToken);
+ NextToken();
+ }
+ else
+ eError = PE_RBRACE_EXPECTED;
+ }
+ else
+ eError = PE_RIGHT_EXPECTED;
+ }
+ else
+ eError = PE_LBRACE_EXPECTED;
+ }
+ else
+ {
+ if (TokenInGroup(TGLBRACES))
+ {
+ pLeft = new SmMathSymbolNode(CurToken);
+
+ NextToken();
+ Bracebody(FALSE);
+ pBody = NodeStack.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 (CurToken.eType == eExpectedType)
+ {
+ pRight = new SmMathSymbolNode(CurToken);
+ 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);
+ NodeStack.Push(pSNode);
+ }
+ else
+ { delete pSNode;
+ delete pBody;
+ delete pLeft;
+ delete pRight;
+
+ Error(eError);
+ }
+}
+
+
+void SmParser::Bracebody(BOOL bIsLeftRight)
+{
+ SmStructureNode *pBody = new SmBracebodyNode(CurToken);
+ SmNodeArray aNodes;
+ USHORT nNum = 0;
+
+ // get body if any
+ if (bIsLeftRight)
+ {
+ do
+ {
+ if (CurToken.eType == TMLINE)
+ {
+ NodeStack.Push(new SmMathSymbolNode(CurToken));
+ NextToken();
+ nNum++;
+ }
+ else if (CurToken.eType != TRIGHT)
+ { Align();
+ nNum++;
+
+ if (CurToken.eType != TMLINE && CurToken.eType != TRIGHT)
+ Error(PE_RIGHT_EXPECTED);
+ }
+ } while (CurToken.eType != TEND && CurToken.eType != TRIGHT);
+ }
+ else
+ {
+ do
+ {
+ if (CurToken.eType == TMLINE)
+ {
+ NodeStack.Push(new SmMathSymbolNode(CurToken));
+ NextToken();
+ nNum++;
+ }
+ else if (!TokenInGroup(TGRBRACES))
+ { Align();
+ nNum++;
+
+ if (CurToken.eType != TMLINE && !TokenInGroup(TGRBRACES))
+ Error(PE_RBRACE_EXPECTED);
+ }
+ } while (CurToken.eType != TEND && !TokenInGroup(TGRBRACES));
+ }
+
+ // build argument vector in parsing order
+ aNodes.resize(nNum);
+ for (USHORT i = 0; i < nNum; i++)
+ aNodes[nNum - 1 - i] = NodeStack.Pop();
+
+ pBody->SetSubNodes(aNodes);
+ pBody->SetScaleMode(bIsLeftRight ? SCALE_HEIGHT : SCALE_NONE);
+ NodeStack.Push(pBody);
+}
+
+
+void SmParser::Function()
+{
+ switch (CurToken.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 :
+ NodeStack.Push(new SmTextNode(CurToken, FNT_FUNCTION));
+ NextToken();
+ break;
+
+ default:
+ Error(PE_FUNC_EXPECTED);
+ }
+}
+
+
+void SmParser::Binom()
+{
+ SmNodeArray ExpressionArray;
+ SmStructureNode *pSNode = new SmTableNode(CurToken);
+
+ NextToken();
+
+ Sum();
+ Sum();
+
+ ExpressionArray.resize(2);
+
+ for (int i = 0; i < 2; i++)
+ ExpressionArray[2 - (i + 1)] = NodeStack.Pop();
+
+ pSNode->SetSubNodes(ExpressionArray);
+ NodeStack.Push(pSNode);
+}
+
+
+void SmParser::Stack()
+{
+ SmNodeArray ExpressionArray;
+ NextToken();
+ if (CurToken.eType == TLGROUP)
+ {
+ USHORT n = 0;
+
+ do
+ {
+ NextToken();
+ Align();
+ n++;
+ }
+ while (CurToken.eType == TPOUND);
+
+ ExpressionArray.resize(n);
+
+ for (USHORT i = 0; i < n; i++)
+ ExpressionArray[n - (i + 1)] = NodeStack.Pop();
+
+ if (CurToken.eType != TRGROUP)
+ Error(PE_RGROUP_EXPECTED);
+
+ NextToken();
+
+ SmStructureNode *pSNode = new SmTableNode(CurToken);
+ pSNode->SetSubNodes(ExpressionArray);
+ NodeStack.Push(pSNode);
+ }
+ else
+ Error(PE_LGROUP_EXPECTED);
+}
+
+
+void SmParser::Matrix()
+{
+ SmNodeArray ExpressionArray;
+
+ NextToken();
+ if (CurToken.eType == TLGROUP)
+ {
+ USHORT c = 0;
+
+ do
+ {
+ NextToken();
+ Align();
+ c++;
+ }
+ while (CurToken.eType == TPOUND);
+
+ USHORT r = 1;
+
+ while (CurToken.eType == TDPOUND)
+ {
+ NextToken();
+ for (USHORT i = 0; i < c; i++)
+ {
+ Align();
+ if (i < (c - 1))
+ {
+ if (CurToken.eType == TPOUND)
+ {
+ NextToken();
+ }
+ else
+ Error(PE_POUND_EXPECTED);
+ }
+ }
+
+ r++;
+ }
+
+ long nRC = r * c;
+
+ ExpressionArray.resize(nRC);
+
+ for (USHORT i = 0; i < (nRC); i++)
+ ExpressionArray[(nRC) - (i + 1)] = NodeStack.Pop();
+
+ if (CurToken.eType != TRGROUP)
+ Error(PE_RGROUP_EXPECTED);
+
+ NextToken();
+
+ SmMatrixNode *pMNode = new SmMatrixNode(CurToken);
+ pMNode->SetSubNodes(ExpressionArray);
+ pMNode->SetRowCol(r, c);
+ NodeStack.Push(pMNode);
+ }
+ else
+ Error(PE_LGROUP_EXPECTED);
+}
+
+
+void SmParser::Special()
+{
+ BOOL bReplace = FALSE;
+ String &rName = CurToken.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 (IsImportSymbolNames())
+ {
+ const SmLocalizedSymbolData &rLSD = SM_MOD1()->GetLocSymbolData();
+ aNewName = rLSD.GetUiSymbolName( rName );
+ bReplace = TRUE;
+ }
+ else if (IsExportSymbolNames())
+ {
+ const SmLocalizedSymbolData &rLSD = SM_MOD1()->GetLocSymbolData();
+ aNewName = rLSD.GetExportSymbolName( rName );
+ bReplace = TRUE;
+ }
+ }
+ else // 5.0 <-> 6.0 formula text (symbol name) conversion
+ {
+ LanguageType nLanguage = GetLanguage();
+ SmLocalizedSymbolData &rData = SM_MOD1()->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" );
+ USHORT nCount = sal::static_int_cast< USHORT >(pFrom->Count());
+ for (USHORT i = 0; i < nCount; ++i)
+ {
+ if (pFrom->GetString(i) == rName)
+ {
+ aNewName = pTo->GetString(i);
+ bReplace = TRUE;
+ }
+ }
+ }
+ // else:
+ // conversion arrays not found or (usually)
+ // conversion not necessary
+ }
+
+ if (bReplace && aNewName.Len() && rName != aNewName)
+ {
+ Replace( GetTokenIndex() + 1, rName.Len(), aNewName );
+ rName = aNewName;
+ }
+
+ NodeStack.Push(new SmSpecialNode(CurToken));
+ NextToken();
+}
+
+
+void SmParser::GlyphSpecial()
+{
+ NodeStack.Push(new SmGlyphSpecialNode(CurToken));
+ NextToken();
+}
+
+
+void SmParser::Error(SmParseError eError)
+{
+ SmStructureNode *pSNode = new SmExpressionNode(CurToken);
+ SmErrorNode *pErr = new SmErrorNode(eError, CurToken);
+ 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
+ NodeStack.Push(pSNode);
+
+ AddError(eError, pSNode);
+
+ NextToken();
+}
+
+
+// end gramar
+
+
+SmParser::SmParser()
+{
+ eConversion = CONVERT_NONE;
+ bImportSymNames = bExportSymNames = FALSE;
+ nLang = Application::GetSettings().GetUILanguage();
+}
+
+
+SmNode *SmParser::Parse(const String &rBuffer)
+{
+ BufferString = rBuffer;
+ BufferString.ConvertLineEnd( LINEEND_LF );
+ BufferIndex =
+ nTokenIndex = 0;
+ Row = 1;
+ ColOff = 0;
+ CurError = -1;
+
+ for (USHORT i = 0; i < ErrDescList.Count(); i++)
+ delete ErrDescList.Remove(i);
+
+ ErrDescList.Clear();
+
+ NodeStack.Clear();
+
+ SetLanguage( Application::GetSettings().GetUILanguage() );
+ NextToken();
+ Table();
+
+ return NodeStack.Pop();
+}
+
+
+USHORT SmParser::AddError(SmParseError Type, SmNode *pNode)
+{
+ SmErrorDesc *pErrDesc = new SmErrorDesc;
+
+ pErrDesc->Type = Type;
+ pErrDesc->pNode = pNode;
+ pErrDesc->Text = String(SmResId(RID_ERR_IDENT));
+
+ USHORT 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);
+
+ ErrDescList.Insert(pErrDesc);
+
+ return (USHORT) ErrDescList.GetPos(pErrDesc);
+}
+
+
+const SmErrorDesc *SmParser::NextError()
+{
+ if (ErrDescList.Count())
+ if (CurError > 0) return ErrDescList.Seek(--CurError);
+ else
+ {
+ CurError = 0;
+ return ErrDescList.Seek(CurError);
+ }
+ else return 0;
+}
+
+
+const SmErrorDesc *SmParser::PrevError()
+{
+ if (ErrDescList.Count())
+ if (CurError < (int) (ErrDescList.Count() - 1)) return ErrDescList.Seek(++CurError);
+ else
+ {
+ CurError = (int) (ErrDescList.Count() - 1);
+ return ErrDescList.Seek(CurError);
+ }
+ else return 0;
+}
+
+
+const SmErrorDesc *SmParser::GetError(USHORT i)
+{
+ return (/*i >= 0 &&*/ i < ErrDescList.Count())
+ ? ErrDescList.Seek(i)
+ : ErrDescList.Seek(CurError);
+}
+
+