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