/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: starmath_parse.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: rt $ $Date: 2006/10/27 19:57:05 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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 for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#pragma hdrstop

#include <stdio.h>

#define SMDLL 1

#include <com/sun/star/i18n/UnicodeType.hpp>

#ifndef INCLUDED_SVTOOLS_SYSLOCALE_HXX
#include <svtools/syslocale.hxx>
#endif

#ifndef _STARMATH_HRC
#include "starmath.hrc"
#endif
#ifndef CONFIG_HXX
#include "config.hxx"
#endif

#include "node.hxx"
namespace binfilter {

using namespace ::com::sun::star::i18n;

///////////////////////////////////////////////////////////////////////////


/*N*/ static const sal_Unicode aDelimiterTable[] =
/*N*/ {
/*N*/ 	' ',	'\t',	'\n',	'\r',	'+',	'-',	'*',	'/',	'=',	'#',
/*N*/ 	'%',	'\\',	'"',	'~',	'`',	'>',	'<',	'&',	'|',	'(',
/*N*/ 	')',	'{',	'}',	'[',	']',	'^',	'_',
/*N*/ 	'\0'	// end of list symbol
/*N*/ };



///////////////////////////////////////////////////////////////////////////

/*N*/ SmToken::SmToken() :
/*N*/ 	eType		(TUNKNOWN),
/*N*/ 	cMathChar	('\0')
/*N*/ {
/*N*/ 	nRow = nCol = nGroup = nLevel = 0;
/*N*/ }

///////////////////////////////////////////////////////////////////////////

/*?*/ 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}
/*?*/ };


/*N*/ static const SmTokenTableEntry * GetTokenTableEntry( const String &rName )
/*N*/ {
/*N*/ 	const SmTokenTableEntry * pRes = 0;
/*N*/ 	if (rName.Len())
/*N*/ 	{
/*N*/ 		INT32 nEntries = sizeof( aTokenTable ) / sizeof( aTokenTable[0] );
/*N*/ 		for (INT32 i = 0;  i < nEntries;  ++i)
/*N*/ 		{
/*N*/ 			if (rName.EqualsIgnoreCaseAscii( aTokenTable[i].pIdent ))
/*N*/ 			{
/*N*/ 				pRes = &aTokenTable[i];
/*N*/ 				break;
/*N*/ 			}
/*N*/ 		}
/*N*/ 
/*N*/ 	}
/*N*/ 
/*N*/ 	return pRes;
/*N*/ }


///////////////////////////////////////////////////////////////////////////

#if OSL_DEBUG_LEVEL > 1

/*N*/ BOOL SmParser::IsDelimiter( const String &rTxt, xub_StrLen nPos )
/*N*/ 	// returns 'TRUE' iff cChar is '\0' or a delimeter
/*N*/ {
/*N*/ 	DBG_ASSERT( nPos <= rTxt.Len(), "index out of range" );
/*N*/ 
/*N*/ 	sal_Unicode cChar = rTxt.GetChar( nPos );
/*N*/ 	if(!cChar)
/*N*/ 		return TRUE;
/*N*/ 
/*N*/ 	// check if 'cChar' is in the delimeter table
/*N*/ 	const sal_Unicode *pDelim = &aDelimiterTable[0];
/*N*/ 	for ( ;  *pDelim != 0;  pDelim++)
/*N*/ 		if (*pDelim == cChar)
/*N*/ 			break;
/*N*/ 
/*N*/ 	BOOL bIsDelim = *pDelim != 0;
/*N*/ 
/*N*/ 	INT16 nTypJp = SM_MOD1()->GetSysLocale().GetCharClass().getType( rTxt, nPos );
/*N*/ 	bIsDelim |= nTypJp == ::com::sun::star::i18n::UnicodeType::SPACE_SEPARATOR ||
/*N*/ 				nTypJp == ::com::sun::star::i18n::UnicodeType::CONTROL;
/*N*/ 
/*N*/ 	return bIsDelim;
/*N*/ }

#endif 


/*N*/ void SmParser::Insert(const String &rText, USHORT nPos)
/*N*/ {
/*N*/ 	BufferString.Insert(rText, nPos);
/*N*/ 
/*N*/ 	xub_StrLen  nLen = rText.Len();
/*N*/ 	BufferIndex += nLen;
/*N*/ 	nTokenIndex += nLen;
/*N*/ }


/*N*/ void SmParser::Replace( USHORT nPos, USHORT nLen, const String &rText )
/*N*/ {
/*N*/     DBG_ASSERT( nPos + nLen <= BufferString.Len(), "argument mismatch" );
/*N*/ 
/*N*/     BufferString.Replace( nPos, nLen, rText );
/*N*/     INT16  nChg = rText.Len() - nLen;
/*N*/     BufferIndex += nChg;
/*N*/     nTokenIndex += nChg;
/*N*/ }


// 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;

