Update ooo320-m1
[ooovba.git] / starmath / source / parse.cxx
blob87f3d17049e8423d00ff54eb1260e846f27671e1
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: parse.cxx,v $
10 * $Revision: 1.35 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_starmath.hxx"
35 #include <stdio.h>
37 #define SMDLL 1
39 #include <com/sun/star/i18n/UnicodeType.hpp>
40 #include <i18npool/lang.h>
41 #include <unotools/charclass.hxx>
42 #include <svx/unolingu.hxx>
43 #include <svtools/syslocale.hxx>
44 #include "parse.hxx"
45 #ifndef _STARMATH_HRC
46 #include "starmath.hrc"
47 #endif
48 #ifndef _SMDLL_HXX
49 #include "smdll.hxx"
50 #endif
51 #include "smmod.hxx"
52 #include "config.hxx"
54 #include "node.hxx"
56 using namespace ::com::sun::star;
57 using namespace ::com::sun::star::i18n;
59 ///////////////////////////////////////////////////////////////////////////
61 static inline BOOL strnccmp(const String &u1, xub_StrLen nIdx,
62 const sal_Char *s2, xub_StrLen nLen)
64 return u1.EqualsIgnoreCaseAscii( s2, nIdx, nLen );
67 static const sal_Unicode aDelimiterTable[] =
69 ' ', '\t', '\n', '\r', '+', '-', '*', '/', '=', '#',
70 '%', '\\', '"', '~', '`', '>', '<', '&', '|', '(',
71 ')', '{', '}', '[', ']', '^', '_',
72 '\0' // end of list symbol
76 static inline BOOL IsDigit( sal_Unicode cChar )
78 return '0' <= cChar && cChar <= '9';
81 ///////////////////////////////////////////////////////////////////////////
83 SmToken::SmToken() :
84 eType (TUNKNOWN),
85 cMathChar ('\0')
87 nGroup = nCol = nRow = nLevel = 0;
90 ///////////////////////////////////////////////////////////////////////////
92 struct SmTokenTableEntry
94 const sal_Char* pIdent;
95 SmTokenType eType;
96 sal_Unicode cMathChar;
97 ULONG nGroup;
98 USHORT nLevel;
101 static const SmTokenTableEntry aTokenTable[] =
103 // { "#", TPOUND, '\0', 0, 0 },
104 // { "##", TDPOUND, '\0', 0, 0 },
105 // { "&", TAND, MS_AND, TGPRODUCT, 0 },
106 // { "(", TLPARENT, MS_LPARENT, TGLBRACES, 5 }, //! 5 to continue expression
107 // { ")", TRPARENT, MS_RPARENT, TGRBRACES, 0 }, //! 0 to terminate expression
108 // { "*", TMULTIPLY, MS_MULTIPLY, TGPRODUCT, 0 },
109 // { "+", TPLUS, MS_PLUS, TGUNOPER | TGSUM, 5 },
110 // { "+-", TPLUSMINUS, MS_PLUSMINUS, TGUNOPER | TGSUM, 5 },
111 // { "-", TMINUS, MS_MINUS, TGUNOPER | TGSUM, 5 },
112 // { "-+", TMINUSPLUS, MS_MINUSPLUS, TGUNOPER | TGSUM, 5 },
113 // { ".", TPOINT, '\0', 0, 0 },
114 // { "/", TDIVIDEBY, MS_SLASH, TGPRODUCT, 0 },
115 // { "<", TLT, MS_LT, TGRELATION, 0 },
116 // { "<<", TLL, MS_LL, TGRELATION, 0 },
117 // { "<=", TLE, MS_LE, TGRELATION, 0 },
118 // { "<>", TNEQ, MS_NEQ, TGRELATION, 0},
119 // { "<?>", TPLACE, MS_PLACE, 0, 5 },
120 // { "=", TASSIGN, MS_ASSIGN, TGRELATION, 0},
121 // { ">", TGT, MS_GT, TGRELATION, 0 },
122 // { ">=", TGE, MS_GE, TGRELATION, 0 },
123 // { ">>", TGG, MS_GG, TGRELATION, 0 },
124 { "Im" , TIM, MS_IM, TGSTANDALONE, 5 },
125 { "MZ23", TDEBUG, '\0', TGATTRIBUT, 0 },
126 { "Re" , TRE, MS_RE, TGSTANDALONE, 5 },
127 { "abs", TABS, '\0', TGUNOPER, 13 },
128 { "arcosh", TACOSH, '\0', TGFUNCTION, 5 },
129 { "arcoth", TACOTH, '\0', TGFUNCTION, 5 },
130 { "acute", TACUTE, MS_ACUTE, TGATTRIBUT, 5 },
131 { "aleph" , TALEPH, MS_ALEPH, TGSTANDALONE, 5 },
132 { "alignb", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0},
133 { "alignc", TALIGNC, '\0', TGALIGN, 0},
134 { "alignl", TALIGNL, '\0', TGALIGN, 0},
135 { "alignm", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0},
136 { "alignr", TALIGNR, '\0', TGALIGN, 0},
137 { "alignt", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0},
138 { "and", TAND, MS_AND, TGPRODUCT, 0},
139 { "approx", TAPPROX, MS_APPROX, TGRELATION, 0},
140 { "arccos", TACOS, '\0', TGFUNCTION, 5},
141 { "arccot", TACOT, '\0', TGFUNCTION, 5},
142 { "arcsin", TASIN, '\0', TGFUNCTION, 5},
143 { "arctan", TATAN, '\0', TGFUNCTION, 5},
144 { "arsinh", TASINH, '\0', TGFUNCTION, 5},
145 { "artanh", TATANH, '\0', TGFUNCTION, 5},
146 { "backepsilon" , TBACKEPSILON, MS_BACKEPSILON, TGSTANDALONE, 5},
147 { "bar", TBAR, MS_BAR, TGATTRIBUT, 5},
148 { "binom", TBINOM, '\0', 0, 5 },
149 { "black", TBLACK, '\0', TGCOLOR, 0},
150 { "blue", TBLUE, '\0', TGCOLOR, 0},
151 { "bold", TBOLD, '\0', TGFONTATTR, 5},
152 { "boper", TBOPER, '\0', TGPRODUCT, 0},
153 { "breve", TBREVE, MS_BREVE, TGATTRIBUT, 5},
154 { "bslash", TBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 },
155 { "cdot", TCDOT, MS_CDOT, TGPRODUCT, 0},
156 { "check", TCHECK, MS_CHECK, TGATTRIBUT, 5},
157 { "circ" , TCIRC, MS_CIRC, TGSTANDALONE, 5},
158 { "circle", TCIRCLE, MS_CIRCLE, TGATTRIBUT, 5},
159 { "color", TCOLOR, '\0', TGFONTATTR, 5},
160 { "coprod", TCOPROD, MS_COPROD, TGOPER, 5},
161 { "cos", TCOS, '\0', TGFUNCTION, 5},
162 { "cosh", TCOSH, '\0', TGFUNCTION, 5},
163 { "cot", TCOT, '\0', TGFUNCTION, 5},
164 { "coth", TCOTH, '\0', TGFUNCTION, 5},
165 { "csub", TCSUB, '\0', TGPOWER, 0},
166 { "csup", TCSUP, '\0', TGPOWER, 0},
167 { "cyan", TCYAN, '\0', TGCOLOR, 0},
168 { "dddot", TDDDOT, MS_DDDOT, TGATTRIBUT, 5},
169 { "ddot", TDDOT, MS_DDOT, TGATTRIBUT, 5},
170 { "def", TDEF, MS_DEF, TGRELATION, 0},
171 { "div", TDIV, MS_DIV, TGPRODUCT, 0},
172 { "divides", TDIVIDES, MS_LINE, TGRELATION, 0},
173 { "dlarrow" , TDLARROW, MS_DLARROW, TGSTANDALONE, 5},
174 { "dlrarrow" , TDLRARROW, MS_DLRARROW, TGSTANDALONE, 5},
175 { "dot", TDOT, MS_DOT, TGATTRIBUT, 5},
176 { "dotsaxis", TDOTSAXIS, MS_DOTSAXIS, TGSTANDALONE, 5}, // 5 to continue expression
177 { "dotsdiag", TDOTSDIAG, MS_DOTSUP, TGSTANDALONE, 5}, //
178 { "dotsdown", TDOTSDOWN, MS_DOTSDOWN, TGSTANDALONE, 5}, //
179 { "dotslow", TDOTSLOW, MS_DOTSLOW, TGSTANDALONE, 5}, //
180 { "dotsup", TDOTSUP, MS_DOTSUP, TGSTANDALONE, 5}, //
181 { "dotsvert", TDOTSVERT, MS_DOTSVERT, TGSTANDALONE, 5}, //
182 { "downarrow" , TDOWNARROW, MS_DOWNARROW, TGSTANDALONE, 5},
183 { "drarrow" , TDRARROW, MS_DRARROW, TGSTANDALONE, 5},
184 { "emptyset" , TEMPTYSET, MS_EMPTYSET, TGSTANDALONE, 5},
185 { "equiv", TEQUIV, MS_EQUIV, TGRELATION, 0},
186 { "exists", TEXISTS, MS_EXISTS, TGSTANDALONE, 5},
187 { "exp", TEXP, '\0', TGFUNCTION, 5},
188 { "fact", TFACT, MS_FACT, TGUNOPER, 5},
189 { "fixed", TFIXED, '\0', TGFONT, 0},
190 { "font", TFONT, '\0', TGFONTATTR, 5},
191 { "forall", TFORALL, MS_FORALL, TGSTANDALONE, 5},
192 { "from", TFROM, '\0', TGLIMIT, 0},
193 { "func", TFUNC, '\0', TGFUNCTION, 5},
194 { "ge", TGE, MS_GE, TGRELATION, 0},
195 { "geslant", TGESLANT, MS_GESLANT, TGRELATION, 0 },
196 { "gg", TGG, MS_GG, TGRELATION, 0},
197 { "grave", TGRAVE, MS_GRAVE, TGATTRIBUT, 5},
198 { "green", TGREEN, '\0', TGCOLOR, 0},
199 { "gt", TGT, MS_GT, TGRELATION, 0},
200 { "hat", THAT, MS_HAT, TGATTRIBUT, 5},
201 { "hbar" , THBAR, MS_HBAR, TGSTANDALONE, 5},
202 { "iiint", TIIINT, MS_IIINT, TGOPER, 5},
203 { "iint", TIINT, MS_IINT, TGOPER, 5},
204 { "in", TIN, MS_IN, TGRELATION, 0},
205 { "infinity" , TINFINITY, MS_INFINITY, TGSTANDALONE, 5},
206 { "infty" , TINFINITY, MS_INFINITY, TGSTANDALONE, 5},
207 { "int", TINT, MS_INT, TGOPER, 5},
208 { "intersection", TINTERSECT, MS_INTERSECT, TGPRODUCT, 0},
209 { "ital", TITALIC, '\0', TGFONTATTR, 5},
210 { "italic", TITALIC, '\0', TGFONTATTR, 5},
211 { "lambdabar" , TLAMBDABAR, MS_LAMBDABAR, TGSTANDALONE, 5},
212 { "langle", TLANGLE, MS_LANGLE, TGLBRACES, 5},
213 { "lbrace", TLBRACE, MS_LBRACE, TGLBRACES, 5},
214 { "lceil", TLCEIL, MS_LCEIL, TGLBRACES, 5},
215 { "ldbracket", TLDBRACKET, MS_LDBRACKET, TGLBRACES, 5},
216 { "ldline", TLDLINE, MS_DLINE, TGLBRACES, 5},
217 { "le", TLE, MS_LE, TGRELATION, 0},
218 { "left", TLEFT, '\0', 0, 5},
219 { "leftarrow" , TLEFTARROW, MS_LEFTARROW, TGSTANDALONE, 5},
220 { "leslant", TLESLANT, MS_LESLANT, TGRELATION, 0 },
221 { "lfloor", TLFLOOR, MS_LFLOOR, TGLBRACES, 5},
222 { "lim", TLIM, '\0', TGOPER, 5},
223 { "liminf", TLIMINF, '\0', TGOPER, 5},
224 { "limsup", TLIMSUP, '\0', TGOPER, 5},
225 { "lint", TLINT, MS_LINT, TGOPER, 5},
226 { "ll", TLL, MS_LL, TGRELATION, 0},
227 { "lline", TLLINE, MS_LINE, TGLBRACES, 5},
228 { "llint", TLLINT, MS_LLINT, TGOPER, 5},
229 { "lllint", TLLLINT, MS_LLLINT, TGOPER, 5},
230 { "ln", TLN, '\0', TGFUNCTION, 5},
231 { "log", TLOG, '\0', TGFUNCTION, 5},
232 { "lsub", TLSUB, '\0', TGPOWER, 0},
233 { "lsup", TLSUP, '\0', TGPOWER, 0},
234 { "lt", TLT, MS_LT, TGRELATION, 0},
235 { "magenta", TMAGENTA, '\0', TGCOLOR, 0},
236 { "matrix", TMATRIX, '\0', 0, 5},
237 { "minusplus", TMINUSPLUS, MS_MINUSPLUS, TGUNOPER | TGSUM, 5},
238 { "mline", TMLINE, MS_LINE, 0, 0}, //! nicht in TGRBRACES, Level 0
239 { "nabla", TNABLA, MS_NABLA, TGSTANDALONE, 5},
240 { "nbold", TNBOLD, '\0', TGFONTATTR, 5},
241 { "ndivides", TNDIVIDES, MS_NDIVIDES, TGRELATION, 0},
242 { "neg", TNEG, MS_NEG, TGUNOPER, 5 },
243 { "neq", TNEQ, MS_NEQ, TGRELATION, 0},
244 { "newline", TNEWLINE, '\0', 0, 0},
245 { "ni", TNI, MS_NI, TGRELATION, 0},
246 { "nitalic", TNITALIC, '\0', TGFONTATTR, 5},
247 { "none", TNONE, '\0', TGLBRACES | TGRBRACES, 0},
248 { "notin", TNOTIN, MS_NOTIN, TGRELATION, 0},
249 { "nsubset", TNSUBSET, MS_NSUBSET, TGRELATION, 0 },
250 { "nsupset", TNSUPSET, MS_NSUPSET, TGRELATION, 0 },
251 { "nsubseteq", TNSUBSETEQ, MS_NSUBSETEQ, TGRELATION, 0 },
252 { "nsupseteq", TNSUPSETEQ, MS_NSUPSETEQ, TGRELATION, 0 },
253 { "nroot", TNROOT, MS_SQRT, TGUNOPER, 5},
254 { "odivide", TODIVIDE, MS_ODIVIDE, TGPRODUCT, 0},
255 { "odot", TODOT, MS_ODOT, TGPRODUCT, 0},
256 { "ominus", TOMINUS, MS_OMINUS, TGSUM, 0},
257 { "oper", TOPER, '\0', TGOPER, 5},
258 { "oplus", TOPLUS, MS_OPLUS, TGSUM, 0},
259 { "or", TOR, MS_OR, TGSUM, 0},
260 { "ortho", TORTHO, MS_ORTHO, TGRELATION, 0},
261 { "otimes", TOTIMES, MS_OTIMES, TGPRODUCT, 0},
262 { "over", TOVER, '\0', TGPRODUCT, 0},
263 { "overbrace", TOVERBRACE, MS_OVERBRACE, TGPRODUCT, 5},
264 { "overline", TOVERLINE, '\0', TGATTRIBUT, 5},
265 { "overstrike", TOVERSTRIKE, '\0', TGATTRIBUT, 5},
266 { "owns", TNI, MS_NI, TGRELATION, 0},
267 { "parallel", TPARALLEL, MS_DLINE, TGRELATION, 0},
268 { "partial", TPARTIAL, MS_PARTIAL, TGSTANDALONE, 5 },
269 { "phantom", TPHANTOM, '\0', TGFONTATTR, 5},
270 { "plusminus", TPLUSMINUS, MS_PLUSMINUS, TGUNOPER | TGSUM, 5},
271 { "prod", TPROD, MS_PROD, TGOPER, 5},
272 { "prop", TPROP, MS_PROP, TGRELATION, 0},
273 { "rangle", TRANGLE, MS_RANGLE, TGRBRACES, 0}, //! 0 to terminate expression
274 { "rbrace", TRBRACE, MS_RBRACE, TGRBRACES, 0}, //
275 { "rceil", TRCEIL, MS_RCEIL, TGRBRACES, 0}, //
276 { "rdbracket", TRDBRACKET, MS_RDBRACKET, TGRBRACES, 0}, //
277 { "rdline", TRDLINE, MS_DLINE, TGRBRACES, 0}, //
278 { "red", TRED, '\0', TGCOLOR, 0},
279 { "rfloor", TRFLOOR, MS_RFLOOR, TGRBRACES, 0}, //! 0 to terminate expression
280 { "right", TRIGHT, '\0', 0, 0},
281 { "rightarrow" , TRIGHTARROW, MS_RIGHTARROW, TGSTANDALONE, 5},
282 { "rline", TRLINE, MS_LINE, TGRBRACES, 0}, //! 0 to terminate expression
283 { "rsub", TRSUB, '\0', TGPOWER, 0},
284 { "rsup", TRSUP, '\0', TGPOWER, 0},
285 { "sans", TSANS, '\0', TGFONT, 0},
286 { "serif", TSERIF, '\0', TGFONT, 0},
287 { "setC" , TSETC, MS_SETC, TGSTANDALONE, 5},
288 { "setN" , TSETN, MS_SETN, TGSTANDALONE, 5},
289 { "setQ" , TSETQ, MS_SETQ, TGSTANDALONE, 5},
290 { "setR" , TSETR, MS_SETR, TGSTANDALONE, 5},
291 { "setZ" , TSETZ, MS_SETZ, TGSTANDALONE, 5},
292 { "setminus", TBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 },
293 { "sim", TSIM, MS_SIM, TGRELATION, 0},
294 { "simeq", TSIMEQ, MS_SIMEQ, TGRELATION, 0},
295 { "sin", TSIN, '\0', TGFUNCTION, 5},
296 { "sinh", TSINH, '\0', TGFUNCTION, 5},
297 { "size", TSIZE, '\0', TGFONTATTR, 5},
298 { "slash", TSLASH, MS_SLASH, TGPRODUCT, 0 },
299 { "sqrt", TSQRT, MS_SQRT, TGUNOPER, 5},
300 { "stack", TSTACK, '\0', 0, 5},
301 { "sub", TRSUB, '\0', TGPOWER, 0},
302 { "subset", TSUBSET, MS_SUBSET, TGRELATION, 0},
303 { "subseteq", TSUBSETEQ, MS_SUBSETEQ, TGRELATION, 0},
304 { "sum", TSUM, MS_SUM, TGOPER, 5},
305 { "sup", TRSUP, '\0', TGPOWER, 0},
306 { "supset", TSUPSET, MS_SUPSET, TGRELATION, 0},
307 { "supseteq", TSUPSETEQ, MS_SUPSETEQ, TGRELATION, 0},
308 { "tan", TTAN, '\0', TGFUNCTION, 5},
309 { "tanh", TTANH, '\0', TGFUNCTION, 5},
310 { "tilde", TTILDE, MS_TILDE, TGATTRIBUT, 5},
311 { "times", TTIMES, MS_TIMES, TGPRODUCT, 0},
312 { "to", TTO, '\0', TGLIMIT, 0},
313 { "toward", TTOWARD, MS_RIGHTARROW, TGRELATION, 0},
314 { "transl", TTRANSL, MS_TRANSL, TGRELATION, 0},
315 { "transr", TTRANSR, MS_TRANSR, TGRELATION, 0},
316 { "underbrace", TUNDERBRACE, MS_UNDERBRACE, TGPRODUCT, 5},
317 { "underline", TUNDERLINE, '\0', TGATTRIBUT, 5},
318 { "union", TUNION, MS_UNION, TGSUM, 0},
319 { "uoper", TUOPER, '\0', TGUNOPER, 5},
320 { "uparrow" , TUPARROW, MS_UPARROW, TGSTANDALONE, 5},
321 { "vec", TVEC, MS_VEC, TGATTRIBUT, 5},
322 { "white", TWHITE, '\0', TGCOLOR, 0},
323 { "widebslash", TWIDEBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 },
324 { "widehat", TWIDEHAT, MS_HAT, TGATTRIBUT, 5},
325 { "widetilde", TWIDETILDE, MS_TILDE, TGATTRIBUT, 5},
326 { "wideslash", TWIDESLASH, MS_SLASH, TGPRODUCT, 0 },
327 { "widevec", TWIDEVEC, MS_VEC, TGATTRIBUT, 5},
328 { "wp" , TWP, MS_WP, TGSTANDALONE, 5},
329 { "yellow", TYELLOW, '\0', TGCOLOR, 0},
330 // { "[", TLBRACKET, MS_LBRACKET, TGLBRACES, 5}, //! 5 to continue expression
331 // { "\\", TESCAPE, '\0', 0, 5},
332 // { "]", TRBRACKET, MS_RBRACKET, TGRBRACES, 0}, //! 0 to terminate expression
333 // { "^", TRSUP, '\0', TGPOWER, 0},
334 // { "_", TRSUB, '\0', TGPOWER, 0},
335 // { "`", TSBLANK, '\0', TGBLANK, 5},
336 // { "{", TLGROUP, MS_LBRACE, 0, 5}, //! 5 to continue expression
337 // { "|", TOR, MS_OR, TGSUM, 0},
338 // { "}", TRGROUP, MS_RBRACE, 0, 0}, //! 0 to terminate expression
339 // { "~", TBLANK, '\0', TGBLANK, 5},
340 { "", TEND, '\0', 0, 0}
344 static const SmTokenTableEntry * GetTokenTableEntry( const String &rName )
346 const SmTokenTableEntry * pRes = 0;
347 if (rName.Len())
349 INT32 nEntries = sizeof( aTokenTable ) / sizeof( aTokenTable[0] );
350 for (INT32 i = 0; i < nEntries; ++i)
352 if (rName.EqualsIgnoreCaseAscii( aTokenTable[i].pIdent ))
354 pRes = &aTokenTable[i];
355 break;
361 return pRes;
365 ///////////////////////////////////////////////////////////////////////////
367 #if OSL_DEBUG_LEVEL
369 BOOL SmParser::IsDelimiter( const String &rTxt, xub_StrLen nPos )
370 // returns 'TRUE' iff cChar is '\0' or a delimeter
372 DBG_ASSERT( nPos <= rTxt.Len(), "index out of range" );
374 sal_Unicode cChar = rTxt.GetChar( nPos );
375 if(!cChar)
376 return TRUE;
378 // check if 'cChar' is in the delimeter table
379 const sal_Unicode *pDelim = &aDelimiterTable[0];
380 for ( ; *pDelim != 0; pDelim++)
381 if (*pDelim == cChar)
382 break;
384 BOOL bIsDelim = *pDelim != 0;
386 INT16 nTypJp = SM_MOD1()->GetSysLocale().GetCharClass().getType( rTxt, nPos );
387 bIsDelim |= nTypJp == com::sun::star::i18n::UnicodeType::SPACE_SEPARATOR ||
388 nTypJp == com::sun::star::i18n::UnicodeType::CONTROL;
390 return bIsDelim;
393 #endif
395 void SmParser::Insert(const String &rText, USHORT nPos)
397 BufferString.Insert(rText, nPos);
399 xub_StrLen nLen = rText.Len();
400 BufferIndex = BufferIndex + nLen;
401 nTokenIndex = nTokenIndex + nLen;
405 void SmParser::Replace( USHORT nPos, USHORT nLen, const String &rText )
407 DBG_ASSERT( nPos + nLen <= BufferString.Len(), "argument mismatch" );
409 BufferString.Replace( nPos, nLen, rText );
410 INT16 nChg = rText.Len() - nLen;
411 BufferIndex = BufferIndex + nChg;
412 nTokenIndex = nTokenIndex + nChg;
416 // First character may be any alphabetic
417 const sal_Int32 coStartFlags =
418 KParseTokens::ANY_LETTER_OR_NUMBER |
419 KParseTokens::IGNORE_LEADING_WS;
421 // Continuing characters may be any alphanumeric or dot.
422 const sal_Int32 coContFlags =
423 ((coStartFlags | KParseTokens::ASC_DOT) & ~KParseTokens::IGNORE_LEADING_WS)
424 | KParseTokens::TWO_DOUBLE_QUOTES_BREAK_STRING;
426 // First character for numbers, may be any numeric or dot
427 const sal_Int32 coNumStartFlags =
428 KParseTokens::ASC_DIGIT |
429 KParseTokens::ASC_DOT |
430 KParseTokens::IGNORE_LEADING_WS;
431 // Continuing characters for numbers, may be any numeric or dot.
432 const sal_Int32 coNumContFlags =
433 (coNumStartFlags | KParseTokens::ASC_DOT) & ~KParseTokens::IGNORE_LEADING_WS;
435 void SmParser::NextToken()
437 static const String aEmptyStr;
439 xub_StrLen nBufLen = BufferString.Len();
440 ParseResult aRes;
441 xub_StrLen nRealStart;
442 BOOL bCont;
443 BOOL bNumStart = FALSE;
444 CharClass aCC(SM_MOD1()->GetSysLocale().GetCharClass().getLocale());
447 // skip white spaces
448 while (UnicodeType::SPACE_SEPARATOR ==
449 aCC.getType( BufferString, BufferIndex ))
450 ++BufferIndex;
452 sal_Int32 nStartFlags = coStartFlags;
453 sal_Int32 nContFlags = coContFlags;
454 sal_Unicode cFirstChar = BufferString.GetChar( BufferIndex );
456 removed because of #i11752#
457 bNumStart = cFirstChar == '.' || ('0' <= cFirstChar && cFirstChar <= '9');
458 if (bNumStart)
460 nStartFlags = coNumStartFlags;
461 nContFlags = coNumContFlags;
464 aRes = aCC.parseAnyToken( BufferString, BufferIndex,
465 nStartFlags, aEmptyStr,
466 nContFlags, aEmptyStr );
468 // #i45779# parse numbers correctly
469 // i.e. independent from the locale setting.
470 // (note that #i11752# remains fixed)
471 if ((aRes.TokenType & KParseType::IDENTNAME) && IsDigit( cFirstChar ))
473 //! locale where '.' is decimal seperator!
474 static lang::Locale aDotLoc( SvxCreateLocale( LANGUAGE_ENGLISH_US ) );
476 ParseResult aTmpRes;
477 lang::Locale aOldLoc( aCC.getLocale() );
478 aCC.setLocale( aDotLoc );
479 aTmpRes = aCC.parsePredefinedToken(
480 KParseType::ASC_NUMBER,
481 BufferString, BufferIndex,
482 KParseTokens::ASC_DIGIT, aEmptyStr,
483 KParseTokens::ASC_DIGIT | KParseTokens::ASC_DOT, aEmptyStr );
484 aCC.setLocale( aOldLoc );
485 if (aTmpRes.TokenType & KParseType::ASC_NUMBER)
486 aRes.TokenType = aTmpRes.TokenType;
489 nRealStart = BufferIndex + sal::static_int_cast< xub_StrLen >(aRes.LeadingWhiteSpace);
490 BufferIndex = nRealStart;
492 bCont = FALSE;
493 if ( aRes.TokenType == 0 &&
494 nRealStart < nBufLen &&
495 '\n' == BufferString.GetChar( nRealStart ) )
497 // keep data needed for tokens row and col entry up to date
498 ++Row;
499 BufferIndex = ColOff = nRealStart + 1;
500 bCont = TRUE;
502 else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR)
504 String aName( BufferString.Copy( nRealStart, 2 ));
505 if ( aName.EqualsAscii( "%%" ))
507 //SkipComment
508 BufferIndex = nRealStart + 2;
509 while (BufferIndex < nBufLen &&
510 '\n' != BufferString.GetChar( BufferIndex ))
511 ++BufferIndex;
512 bCont = TRUE;
516 } while (bCont);
518 // set index of current token
519 nTokenIndex = BufferIndex;
521 CurToken.nRow = Row;
522 CurToken.nCol = nRealStart - ColOff + 1;
524 BOOL bHandled = TRUE;
525 if (nRealStart >= nBufLen)
527 CurToken.eType = TEND;
528 CurToken.cMathChar = '\0';
529 CurToken.nGroup = 0;
530 CurToken.nLevel = 0;
531 CurToken.aText.Erase();
533 else if ((aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER))
534 || (bNumStart && (aRes.TokenType & KParseType::IDENTNAME)))
536 INT32 n = aRes.EndPos - nRealStart;
537 DBG_ASSERT( n >= 0, "length < 0" );
538 CurToken.eType = TNUMBER;
539 CurToken.cMathChar = '\0';
540 CurToken.nGroup = 0;
541 CurToken.nLevel = 5;
542 CurToken.aText = BufferString.Copy( nRealStart, sal::static_int_cast< xub_StrLen >(n) );
544 #if OSL_DEBUG_LEVEL > 1
545 if (!IsDelimiter( BufferString, static_cast< xub_StrLen >(aRes.EndPos) ))
547 DBG_WARNING( "identifier really finished? (compatibility!)" );
549 #endif
551 else if (aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING)
553 CurToken.eType = TTEXT;
554 CurToken.cMathChar = '\0';
555 CurToken.nGroup = 0;
556 CurToken.nLevel = 5;
557 CurToken.aText = aRes.DequotedNameOrString;
558 CurToken.nRow = Row;
559 CurToken.nCol = nRealStart - ColOff + 2;
561 else if (aRes.TokenType & KParseType::IDENTNAME)
563 INT32 n = aRes.EndPos - nRealStart;
564 DBG_ASSERT( n >= 0, "length < 0" );
565 String aName( BufferString.Copy( nRealStart, sal::static_int_cast< xub_StrLen >(n) ) );
566 const SmTokenTableEntry *pEntry = GetTokenTableEntry( aName );
568 if (pEntry)
570 CurToken.eType = pEntry->eType;
571 CurToken.cMathChar = pEntry->cMathChar;
572 CurToken.nGroup = pEntry->nGroup;
573 CurToken.nLevel = pEntry->nLevel;
574 CurToken.aText.AssignAscii( pEntry->pIdent );
576 else
578 CurToken.eType = TIDENT;
579 CurToken.cMathChar = '\0';
580 CurToken.nGroup = 0;
581 CurToken.nLevel = 5;
582 CurToken.aText = aName;
584 #if OSL_DEBUG_LEVEL > 1
585 if (!IsDelimiter( BufferString, static_cast< xub_StrLen >(aRes.EndPos) ))
587 DBG_WARNING( "identifier really finished? (compatibility!)" );
589 #endif
592 else if (aRes.TokenType == 0 && '_' == BufferString.GetChar( nRealStart ))
594 CurToken.eType = TRSUB;
595 CurToken.cMathChar = '\0';
596 CurToken.nGroup = TGPOWER;
597 CurToken.nLevel = 0;
598 CurToken.aText.AssignAscii( "_" );
600 aRes.EndPos = nRealStart + 1;
602 else if (aRes.TokenType & KParseType::BOOLEAN)
604 sal_Int32 &rnEndPos = aRes.EndPos;
605 String aName( BufferString.Copy( nRealStart,
606 sal::static_int_cast< xub_StrLen >(rnEndPos - nRealStart) ));
607 if (2 >= aName.Len())
609 sal_Unicode ch = aName.GetChar( 0 );
610 switch (ch)
612 case '<':
614 if (BufferString.Copy( nRealStart, 2 ).
615 EqualsAscii( "<<" ))
617 CurToken.eType = TLL;
618 CurToken.cMathChar = MS_LL;
619 CurToken.nGroup = TGRELATION;
620 CurToken.nLevel = 0;
621 CurToken.aText.AssignAscii( "<<" );
623 rnEndPos = nRealStart + 2;
625 else if (BufferString.Copy( nRealStart, 2 ).
626 EqualsAscii( "<=" ))
628 CurToken.eType = TLE;
629 CurToken.cMathChar = MS_LE;
630 CurToken.nGroup = TGRELATION;
631 CurToken.nLevel = 0;
632 CurToken.aText.AssignAscii( "<=" );
634 rnEndPos = nRealStart + 2;
636 else if (BufferString.Copy( nRealStart, 2 ).
637 EqualsAscii( "<>" ))
639 CurToken.eType = TNEQ;
640 CurToken.cMathChar = MS_NEQ;
641 CurToken.nGroup = TGRELATION;
642 CurToken.nLevel = 0;
643 CurToken.aText.AssignAscii( "<>" );
645 rnEndPos = nRealStart + 2;
647 else if (BufferString.Copy( nRealStart, 3 ).
648 EqualsAscii( "<?>" ))
650 CurToken.eType = TPLACE;
651 CurToken.cMathChar = MS_PLACE;
652 CurToken.nGroup = 0;
653 CurToken.nLevel = 5;
654 CurToken.aText.AssignAscii( "<?>" );
656 rnEndPos = nRealStart + 3;
658 else
660 CurToken.eType = TLT;
661 CurToken.cMathChar = MS_LT;
662 CurToken.nGroup = TGRELATION;
663 CurToken.nLevel = 0;
664 CurToken.aText.AssignAscii( "<" );
667 break;
668 case '>':
670 if (BufferString.Copy( nRealStart, 2 ).
671 EqualsAscii( ">=" ))
673 CurToken.eType = TGE;
674 CurToken.cMathChar = MS_GE;
675 CurToken.nGroup = TGRELATION;
676 CurToken.nLevel = 0;
677 CurToken.aText.AssignAscii( ">=" );
679 rnEndPos = nRealStart + 2;
681 else if (BufferString.Copy( nRealStart, 2 ).
682 EqualsAscii( ">>" ))
684 CurToken.eType = TGG;
685 CurToken.cMathChar = MS_GG;
686 CurToken.nGroup = TGRELATION;
687 CurToken.nLevel = 0;
688 CurToken.aText.AssignAscii( ">>" );
690 rnEndPos = nRealStart + 2;
692 else
694 CurToken.eType = TGT;
695 CurToken.cMathChar = MS_GT;
696 CurToken.nGroup = TGRELATION;
697 CurToken.nLevel = 0;
698 CurToken.aText.AssignAscii( ">" );
701 break;
702 default:
703 bHandled = FALSE;
707 else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR)
709 sal_Int32 &rnEndPos = aRes.EndPos;
710 String aName( BufferString.Copy( nRealStart,
711 sal::static_int_cast< xub_StrLen >(rnEndPos - nRealStart) ) );
713 if (1 == aName.Len())
715 sal_Unicode ch = aName.GetChar( 0 );
716 switch (ch)
718 case '%':
720 //! modifies aRes.EndPos
722 DBG_ASSERT( rnEndPos >= nBufLen ||
723 '%' != BufferString.GetChar( sal::static_int_cast< xub_StrLen >(rnEndPos) ),
724 "unexpected comment start" );
726 // get identifier of user-defined character
727 ParseResult aTmpRes = aCC.parseAnyToken(
728 BufferString, rnEndPos,
729 KParseTokens::ANY_LETTER,
730 aEmptyStr,
731 coContFlags,
732 aEmptyStr );
734 xub_StrLen nTmpStart = sal::static_int_cast< xub_StrLen >(rnEndPos +
735 aTmpRes.LeadingWhiteSpace);
737 // default setting fo the case that no identifier
738 // i.e. a valid symbol-name is following the '%'
739 // character
740 CurToken.eType = TTEXT;
741 CurToken.cMathChar = '\0';
742 CurToken.nGroup = 0;
743 CurToken.nLevel = 5;
744 CurToken.aText = String();
745 CurToken.nRow = sal::static_int_cast< xub_StrLen >(Row);
746 CurToken.nCol = nTmpStart - ColOff + 1;
748 if (aTmpRes.TokenType & KParseType::IDENTNAME)
751 xub_StrLen n = sal::static_int_cast< xub_StrLen >(aTmpRes.EndPos - nTmpStart);
752 CurToken.eType = TSPECIAL;
753 CurToken.aText = BufferString.Copy( sal::static_int_cast< xub_StrLen >(nTmpStart), n );
755 DBG_ASSERT( aTmpRes.EndPos > rnEndPos,
756 "empty identifier" );
757 if (aTmpRes.EndPos > rnEndPos)
758 rnEndPos = aTmpRes.EndPos;
759 else
760 ++rnEndPos;
763 // if no symbol-name was found we start-over with
764 // finding the next token right afer the '%' sign.
765 // I.e. we leave rnEndPos unmodified.
767 break;
768 case '[':
770 CurToken.eType = TLBRACKET;
771 CurToken.cMathChar = MS_LBRACKET;
772 CurToken.nGroup = TGLBRACES;
773 CurToken.nLevel = 5;
774 CurToken.aText.AssignAscii( "[" );
776 break;
777 case '\\':
779 CurToken.eType = TESCAPE;
780 CurToken.cMathChar = '\0';
781 CurToken.nGroup = 0;
782 CurToken.nLevel = 5;
783 CurToken.aText.AssignAscii( "\\" );
785 break;
786 case ']':
788 CurToken.eType = TRBRACKET;
789 CurToken.cMathChar = MS_RBRACKET;
790 CurToken.nGroup = TGRBRACES;
791 CurToken.nLevel = 0;
792 CurToken.aText.AssignAscii( "]" );
794 break;
795 case '^':
797 CurToken.eType = TRSUP;
798 CurToken.cMathChar = '\0';
799 CurToken.nGroup = TGPOWER;
800 CurToken.nLevel = 0;
801 CurToken.aText.AssignAscii( "^" );
803 break;
804 case '`':
806 CurToken.eType = TSBLANK;
807 CurToken.cMathChar = '\0';
808 CurToken.nGroup = TGBLANK;
809 CurToken.nLevel = 5;
810 CurToken.aText.AssignAscii( "`" );
812 break;
813 case '{':
815 CurToken.eType = TLGROUP;
816 CurToken.cMathChar = MS_LBRACE;
817 CurToken.nGroup = 0;
818 CurToken.nLevel = 5;
819 CurToken.aText.AssignAscii( "{" );
821 break;
822 case '|':
824 CurToken.eType = TOR;
825 CurToken.cMathChar = MS_OR;
826 CurToken.nGroup = TGSUM;
827 CurToken.nLevel = 0;
828 CurToken.aText.AssignAscii( "|" );
830 break;
831 case '}':
833 CurToken.eType = TRGROUP;
834 CurToken.cMathChar = MS_RBRACE;
835 CurToken.nGroup = 0;
836 CurToken.nLevel = 0;
837 CurToken.aText.AssignAscii( "}" );
839 break;
840 case '~':
842 CurToken.eType = TBLANK;
843 CurToken.cMathChar = '\0';
844 CurToken.nGroup = TGBLANK;
845 CurToken.nLevel = 5;
846 CurToken.aText.AssignAscii( "~" );
848 break;
849 case '#':
851 if (BufferString.Copy( nRealStart, 2 ).
852 EqualsAscii( "##" ))
854 CurToken.eType = TDPOUND;
855 CurToken.cMathChar = '\0';
856 CurToken.nGroup = 0;
857 CurToken.nLevel = 0;
858 CurToken.aText.AssignAscii( "##" );
860 rnEndPos = nRealStart + 2;
862 else
864 CurToken.eType = TPOUND;
865 CurToken.cMathChar = '\0';
866 CurToken.nGroup = 0;
867 CurToken.nLevel = 0;
868 CurToken.aText.AssignAscii( "#" );
871 break;
872 case '&':
874 CurToken.eType = TAND;
875 CurToken.cMathChar = MS_AND;
876 CurToken.nGroup = TGPRODUCT;
877 CurToken.nLevel = 0;
878 CurToken.aText.AssignAscii( "&" );
880 break;
881 case '(':
883 CurToken.eType = TLPARENT;
884 CurToken.cMathChar = MS_LPARENT;
885 CurToken.nGroup = TGLBRACES;
886 CurToken.nLevel = 5; //! 0 to continue expression
887 CurToken.aText.AssignAscii( "(" );
889 break;
890 case ')':
892 CurToken.eType = TRPARENT;
893 CurToken.cMathChar = MS_RPARENT;
894 CurToken.nGroup = TGRBRACES;
895 CurToken.nLevel = 0; //! 0 to terminate expression
896 CurToken.aText.AssignAscii( ")" );
898 break;
899 case '*':
901 CurToken.eType = TMULTIPLY;
902 CurToken.cMathChar = MS_MULTIPLY;
903 CurToken.nGroup = TGPRODUCT;
904 CurToken.nLevel = 0;
905 CurToken.aText.AssignAscii( "*" );
907 break;
908 case '+':
910 if (BufferString.Copy( nRealStart, 2 ).
911 EqualsAscii( "+-" ))
913 CurToken.eType = TPLUSMINUS;
914 CurToken.cMathChar = MS_PLUSMINUS;
915 CurToken.nGroup = TGUNOPER | TGSUM;
916 CurToken.nLevel = 5;
917 CurToken.aText.AssignAscii( "+-" );
919 rnEndPos = nRealStart + 2;
921 else
923 CurToken.eType = TPLUS;
924 CurToken.cMathChar = MS_PLUS;
925 CurToken.nGroup = TGUNOPER | TGSUM;
926 CurToken.nLevel = 5;
927 CurToken.aText.AssignAscii( "+" );
930 break;
931 case '-':
933 if (BufferString.Copy( nRealStart, 2 ).
934 EqualsAscii( "-+" ))
936 CurToken.eType = TMINUSPLUS;
937 CurToken.cMathChar = MS_MINUSPLUS;
938 CurToken.nGroup = TGUNOPER | TGSUM;
939 CurToken.nLevel = 5;
940 CurToken.aText.AssignAscii( "-+" );
942 rnEndPos = nRealStart + 2;
944 else
946 CurToken.eType = TMINUS;
947 CurToken.cMathChar = MS_MINUS;
948 CurToken.nGroup = TGUNOPER | TGSUM;
949 CurToken.nLevel = 5;
950 CurToken.aText.AssignAscii( "-" );
953 break;
954 case '.':
956 // for compatibility with SO5.2
957 // texts like .34 ...56 ... h ...78..90
958 // will be treated as numbers
959 CurToken.eType = TNUMBER;
960 CurToken.cMathChar = '\0';
961 CurToken.nGroup = 0;
962 CurToken.nLevel = 5;
964 xub_StrLen nTxtStart = BufferIndex;
965 sal_Unicode cChar;
968 cChar = BufferString.GetChar( ++BufferIndex );
970 while ( cChar == '.' || IsDigit( cChar ) );
972 CurToken.aText = BufferString.Copy( sal::static_int_cast< xub_StrLen >(nTxtStart),
973 sal::static_int_cast< xub_StrLen >(BufferIndex - nTxtStart) );
974 aRes.EndPos = BufferIndex;
976 break;
977 case '/':
979 CurToken.eType = TDIVIDEBY;
980 CurToken.cMathChar = MS_SLASH;
981 CurToken.nGroup = TGPRODUCT;
982 CurToken.nLevel = 0;
983 CurToken.aText.AssignAscii( "/" );
985 break;
986 case '=':
988 CurToken.eType = TASSIGN;
989 CurToken.cMathChar = MS_ASSIGN;
990 CurToken.nGroup = TGRELATION;
991 CurToken.nLevel = 0;
992 CurToken.aText.AssignAscii( "=" );
994 break;
995 default:
996 bHandled = FALSE;
1000 else
1001 bHandled = FALSE;
1003 if (!bHandled)
1005 CurToken.eType = TCHARACTER;
1006 CurToken.cMathChar = '\0';
1007 CurToken.nGroup = 0;
1008 CurToken.nLevel = 5;
1009 CurToken.aText = BufferString.Copy( nRealStart, 1 );
1011 aRes.EndPos = nRealStart + 1;
1014 if (TEND != CurToken.eType)
1015 BufferIndex = sal::static_int_cast< xub_StrLen >(aRes.EndPos);
1019 ////////////////////////////////////////
1020 // grammar
1024 void SmParser::Table()
1026 SmNodeArray LineArray;
1028 Line();
1029 while (CurToken.eType == TNEWLINE)
1031 NextToken();
1032 Line();
1035 if (CurToken.eType != TEND)
1036 Error(PE_UNEXPECTED_CHAR);
1038 ULONG n = NodeStack.Count();
1040 LineArray.resize(n);
1042 for (ULONG i = 0; i < n; i++)
1043 LineArray[n - (i + 1)] = NodeStack.Pop();
1045 SmStructureNode *pSNode = new SmTableNode(CurToken);
1046 pSNode->SetSubNodes(LineArray);
1047 NodeStack.Push(pSNode);
1051 void SmParser::Align()
1052 // parse alignment info (if any), then go on with rest of expression
1054 SmStructureNode *pSNode = 0;
1055 BOOL bNeedGroupClose = FALSE;
1057 if (TokenInGroup(TGALIGN))
1059 if (CONVERT_40_TO_50 == GetConversion())
1060 // encapsulate expression to be aligned in group braces
1061 // (here group-open brace)
1062 { Insert('{', GetTokenIndex());
1063 bNeedGroupClose = TRUE;
1065 // get first valid align statement in sequence
1066 // (the dominant one in 4.0) and erase all others (especially old
1067 // discarded tokens) from command string.
1068 while (TokenInGroup(TGALIGN))
1069 { if (TokenInGroup(TGDISCARDED) || pSNode)
1070 { BufferIndex = GetTokenIndex();
1071 BufferString.Erase(BufferIndex, CurToken.aText.Len());
1073 else
1074 pSNode = new SmAlignNode(CurToken);
1076 NextToken();
1079 else
1081 pSNode = new SmAlignNode(CurToken);
1083 NextToken();
1085 // allow for just one align statement in 5.0
1086 if (CONVERT_40_TO_50 != GetConversion() && TokenInGroup(TGALIGN))
1087 { Error(PE_DOUBLE_ALIGN);
1088 return;
1093 Expression();
1095 if (bNeedGroupClose)
1096 Insert('}', GetTokenIndex());
1098 if (pSNode)
1099 { pSNode->SetSubNodes(NodeStack.Pop(), 0);
1100 NodeStack.Push(pSNode);
1105 void SmParser::Line()
1107 USHORT n = 0;
1108 SmNodeArray ExpressionArray;
1110 ExpressionArray.resize(n);
1112 // start with single expression that may have an alignment statement
1113 // (and go on with expressions that must not have alignment
1114 // statements in 'while' loop below. See also 'Expression()'.)
1115 if (CurToken.eType != TEND && CurToken.eType != TNEWLINE)
1116 { Align();
1117 ExpressionArray.resize(++n);
1118 ExpressionArray[n - 1] = NodeStack.Pop();
1121 while (CurToken.eType != TEND && CurToken.eType != TNEWLINE)
1122 { if (CONVERT_40_TO_50 != GetConversion())
1123 Expression();
1124 else
1125 Align();
1126 ExpressionArray.resize(++n);
1127 ExpressionArray[n - 1] = NodeStack.Pop();
1130 SmStructureNode *pSNode = new SmLineNode(CurToken);
1131 pSNode->SetSubNodes(ExpressionArray);
1132 NodeStack.Push(pSNode);
1136 void SmParser::Expression()
1138 USHORT n = 0;
1139 SmNodeArray RelationArray;
1141 RelationArray.resize(n);
1143 Relation();
1144 RelationArray.resize(++n);
1145 RelationArray[n - 1] = NodeStack.Pop();
1147 while (CurToken.nLevel >= 4)
1148 { Relation();
1149 RelationArray.resize(++n);
1150 RelationArray[n - 1] = NodeStack.Pop();
1153 SmStructureNode *pSNode = new SmExpressionNode(CurToken);
1154 pSNode->SetSubNodes(RelationArray);
1155 NodeStack.Push(pSNode);
1159 void SmParser::Relation()
1161 Sum();
1162 while (TokenInGroup(TGRELATION))
1164 SmStructureNode *pSNode = new SmBinHorNode(CurToken);
1165 SmNode *pFirst = NodeStack.Pop();
1167 OpSubSup();
1168 SmNode *pSecond = NodeStack.Pop();
1170 Sum();
1172 pSNode->SetSubNodes(pFirst, pSecond, NodeStack.Pop());
1173 NodeStack.Push(pSNode);
1178 void SmParser::Sum()
1180 Product();
1181 while (TokenInGroup(TGSUM))
1183 SmStructureNode *pSNode = new SmBinHorNode(CurToken);
1184 SmNode *pFirst = NodeStack.Pop();
1186 OpSubSup();
1187 SmNode *pSecond = NodeStack.Pop();
1189 Product();
1191 pSNode->SetSubNodes(pFirst, pSecond, NodeStack.Pop());
1192 NodeStack.Push(pSNode);
1197 void SmParser::Product()
1199 Power();
1201 while (TokenInGroup(TGPRODUCT))
1202 { SmStructureNode *pSNode;
1203 SmNode *pFirst = NodeStack.Pop(),
1204 *pOper;
1205 BOOL bSwitchArgs = FALSE;
1207 SmTokenType eType = CurToken.eType;
1208 switch (eType)
1210 case TOVER:
1211 pSNode = new SmBinVerNode(CurToken);
1212 pOper = new SmRectangleNode(CurToken);
1213 NextToken();
1214 break;
1216 case TBOPER:
1217 pSNode = new SmBinHorNode(CurToken);
1219 NextToken();
1221 GlyphSpecial();
1222 pOper = NodeStack.Pop();
1223 break;
1225 case TOVERBRACE :
1226 case TUNDERBRACE :
1227 pSNode = new SmVerticalBraceNode(CurToken);
1228 pOper = new SmMathSymbolNode(CurToken);
1230 NextToken();
1231 break;
1233 case TWIDEBACKSLASH:
1234 case TWIDESLASH:
1236 SmBinDiagonalNode *pSTmp = new SmBinDiagonalNode(CurToken);
1237 pSTmp->SetAscending(eType == TWIDESLASH);
1238 pSNode = pSTmp;
1240 pOper = new SmPolyLineNode(CurToken);
1241 NextToken();
1243 bSwitchArgs =TRUE;
1244 break;
1247 default:
1248 pSNode = new SmBinHorNode(CurToken);
1250 OpSubSup();
1251 pOper = NodeStack.Pop();
1254 Power();
1256 if (bSwitchArgs)
1257 //! vgl siehe SmBinDiagonalNode::Arrange
1258 pSNode->SetSubNodes(pFirst, NodeStack.Pop(), pOper);
1259 else
1260 pSNode->SetSubNodes(pFirst, pOper, NodeStack.Pop());
1261 NodeStack.Push(pSNode);
1266 void SmParser::SubSup(ULONG nActiveGroup)
1268 DBG_ASSERT(nActiveGroup == TGPOWER || nActiveGroup == TGLIMIT,
1269 "Sm: falsche Tokengruppe");
1271 if (!TokenInGroup(nActiveGroup))
1272 // already finish
1273 return;
1275 SmSubSupNode *pNode = new SmSubSupNode(CurToken);
1276 //! Of course 'CurToken' ist just the first sub-/supscript token.
1277 //! It should be of no further interest. The positions of the
1278 //! sub-/supscripts will be identified by the corresponding subnodes
1279 //! index in the 'aSubNodes' array (enum value from 'SmSubSup').
1281 pNode->SetUseLimits(nActiveGroup == TGLIMIT);
1283 // initialize subnodes array
1284 SmNodeArray aSubNodes;
1285 aSubNodes.resize(1 + SUBSUP_NUM_ENTRIES);
1286 aSubNodes[0] = NodeStack.Pop();
1287 for (USHORT i = 1; i < aSubNodes.size(); i++)
1288 aSubNodes[i] = NULL;
1290 // process all sub-/supscripts
1291 int nIndex = 0;
1292 while (TokenInGroup(nActiveGroup))
1293 { SmTokenType eType (CurToken.eType);
1295 // skip sub-/supscript token
1296 NextToken();
1298 // get sub-/supscript node on top of stack
1299 if (eType == TFROM || eType == TTO)
1301 // parse limits in old 4.0 and 5.0 style
1302 Relation();
1304 else
1305 Term();
1307 switch (eType)
1308 { case TRSUB : nIndex = (int) RSUB; break;
1309 case TRSUP : nIndex = (int) RSUP; break;
1310 case TFROM :
1311 case TCSUB : nIndex = (int) CSUB; break;
1312 case TTO :
1313 case TCSUP : nIndex = (int) CSUP; break;
1314 case TLSUB : nIndex = (int) LSUB; break;
1315 case TLSUP : nIndex = (int) LSUP; break;
1316 default :
1317 DBG_ASSERT(FALSE, "Sm: unbekannter Fall");
1319 nIndex++;
1320 DBG_ASSERT(1 <= nIndex && nIndex <= 1 + SUBSUP_NUM_ENTRIES,
1321 "SmParser::Power() : sub-/supscript index falsch");
1323 // set sub-/supscript if not already done
1324 if (aSubNodes[nIndex] != NULL)
1325 Error(PE_DOUBLE_SUBSUPSCRIPT);
1326 aSubNodes[nIndex] = NodeStack.Pop();
1329 pNode->SetSubNodes(aSubNodes);
1330 NodeStack.Push(pNode);
1334 void SmParser::OpSubSup()
1336 // push operator symbol
1337 NodeStack.Push(new SmMathSymbolNode(CurToken));
1338 // skip operator token
1339 NextToken();
1340 // get sub- supscripts if any
1341 if (TokenInGroup(TGPOWER))
1342 SubSup(TGPOWER);
1346 void SmParser::Power()
1348 // get body for sub- supscripts on top of stack
1349 Term();
1351 SubSup(TGPOWER);
1355 void SmParser::Blank()
1357 DBG_ASSERT(TokenInGroup(TGBLANK), "Sm : falsches Token");
1358 SmBlankNode *pBlankNode = new SmBlankNode(CurToken);
1360 while (TokenInGroup(TGBLANK))
1362 pBlankNode->IncreaseBy(CurToken);
1363 NextToken();
1366 // Blanks am Zeilenende ignorieren wenn die entsprechende Option gesetzt ist
1367 if ( CurToken.eType == TNEWLINE ||
1368 (CurToken.eType == TEND && SM_MOD1()->GetConfig()->IsIgnoreSpacesRight()) )
1370 pBlankNode->Clear();
1373 NodeStack.Push(pBlankNode);
1377 void SmParser::Term()
1379 switch (CurToken.eType)
1380 { case TESCAPE :
1381 Escape();
1382 break;
1384 case TLGROUP :
1385 NextToken();
1387 // allow for empty group
1388 if (CurToken.eType == TRGROUP)
1389 { SmStructureNode *pSNode = new SmExpressionNode(CurToken);
1390 pSNode->SetSubNodes(NULL, NULL);
1391 NodeStack.Push(pSNode);
1393 NextToken();
1395 else // go as usual
1396 { Align();
1397 if (CurToken.eType != TRGROUP)
1398 Error(PE_RGROUP_EXPECTED);
1399 else
1400 { NextToken();
1403 break;
1405 case TLEFT :
1406 Brace();
1407 break;
1409 case TBLANK :
1410 case TSBLANK :
1411 Blank();
1412 break;
1414 case TTEXT :
1415 NodeStack.Push(new SmTextNode(CurToken, FNT_TEXT));
1416 NextToken();
1417 break;
1418 case TIDENT :
1419 case TCHARACTER :
1420 NodeStack.Push(new SmTextNode(CurToken, FNT_VARIABLE));
1421 NextToken();
1422 break;
1423 case TNUMBER :
1424 NodeStack.Push(new SmTextNode(CurToken, FNT_NUMBER));
1425 NextToken();
1426 break;
1428 case TLEFTARROW :
1429 case TRIGHTARROW :
1430 case TUPARROW :
1431 case TDOWNARROW :
1432 case TSETN :
1433 case TSETZ :
1434 case TSETQ :
1435 case TSETR :
1436 case TSETC :
1437 case THBAR :
1438 case TLAMBDABAR :
1439 case TCIRC :
1440 case TDRARROW :
1441 case TDLARROW :
1442 case TDLRARROW :
1443 case TBACKEPSILON :
1444 case TALEPH :
1445 case TIM :
1446 case TRE :
1447 case TWP :
1448 case TEMPTYSET :
1449 case TINFINITY :
1450 case TEXISTS :
1451 case TFORALL :
1452 case TPARTIAL :
1453 case TNABLA :
1454 case TTOWARD :
1455 case TDOTSAXIS :
1456 case TDOTSDIAG :
1457 case TDOTSDOWN :
1458 case TDOTSLOW :
1459 case TDOTSUP :
1460 case TDOTSVERT :
1461 NodeStack.Push(new SmMathSymbolNode(CurToken));
1462 NextToken();
1463 break;
1465 case TPLACE:
1466 NodeStack.Push(new SmPlaceNode(CurToken));
1467 NextToken();
1468 break;
1470 case TSPECIAL:
1471 Special();
1472 break;
1474 case TBINOM:
1475 Binom();
1476 break;
1478 case TSTACK:
1479 Stack();
1480 break;
1482 case TMATRIX:
1483 Matrix();
1484 break;
1486 default:
1487 if (TokenInGroup(TGLBRACES))
1488 { Brace();
1490 else if (TokenInGroup(TGOPER))
1491 { Operator();
1493 else if (TokenInGroup(TGUNOPER))
1494 { UnOper();
1496 else if ( TokenInGroup(TGATTRIBUT)
1497 || TokenInGroup(TGFONTATTR))
1498 { SmStructureNodeArray aArray;
1500 BOOL bIsAttr;
1501 USHORT n = 0;
1502 while (TRUE == (bIsAttr = TokenInGroup(TGATTRIBUT))
1503 || TokenInGroup(TGFONTATTR))
1504 { aArray.resize(n + 1);
1506 if (bIsAttr)
1507 Attribut();
1508 else
1509 FontAttribut();
1511 // check if casting in following line is ok
1512 DBG_ASSERT(!NodeStack.Top()->IsVisible(), "Sm : Ooops...");
1514 aArray[n] = (SmStructureNode *) NodeStack.Pop();
1515 n++;
1518 Power();
1520 SmNode *pFirstNode = NodeStack.Pop();
1521 while (n > 0)
1522 { aArray[n - 1]->SetSubNodes(0, pFirstNode);
1523 pFirstNode = aArray[n - 1];
1524 n--;
1526 NodeStack.Push(pFirstNode);
1528 else if (TokenInGroup(TGFUNCTION))
1529 { if (CONVERT_40_TO_50 != GetConversion())
1530 { Function();
1532 else // encapsulate old 4.0 style parsing in braces
1534 // insert opening brace
1535 Insert('{', GetTokenIndex());
1538 // parse in 4.0 style
1540 Function();
1542 SmNode *pFunc = NodeStack.Pop();
1544 if (CurToken.eType == TLPARENT)
1545 { Term();
1547 else
1548 { Align();
1551 // insert closing brace
1552 Insert('}', GetTokenIndex());
1554 SmStructureNode *pSNode = new SmExpressionNode(pFunc->GetToken());
1555 pSNode->SetSubNodes(pFunc, NodeStack.Pop());
1556 NodeStack.Push(pSNode);
1559 else
1560 Error(PE_UNEXPECTED_CHAR);
1565 void SmParser::Escape()
1567 NextToken();
1569 sal_Unicode cChar;
1570 switch (CurToken.eType)
1571 { case TLPARENT : cChar = MS_LPARENT; break;
1572 case TRPARENT : cChar = MS_RPARENT; break;
1573 case TLBRACKET : cChar = MS_LBRACKET; break;
1574 case TRBRACKET : cChar = MS_RBRACKET; break;
1575 case TLDBRACKET : cChar = MS_LDBRACKET; break;
1576 case TRDBRACKET : cChar = MS_RDBRACKET; break;
1577 case TLBRACE :
1578 case TLGROUP : cChar = MS_LBRACE; break;
1579 case TRBRACE :
1580 case TRGROUP : cChar = MS_RBRACE; break;
1581 case TLANGLE : cChar = MS_LANGLE; break;
1582 case TRANGLE : cChar = MS_RANGLE; break;
1583 case TLCEIL : cChar = MS_LCEIL; break;
1584 case TRCEIL : cChar = MS_RCEIL; break;
1585 case TLFLOOR : cChar = MS_LFLOOR; break;
1586 case TRFLOOR : cChar = MS_RFLOOR; break;
1587 case TLLINE :
1588 case TRLINE : cChar = MS_LINE; break;
1589 case TLDLINE :
1590 case TRDLINE : cChar = MS_DLINE; break;
1591 default:
1592 Error(PE_UNEXPECTED_TOKEN);
1595 SmNode *pNode = new SmMathSymbolNode(CurToken);
1596 NodeStack.Push(pNode);
1598 NextToken();
1602 void SmParser::Operator()
1604 if (TokenInGroup(TGOPER))
1605 { SmStructureNode *pSNode = new SmOperNode(CurToken);
1607 // put operator on top of stack
1608 Oper();
1610 if (TokenInGroup(TGLIMIT) || TokenInGroup(TGPOWER))
1611 SubSup(CurToken.nGroup);
1612 SmNode *pOperator = NodeStack.Pop();
1614 // get argument
1615 Power();
1617 pSNode->SetSubNodes(pOperator, NodeStack.Pop());
1618 NodeStack.Push(pSNode);
1623 void SmParser::Oper()
1625 SmTokenType eType (CurToken.eType);
1626 SmNode *pNode = NULL;
1628 switch (eType)
1630 case TSUM :
1631 case TPROD :
1632 case TCOPROD :
1633 case TINT :
1634 case TIINT :
1635 case TIIINT :
1636 case TLINT :
1637 case TLLINT :
1638 case TLLLINT :
1639 pNode = new SmMathSymbolNode(CurToken);
1640 break;
1642 case TLIM :
1643 case TLIMSUP :
1644 case TLIMINF :
1646 const sal_Char* pLim = 0;
1647 switch (eType)
1649 case TLIM : pLim = "lim"; break;
1650 case TLIMSUP : pLim = "lim sup"; break;
1651 case TLIMINF : pLim = "lim inf"; break;
1652 default:
1653 break;
1655 if( pLim )
1656 CurToken.aText.AssignAscii( pLim );
1657 pNode = new SmTextNode(CurToken, FNT_TEXT);
1659 break;
1661 case TOVERBRACE :
1662 case TUNDERBRACE :
1663 pNode = new SmMathSymbolNode(CurToken);
1664 break;
1666 case TOPER :
1667 NextToken();
1669 DBG_ASSERT(CurToken.eType == TSPECIAL, "Sm: falsches Token");
1670 pNode = new SmGlyphSpecialNode(CurToken);
1671 break;
1673 default :
1674 DBG_ASSERT(0, "Sm: unbekannter Fall");
1676 NodeStack.Push(pNode);
1678 NextToken();
1682 void SmParser::UnOper()
1684 DBG_ASSERT(TokenInGroup(TGUNOPER), "Sm: falsches Token");
1686 SmToken aNodeToken = CurToken;
1687 SmTokenType eType = CurToken.eType;
1688 BOOL bIsPostfix = eType == TFACT;
1690 SmStructureNode *pSNode;
1691 SmNode *pOper = 0,
1692 *pExtra = 0,
1693 *pArg;
1695 switch (eType)
1697 case TABS :
1698 case TSQRT :
1699 NextToken();
1700 break;
1702 case TNROOT :
1703 NextToken();
1704 Power();
1705 pExtra = NodeStack.Pop();
1706 break;
1708 case TUOPER :
1709 NextToken();
1710 GlyphSpecial();
1711 pOper = NodeStack.Pop();
1712 break;
1714 case TPLUS :
1715 case TMINUS :
1716 case TPLUSMINUS :
1717 case TMINUSPLUS :
1718 case TNEG :
1719 case TFACT :
1720 OpSubSup();
1721 pOper = NodeStack.Pop();
1722 break;
1724 default :
1725 Error(PE_UNOPER_EXPECTED);
1728 // get argument
1729 Power();
1730 pArg = NodeStack.Pop();
1732 if (eType == TABS)
1733 { pSNode = new SmBraceNode(aNodeToken);
1734 pSNode->SetScaleMode(SCALE_HEIGHT);
1736 // build nodes for left & right lines
1737 // (text, group, level of the used token are of no interrest here)
1738 // we'll use row & column of the keyword for abs
1739 aNodeToken.eType = TABS;
1741 aNodeToken.cMathChar = MS_LINE;
1742 SmNode* pLeft = new SmMathSymbolNode(aNodeToken);
1744 aNodeToken.cMathChar = MS_LINE;
1745 SmNode* pRight = new SmMathSymbolNode(aNodeToken);
1747 pSNode->SetSubNodes(pLeft, pArg, pRight);
1749 else if (eType == TSQRT || eType == TNROOT)
1750 { pSNode = new SmRootNode(aNodeToken);
1751 pOper = new SmRootSymbolNode(aNodeToken);
1752 pSNode->SetSubNodes(pExtra, pOper, pArg);
1754 else
1755 { pSNode = new SmUnHorNode(aNodeToken);
1757 if (bIsPostfix)
1758 pSNode->SetSubNodes(pArg, pOper);
1759 else
1760 // prefix operator
1761 pSNode->SetSubNodes(pOper, pArg);
1764 NodeStack.Push(pSNode);
1768 void SmParser::Attribut()
1770 DBG_ASSERT(TokenInGroup(TGATTRIBUT), "Sm: falsche Tokengruppe");
1772 SmStructureNode *pSNode = new SmAttributNode(CurToken);
1773 SmNode *pAttr;
1774 SmScaleMode eScaleMode = SCALE_NONE;
1776 // get appropriate node for the attribut itself
1777 switch (CurToken.eType)
1778 { case TUNDERLINE :
1779 case TOVERLINE :
1780 case TOVERSTRIKE :
1781 pAttr = new SmRectangleNode(CurToken);
1782 eScaleMode = SCALE_WIDTH;
1783 break;
1785 case TWIDEVEC :
1786 case TWIDEHAT :
1787 case TWIDETILDE :
1788 pAttr = new SmMathSymbolNode(CurToken);
1789 eScaleMode = SCALE_WIDTH;
1790 break;
1792 default :
1793 pAttr = new SmMathSymbolNode(CurToken);
1796 NextToken();
1798 pSNode->SetSubNodes(pAttr, 0);
1799 pSNode->SetScaleMode(eScaleMode);
1800 NodeStack.Push(pSNode);
1804 void SmParser::FontAttribut()
1806 DBG_ASSERT(TokenInGroup(TGFONTATTR), "Sm: falsche Tokengruppe");
1808 switch (CurToken.eType)
1810 case TITALIC :
1811 case TNITALIC :
1812 case TBOLD :
1813 case TNBOLD :
1814 case TPHANTOM :
1815 NodeStack.Push(new SmFontNode(CurToken));
1816 NextToken();
1817 break;
1819 case TSIZE :
1820 FontSize();
1821 break;
1823 case TFONT :
1824 Font();
1825 break;
1827 case TCOLOR :
1828 Color();
1829 break;
1831 default :
1832 DBG_ASSERT(0, "Sm: unbekannter Fall");
1837 void SmParser::Color()
1839 DBG_ASSERT(CurToken.eType == TCOLOR, "Sm : Ooops...");
1841 // last color rules, get that one
1842 SmToken aToken;
1844 { NextToken();
1846 if (TokenInGroup(TGCOLOR))
1847 { aToken = CurToken;
1848 NextToken();
1850 else
1851 Error(PE_COLOR_EXPECTED);
1852 } while (CurToken.eType == TCOLOR);
1854 NodeStack.Push(new SmFontNode(aToken));
1858 void SmParser::Font()
1860 DBG_ASSERT(CurToken.eType == TFONT, "Sm : Ooops...");
1862 // last font rules, get that one
1863 SmToken aToken;
1865 { NextToken();
1867 if (TokenInGroup(TGFONT))
1868 { aToken = CurToken;
1869 NextToken();
1871 else
1872 Error(PE_FONT_EXPECTED);
1873 } while (CurToken.eType == TFONT);
1875 NodeStack.Push(new SmFontNode(aToken));
1879 // gets number used as arguments in Math formulas (e.g. 'size' command)
1880 // Format: no negative numbers, must start with a digit, no exponent notation, ...
1881 BOOL lcl_IsNumber(const UniString& rText)
1883 BOOL bPoint = FALSE;
1884 const sal_Unicode* pBuffer = rText.GetBuffer();
1885 for(xub_StrLen nPos = 0; nPos < rText.Len(); nPos++, pBuffer++)
1887 const sal_Unicode cChar = *pBuffer;
1888 if(cChar == '.')
1890 if(bPoint)
1891 return FALSE;
1892 else
1893 bPoint = TRUE;
1895 else if ( !IsDigit( cChar ) )
1896 return FALSE;
1898 return TRUE;
1901 void SmParser::FontSize()
1903 DBG_ASSERT(CurToken.eType == TSIZE, "Sm : Ooops...");
1905 USHORT Type;
1906 SmFontNode *pFontNode = new SmFontNode(CurToken);
1908 NextToken();
1910 switch (CurToken.eType)
1912 case TNUMBER: Type = FNTSIZ_ABSOLUT; break;
1913 case TPLUS: Type = FNTSIZ_PLUS; break;
1914 case TMINUS: Type = FNTSIZ_MINUS; break;
1915 case TMULTIPLY: Type = FNTSIZ_MULTIPLY; break;
1916 case TDIVIDEBY: Type = FNTSIZ_DIVIDE; break;
1918 default:
1919 delete pFontNode;
1920 Error(PE_SIZE_EXPECTED);
1921 return;
1924 if (Type != FNTSIZ_ABSOLUT)
1926 NextToken();
1927 if (CurToken.eType != TNUMBER)
1929 delete pFontNode;
1930 Error(PE_SIZE_EXPECTED);
1931 return;
1935 // get number argument
1936 Fraction aValue( 1L );
1937 if (lcl_IsNumber( CurToken.aText ))
1939 double fTmp;
1940 if ((fTmp = CurToken.aText.ToDouble()) != 0.0)
1942 aValue = fTmp;
1944 //!! keep the numerator and denominator from being to large
1945 //!! otherwise ongoing multiplications may result in overflows
1946 //!! (for example in SmNode::SetFontSize the font size calculated
1947 //!! may become 0 because of this!!! Happens e.g. for ftmp = 2.9 with Linux
1948 //!! or ftmp = 1.11111111111111111... (11/9) on every platform.)
1949 if (aValue.GetDenominator() > 1000)
1951 long nNum = aValue.GetNumerator();
1952 long nDenom = aValue.GetDenominator();
1953 while (nDenom > 1000)
1955 nNum /= 10;
1956 nDenom /= 10;
1958 aValue = Fraction( nNum, nDenom );
1963 NextToken();
1965 pFontNode->SetSizeParameter(aValue, Type);
1966 NodeStack.Push(pFontNode);
1970 void SmParser::Brace()
1972 DBG_ASSERT(CurToken.eType == TLEFT || TokenInGroup(TGLBRACES),
1973 "Sm: kein Klammer Ausdruck");
1975 SmStructureNode *pSNode = new SmBraceNode(CurToken);
1976 SmNode *pBody = 0,
1977 *pLeft = 0,
1978 *pRight = 0;
1979 SmScaleMode eScaleMode = SCALE_NONE;
1980 SmParseError eError = PE_NONE;
1982 if (CurToken.eType == TLEFT)
1983 { NextToken();
1985 eScaleMode = SCALE_HEIGHT;
1987 // check for left bracket
1988 if (TokenInGroup(TGLBRACES) || TokenInGroup(TGRBRACES))
1990 pLeft = new SmMathSymbolNode(CurToken);
1992 NextToken();
1993 Bracebody(TRUE);
1994 pBody = NodeStack.Pop();
1996 if (CurToken.eType == TRIGHT)
1997 { NextToken();
1999 // check for right bracket
2000 if (TokenInGroup(TGLBRACES) || TokenInGroup(TGRBRACES))
2002 pRight = new SmMathSymbolNode(CurToken);
2003 NextToken();
2005 else
2006 eError = PE_RBRACE_EXPECTED;
2008 else
2009 eError = PE_RIGHT_EXPECTED;
2011 else
2012 eError = PE_LBRACE_EXPECTED;
2014 else
2016 if (TokenInGroup(TGLBRACES))
2018 pLeft = new SmMathSymbolNode(CurToken);
2020 NextToken();
2021 Bracebody(FALSE);
2022 pBody = NodeStack.Pop();
2024 SmTokenType eExpectedType = TUNKNOWN;
2025 switch (pLeft->GetToken().eType)
2026 { case TLPARENT : eExpectedType = TRPARENT; break;
2027 case TLBRACKET : eExpectedType = TRBRACKET; break;
2028 case TLBRACE : eExpectedType = TRBRACE; break;
2029 case TLDBRACKET : eExpectedType = TRDBRACKET; break;
2030 case TLLINE : eExpectedType = TRLINE; break;
2031 case TLDLINE : eExpectedType = TRDLINE; break;
2032 case TLANGLE : eExpectedType = TRANGLE; break;
2033 case TLFLOOR : eExpectedType = TRFLOOR; break;
2034 case TLCEIL : eExpectedType = TRCEIL; break;
2035 default :
2036 DBG_ASSERT(0, "Sm: unbekannter Fall");
2039 if (CurToken.eType == eExpectedType)
2041 pRight = new SmMathSymbolNode(CurToken);
2042 NextToken();
2044 else
2045 eError = PE_PARENT_MISMATCH;
2047 else
2048 eError = PE_LBRACE_EXPECTED;
2051 if (eError == PE_NONE)
2052 { DBG_ASSERT(pLeft, "Sm: NULL pointer");
2053 DBG_ASSERT(pRight, "Sm: NULL pointer");
2054 pSNode->SetSubNodes(pLeft, pBody, pRight);
2055 pSNode->SetScaleMode(eScaleMode);
2056 NodeStack.Push(pSNode);
2058 else
2059 { delete pSNode;
2060 delete pBody;
2061 delete pLeft;
2062 delete pRight;
2064 Error(eError);
2069 void SmParser::Bracebody(BOOL bIsLeftRight)
2071 SmStructureNode *pBody = new SmBracebodyNode(CurToken);
2072 SmNodeArray aNodes;
2073 USHORT nNum = 0;
2075 // get body if any
2076 if (bIsLeftRight)
2080 if (CurToken.eType == TMLINE)
2082 NodeStack.Push(new SmMathSymbolNode(CurToken));
2083 NextToken();
2084 nNum++;
2086 else if (CurToken.eType != TRIGHT)
2087 { Align();
2088 nNum++;
2090 if (CurToken.eType != TMLINE && CurToken.eType != TRIGHT)
2091 Error(PE_RIGHT_EXPECTED);
2093 } while (CurToken.eType != TEND && CurToken.eType != TRIGHT);
2095 else
2099 if (CurToken.eType == TMLINE)
2101 NodeStack.Push(new SmMathSymbolNode(CurToken));
2102 NextToken();
2103 nNum++;
2105 else if (!TokenInGroup(TGRBRACES))
2106 { Align();
2107 nNum++;
2109 if (CurToken.eType != TMLINE && !TokenInGroup(TGRBRACES))
2110 Error(PE_RBRACE_EXPECTED);
2112 } while (CurToken.eType != TEND && !TokenInGroup(TGRBRACES));
2115 // build argument vector in parsing order
2116 aNodes.resize(nNum);
2117 for (USHORT i = 0; i < nNum; i++)
2118 aNodes[nNum - 1 - i] = NodeStack.Pop();
2120 pBody->SetSubNodes(aNodes);
2121 pBody->SetScaleMode(bIsLeftRight ? SCALE_HEIGHT : SCALE_NONE);
2122 NodeStack.Push(pBody);
2126 void SmParser::Function()
2128 switch (CurToken.eType)
2130 case TFUNC:
2131 NextToken(); // skip "FUNC"-statement
2132 // fall through
2134 case TSIN :
2135 case TCOS :
2136 case TTAN :
2137 case TCOT :
2138 case TASIN :
2139 case TACOS :
2140 case TATAN :
2141 case TACOT :
2142 case TSINH :
2143 case TCOSH :
2144 case TTANH :
2145 case TCOTH :
2146 case TASINH :
2147 case TACOSH :
2148 case TATANH :
2149 case TACOTH :
2150 case TLN :
2151 case TLOG :
2152 case TEXP :
2153 NodeStack.Push(new SmTextNode(CurToken, FNT_FUNCTION));
2154 NextToken();
2155 break;
2157 default:
2158 Error(PE_FUNC_EXPECTED);
2163 void SmParser::Binom()
2165 SmNodeArray ExpressionArray;
2166 SmStructureNode *pSNode = new SmTableNode(CurToken);
2168 NextToken();
2170 Sum();
2171 Sum();
2173 ExpressionArray.resize(2);
2175 for (int i = 0; i < 2; i++)
2176 ExpressionArray[2 - (i + 1)] = NodeStack.Pop();
2178 pSNode->SetSubNodes(ExpressionArray);
2179 NodeStack.Push(pSNode);
2183 void SmParser::Stack()
2185 SmNodeArray ExpressionArray;
2186 NextToken();
2187 if (CurToken.eType == TLGROUP)
2189 USHORT n = 0;
2193 NextToken();
2194 Align();
2195 n++;
2197 while (CurToken.eType == TPOUND);
2199 ExpressionArray.resize(n);
2201 for (USHORT i = 0; i < n; i++)
2202 ExpressionArray[n - (i + 1)] = NodeStack.Pop();
2204 if (CurToken.eType != TRGROUP)
2205 Error(PE_RGROUP_EXPECTED);
2207 NextToken();
2209 SmStructureNode *pSNode = new SmTableNode(CurToken);
2210 pSNode->SetSubNodes(ExpressionArray);
2211 NodeStack.Push(pSNode);
2213 else
2214 Error(PE_LGROUP_EXPECTED);
2218 void SmParser::Matrix()
2220 SmNodeArray ExpressionArray;
2222 NextToken();
2223 if (CurToken.eType == TLGROUP)
2225 USHORT c = 0;
2229 NextToken();
2230 Align();
2231 c++;
2233 while (CurToken.eType == TPOUND);
2235 USHORT r = 1;
2237 while (CurToken.eType == TDPOUND)
2239 NextToken();
2240 for (USHORT i = 0; i < c; i++)
2242 Align();
2243 if (i < (c - 1))
2245 if (CurToken.eType == TPOUND)
2247 NextToken();
2249 else
2250 Error(PE_POUND_EXPECTED);
2254 r++;
2257 long nRC = r * c;
2259 ExpressionArray.resize(nRC);
2261 for (USHORT i = 0; i < (nRC); i++)
2262 ExpressionArray[(nRC) - (i + 1)] = NodeStack.Pop();
2264 if (CurToken.eType != TRGROUP)
2265 Error(PE_RGROUP_EXPECTED);
2267 NextToken();
2269 SmMatrixNode *pMNode = new SmMatrixNode(CurToken);
2270 pMNode->SetSubNodes(ExpressionArray);
2271 pMNode->SetRowCol(r, c);
2272 NodeStack.Push(pMNode);
2274 else
2275 Error(PE_LGROUP_EXPECTED);
2279 void SmParser::Special()
2281 BOOL bReplace = FALSE;
2282 String &rName = CurToken.aText;
2283 String aNewName;
2285 if (CONVERT_NONE == GetConversion())
2287 // conversion of symbol names for 6.0 (XML) file format
2288 // (name change on import / export.
2289 // UI uses localized names XML file format does not.)
2290 if (IsImportSymbolNames())
2292 const SmLocalizedSymbolData &rLSD = SM_MOD1()->GetLocSymbolData();
2293 aNewName = rLSD.GetUiSymbolName( rName );
2294 bReplace = TRUE;
2296 else if (IsExportSymbolNames())
2298 const SmLocalizedSymbolData &rLSD = SM_MOD1()->GetLocSymbolData();
2299 aNewName = rLSD.GetExportSymbolName( rName );
2300 bReplace = TRUE;
2303 else // 5.0 <-> 6.0 formula text (symbol name) conversion
2305 LanguageType nLanguage = GetLanguage();
2306 SmLocalizedSymbolData &rData = SM_MOD1()->GetLocSymbolData();
2307 const ResStringArray *pFrom = 0;
2308 const ResStringArray *pTo = 0;
2309 if (CONVERT_50_TO_60 == GetConversion())
2311 pFrom = rData.Get50NamesArray( nLanguage );
2312 pTo = rData.Get60NamesArray( nLanguage );
2314 else if (CONVERT_60_TO_50 == GetConversion())
2316 pFrom = rData.Get60NamesArray( nLanguage );
2317 pTo = rData.Get50NamesArray( nLanguage );
2319 if (pFrom && pTo)
2321 DBG_ASSERT( pFrom->Count() == pTo->Count(),
2322 "array length mismatch" );
2323 USHORT nCount = sal::static_int_cast< USHORT >(pFrom->Count());
2324 for (USHORT i = 0; i < nCount; ++i)
2326 if (pFrom->GetString(i) == rName)
2328 aNewName = pTo->GetString(i);
2329 bReplace = TRUE;
2333 // else:
2334 // conversion arrays not found or (usually)
2335 // conversion not necessary
2338 if (bReplace && aNewName.Len() && rName != aNewName)
2340 Replace( GetTokenIndex() + 1, rName.Len(), aNewName );
2341 rName = aNewName;
2344 NodeStack.Push(new SmSpecialNode(CurToken));
2345 NextToken();
2349 void SmParser::GlyphSpecial()
2351 NodeStack.Push(new SmGlyphSpecialNode(CurToken));
2352 NextToken();
2356 void SmParser::Error(SmParseError eError)
2358 SmStructureNode *pSNode = new SmExpressionNode(CurToken);
2359 SmErrorNode *pErr = new SmErrorNode(eError, CurToken);
2360 pSNode->SetSubNodes(pErr, 0);
2362 //! put a structure node on the stack (instead of the error node itself)
2363 //! because sometimes such a node is expected in order to attach some
2364 //! subnodes
2365 NodeStack.Push(pSNode);
2367 AddError(eError, pSNode);
2369 NextToken();
2373 // end gramar
2376 SmParser::SmParser()
2378 eConversion = CONVERT_NONE;
2379 bImportSymNames = bExportSymNames = FALSE;
2380 nLang = Application::GetSettings().GetUILanguage();
2384 SmNode *SmParser::Parse(const String &rBuffer)
2386 BufferString = rBuffer;
2387 BufferString.ConvertLineEnd( LINEEND_LF );
2388 BufferIndex =
2389 nTokenIndex = 0;
2390 Row = 1;
2391 ColOff = 0;
2392 CurError = -1;
2394 for (USHORT i = 0; i < ErrDescList.Count(); i++)
2395 delete ErrDescList.Remove(i);
2397 ErrDescList.Clear();
2399 NodeStack.Clear();
2401 SetLanguage( Application::GetSettings().GetUILanguage() );
2402 NextToken();
2403 Table();
2405 return NodeStack.Pop();
2409 USHORT SmParser::AddError(SmParseError Type, SmNode *pNode)
2411 SmErrorDesc *pErrDesc = new SmErrorDesc;
2413 pErrDesc->Type = Type;
2414 pErrDesc->pNode = pNode;
2415 pErrDesc->Text = String(SmResId(RID_ERR_IDENT));
2417 USHORT nRID;
2418 switch (Type)
2420 case PE_UNEXPECTED_CHAR: nRID = RID_ERR_UNEXPECTEDCHARACTER; break;
2421 case PE_LGROUP_EXPECTED: nRID = RID_ERR_LGROUPEXPECTED; break;
2422 case PE_RGROUP_EXPECTED: nRID = RID_ERR_RGROUPEXPECTED; break;
2423 case PE_LBRACE_EXPECTED: nRID = RID_ERR_LBRACEEXPECTED; break;
2424 case PE_RBRACE_EXPECTED: nRID = RID_ERR_RBRACEEXPECTED; break;
2425 case PE_FUNC_EXPECTED: nRID = RID_ERR_FUNCEXPECTED; break;
2426 case PE_UNOPER_EXPECTED: nRID = RID_ERR_UNOPEREXPECTED; break;
2427 case PE_BINOPER_EXPECTED: nRID = RID_ERR_BINOPEREXPECTED; break;
2428 case PE_SYMBOL_EXPECTED: nRID = RID_ERR_SYMBOLEXPECTED; break;
2429 case PE_IDENTIFIER_EXPECTED: nRID = RID_ERR_IDENTEXPECTED; break;
2430 case PE_POUND_EXPECTED: nRID = RID_ERR_POUNDEXPECTED; break;
2431 case PE_COLOR_EXPECTED: nRID = RID_ERR_COLOREXPECTED; break;
2432 case PE_RIGHT_EXPECTED: nRID = RID_ERR_RIGHTEXPECTED; break;
2434 default:
2435 nRID = RID_ERR_UNKOWN;
2437 pErrDesc->Text += SmResId(nRID);
2439 ErrDescList.Insert(pErrDesc);
2441 return (USHORT) ErrDescList.GetPos(pErrDesc);
2445 const SmErrorDesc *SmParser::NextError()
2447 if (ErrDescList.Count())
2448 if (CurError > 0) return ErrDescList.Seek(--CurError);
2449 else
2451 CurError = 0;
2452 return ErrDescList.Seek(CurError);
2454 else return 0;
2458 const SmErrorDesc *SmParser::PrevError()
2460 if (ErrDescList.Count())
2461 if (CurError < (int) (ErrDescList.Count() - 1)) return ErrDescList.Seek(++CurError);
2462 else
2464 CurError = (int) (ErrDescList.Count() - 1);
2465 return ErrDescList.Seek(CurError);
2467 else return 0;
2471 const SmErrorDesc *SmParser::GetError(USHORT i)
2473 return (/*i >= 0 &&*/ i < ErrDescList.Count())
2474 ? ErrDescList.Seek(i)
2475 : ErrDescList.Seek(CurError);