xref: /trunk/main/starmath/source/parse.cxx (revision ffd38472365e95f6a578737bc9a5eb0fac624a86)
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 
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 
69 static inline sal_Bool IsDigit( sal_Unicode cChar )
70 {
71     return '0' <= cChar && cChar <= '9';
72 }
73 
74 ///////////////////////////////////////////////////////////////////////////
75 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
1363 void SmParser::Power()
1364 {
1365     // get body for sub- supscripts on top of stack
1366     Term();
1367 
1368     SubSup(TGPOWER);
1369 }
1370 
1371 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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, ...
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 
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 
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 
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 
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 
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 
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 
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 
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 
2397 void SmParser::GlyphSpecial()
2398 {
2399     m_aNodeStack.Push(new SmGlyphSpecialNode(m_aCurToken));
2400     NextToken();
2401 }
2402 
2403 
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 
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 
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 
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 
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 
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 
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