/*N*/ void SmParser::NextToken()
/*N*/ {
/*N*/ 	static const String aEmptyStr;
/*N*/ 
/*N*/ 	xub_StrLen	nBufLen = BufferString.Len();
/*N*/ 	ParseResult	aRes;
/*N*/ 	xub_StrLen	nRealStart;
/*N*/ 	BOOL		bCont;
/*N*/     BOOL        bNumStart;
/*N*/ 	const CharClass& rCC = SM_MOD1()->GetSysLocale().GetCharClass();
/*N*/ 	do
/*N*/ 	{
/*N*/         // skip white spaces
/*N*/         while (UnicodeType::SPACE_SEPARATOR ==
/*N*/                         rCC.getType( BufferString, BufferIndex ))
/*N*/            ++BufferIndex;
/*N*/ 
/*N*/         sal_Int32 nStartFlags = coStartFlags;
/*N*/         sal_Int32 nContFlags  = coContFlags;
/*N*/         sal_Unicode cFirstChar = BufferString.GetChar( BufferIndex );
/*N*/         bNumStart = cFirstChar == '.' || ('0' <= cFirstChar && cFirstChar <= '9');
/*N*/         if (bNumStart)
/*N*/         {
/*N*/             nStartFlags = coNumStartFlags;
/*N*/             nContFlags  = coNumContFlags;
/*N*/         }
/*N*/ 
/*N*/ 		aRes = rCC.parseAnyToken( BufferString, BufferIndex,
/*N*/                                             nStartFlags, aEmptyStr,
/*N*/                                             nContFlags, aEmptyStr );
/*N*/ 
/*N*/ 		nRealStart = BufferIndex + (xub_StrLen) aRes.LeadingWhiteSpace;
/*N*/         BufferIndex = nRealStart;
/*N*/ 
/*N*/ 		bCont = FALSE;
/*N*/ 		if ( aRes.TokenType == 0  &&
/*N*/ 				nRealStart < nBufLen &&
/*N*/ 				'\n' == BufferString.GetChar( nRealStart ) )
/*N*/ 		{
/*N*/ 			// keep data needed for tokens row and col entry up to date
/*N*/ 			++Row;
/*N*/ 			BufferIndex = ColOff = nRealStart + 1;
/*N*/ 			bCont = TRUE;
/*N*/ 		}
/*N*/ 		else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR)
/*N*/ 		{
/*N*/ 			String aName( BufferString.Copy( nRealStart, 2 ));
/*N*/ 			if ( aName.EqualsAscii( "%%" ))
/*N*/ 			{
/*N*/ 				//SkipComment
/*N*/ 				BufferIndex = nRealStart + 2;
/*N*/ 				while (BufferIndex < nBufLen  &&
/*N*/ 					'\n' != BufferString.GetChar( BufferIndex ))
/*N*/ 					++BufferIndex;
/*N*/ 				bCont = TRUE;
/*N*/ 			}
/*N*/ 		}
/*N*/ 
/*N*/ 	} while (bCont);
/*N*/ 
/*N*/ 	// set index of current token
/*N*/ 	nTokenIndex = BufferIndex;
/*N*/ 
/*N*/ 	CurToken.nRow	= Row;
/*N*/ 	CurToken.nCol	= nRealStart - ColOff + 1;
/*N*/ 
/*N*/ 	BOOL bHandled = TRUE;
/*N*/ 	if (nRealStart >= nBufLen)
/*N*/ 	{
/*N*/ 		CurToken.eType	   = TEND;
/*N*/ 		CurToken.cMathChar = '\0';
/*N*/ 		CurToken.nGroup	   = 0;
/*N*/ 		CurToken.nLevel	   = 0;
/*N*/ 		CurToken.aText.Erase();
/*N*/ 	}
/*N*/     else if ((aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER))
/*N*/              || (bNumStart && (aRes.TokenType & KParseType::IDENTNAME)))
/*N*/ 	{
/*N*/ 		INT32 n = aRes.EndPos - nRealStart;
/*N*/ 		DBG_ASSERT( n >= 0, "length < 0" );
/*N*/ 		CurToken.eType      = TNUMBER;
/*N*/ 		CurToken.cMathChar  = '\0';
/*N*/ 		CurToken.nGroup     = 0;
/*N*/ 		CurToken.nLevel     = 5;
/*N*/ 		CurToken.aText      = BufferString.Copy( nRealStart, (xub_StrLen) n );
/*N*/ 
/*N*/ #if OSL_DEBUG_LEVEL > 1
/*N*/             if (!IsDelimiter( BufferString, aRes.EndPos ))
/*N*/                 DBG_WARNING( "identifier really finished? (compatibility!)" );
/*N*/ #endif
/*N*/ 	}
/*N*/ 	else if (aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING)
/*N*/ 	{
/*N*/ 		CurToken.eType      = TTEXT;
/*N*/ 		CurToken.cMathChar  = '\0';
/*N*/ 		CurToken.nGroup     = 0;
/*N*/ 		CurToken.nLevel     = 5;
/*N*/ 		CurToken.aText		= aRes.DequotedNameOrString;
/*N*/ 		CurToken.nRow       = Row;
/*N*/ 		CurToken.nCol       = nRealStart - ColOff + 2;
/*N*/ 	}
/*N*/ 	else if (aRes.TokenType & KParseType::IDENTNAME)
/*N*/ 	{
/*N*/ 		INT32 n = aRes.EndPos - nRealStart;
/*N*/ 		DBG_ASSERT( n >= 0, "length < 0" );
/*N*/ 		String aName( BufferString.Copy( nRealStart, (xub_StrLen) n ) );
/*N*/ 		const SmTokenTableEntry *pEntry = GetTokenTableEntry( aName );
/*N*/ 
/*N*/ 		if (pEntry)
/*N*/ 		{
/*N*/ 			CurToken.eType      = pEntry->eType;
/*N*/ 			CurToken.cMathChar  = pEntry->cMathChar;
/*N*/ 			CurToken.nGroup     = pEntry->nGroup;
/*N*/ 			CurToken.nLevel     = pEntry->nLevel;
/*N*/ 			CurToken.aText.AssignAscii( pEntry->pIdent );
/*N*/ 		}
/*N*/ 		else
/*N*/ 		{
/*N*/ 			CurToken.eType      = TIDENT;
/*N*/ 			CurToken.cMathChar  = '\0';
/*N*/ 			CurToken.nGroup     = 0;
/*N*/ 			CurToken.nLevel     = 5;
/*N*/ 			CurToken.aText      = aName;
/*N*/ 
/*N*/ #if OSL_DEBUG_LEVEL > 1
/*N*/             if (!IsDelimiter( BufferString, aRes.EndPos ))
/*N*/                 DBG_WARNING( "identifier really finished? (compatibility!)" );
/*N*/ #endif
/*N*/ 		}
/*N*/ 	}
/*N*/ 	else if (aRes.TokenType == 0  &&  '_' == BufferString.GetChar( nRealStart ))
/*N*/ 	{
/*N*/ 		CurToken.eType	   = TRSUB;
/*N*/ 		CurToken.cMathChar = '\0';
/*N*/ 		CurToken.nGroup	   = TGPOWER;
/*N*/ 		CurToken.nLevel	   = 0;
/*N*/ 		CurToken.aText.AssignAscii( "_" );
/*N*/ 
/*N*/ 		aRes.EndPos = nRealStart + 1;
/*N*/ 	}
/*N*/ 	else if (aRes.TokenType & KParseType::BOOLEAN)
/*N*/ 	{
/*N*/ 		sal_Int32   &rnEndPos = aRes.EndPos;
/*N*/ 		String	aName( BufferString.Copy( nRealStart, rnEndPos - nRealStart ) );
/*N*/ 		if (2 >= aName.Len())
/*N*/ 		{
/*N*/ 			sal_Unicode ch = aName.GetChar( 0 );
/*N*/ 			switch (ch)
/*N*/ 			{
/*N*/ 				case '<':
/*N*/ 					{
/*N*/ 						if (BufferString.Copy( nRealStart, 2 ).
/*N*/ 								EqualsAscii( "<<" ))
/*N*/ 						{
/*N*/ 							CurToken.eType	   = TLL;
/*N*/ 							CurToken.cMathChar = MS_LL;
/*N*/ 							CurToken.nGroup	   = TGRELATION;
/*N*/ 							CurToken.nLevel	   = 0;
/*N*/ 							CurToken.aText.AssignAscii( "<<" );
/*N*/ 
/*N*/ 							rnEndPos = nRealStart + 2;
/*N*/ 						}
/*N*/ 						else if (BufferString.Copy( nRealStart, 2 ).
/*N*/ 								EqualsAscii( "<=" ))
/*N*/ 						{
/*N*/ 							CurToken.eType	   = TLE;
/*N*/ 							CurToken.cMathChar = MS_LE;
/*N*/ 							CurToken.nGroup	   = TGRELATION;
/*N*/ 							CurToken.nLevel	   = 0;
/*N*/ 							CurToken.aText.AssignAscii( "<=" );
/*N*/ 
/*N*/ 							rnEndPos = nRealStart + 2;
/*N*/ 						}
/*N*/ 						else if (BufferString.Copy( nRealStart, 2 ).
/*N*/ 								EqualsAscii( "<>" ))
/*N*/ 						{
/*N*/ 							CurToken.eType	   = TNEQ;
/*N*/ 							CurToken.cMathChar = MS_NEQ;
/*N*/ 							CurToken.nGroup	   = TGRELATION;
/*N*/ 							CurToken.nLevel	   = 0;
/*N*/ 							CurToken.aText.AssignAscii( "<>" );
/*N*/ 
/*N*/ 							rnEndPos = nRealStart + 2;
/*N*/ 						}
/*N*/ 						else if (BufferString.Copy( nRealStart, 3 ).
/*N*/ 								EqualsAscii( "<?>" ))
/*N*/ 						{
/*N*/ 							CurToken.eType	   = TPLACE;
/*N*/ 							CurToken.cMathChar = MS_PLACE;
/*N*/ 							CurToken.nGroup	   = 0;
/*N*/ 							CurToken.nLevel	   = 5;
/*N*/ 							CurToken.aText.AssignAscii( "<?>" );
/*N*/ 
/*N*/ 							rnEndPos = nRealStart + 3;
/*N*/ 						}
/*N*/ 						else
/*N*/ 						{
/*N*/ 							CurToken.eType	   = TLT;
/*N*/ 							CurToken.cMathChar = MS_LT;
/*N*/ 							CurToken.nGroup	   = TGRELATION;
/*N*/ 							CurToken.nLevel	   = 0;
/*N*/ 							CurToken.aText.AssignAscii( "<" );
/*N*/ 						}
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '>':
/*N*/ 					{
/*N*/ 						if (BufferString.Copy( nRealStart, 2 ).
/*N*/ 								EqualsAscii( ">=" ))
/*N*/ 						{
/*N*/ 							CurToken.eType	   = TGE;
/*N*/ 							CurToken.cMathChar = MS_GE;
/*N*/ 							CurToken.nGroup	   = TGRELATION;
/*N*/ 							CurToken.nLevel	   = 0;
/*N*/ 							CurToken.aText.AssignAscii( ">=" );
/*N*/ 
/*N*/ 							rnEndPos = nRealStart + 2;
/*N*/ 						}
/*N*/ 						else if (BufferString.Copy( nRealStart, 2 ).
/*N*/ 								EqualsAscii( ">>" ))
/*N*/ 						{
/*N*/ 							CurToken.eType	   = TGG;
/*N*/ 							CurToken.cMathChar = MS_GG;
/*N*/ 							CurToken.nGroup	   = TGRELATION;
/*N*/ 							CurToken.nLevel	   = 0;
/*N*/ 							CurToken.aText.AssignAscii( ">>" );
/*N*/ 
/*N*/ 							rnEndPos = nRealStart + 2;
/*N*/ 						}
/*N*/ 						else
/*N*/ 						{
/*N*/ 							CurToken.eType	   = TGT;
/*N*/ 							CurToken.cMathChar = MS_GT;
/*N*/ 							CurToken.nGroup	   = TGRELATION;
/*N*/ 							CurToken.nLevel	   = 0;
/*N*/ 							CurToken.aText.AssignAscii( ">" );
/*N*/ 						}
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				default:
/*N*/ 					bHandled = FALSE;
/*N*/ 			}
/*N*/ 		}
/*N*/ 	}
/*N*/ 	else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR)
/*N*/ 	{
/*N*/ 		sal_Int32 &rnEndPos = aRes.EndPos;
/*N*/ 		String	aName( BufferString.Copy( nRealStart, rnEndPos - nRealStart ) );
/*N*/ 
/*N*/ 		if (1 == aName.Len())
/*N*/ 		{
/*N*/ 			sal_Unicode ch = aName.GetChar( 0 );
/*N*/ 			switch (ch)
/*N*/ 			{
/*N*/ 				case '%':
/*N*/ 					{
/*N*/ 						//! modifies aRes.EndPos
/*N*/ 
/*N*/ 						DBG_ASSERT( rnEndPos >= nBufLen  ||
/*N*/ 									'%' != BufferString.GetChar( rnEndPos ),
/*N*/ 								"unexpected comment start" );
/*N*/ 
/*N*/ 						// get identifier of user-defined character
/*N*/ 						ParseResult aTmpRes = rCC.parseAnyToken(
/*N*/ 								BufferString, rnEndPos,
/*N*/ 								KParseTokens::ANY_LETTER,
/*N*/ 								aEmptyStr,
/*N*/                                 coContFlags,
/*N*/ 								aEmptyStr );
/*N*/ 
/*N*/                         xub_StrLen nTmpStart = rnEndPos +
/*N*/                                 (xub_StrLen) aTmpRes.LeadingWhiteSpace;
/*N*/ 
/*N*/                         // default setting fo the case that no identifier
/*N*/                         // i.e. a valid symbol-name is following the '%'
/*N*/                         // character
/*N*/                         CurToken.eType      = TTEXT;
/*N*/                         CurToken.cMathChar  = '\0';
/*N*/                         CurToken.nGroup     = 0;
/*N*/                         CurToken.nLevel     = 5;
/*N*/                         CurToken.aText      = String();
/*N*/                         CurToken.nRow       = Row;
/*N*/                         CurToken.nCol       = nTmpStart - ColOff + 1;
/*N*/ 
/*N*/                         if (aTmpRes.TokenType & KParseType::IDENTNAME)
/*N*/                         {
/*N*/ 
/*N*/                             INT32 n = aTmpRes.EndPos - nTmpStart;
/*N*/                             CurToken.eType      = TSPECIAL;
/*N*/                             CurToken.aText      = BufferString.Copy( nTmpStart, n );
/*N*/ 
/*N*/                             DBG_ASSERT( aTmpRes.EndPos > rnEndPos,
/*N*/                                     "empty identifier" );
/*N*/                             if (aTmpRes.EndPos > rnEndPos)
/*N*/                                 rnEndPos = aTmpRes.EndPos;
/*N*/                             else
/*N*/                                 ++rnEndPos;
/*N*/                         }
/*N*/ 
/*N*/                         // if no symbol-name was found we start-over with
/*N*/                         // finding the next token right afer the '%' sign.
/*N*/                         // I.e. we leave rnEndPos unmodified.
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '[':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TLBRACKET;
/*N*/ 						CurToken.cMathChar = MS_LBRACKET;
/*N*/ 						CurToken.nGroup	   = TGLBRACES;
/*N*/ 						CurToken.nLevel	   = 5;
/*N*/ 						CurToken.aText.AssignAscii( "[" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '\\':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TESCAPE;
/*N*/ 						CurToken.cMathChar = '\0';
/*N*/ 						CurToken.nGroup	   = 0;
/*N*/ 						CurToken.nLevel	   = 5;
/*N*/ 						CurToken.aText.AssignAscii( "\\" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case ']':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TRBRACKET;
/*N*/ 						CurToken.cMathChar = MS_RBRACKET;
/*N*/ 						CurToken.nGroup	   = TGRBRACES;
/*N*/ 						CurToken.nLevel	   = 0;
/*N*/ 						CurToken.aText.AssignAscii( "]" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '^':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TRSUP;
/*N*/ 						CurToken.cMathChar = '\0';
/*N*/ 						CurToken.nGroup	   = TGPOWER;
/*N*/ 						CurToken.nLevel	   = 0;
/*N*/ 						CurToken.aText.AssignAscii( "^" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '`':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TSBLANK;
/*N*/ 						CurToken.cMathChar = '\0';
/*N*/ 						CurToken.nGroup	   = TGBLANK;
/*N*/ 						CurToken.nLevel	   = 5;
/*N*/ 						CurToken.aText.AssignAscii( "`" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '{':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TLGROUP;
/*N*/ 						CurToken.cMathChar = MS_LBRACE;
/*N*/ 						CurToken.nGroup	   = 0;
/*N*/ 						CurToken.nLevel	   = 5;
/*N*/ 						CurToken.aText.AssignAscii( "{" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '|':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TOR;
/*N*/ 						CurToken.cMathChar = MS_OR;
/*N*/ 						CurToken.nGroup	   = TGSUM;
/*N*/ 						CurToken.nLevel	   = 0;
/*N*/ 						CurToken.aText.AssignAscii( "|" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '}':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TRGROUP;
/*N*/ 						CurToken.cMathChar = MS_RBRACE;
/*N*/ 						CurToken.nGroup	   = 0;
/*N*/ 						CurToken.nLevel	   = 0;
/*N*/ 						CurToken.aText.AssignAscii( "}" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '~':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TBLANK;
/*N*/ 						CurToken.cMathChar = '\0';
/*N*/ 						CurToken.nGroup	   = TGBLANK;
/*N*/ 						CurToken.nLevel	   = 5;
/*N*/ 						CurToken.aText.AssignAscii( "~" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '#':
/*N*/ 					{
/*N*/ 						if (BufferString.Copy( nRealStart, 2 ).
/*N*/ 								EqualsAscii( "##" ))
/*N*/ 						{
/*N*/ 							CurToken.eType	   = TDPOUND;
/*N*/ 							CurToken.cMathChar = '\0';
/*N*/ 							CurToken.nGroup	   = 0;
/*N*/ 							CurToken.nLevel	   = 0;
/*N*/ 							CurToken.aText.AssignAscii( "##" );
/*N*/ 
/*N*/ 							rnEndPos = nRealStart + 2;
/*N*/ 						}
/*N*/ 						else
/*N*/ 						{
/*N*/ 							CurToken.eType	   = TPOUND;
/*N*/ 							CurToken.cMathChar = '\0';
/*N*/ 							CurToken.nGroup	   = 0;
/*N*/ 							CurToken.nLevel	   = 0;
/*N*/ 							CurToken.aText.AssignAscii( "#" );
/*N*/ 						}
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '&':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TAND;
/*N*/ 						CurToken.cMathChar = MS_AND;
/*N*/ 						CurToken.nGroup	   = TGPRODUCT;
/*N*/ 						CurToken.nLevel	   = 0;
/*N*/ 						CurToken.aText.AssignAscii( "&" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '(':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TLPARENT;
/*N*/ 						CurToken.cMathChar = MS_LPARENT;
/*N*/ 						CurToken.nGroup	   = TGLBRACES;
/*N*/ 						CurToken.nLevel	   = 5;		//! 0 to continue expression
/*N*/ 						CurToken.aText.AssignAscii( "(" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case ')':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TRPARENT;
/*N*/ 						CurToken.cMathChar = MS_RPARENT;
/*N*/ 						CurToken.nGroup	   = TGRBRACES;
/*N*/ 						CurToken.nLevel	   = 0;		//! 0 to terminate expression
/*N*/ 						CurToken.aText.AssignAscii( ")" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '*':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TMULTIPLY;
/*N*/ 						CurToken.cMathChar = MS_MULTIPLY;
/*N*/ 						CurToken.nGroup	   = TGPRODUCT;
/*N*/ 						CurToken.nLevel	   = 0;
/*N*/ 						CurToken.aText.AssignAscii( "*" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '+':
/*N*/ 					{
/*N*/ 						if (BufferString.Copy( nRealStart, 2 ).
/*N*/ 								EqualsAscii( "+-" ))
/*N*/ 						{
/*N*/ 							CurToken.eType	   = TPLUSMINUS;
/*N*/ 							CurToken.cMathChar = MS_PLUSMINUS;
/*N*/ 							CurToken.nGroup	   = TGUNOPER | TGSUM;
/*N*/ 							CurToken.nLevel	   = 5;
/*N*/ 							CurToken.aText.AssignAscii( "+-" );
/*N*/ 
/*N*/ 							rnEndPos = nRealStart + 2;
/*N*/ 						}
/*N*/ 						else
/*N*/ 						{
/*N*/ 							CurToken.eType	   = TPLUS;
/*N*/ 							CurToken.cMathChar = MS_PLUS;
/*N*/ 							CurToken.nGroup	   = TGUNOPER | TGSUM;
/*N*/ 							CurToken.nLevel	   = 5;
/*N*/ 							CurToken.aText.AssignAscii( "+" );
/*N*/ 						}
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '-':
/*N*/ 					{
/*N*/ 						if (BufferString.Copy( nRealStart, 2 ).
/*N*/ 								EqualsAscii( "-+" ))
/*N*/ 						{
/*N*/ 							CurToken.eType	   = TMINUSPLUS;
/*N*/ 							CurToken.cMathChar = MS_MINUSPLUS;
/*N*/ 							CurToken.nGroup	   = TGUNOPER | TGSUM;
/*N*/ 							CurToken.nLevel	   = 5;
/*N*/ 							CurToken.aText.AssignAscii( "-+" );
/*N*/ 
/*N*/ 							rnEndPos = nRealStart + 2;
/*N*/ 						}
/*N*/ 						else
/*N*/ 						{
/*N*/ 							CurToken.eType	   = TMINUS;
/*N*/ 							CurToken.cMathChar = MS_MINUS;
/*N*/ 							CurToken.nGroup	   = TGUNOPER | TGSUM;
/*N*/ 							CurToken.nLevel	   = 5;
/*N*/ 							CurToken.aText.AssignAscii( "-" );
/*N*/ 						}
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '.':
/*N*/ 					{
/*N*/                         // for compatibility with SO5.2
/*N*/                         // texts like .34 ...56 ... h ...78..90
/*N*/                         // will be treated as numbers
/*N*/                         CurToken.eType     = TNUMBER;
/*N*/ 						CurToken.cMathChar = '\0';
/*N*/ 						CurToken.nGroup	   = 0;
/*N*/                         CurToken.nLevel    = 5;
/*N*/ 
/*N*/                         xub_StrLen nTxtStart = BufferIndex;
/*N*/                         sal_Unicode cChar;
/*N*/                         do
/*N*/                         {
/*N*/                             cChar = BufferString.GetChar( ++BufferIndex );
/*N*/                         }
/*N*/                         while ( cChar == '.' || ('0' <= cChar && cChar <= '9') );
/*N*/ 
/*N*/                         CurToken.aText = BufferString.Copy( nTxtStart, BufferIndex - nTxtStart );
/*N*/                         aRes.EndPos = BufferIndex;
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '/':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TDIVIDEBY;
/*N*/ 						CurToken.cMathChar = MS_SLASH;
/*N*/ 						CurToken.nGroup	   = TGPRODUCT;
/*N*/ 						CurToken.nLevel	   = 0;
/*N*/ 						CurToken.aText.AssignAscii( "/" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				case '=':
/*N*/ 					{
/*N*/ 						CurToken.eType	   = TASSIGN;
/*N*/ 						CurToken.cMathChar = MS_ASSIGN;
/*N*/ 						CurToken.nGroup	   = TGRELATION;
/*N*/ 						CurToken.nLevel	   = 0;
/*N*/ 						CurToken.aText.AssignAscii( "=" );
/*N*/ 					}
/*N*/ 					break;
/*N*/ 				default:
/*N*/ 					bHandled = FALSE;
/*N*/ 			}
/*N*/ 		}
/*N*/ 	}
/*N*/ 	else
/*N*/ 		bHandled = FALSE;
/*N*/ 
/*N*/ 	if (!bHandled)
/*N*/ 	{
/*N*/ 		CurToken.eType      = TCHARACTER;
/*N*/ 		CurToken.cMathChar  = '\0';
/*N*/ 		CurToken.nGroup     = 0;
/*N*/ 		CurToken.nLevel     = 5;
/*N*/ 		CurToken.aText      = BufferString.Copy( nRealStart, 1 );
/*N*/ 
/*N*/ 		aRes.EndPos = nRealStart + 1;
/*N*/ 	}
/*N*/ 
/*N*/ 	if (TEND != CurToken.eType)
/*N*/ 		BufferIndex = (xub_StrLen)aRes.EndPos;
/*N*/ }
/*N*/ 
/*N*/ 
////////////////////////////////////////
// grammar
//


/*N*/ void SmParser::Table()
/*N*/ {
/*N*/ 	SmNodeArray  LineArray;
/*N*/ 
/*N*/ 	Line();
/*N*/ 	while (CurToken.eType == TNEWLINE)
/*N*/ 	{
/*N*/ 		NextToken();
/*N*/ 		Line();
/*N*/ 	}
/*N*/ 
/*N*/ 	if (CurToken.eType != TEND)
/*?*/ 		Error(PE_UNEXPECTED_CHAR);
/*N*/ 
/*N*/ 	ULONG n = NodeStack.Count();
/*N*/ 
/*N*/ 	LineArray.SetSize(n);
/*N*/ 
/*N*/ 	for (ULONG i = 0; i < n; i++)
/*N*/ 		LineArray.Put(n - (i + 1), NodeStack.Pop());
/*N*/ 
/*N*/ 	SmStructureNode *pSNode = new SmTableNode(CurToken);
/*N*/ 	pSNode->SetSubNodes(LineArray);
/*N*/ 	NodeStack.Push(pSNode);
/*N*/ }


/*N*/ void SmParser::Align()
/*N*/ 	// parse alignment info (if any), then go on with rest of expression
/*N*/ {
/*N*/ 	SmStructureNode *pSNode = 0;
/*N*/ 	BOOL    bNeedGroupClose = FALSE;
/*N*/ 
/*N*/ 	if (TokenInGroup(TGALIGN))
/*N*/ 	{
/*?*/         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;
/*?*/           }
/*?*/ 		}
/*?*/ 	}
/*N*/ 
/*N*/ 	Expression();
/*N*/ 
/*N*/ 	if (bNeedGroupClose)
/*?*/ 		Insert('}', GetTokenIndex());
/*N*/ 
/*N*/ 	if (pSNode)
/*?*/ 	{	pSNode->SetSubNodes(NodeStack.Pop(), 0);
/*?*/ 		NodeStack.Push(pSNode);
/*N*/ 	}
/*N*/ }


/*N*/ void SmParser::Line()
/*N*/ {
/*N*/ 	USHORT  n = 0;
/*N*/ 	SmNodeArray  ExpressionArray;
/*N*/ 
/*N*/ 	ExpressionArray.SetSize(n);
/*N*/ 
/*N*/ 	// start with single expression that may have an alignment statement
/*N*/ 	// (and go on with expressions that must not have alignment
/*N*/ 	// statements in 'while' loop below. See also 'Expression()'.)
/*N*/ 	if (CurToken.eType != TEND  &&  CurToken.eType != TNEWLINE)
/*N*/ 	{	Align();
/*N*/ 		ExpressionArray.SetSize(++n);
/*N*/ 		ExpressionArray.Put(n - 1, NodeStack.Pop());
/*N*/ 	}
/*N*/ 
/*N*/ 	while (CurToken.eType != TEND  &&  CurToken.eType != TNEWLINE)
/*N*/     {   if (CONVERT_40_TO_50 != GetConversion())
/*N*/ 			Expression();
/*N*/ 		else
/*?*/ 			Align();
/*N*/ 		ExpressionArray.SetSize(++n);
/*N*/ 		ExpressionArray.Put(n - 1, NodeStack.Pop());
/*N*/ 	}
/*N*/ 
/*N*/ 	SmStructureNode *pSNode = new SmLineNode(CurToken);
/*N*/ 	pSNode->SetSubNodes(ExpressionArray);
/*N*/ 	NodeStack.Push(pSNode);
/*N*/ }


/*N*/ void SmParser::Expression()
/*N*/ {
/*N*/ 	USHORT		 n = 0;
/*N*/ 	SmNodeArray  RelationArray;
/*N*/ 
/*N*/ 	RelationArray.SetSize(n);
/*N*/ 
/*N*/ 	Relation();
/*N*/ 	RelationArray.SetSize(++n);
/*N*/ 	RelationArray.Put(n - 1, NodeStack.Pop());
/*N*/ 
/*N*/ 	while (CurToken.nLevel >= 4)
/*N*/ 	{	Relation();
/*N*/ 		RelationArray.SetSize(++n);
/*N*/ 		RelationArray.Put(n - 1, NodeStack.Pop());
/*N*/ 	}
/*N*/ 
/*N*/ 	SmStructureNode *pSNode = new SmExpressionNode(CurToken);
/*N*/ 	pSNode->SetSubNodes(RelationArray);
/*N*/ 	NodeStack.Push(pSNode);
/*N*/ }


/*N*/ void SmParser::Relation()
/*N*/ {
/*N*/ 	Sum();
/*N*/ 	while (TokenInGroup(TGRELATION))
/*N*/ 	{
/*N*/ 		SmStructureNode *pSNode  = new SmBinHorNode(CurToken);
/*N*/ 		SmNode *pFirst = NodeStack.Pop();
/*N*/ 
/*N*/ 		OpSubSup();
/*N*/ 		SmNode *pSecond = NodeStack.Pop();
/*N*/ 
/*N*/ 		Sum();
/*N*/ 
/*N*/ 		pSNode->SetSubNodes(pFirst, pSecond, NodeStack.Pop());
/*N*/ 		NodeStack.Push(pSNode);
/*N*/ 	}
/*N*/ }


/*N*/ void SmParser::Sum()
/*N*/ {
/*N*/ 	Product();
/*N*/ 	while (TokenInGroup(TGSUM))
/*N*/ 	{
/*N*/ 		SmStructureNode *pSNode  = new SmBinHorNode(CurToken);
/*N*/ 		SmNode *pFirst = NodeStack.Pop();
/*N*/ 
/*N*/ 		OpSubSup();
/*N*/ 		SmNode *pSecond = NodeStack.Pop();
/*N*/ 
/*N*/ 		Product();
/*N*/ 
/*N*/ 		pSNode->SetSubNodes(pFirst, pSecond, NodeStack.Pop());
/*N*/ 		NodeStack.Push(pSNode);
/*N*/ 	}
/*N*/ }


/*N*/ void SmParser::Product()
/*N*/ {
/*N*/ 	Power();
/*N*/ 
/*N*/ 	while (TokenInGroup(TGPRODUCT))
/*N*/ 	{	SmStructureNode *pSNode;
/*N*/ 		SmNode *pFirst = NodeStack.Pop(),
/*N*/ 			   *pOper;
/*N*/ 		BOOL bSwitchArgs = FALSE;
/*N*/ 
/*N*/ 		SmTokenType eType = CurToken.eType;
/*N*/ 		switch (eType)
/*N*/ 		{
/*N*/ 			case TOVER:
/*N*/ 				pSNode = new SmBinVerNode(CurToken);
/*N*/ 				pOper = new SmRectangleNode(CurToken);
/*N*/ 				NextToken();
/*N*/ 				break;
/*N*/ 
/*N*/ 			case TBOPER:
/*?*/ 				pSNode = new SmBinHorNode(CurToken);
/*?*/ 
/*?*/ 				NextToken();
/*?*/ 
/*?*/ 				GlyphSpecial();
/*?*/ 				pOper = NodeStack.Pop();
/*?*/ 				break;
/*N*/ 
/*N*/ 			case TOVERBRACE :
/*N*/ 			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;
/*?*/ 			}
/*?*/ 
/*N*/ 			default:
/*N*/ 				pSNode = new SmBinHorNode(CurToken);
/*N*/ 
/*N*/ 				OpSubSup();
/*N*/ 				pOper = NodeStack.Pop();
/*N*/ 		}
/*N*/ 
/*N*/ 		Power();
/*N*/ 
/*N*/ 		if (bSwitchArgs)
/*N*/ 			//! vgl siehe SmBinDiagonalNode::Arrange
/*?*/ 			pSNode->SetSubNodes(pFirst, NodeStack.Pop(), pOper);
/*N*/ 		else
/*N*/ 			pSNode->SetSubNodes(pFirst, pOper, NodeStack.Pop());
/*N*/ 		NodeStack.Push(pSNode);
/*N*/ 	}
/*N*/ }


/*N*/ void SmParser::SubSup(ULONG nActiveGroup)
/*N*/ {
/*N*/ 	DBG_ASSERT(nActiveGroup == TGPOWER  ||  nActiveGroup == TGLIMIT,
/*N*/ 			   "Sm: falsche Tokengruppe");
/*N*/ 
/*N*/ 	if (!TokenInGroup(nActiveGroup))
/*N*/ 		// already finish
/*N*/ 		return;
/*N*/ 
/*N*/ 	SmSubSupNode *pNode = new SmSubSupNode(CurToken);
/*N*/ 	//! Of course 'CurToken' ist just the first sub-/supscript token.
/*N*/ 	//! It should be of no further interest. The positions of the
/*N*/ 	//! sub-/supscripts will be identified by the corresponding subnodes
/*N*/ 	//! index in the 'aSubNodes' array (enum value from 'SmSubSup').
/*N*/ 
/*N*/ 	pNode->SetUseLimits(nActiveGroup == TGLIMIT);
/*N*/ 
/*N*/ 	// initialize subnodes array
/*N*/ 	SmNodeArray  aSubNodes;
/*N*/ 	aSubNodes.SetSize(1 + SUBSUP_NUM_ENTRIES);
/*N*/ 	aSubNodes.Put(0, NodeStack.Pop());
/*N*/ 	for (USHORT i = 1;  i < aSubNodes.GetSize();  i++)
/*N*/ 		aSubNodes.Put(i, NULL);
/*N*/ 
/*N*/ 	// process all sub-/supscripts
/*N*/ 	int  nIndex;
/*N*/ 	while (TokenInGroup(nActiveGroup))
/*N*/ 	{	SmTokenType  eType (CurToken.eType);
/*N*/ 
/*N*/ 		// skip sub-/supscript token
/*N*/ 		NextToken();
/*N*/ 
/*N*/ 		// get sub-/supscript node on top of stack
/*N*/ 		if (eType == TFROM  ||  eType == TTO)
/*N*/ 		{
/*N*/ 			// parse limits in old 4.0 and 5.0 style
/*N*/ 			Relation();
/*N*/ 		}
/*N*/ 		else
/*N*/ 			Term();
/*N*/ 
/*N*/ 		switch (eType)
/*N*/ 		{	case TRSUB :	nIndex = (int) RSUB;	break;
/*N*/ 			case TRSUP :	nIndex = (int) RSUP;	break;
/*N*/ 			case TFROM :
/*N*/ 			case TCSUB :	nIndex = (int) CSUB;	break;
/*N*/ 			case TTO :
/*N*/ 			case TCSUP :	nIndex = (int) CSUP;	break;
/*N*/ 			case TLSUB :	nIndex = (int) LSUB;	break;
/*N*/ 			case TLSUP :	nIndex = (int) LSUP;	break;
/*N*/ 			default :
/*N*/ 				DBG_ASSERT(FALSE, "Sm: unbekannter Fall");
/*N*/ 		}
/*N*/ 		nIndex++;
/*N*/ 		DBG_ASSERT(1 <= nIndex	&&	nIndex <= 1 + SUBSUP_NUM_ENTRIES,
/*N*/ 				   "SmParser::Power() : sub-/supscript index falsch")
/*N*/ 
/*N*/ 		// set sub-/supscript if not already done
/*N*/ 		if (aSubNodes.Get(nIndex) != NULL)
/*?*/ 			Error(PE_DOUBLE_SUBSUPSCRIPT);
/*N*/ 		aSubNodes.Put(nIndex, NodeStack.Pop());
/*N*/ 	}
/*N*/ 
/*N*/ 	pNode->SetSubNodes(aSubNodes);
/*N*/ 	NodeStack.Push(pNode);
/*N*/ }


/*N*/ void SmParser::OpSubSup()
/*N*/ {
/*N*/ 	// push operator symbol
/*N*/ 	NodeStack.Push(new SmMathSymbolNode(CurToken));
/*N*/ 	// skip operator token
/*N*/ 	NextToken();
/*N*/ 	// get sub- supscripts if any
/*N*/ 	if (TokenInGroup(TGPOWER))
/*?*/ 		SubSup(TGPOWER);
/*N*/ }


/*N*/ void SmParser::Power()
/*N*/ {
/*N*/ 	// get body for sub- supscripts on top of stack
/*N*/ 	Term();
/*N*/ 
/*N*/ 	SubSup(TGPOWER);
/*N*/ }


/*N*/ void SmParser::Blank()
/*N*/ {
/*N*/ 	DBG_ASSERT(TokenInGroup(TGBLANK), "Sm : falsches Token");
/*N*/ 	SmBlankNode *pBlankNode = new SmBlankNode(CurToken);
/*N*/ 
/*N*/ 	while (TokenInGroup(TGBLANK))
/*N*/ 	{
/*N*/ 		pBlankNode->IncreaseBy(CurToken);
/*N*/ 		NextToken();
/*N*/ 	}
/*N*/ 
/*N*/ 	// Blanks am Zeilenende ignorieren wenn die entsprechende Option gesetzt ist
/*N*/ 	if (CurToken.eType == TNEWLINE  ||  CurToken.eType == TEND
/*N*/         &&  SM_MOD1()->GetConfig()->IsIgnoreSpacesRight())
/*?*/ 		pBlankNode->Clear();
/*N*/ 
/*N*/ 	NodeStack.Push(pBlankNode);
/*N*/ }


/*N*/ void SmParser::Term()
/*N*/ {
/*N*/ 	switch (CurToken.eType)
/*N*/ 	{	case TESCAPE :
/*N*/ 			Escape();
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TLGROUP :
/*N*/ 			NextToken();
/*N*/ 
/*N*/ 			// allow for empty group
/*N*/ 			if (CurToken.eType == TRGROUP)
/*N*/ 			{	SmStructureNode *pSNode = new SmExpressionNode(CurToken);
/*N*/ 				pSNode->SetSubNodes(NULL, NULL);
/*N*/ 				NodeStack.Push(pSNode);
/*N*/ 
/*N*/ 				NextToken();
/*N*/ 			}
/*N*/ 			else	// go as usual
/*N*/ 			{	Align();
/*N*/ 				if (CurToken.eType != TRGROUP)
/*N*/ 					Error(PE_RGROUP_EXPECTED);
/*N*/ 				else
/*N*/ 				{	NextToken();
/*N*/ 				}
/*N*/ 			}
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TLEFT :
/*N*/ 			Brace();
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TBLANK :
/*N*/ 		case TSBLANK :
/*N*/ 			Blank();
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TTEXT :
/*N*/ 			NodeStack.Push(new SmTextNode(CurToken, FNT_TEXT));
/*N*/ 			NextToken();
/*N*/ 			break;
/*N*/ 		case TIDENT :
/*N*/ 		case TCHARACTER :
/*N*/ 			NodeStack.Push(new SmTextNode(CurToken, FNT_VARIABLE));
/*N*/ 			NextToken();
/*N*/ 			break;
/*N*/ 		case TNUMBER :
/*N*/ 			NodeStack.Push(new SmTextNode(CurToken, FNT_NUMBER));
/*N*/ 			NextToken();
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TLEFTARROW :
/*N*/ 		case TRIGHTARROW :
/*N*/ 		case TUPARROW :
/*N*/ 		case TDOWNARROW :
/*N*/ 		case TSETN :
/*N*/ 		case TSETZ :
/*N*/ 		case TSETQ :
/*N*/ 		case TSETR :
/*N*/ 		case TSETC :
/*N*/ 		case THBAR :
/*N*/ 		case TLAMBDABAR :
/*N*/ 		case TCIRC :
/*N*/ 		case TDRARROW :
/*N*/ 		case TDLARROW :
/*N*/ 		case TDLRARROW :
/*N*/ 		case TBACKEPSILON :
/*N*/ 		case TALEPH :
/*N*/ 		case TIM :
/*N*/ 		case TRE :
/*N*/ 		case TWP :
/*N*/ 		case TEMPTYSET :
/*N*/ 		case TINFINITY :
/*N*/ 		case TEXISTS :
/*N*/ 		case TFORALL :
/*N*/ 		case TPARTIAL :
/*N*/ 		case TNABLA :
/*N*/ 		case TTOWARD :
/*N*/ 		case TDOTSAXIS :
/*N*/ 		case TDOTSDIAG :
/*N*/ 		case TDOTSDOWN :
/*N*/ 		case TDOTSLOW :
/*N*/ 		case TDOTSUP :
/*N*/ 		case TDOTSVERT :
/*N*/ 			NodeStack.Push(new SmMathSymbolNode(CurToken));
/*N*/ 			NextToken();
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TPLACE:
/*N*/ 			NodeStack.Push(new SmPlaceNode(CurToken));
/*N*/ 			NextToken();
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TSPECIAL:
/*N*/ 			Special();
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TBINOM:
/*N*/			Binom(); // matrixfett.smf
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TSTACK:
/*N*/			Stack(); // matrixfett.smf
/*?*/ 			break;
/*N*/ 
/*N*/ 		case TMATRIX:
/*N*/ 			Matrix();
/*N*/ 			break;
/*N*/ 
/*N*/ 		default:
/*N*/ 			if (TokenInGroup(TGLBRACES))
/*N*/ 			{	Brace();
/*N*/ 			}
/*N*/ 			else if (TokenInGroup(TGOPER))
/*N*/ 			{	Operator();
/*N*/ 			}
/*N*/ 			else if (TokenInGroup(TGUNOPER))
/*N*/ 			{	UnOper();
/*N*/ 			}
/*N*/ 			else if (    TokenInGroup(TGATTRIBUT)
/*N*/ 					 ||  TokenInGroup(TGFONTATTR))
/*N*/ 			{	SmStructureNodeArray  aArray;
/*N*/ 
/*N*/ 				BOOL    bIsAttr;
/*N*/ 				USHORT  n = 0;
/*N*/ 				while ((bIsAttr = TokenInGroup(TGATTRIBUT))
/*N*/ 					   ||  TokenInGroup(TGFONTATTR))
/*N*/ 				{	aArray.SetSize(n + 1);
/*N*/ 
/*N*/ 					if (bIsAttr)
/*N*/ 						Attribut();
/*N*/ 					else
/*N*/ 						FontAttribut();
/*N*/ 
/*N*/ 					// check if casting in following line is ok
/*N*/ 					DBG_ASSERT(!NodeStack.Top()->IsVisible(), "Sm : Ooops...");
/*N*/ 
/*N*/ 					aArray.Put(n, (SmStructureNode *) NodeStack.Pop());
/*N*/ 					n++;
/*N*/ 				}
/*N*/ 
/*N*/ 				Power();
/*N*/ 
/*N*/ 				SmNode *pFirstNode = NodeStack.Pop();
/*N*/ 				while (n > 0)
/*N*/ 				{	aArray.Get(n - 1)->SetSubNodes(0, pFirstNode);
/*N*/ 					pFirstNode = aArray.Get(n - 1);
/*N*/ 					n--;
/*N*/ 				}
/*N*/ 				NodeStack.Push(pFirstNode);
/*N*/ 			}
/*N*/ 			else if (TokenInGroup(TGFUNCTION))
/*N*/             {   if (CONVERT_40_TO_50 != GetConversion())
/*N*/ 				{	Function();
/*N*/ 				}
/*N*/ 				else	// encapsulate old 4.0 style parsing in braces
/*N*/ 				{
/*N*/ 					// insert opening brace
/*N*/ 					Insert('{', GetTokenIndex());
/*N*/ 
/*N*/ 					//
/*N*/ 					// parse in 4.0 style
/*N*/ 					//
/*N*/ 					Function();
/*N*/ 
/*N*/ 					SmNode *pFunc = NodeStack.Pop();
/*N*/ 
/*N*/ 					if (CurToken.eType == TLPARENT)
/*?*/ 					{	Term();
/*N*/ 					}
/*N*/ 					else
/*N*/ 					{	Align();
/*N*/ 					}
/*N*/ 
/*N*/ 					// insert closing brace
/*N*/ 					Insert('}', GetTokenIndex());
/*N*/ 
/*N*/ 					SmStructureNode *pSNode = new SmExpressionNode(pFunc->GetToken());
/*N*/ 					pSNode->SetSubNodes(pFunc, NodeStack.Pop());
/*N*/ 					NodeStack.Push(pSNode);
/*N*/ 				}
/*N*/ 			}
/*N*/ 			else
/*N*/ 				Error(PE_UNEXPECTED_CHAR);
/*N*/ 	}
/*N*/ }


/*N*/ void SmParser::Escape()
/*N*/ {
/*N*/ 	NextToken();
/*N*/ 
/*N*/ 	sal_Unicode	cChar;
/*N*/ 	switch (CurToken.eType)
/*N*/ 	{	case TLPARENT :		cChar = MS_LPARENT;		break;
/*N*/ 		case TRPARENT :		cChar = MS_RPARENT;		break;
/*N*/ 		case TLBRACKET :	cChar = MS_LBRACKET;	break;
/*N*/ 		case TRBRACKET :	cChar = MS_RBRACKET;	break;
/*N*/         case TLDBRACKET :   cChar = MS_LDBRACKET;   break;
/*N*/         case TRDBRACKET :   cChar = MS_RDBRACKET;   break;
/*N*/ 		case TLBRACE :
/*N*/ 		case TLGROUP :		cChar = MS_LBRACE;		break;
/*N*/ 		case TRBRACE :
/*N*/ 		case TRGROUP :		cChar = MS_RBRACE;		break;
/*N*/ 		case TLANGLE :		cChar = MS_LANGLE;		break;
/*N*/ 		case TRANGLE :		cChar = MS_RANGLE;		break;
/*N*/ 		case TLCEIL :		cChar = MS_LCEIL;		break;
/*N*/ 		case TRCEIL :		cChar = MS_RCEIL;		break;
/*N*/ 		case TLFLOOR :		cChar = MS_LFLOOR;		break;
/*N*/ 		case TRFLOOR :		cChar = MS_RFLOOR;		break;
/*N*/ 		case TLLINE :
/*N*/ 		case TRLINE :		cChar = MS_LINE;		break;
/*N*/ 		case TLDLINE :
/*N*/ 		case TRDLINE :		cChar = MS_DLINE;		break;
/*N*/ 		default:
/*N*/ 			Error(PE_UNEXPECTED_TOKEN);
/*N*/ 	}
/*N*/ 
/*N*/ 	SmNode *pNode = new SmMathSymbolNode(CurToken);
/*N*/ 	NodeStack.Push(pNode);
/*N*/ 
/*N*/ 	NextToken();
/*N*/ }


/*N*/ void SmParser::Operator()
/*N*/ {
/*N*/ 	if (TokenInGroup(TGOPER))
/*N*/ 	{	SmStructureNode *pSNode = new SmOperNode(CurToken);
/*N*/ 
/*N*/ 		// put operator on top of stack
/*N*/ 		Oper();
/*N*/ 
/*N*/ 		if (TokenInGroup(TGLIMIT) || TokenInGroup(TGPOWER))
/*N*/ 			SubSup(CurToken.nGroup);
/*N*/ 		SmNode *pOperator = NodeStack.Pop();
/*N*/ 
/*N*/ 		// get argument
/*N*/ 		Power();
/*N*/ 
/*N*/ 		pSNode->SetSubNodes(pOperator, NodeStack.Pop());
/*N*/ 		NodeStack.Push(pSNode);
/*N*/ 	}
/*N*/ }


/*N*/ void SmParser::Oper()
/*N*/ {
/*N*/ 	SmTokenType  eType (CurToken.eType);
/*N*/ 	SmNode      *pNode = NULL;
/*N*/ 
/*N*/ 	switch (eType)
/*N*/ 	{
/*N*/ 		case TSUM :
/*N*/ 		case TPROD :
/*N*/ 		case TCOPROD :
/*N*/ 		case TINT :
/*N*/ 		case TIINT :
/*N*/ 		case TIIINT :
/*N*/ 		case TLINT :
/*N*/ 		case TLLINT :
/*N*/ 		case TLLLINT :
/*N*/ 			pNode = new SmMathSymbolNode(CurToken);
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TLIM :
/*N*/ 		case TLIMSUP :
/*N*/ 		case TLIMINF :
/*N*/ 			{
/*N*/ 				const sal_Char* pLim = 0;
/*N*/ 				switch (eType)
/*N*/ 				{
/*N*/ 					case TLIM :		pLim = "lim";		break;
/*N*/ 					case TLIMSUP :  pLim = "lim sup";	break;
/*N*/ 					case TLIMINF :  pLim = "lim inf";	break;
/*N*/ 				}
/*N*/ 				if( pLim )
/*N*/ 					CurToken.aText.AssignAscii( pLim );
/*N*/ 				pNode = new SmTextNode(CurToken, FNT_TEXT);
/*N*/ 			}
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TOVERBRACE :
/*N*/ 		case TUNDERBRACE :
/*N*/ 				pNode = new SmMathSymbolNode(CurToken);
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TOPER :
/*?*/ 			NextToken();
/*N*/ 
/*?*/ 			DBG_ASSERT(CurToken.eType == TSPECIAL, "Sm: falsches Token");
/*?*/ 			pNode = new SmGlyphSpecialNode(CurToken);
/*?*/ 			break;
/*N*/ 
/*N*/ 		default :
/*N*/ 			DBG_ASSERT(0, "Sm: unbekannter Fall");
/*N*/ 	}
/*N*/ 	NodeStack.Push(pNode);
/*N*/ 
/*N*/ 	NextToken();
/*N*/ }


/*N*/ void SmParser::UnOper()
/*N*/ {
/*N*/ 	DBG_ASSERT(TokenInGroup(TGUNOPER), "Sm: falsches Token");
/*N*/ 
/*N*/ 	SmToken		 aNodeToken = CurToken;
/*N*/ 	SmTokenType  eType 		= CurToken.eType;
/*N*/ 	BOOL		 bIsPostfix = eType == TFACT;
/*N*/ 
/*N*/ 	SmStructureNode *pSNode;
/*N*/ 	SmNode *pOper,
/*N*/ 		   *pExtra = 0,
/*N*/ 		   *pArg;
/*N*/ 
/*N*/ 	switch (eType)
/*N*/ 	{
/*N*/ 		case TABS :
/*N*/ 		case TSQRT :
/*N*/ 			NextToken();
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TNROOT :
/*N*/ 			NextToken();
/*N*/ 			Power();
/*N*/ 			pExtra = NodeStack.Pop();
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TUOPER :
/*?*/ 			NextToken();
/*?*/ 			GlyphSpecial();
/*?*/ 			pOper = NodeStack.Pop();
/*?*/ 			break;
/*N*/ 
/*N*/ 		case TPLUS :
/*N*/ 		case TMINUS :
/*N*/ 		case TPLUSMINUS :
/*N*/ 		case TMINUSPLUS :
/*N*/ 		case TNEG :
/*N*/ 		case TFACT :
/*N*/ 			OpSubSup();
/*N*/ 			pOper = NodeStack.Pop();
/*N*/ 			break;
/*N*/ 
/*N*/ 		default :
/*N*/ 			Error(PE_UNOPER_EXPECTED);
/*N*/ 	}
/*N*/ 
/*N*/ 	// get argument
/*N*/ 	Power();
/*N*/ 	pArg = NodeStack.Pop();
/*N*/ 
/*N*/ 	if (eType == TABS)
/*N*/ 	{	pSNode = new SmBraceNode(aNodeToken);
/*N*/ 		pSNode->SetScaleMode(SCALE_HEIGHT);
/*N*/ 
/*N*/ 		// build nodes for left & right lines
/*N*/ 		// (text, group, level of the used token are of no interrest here)
/*N*/ 		// we'll use row & column of the keyword for abs
/*N*/ 		aNodeToken.eType = TABS;
/*N*/ 		//
/*N*/ 		aNodeToken.cMathChar = MS_LINE;
/*N*/ 		SmNode* pLeft = new SmMathSymbolNode(aNodeToken);
/*N*/ 		//
/*N*/ 		aNodeToken.cMathChar = MS_LINE;
/*N*/ 		SmNode* pRight = new SmMathSymbolNode(aNodeToken);
/*N*/ 
/*N*/ 		pSNode->SetSubNodes(pLeft, pArg, pRight);
/*N*/ 	}
/*N*/ 	else if (eType == TSQRT  ||  eType == TNROOT)
/*N*/ 	{	pSNode = new SmRootNode(aNodeToken);
/*N*/ 		pOper = new SmRootSymbolNode(aNodeToken);
/*N*/ 		pSNode->SetSubNodes(pExtra, pOper, pArg);
/*N*/ 	}
/*N*/ 	else
/*N*/ 	{	pSNode = new SmUnHorNode(aNodeToken);
/*N*/ 
/*N*/ 		if (bIsPostfix)
/*N*/ 			pSNode->SetSubNodes(pArg, pOper);
/*N*/ 		else
/*N*/ 			// prefix operator
/*N*/ 			pSNode->SetSubNodes(pOper, pArg);
/*N*/ 	}
/*N*/ 
/*N*/ 	NodeStack.Push(pSNode);
/*N*/ }


/*N*/ void SmParser::Attribut()
/*N*/ {
/*N*/ 	DBG_ASSERT(TokenInGroup(TGATTRIBUT), "Sm: falsche Tokengruppe");
/*N*/ 
/*N*/ 	SmStructureNode	*pSNode = new SmAttributNode(CurToken);
/*N*/ 	SmNode		*pAttr;
/*N*/ 	SmScaleMode  eScaleMode = SCALE_NONE;
/*N*/ 
/*N*/ 	// get appropriate node for the attribut itself
/*N*/ 	switch (CurToken.eType)
/*N*/ 	{	case TUNDERLINE :
/*N*/ 		case TOVERLINE :
/*N*/ 		case TOVERSTRIKE :
/*?*/ 			pAttr = new SmRectangleNode(CurToken);
/*?*/ 			eScaleMode = SCALE_WIDTH;
/*?*/ 			break;
/*N*/ 
/*N*/ 		case TWIDEVEC :
/*N*/ 		case TWIDEHAT :
/*N*/ 		case TWIDETILDE :
/*N*/ 			pAttr = new SmMathSymbolNode(CurToken);
/*N*/ 			eScaleMode = SCALE_WIDTH;
/*?*/ 			break;
/*N*/ 
/*N*/ 		default :
/*N*/ 			pAttr = new SmMathSymbolNode(CurToken);
/*N*/ 	}
/*N*/ 
/*N*/ 	NextToken();
/*N*/ 
/*N*/ 	pSNode->SetSubNodes(pAttr, 0);
/*N*/ 	pSNode->SetScaleMode(eScaleMode);
/*N*/ 	NodeStack.Push(pSNode);
/*N*/ }


/*N*/ void SmParser::FontAttribut()
/*N*/ {
/*N*/ 	DBG_ASSERT(TokenInGroup(TGFONTATTR), "Sm: falsche Tokengruppe");
/*N*/ 
/*N*/ 	switch (CurToken.eType)
/*N*/ 	{
/*N*/ 		case TITALIC :
/*N*/ 		case TNITALIC :
/*N*/ 		case TBOLD :
/*N*/ 		case TNBOLD :
/*N*/ 		case TPHANTOM :
/*N*/ 			NodeStack.Push(new SmFontNode(CurToken));
/*N*/ 			NextToken();
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TSIZE :
/*N*/ 			FontSize();
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TFONT :
/*N*/ 			Font();
/*N*/ 			break;
/*N*/ 
/*N*/ 		case TCOLOR :
/*N*/ 			Color();
/*N*/ 			break;
/*N*/ 
/*N*/ 		default :
/*N*/ 			DBG_ASSERT(0, "Sm: unbekannter Fall");
/*N*/ 	}
/*N*/ }


/*N*/ void SmParser::Color()
/*N*/ {
/*N*/     DBG_ASSERT(CurToken.eType == TCOLOR, "Sm : Ooops...");
/*N*/ 
/*N*/     // last color rules, get that one
/*N*/     SmToken  aToken;
/*N*/     do
/*N*/     {   NextToken();
/*N*/ 
/*N*/         if (TokenInGroup(TGCOLOR))
/*N*/         {   aToken = CurToken;
/*N*/             NextToken();
/*N*/         }
/*N*/         else
/*N*/             Error(PE_COLOR_EXPECTED);
/*N*/     } while (CurToken.eType == TCOLOR);
/*N*/ 
/*N*/     NodeStack.Push(new SmFontNode(aToken));
/*N*/ }


/*N*/ void SmParser::Font()
/*N*/ {
/*N*/ 	DBG_ASSERT(CurToken.eType == TFONT, "Sm : Ooops...");
/*N*/ 
/*N*/ 	// last font rules, get that one
/*N*/ 	SmToken  aToken;
/*N*/ 	do
/*N*/ 	{	NextToken();
/*N*/ 
/*N*/ 		if (TokenInGroup(TGFONT))
/*N*/ 		{	aToken = CurToken;
/*N*/ 			NextToken();
/*N*/ 		}
/*N*/ 		else
/*N*/ 			Error(PE_FONT_EXPECTED);
/*N*/ 	} while (CurToken.eType == TFONT);
/*N*/ 
/*N*/ 	NodeStack.Push(new SmFontNode(aToken));
/*N*/ }
/*N*/ BOOL lcl_IsNumber(const UniString& rText)
/*N*/ {
/*N*/ 	BOOL bPoint = FALSE;
/*N*/ 	const sal_Unicode* pBuffer = rText.GetBuffer();
/*N*/ 	for(xub_StrLen nPos = 0; nPos < rText.Len(); nPos++, pBuffer++)
/*N*/ 	{
/*N*/ 		const sal_Unicode cChar = *pBuffer;
/*N*/ 		if(cChar == '.')
/*N*/ 		{
/*N*/ 			if(bPoint)
/*N*/ 				return FALSE;
/*N*/ 			else
/*N*/ 				bPoint = TRUE;
/*N*/ 		}
/*N*/ 		else if ( (cChar < 48) || (cChar > 57) )
/*N*/ 			return FALSE;
/*N*/ 	}
/*N*/ 	return TRUE;
/*N*/ }

/*N*/ void SmParser::FontSize()
/*N*/ {
/*N*/ 	DBG_ASSERT(CurToken.eType == TSIZE, "Sm : Ooops...");
/*N*/ 
/*N*/ 	USHORT	   Type;
/*N*/ 	SmFontNode *pFontNode = new SmFontNode(CurToken);
/*N*/ 
/*N*/ 	NextToken();
/*N*/ 
/*N*/ 	switch (CurToken.eType)
/*N*/ 	{
/*N*/ 		case TNUMBER:	Type = FNTSIZ_ABSOLUT;	break;
/*N*/ 		case TPLUS:		Type = FNTSIZ_PLUS;		break;
/*N*/ 		case TMINUS:	Type = FNTSIZ_MINUS;	break;
/*N*/ 		case TMULTIPLY:	Type = FNTSIZ_MULTIPLY;	break;
/*N*/ 		case TDIVIDEBY:	Type = FNTSIZ_DIVIDE;	break;
/*N*/ 
/*N*/ 		default:
/*?*/ 			delete pFontNode;
/*?*/ 			Error(PE_SIZE_EXPECTED);
/*?*/ 			return;
/*N*/ 	}
/*N*/ 
/*N*/ 	if (Type != FNTSIZ_ABSOLUT)
/*N*/ 	{
/*N*/ 		NextToken();
/*N*/ 		if (CurToken.eType != TNUMBER)
/*N*/ 		{
/*?*/ 			delete pFontNode;
/*?*/ 			Error(PE_SIZE_EXPECTED);
/*?*/ 			return;
/*N*/ 		}
/*N*/ 	}
/*N*/ 
/*N*/ 	// get number argument
/*N*/ 	double	  fTmp;
/*N*/ 	Fraction  aValue;
/*N*/ 	if(lcl_IsNumber(CurToken.aText) &&
/*N*/ 		sscanf(ByteString(CurToken.aText, RTL_TEXTENCODING_ASCII_US).GetBuffer(), "%lf", &fTmp) == 1)
/*N*/ 		aValue = fTmp;
/*N*/ 
/*N*/ 	NextToken();
/*N*/ 
/*N*/ 	pFontNode->SetSizeParameter(aValue, Type);
/*N*/ 	NodeStack.Push(pFontNode);
/*N*/ }


/*N*/ void SmParser::Brace()
/*N*/ {
/*N*/ 	DBG_ASSERT(CurToken.eType == TLEFT  ||  TokenInGroup(TGLBRACES),
/*N*/ 		"Sm: kein Klammer Ausdruck");
/*N*/ 
/*N*/ 	SmStructureNode *pSNode  = new SmBraceNode(CurToken);
/*N*/ 	SmNode *pBody   = 0,
/*N*/ 		   *pLeft   = 0,
/*N*/ 		   *pRight  = 0;
/*N*/ 	SmScaleMode   eScaleMode = SCALE_NONE;
/*N*/ 	SmParseError  eError     = PE_NONE;
/*N*/ 
/*N*/ 	if (CurToken.eType == TLEFT)
/*N*/ 	{	NextToken();
/*N*/ 
/*N*/ 		eScaleMode = SCALE_HEIGHT;
/*N*/ 
/*N*/ 		// check for left bracket
/*N*/ 		if (TokenInGroup(TGLBRACES) || TokenInGroup(TGRBRACES))
/*N*/ 		{
/*N*/ 			pLeft = new SmMathSymbolNode(CurToken);
/*N*/ 
/*N*/ 			NextToken();
/*N*/ 			Bracebody(TRUE);
/*N*/ 			pBody = NodeStack.Pop();
/*N*/ 
/*N*/ 			if (CurToken.eType == TRIGHT)
/*N*/ 			{	NextToken();
/*N*/ 
/*N*/ 				// check for right bracket
/*N*/ 				if (TokenInGroup(TGLBRACES) || TokenInGroup(TGRBRACES))
/*N*/ 				{
/*N*/ 					pRight = new SmMathSymbolNode(CurToken);
/*N*/ 					NextToken();
/*N*/ 				}
/*N*/ 				else
/*N*/ 					eError = PE_RBRACE_EXPECTED;
/*N*/ 			}
/*N*/ 			else
/*N*/ 				eError = PE_RIGHT_EXPECTED;
/*N*/ 		}
/*N*/ 		else
/*N*/ 			eError = PE_LBRACE_EXPECTED;
/*N*/ 	}
/*N*/ 	else
/*N*/ 	{
/*N*/ 		if (TokenInGroup(TGLBRACES))
/*N*/ 		{
/*N*/ 			pLeft = new SmMathSymbolNode(CurToken);
/*N*/ 
/*N*/ 			NextToken();
/*N*/ 			Bracebody(FALSE);
/*N*/ 			pBody = NodeStack.Pop();
/*N*/ 
/*N*/ 			SmTokenType  eExpectedType;
/*N*/ 			switch (pLeft->GetToken().eType)
/*N*/ 			{	case TLPARENT :	 	eExpectedType = TRPARENT;	break;
/*N*/ 				case TLBRACKET : 	eExpectedType = TRBRACKET;	break;
/*N*/ 				case TLBRACE : 	 	eExpectedType = TRBRACE;	break;
/*N*/ 				case TLDBRACKET :	eExpectedType = TRDBRACKET;	break;
/*N*/ 				case TLLINE : 	 	eExpectedType = TRLINE;		break;
/*N*/ 				case TLDLINE :   	eExpectedType = TRDLINE;	break;
/*N*/ 				case TLANGLE :   	eExpectedType = TRANGLE;	break;
/*N*/ 				case TLFLOOR :   	eExpectedType = TRFLOOR;	break;
/*N*/ 				case TLCEIL : 	 	eExpectedType = TRCEIL;		break;
/*N*/ 				default :
/*N*/ 					DBG_ASSERT(0, "Sm: unbekannter Fall");
/*N*/ 			}
/*N*/ 
/*N*/ 			if (CurToken.eType == eExpectedType)
/*N*/ 			{
/*N*/ 				pRight = new SmMathSymbolNode(CurToken);
/*N*/ 				NextToken();
/*N*/ 			}
/*N*/ 			else
/*N*/ 				eError = PE_PARENT_MISMATCH;
/*N*/ 		}
/*N*/ 		else
/*N*/ 			eError = PE_LBRACE_EXPECTED;
/*N*/ 	}
/*N*/ 
/*N*/ 	if (eError == PE_NONE)
/*N*/ 	{   DBG_ASSERT(pLeft,  "Sm: NULL pointer");
/*N*/ 		DBG_ASSERT(pRight, "Sm: NULL pointer");
/*N*/ 		pSNode->SetSubNodes(pLeft, pBody, pRight);
/*N*/ 		pSNode->SetScaleMode(eScaleMode);
/*N*/ 		NodeStack.Push(pSNode);
/*N*/ 	}
/*N*/ 	else
/*N*/ 	{	delete pSNode;
/*N*/ 		delete pBody;
/*N*/ 		delete pLeft;
/*N*/ 		delete pRight;
/*N*/ 
/*N*/ 		Error(eError);
/*N*/ 	}
/*N*/ }


/*N*/ void SmParser::Bracebody(BOOL bIsLeftRight)
/*N*/ {
/*N*/ 	SmStructureNode *pBody = new SmBracebodyNode(CurToken);
/*N*/ 	SmNodeArray  	 aNodes;
/*N*/ 	USHORT		 	 nNum = 0;
/*N*/ 
/*N*/ 	// get body if any
/*N*/ 	if (bIsLeftRight)
/*N*/ 	{
/*N*/ 		do
/*N*/ 		{
/*N*/ 			if (CurToken.eType == TMLINE)
/*N*/ 			{
/*N*/ 				NodeStack.Push(new SmMathSymbolNode(CurToken));
/*N*/                 NextToken();
/*N*/ 				nNum++;
/*N*/ 			}
/*N*/ 			else if (CurToken.eType != TRIGHT)
/*N*/ 			{	Align();
/*N*/ 				nNum++;
/*N*/ 
/*N*/ 				if (CurToken.eType != TMLINE  &&  CurToken.eType != TRIGHT)
/*N*/ 					Error(PE_RIGHT_EXPECTED);
/*N*/ 			}
/*N*/ 		} while (CurToken.eType != TEND  &&  CurToken.eType != TRIGHT);
/*N*/ 	}
/*N*/ 	else
/*N*/ 	{
/*N*/ 		do
/*N*/ 		{
/*N*/ 			if (CurToken.eType == TMLINE)
/*N*/ 			{
/*N*/ 				NodeStack.Push(new SmMathSymbolNode(CurToken));
/*N*/ 				NextToken();
/*N*/ 				nNum++;
/*N*/ 			}
/*N*/ 			else if (!TokenInGroup(TGRBRACES))
/*N*/ 			{	Align();
/*N*/ 				nNum++;
/*N*/ 
/*N*/ 				if (CurToken.eType != TMLINE  &&  !TokenInGroup(TGRBRACES))
/*N*/ 					Error(PE_RBRACE_EXPECTED);
/*N*/ 			}
/*N*/ 		} while (CurToken.eType != TEND  &&  !TokenInGroup(TGRBRACES));
/*N*/ 	}
/*N*/ 
/*N*/ 	// build argument vector in parsing order
/*N*/ 	aNodes.SetSize(nNum);
/*N*/ 	for (USHORT i = 0;  i < nNum;  i++)
/*N*/ 		aNodes.Put(nNum - 1 - i, NodeStack.Pop());
/*N*/ 
/*N*/ 	pBody->SetSubNodes(aNodes);
/*N*/ 	pBody->SetScaleMode(bIsLeftRight ? SCALE_HEIGHT : SCALE_NONE);
/*N*/ 	NodeStack.Push(pBody);
/*N*/ }


/*N*/ void SmParser::Function()
/*N*/ {
/*N*/ 	switch (CurToken.eType)
/*N*/ 	{
/*N*/ 		case TFUNC:
/*N*/ 			NextToken();	// skip "FUNC"-statement
/*N*/ 			// fall through
/*N*/ 
/*N*/ 		case TSIN :
/*N*/ 		case TCOS :
/*N*/ 		case TTAN :
/*N*/ 		case TCOT :
/*N*/ 		case TASIN :
/*N*/ 		case TACOS :
/*N*/ 		case TATAN :
/*N*/ 		case TACOT :
/*N*/ 		case TSINH :
/*N*/ 		case TCOSH :
/*N*/ 		case TTANH :
/*N*/ 		case TCOTH :
/*N*/ 		case TASINH :
/*N*/ 		case TACOSH :
/*N*/ 		case TATANH :
/*N*/ 		case TACOTH :
/*N*/ 		case TLN :
/*N*/ 		case TLOG :
/*N*/ 		case TEXP :
/*N*/ 			NodeStack.Push(new SmTextNode(CurToken, FNT_FUNCTION));
/*N*/ 			NextToken();
/*N*/ 			break;
/*N*/ 
/*N*/ 		default:
/*N*/ 			Error(PE_FUNC_EXPECTED);
/*N*/ 	}
/*N*/ }


/*N*/ void SmParser::Binom() // matrixfett.smf
/*N*/ {
/*N*/ 	SmNodeArray  ExpressionArray;
/*N*/ 	SmStructureNode	*pSNode = new SmTableNode(CurToken);
/*N*/ 
/*N*/ 	NextToken();
/*N*/ 
/*N*/ 	Sum();
/*N*/ 	Sum();
/*N*/ 
/*N*/ 	ExpressionArray.SetSize(2);
/*N*/ 
/*N*/ 	for (int i = 0;  i < 2;  i++)
/*N*/ 		ExpressionArray.Put(2 - (i + 1), NodeStack.Pop());
/*N*/ 
/*N*/ 	pSNode->SetSubNodes(ExpressionArray);
/*N*/ 	NodeStack.Push(pSNode);
/*N*/ }


/*N*/ void SmParser::Stack() // matrixfett.smf
/*N*/ {
/*N*/ 	SmNodeArray  ExpressionArray;
/*N*/ 	NextToken();
/*N*/ 	if (CurToken.eType == TLGROUP)
/*N*/ 	{
/*N*/ 		USHORT n = 0;
/*N*/ 
/*N*/ 		do
/*N*/ 		{
/*N*/ 			NextToken();
/*N*/ 			Align();
/*N*/ 			n++;
/*N*/ 		}
/*N*/ 		while (CurToken.eType == TPOUND);
/*N*/ 
/*N*/ 		ExpressionArray.SetSize(n);
/*N*/ 
/*N*/ 		for (USHORT i = 0; i < n; i++)
/*N*/ 			ExpressionArray.Put(n - (i + 1), NodeStack.Pop());
/*N*/ 
/*N*/ 		if (CurToken.eType != TRGROUP)
/*N*/ 			Error(PE_RGROUP_EXPECTED);
/*N*/ 
/*N*/ 		NextToken();
/*N*/ 
/*N*/ 		SmStructureNode *pSNode = new SmTableNode(CurToken);
/*N*/ 		pSNode->SetSubNodes(ExpressionArray);
/*N*/ 		NodeStack.Push(pSNode);
/*N*/ 	}
/*N*/ 	else
/*N*/ 		Error(PE_LGROUP_EXPECTED);
/*N*/ }


/*N*/ void SmParser::Matrix()
/*N*/ {
/*N*/ 	SmNodeArray  ExpressionArray;
/*N*/ 
/*N*/ 	NextToken();
/*N*/ 	if (CurToken.eType == TLGROUP)
/*N*/ 	{
/*N*/ 		USHORT c = 0;
/*N*/ 
/*N*/ 		do
/*N*/ 		{
/*N*/ 			NextToken();
/*N*/ 			Align();
/*N*/ 			c++;
/*N*/ 		}
/*N*/ 		while (CurToken.eType == TPOUND);
/*N*/ 
/*N*/ 		USHORT r = 1;
/*N*/ 
/*N*/ 		while (CurToken.eType == TDPOUND)
/*N*/ 		{
/*N*/ 			NextToken();
/*N*/ 			for (USHORT i = 0; i < c; i++)
/*N*/ 			{
/*N*/ 				Align();
/*N*/ 				if (i < (c - 1))
/*N*/ 				{
/*N*/ 					if (CurToken.eType == TPOUND)
/*N*/ 					{
/*N*/ 						NextToken();
/*N*/ 					}
/*N*/ 					else
/*N*/ 						Error(PE_POUND_EXPECTED);
/*N*/ 				}
/*N*/ 			}
/*N*/ 
/*N*/ 			r++;
/*N*/ 		}
/*N*/ 
/*N*/ 		long nRC = r * c;
/*N*/ 
/*N*/ 		ExpressionArray.SetSize(nRC);
/*N*/ 
/*N*/ 		for (USHORT i = 0; i < (nRC); i++)
/*N*/ 			ExpressionArray.Put((nRC) - (i + 1), NodeStack.Pop());
/*N*/ 
/*N*/ 		if (CurToken.eType != TRGROUP)
/*N*/ 			Error(PE_RGROUP_EXPECTED);
/*N*/ 
/*N*/ 		NextToken();
/*N*/ 
/*N*/ 		SmMatrixNode *pMNode = new SmMatrixNode(CurToken);
/*N*/ 		pMNode->SetSubNodes(ExpressionArray);
/*N*/ 		pMNode->SetRowCol(r, c);
/*N*/ 		NodeStack.Push(pMNode);
/*N*/ 	}
/*N*/ 	else
/*N*/ 		Error(PE_LGROUP_EXPECTED);
/*N*/ }


/*N*/ void SmParser::Special()
/*M*/ {
/*M*/     BOOL bReplace = FALSE;
/*M*/     String &rName = CurToken.aText;
/*M*/     String aNewName;
/*M*/ 
/*M*/     if (CONVERT_NONE == GetConversion())
/*M*/     {
/*M*/         // conversion of symbol names for 6.0 (XML) file format
/*M*/         // (name change on import / export.
/*M*/         // UI uses localized names XML file format does not.)
/*M*/         if (IsImportSymbolNames())
/*M*/         {
/*M*/             const SmLocalizedSymbolData &rLSD = SM_MOD1()->GetLocSymbolData();
/*M*/             aNewName = rLSD.GetUiSymbolName( rName );
/*M*/             bReplace = TRUE;
/*M*/         }
/*M*/         else if (IsExportSymbolNames())
/*M*/         {
/*M*/             const SmLocalizedSymbolData &rLSD = SM_MOD1()->GetLocSymbolData();
/*M*/             aNewName = rLSD.GetExportSymbolName( rName );
/*M*/             bReplace = TRUE;
/*M*/         }
/*M*/     }
/*M*/     else    // 5.0 <-> 6.0 formula text (symbol name) conversion
/*M*/     {
/*M*/         LanguageType nLang = GetLanguage();
/*M*/         SmLocalizedSymbolData &rData = SM_MOD1()->GetLocSymbolData();
/*M*/         const ResStringArray *pFrom = 0;
/*M*/         const ResStringArray *pTo   = 0;
/*M*/         if (CONVERT_50_TO_60 == GetConversion())
/*M*/         {
/*M*/             pFrom = rData.Get50NamesArray( nLang );
/*M*/             pTo   = rData.Get60NamesArray( nLang );
/*M*/         }
/*M*/         else if (CONVERT_60_TO_50 == GetConversion())
/*M*/         {
/*M*/             pFrom = rData.Get60NamesArray( nLang );
/*M*/             pTo   = rData.Get50NamesArray( nLang );
/*M*/         }
/*M*/         if (pFrom  &&  pTo)
/*M*/         {
/*M*/             DBG_ASSERT( pFrom->Count() == pTo->Count(),
/*M*/                     "array length mismatch" );
/*M*/             USHORT nCount = pFrom->Count();
/*M*/             for (USHORT i = 0;  i < nCount;  ++i)
/*M*/             {
/*M*/                 if (pFrom->GetString(i) == rName)
/*M*/                 {
/*M*/                     aNewName = pTo->GetString(i);
/*M*/                     bReplace = TRUE;
/*M*/                 }
/*M*/             }
/*M*/         }
/*M*/         // else:
/*M*/         // conversion arrays not found or (usually)
/*M*/         // conversion not necessary
/*M*/     }
/*M*/ 
/*M*/     if (bReplace  &&  aNewName.Len()  &&  rName != aNewName)
/*M*/     {
/*M*/         Replace( GetTokenIndex() + 1, rName.Len(), aNewName );
/*M*/         rName = aNewName;
/*M*/     }
/*M*/ 
/*M*/ 	NodeStack.Push(new SmSpecialNode(CurToken));
/*M*/ 	NextToken();
/*M*/ }


/*?*/ void SmParser::GlyphSpecial()
/*?*/ {
/*?*/ 	NodeStack.Push(new SmGlyphSpecialNode(CurToken));
/*?*/ 	NextToken();
/*?*/ }


/*N*/ void SmParser::Error(SmParseError eError)
/*N*/ {
/*N*/ 	SmStructureNode *pSNode = new SmExpressionNode(CurToken);
/*N*/ 	SmErrorNode		*pErr   = new SmErrorNode(eError, CurToken);
/*N*/ 	pSNode->SetSubNodes(pErr, 0);
/*N*/ 
/*N*/ 	//! put a structure node on the stack (instead of the error node itself)
/*N*/ 	//! because sometimes such a node is expected in order to attach some
/*N*/ 	//! subnodes
/*N*/ 	NodeStack.Push(pSNode);
/*N*/ 
/*N*/ 	AddError(eError, pSNode);
/*N*/ 
/*N*/ 	NextToken();
/*N*/ }


// end gramar


/*N*/ SmParser::SmParser()
/*N*/ {
/*N*/     eConversion = CONVERT_NONE;
/*N*/     bImportSymNames = bExportSymNames = FALSE;
/*N*/     nLang = Application::GetSettings().GetUILanguage();
/*N*/ }


/*N*/ SmNode *SmParser::Parse(const String &rBuffer)
/*N*/ {
/*N*/ 	BufferString = rBuffer;
/*N*/ 	BufferString.ConvertLineEnd( LINEEND_LF );
/*N*/ 	BufferIndex  =
/*N*/ 	nTokenIndex  = 0;
/*N*/ 	Row 		 = 1;
/*N*/ 	ColOff		 = 0;
/*N*/ 	CurError	 = -1;
/*N*/ 
/*N*/ 	for (USHORT i = 0;  i < ErrDescList.Count();  i++)
/*N*/ 		delete ErrDescList.Remove(i);
/*N*/ 
/*N*/ 	ErrDescList.Clear();
/*N*/ 
/*N*/ 	NodeStack.Clear();
/*N*/ 
/*N*/     SetLanguage( Application::GetSettings().GetUILanguage() );
/*N*/ 	NextToken();
/*N*/ 	Table();
/*N*/ 
/*N*/ 	return NodeStack.Pop();
/*N*/ }


/*N*/ USHORT SmParser::AddError(SmParseError Type, SmNode *pNode)
/*N*/ {
/*N*/ 	SmErrorDesc *pErrDesc = new SmErrorDesc;
/*N*/ 
/*N*/ 	pErrDesc->Type  = Type;
/*N*/ 	pErrDesc->pNode = pNode;
/*N*/ 	pErrDesc->Text  = String(SmResId(RID_ERR_IDENT));
/*N*/ 
/*N*/ 	USHORT  nRID;
/*N*/ 	switch (Type)
/*N*/ 	{
/*N*/ 		case PE_UNEXPECTED_CHAR:	 nRID = RID_ERR_UNEXPECTEDCHARACTER;	break;
/*N*/ 		case PE_LGROUP_EXPECTED:	 nRID = RID_ERR_LGROUPEXPECTED;			break;
/*N*/ 		case PE_RGROUP_EXPECTED:	 nRID = RID_ERR_RGROUPEXPECTED;			break;
/*N*/ 		case PE_LBRACE_EXPECTED:	 nRID = RID_ERR_LBRACEEXPECTED;			break;
/*N*/ 		case PE_RBRACE_EXPECTED:	 nRID = RID_ERR_RBRACEEXPECTED;			break;
/*N*/ 		case PE_FUNC_EXPECTED:		 nRID = RID_ERR_FUNCEXPECTED;			break;
/*N*/ 		case PE_UNOPER_EXPECTED:	 nRID = RID_ERR_UNOPEREXPECTED;			break;
/*N*/ 		case PE_BINOPER_EXPECTED:	 nRID = RID_ERR_BINOPEREXPECTED;		break;
/*N*/ 		case PE_SYMBOL_EXPECTED:	 nRID = RID_ERR_SYMBOLEXPECTED;			break;
/*N*/ 		case PE_IDENTIFIER_EXPECTED: nRID = RID_ERR_IDENTEXPECTED;			break;
/*N*/ 		case PE_POUND_EXPECTED:		 nRID = RID_ERR_POUNDEXPECTED;			break;
/*N*/ 		case PE_COLOR_EXPECTED:		 nRID = RID_ERR_COLOREXPECTED;			break;
/*N*/ 		case PE_RIGHT_EXPECTED:		 nRID = RID_ERR_RIGHTEXPECTED;			break;
/*N*/ 
/*N*/ 		default:
/*N*/ 			nRID = RID_ERR_UNKOWN;
/*N*/ 	}
/*N*/ 	pErrDesc->Text += SmResId(nRID);
/*N*/ 
/*N*/ 	ErrDescList.Insert(pErrDesc);
/*N*/ 
/*N*/ 	return (USHORT) ErrDescList.GetPos(pErrDesc);
/*N*/ }








}
