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