merged tag ooo/DEV300_m102
[LibreOffice.git] / starmath / source / parse.cxx
blob4a85ccbaac561e41f9c2dd71bba5db47e7e6881f
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_starmath.hxx"
32 #include <stdio.h>
34 #define SMDLL 1
36 #include <com/sun/star/i18n/UnicodeType.hpp>
37 #include <i18npool/lang.h>
38 #include <unotools/charclass.hxx>
39 #include <editeng/unolingu.hxx>
40 #include <unotools/syslocale.hxx>
41 #include "parse.hxx"
42 #ifndef _STARMATH_HRC
43 #include "starmath.hrc"
44 #endif
45 #ifndef _SMDLL_HXX
46 #include "smdll.hxx"
47 #endif
48 #include "smmod.hxx"
49 #include "config.hxx"
51 #include "node.hxx"
53 using namespace ::com::sun::star;
54 using namespace ::com::sun::star::i18n;
56 ///////////////////////////////////////////////////////////////////////////
58 static inline sal_Bool strnccmp(const String &u1, xub_StrLen nIdx,
59 const sal_Char *s2, xub_StrLen nLen)
61 return u1.EqualsIgnoreCaseAscii( s2, nIdx, nLen );
64 static const sal_Unicode aDelimiterTable[] =
66 ' ', '\t', '\n', '\r', '+', '-', '*', '/', '=', '#',
67 '%', '\\', '"', '~', '`', '>', '<', '&', '|', '(',
68 ')', '{', '}', '[', ']', '^', '_',
69 '\0' // end of list symbol
73 static inline sal_Bool IsDigit( sal_Unicode cChar )
75 return '0' <= cChar && cChar <= '9';
78 ///////////////////////////////////////////////////////////////////////////
80 SmToken::SmToken() :
81 eType (TUNKNOWN),
82 cMathChar ('\0')
84 nGroup = nCol = nRow = nLevel = 0;
87 ///////////////////////////////////////////////////////////////////////////
89 struct SmTokenTableEntry
91 const sal_Char* pIdent;
92 SmTokenType eType;
93 sal_Unicode cMathChar;
94 sal_uLong nGroup;
95 sal_uInt16 nLevel;
98 static const SmTokenTableEntry aTokenTable[] =
100 // { "#", TPOUND, '\0', 0, 0 },
101 // { "##", TDPOUND, '\0', 0, 0 },
102 // { "&", TAND, MS_AND, TGPRODUCT, 0 },
103 // { "(", TLPARENT, MS_LPARENT, TGLBRACES, 5 }, //! 5 to continue expression
104 // { ")", TRPARENT, MS_RPARENT, TGRBRACES, 0 }, //! 0 to terminate expression
105 // { "*", TMULTIPLY, MS_MULTIPLY, TGPRODUCT, 0 },
106 // { "+", TPLUS, MS_PLUS, TGUNOPER | TGSUM, 5 },
107 // { "+-", TPLUSMINUS, MS_PLUSMINUS, TGUNOPER | TGSUM, 5 },
108 // { "-", TMINUS, MS_MINUS, TGUNOPER | TGSUM, 5 },
109 // { "-+", TMINUSPLUS, MS_MINUSPLUS, TGUNOPER | TGSUM, 5 },
110 // { ".", TPOINT, '\0', 0, 0 },
111 // { "/", TDIVIDEBY, MS_SLASH, TGPRODUCT, 0 },
112 // { "<", TLT, MS_LT, TGRELATION, 0 },
113 // { "<<", TLL, MS_LL, TGRELATION, 0 },
114 // { "<=", TLE, MS_LE, TGRELATION, 0 },
115 // { "<>", TNEQ, MS_NEQ, TGRELATION, 0},
116 // { "<?>", TPLACE, MS_PLACE, 0, 5 },
117 // { "=", TASSIGN, MS_ASSIGN, TGRELATION, 0},
118 // { ">", TGT, MS_GT, TGRELATION, 0 },
119 // { ">=", TGE, MS_GE, TGRELATION, 0 },
120 // { ">>", TGG, MS_GG, TGRELATION, 0 },
121 { "Im" , TIM, MS_IM, TGSTANDALONE, 5 },
122 { "MZ23", TDEBUG, '\0', TGATTRIBUT, 0 },
123 { "Re" , TRE, MS_RE, TGSTANDALONE, 5 },
124 { "abs", TABS, '\0', TGUNOPER, 13 },
125 { "arcosh", TACOSH, '\0', TGFUNCTION, 5 },
126 { "arcoth", TACOTH, '\0', TGFUNCTION, 5 },
127 { "acute", TACUTE, MS_ACUTE, TGATTRIBUT, 5 },
128 { "aleph" , TALEPH, MS_ALEPH, TGSTANDALONE, 5 },
129 { "alignb", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0},
130 { "alignc", TALIGNC, '\0', TGALIGN, 0},
131 { "alignl", TALIGNL, '\0', TGALIGN, 0},
132 { "alignm", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0},
133 { "alignr", TALIGNR, '\0', TGALIGN, 0},
134 { "alignt", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0},
135 { "and", TAND, MS_AND, TGPRODUCT, 0},
136 { "approx", TAPPROX, MS_APPROX, TGRELATION, 0},
137 { "arccos", TACOS, '\0', TGFUNCTION, 5},
138 { "arccot", TACOT, '\0', TGFUNCTION, 5},
139 { "arcsin", TASIN, '\0', TGFUNCTION, 5},
140 { "arctan", TATAN, '\0', TGFUNCTION, 5},
141 { "arsinh", TASINH, '\0', TGFUNCTION, 5},
142 { "artanh", TATANH, '\0', TGFUNCTION, 5},
143 { "backepsilon" , TBACKEPSILON, MS_BACKEPSILON, TGSTANDALONE, 5},
144 { "bar", TBAR, MS_BAR, TGATTRIBUT, 5},
145 { "binom", TBINOM, '\0', 0, 5 },
146 { "black", TBLACK, '\0', TGCOLOR, 0},
147 { "blue", TBLUE, '\0', TGCOLOR, 0},
148 { "bold", TBOLD, '\0', TGFONTATTR, 5},
149 { "boper", TBOPER, '\0', TGPRODUCT, 0},
150 { "breve", TBREVE, MS_BREVE, TGATTRIBUT, 5},
151 { "bslash", TBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 },
152 { "cdot", TCDOT, MS_CDOT, TGPRODUCT, 0},
153 { "check", TCHECK, MS_CHECK, TGATTRIBUT, 5},
154 { "circ" , TCIRC, MS_CIRC, TGSTANDALONE, 5},
155 { "circle", TCIRCLE, MS_CIRCLE, TGATTRIBUT, 5},
156 { "color", TCOLOR, '\0', TGFONTATTR, 5},
157 { "coprod", TCOPROD, MS_COPROD, TGOPER, 5},
158 { "cos", TCOS, '\0', TGFUNCTION, 5},
159 { "cosh", TCOSH, '\0', TGFUNCTION, 5},
160 { "cot", TCOT, '\0', TGFUNCTION, 5},
161 { "coth", TCOTH, '\0', TGFUNCTION, 5},
162 { "csub", TCSUB, '\0', TGPOWER, 0},
163 { "csup", TCSUP, '\0', TGPOWER, 0},
164 { "cyan", TCYAN, '\0', TGCOLOR, 0},
165 { "dddot", TDDDOT, MS_DDDOT, TGATTRIBUT, 5},
166 { "ddot", TDDOT, MS_DDOT, TGATTRIBUT, 5},
167 { "def", TDEF, MS_DEF, TGRELATION, 0},
168 { "div", TDIV, MS_DIV, TGPRODUCT, 0},
169 { "divides", TDIVIDES, MS_LINE, TGRELATION, 0},
170 { "dlarrow" , TDLARROW, MS_DLARROW, TGSTANDALONE, 5},
171 { "dlrarrow" , TDLRARROW, MS_DLRARROW, TGSTANDALONE, 5},
172 { "dot", TDOT, MS_DOT, TGATTRIBUT, 5},
173 { "dotsaxis", TDOTSAXIS, MS_DOTSAXIS, TGSTANDALONE, 5}, // 5 to continue expression
174 { "dotsdiag", TDOTSDIAG, MS_DOTSUP, TGSTANDALONE, 5}, //
175 { "dotsdown", TDOTSDOWN, MS_DOTSDOWN, TGSTANDALONE, 5}, //
176 { "dotslow", TDOTSLOW, MS_DOTSLOW, TGSTANDALONE, 5}, //
177 { "dotsup", TDOTSUP, MS_DOTSUP, TGSTANDALONE, 5}, //
178 { "dotsvert", TDOTSVERT, MS_DOTSVERT, TGSTANDALONE, 5}, //
179 { "downarrow" , TDOWNARROW, MS_DOWNARROW, TGSTANDALONE, 5},
180 { "drarrow" , TDRARROW, MS_DRARROW, TGSTANDALONE, 5},
181 { "emptyset" , TEMPTYSET, MS_EMPTYSET, TGSTANDALONE, 5},
182 { "equiv", TEQUIV, MS_EQUIV, TGRELATION, 0},
183 { "exists", TEXISTS, MS_EXISTS, TGSTANDALONE, 5},
184 { "exp", TEXP, '\0', TGFUNCTION, 5},
185 { "fact", TFACT, MS_FACT, TGUNOPER, 5},
186 { "fixed", TFIXED, '\0', TGFONT, 0},
187 { "font", TFONT, '\0', TGFONTATTR, 5},
188 { "forall", TFORALL, MS_FORALL, TGSTANDALONE, 5},
189 { "from", TFROM, '\0', TGLIMIT, 0},
190 { "func", TFUNC, '\0', TGFUNCTION, 5},
191 { "ge", TGE, MS_GE, TGRELATION, 0},
192 { "geslant", TGESLANT, MS_GESLANT, TGRELATION, 0 },
193 { "gg", TGG, MS_GG, TGRELATION, 0},
194 { "grave", TGRAVE, MS_GRAVE, TGATTRIBUT, 5},
195 { "green", TGREEN, '\0', TGCOLOR, 0},
196 { "gt", TGT, MS_GT, TGRELATION, 0},
197 { "hat", THAT, MS_HAT, TGATTRIBUT, 5},
198 { "hbar" , THBAR, MS_HBAR, TGSTANDALONE, 5},
199 { "iiint", TIIINT, MS_IIINT, TGOPER, 5},
200 { "iint", TIINT, MS_IINT, TGOPER, 5},
201 { "in", TIN, MS_IN, TGRELATION, 0},
202 { "infinity" , TINFINITY, MS_INFINITY, TGSTANDALONE, 5},
203 { "infty" , TINFINITY, MS_INFINITY, TGSTANDALONE, 5},
204 { "int", TINT, MS_INT, TGOPER, 5},
205 { "intersection", TINTERSECT, MS_INTERSECT, TGPRODUCT, 0},
206 { "ital", TITALIC, '\0', TGFONTATTR, 5},
207 { "italic", TITALIC, '\0', TGFONTATTR, 5},
208 { "lambdabar" , TLAMBDABAR, MS_LAMBDABAR, TGSTANDALONE, 5},
209 { "langle", TLANGLE, MS_LANGLE, TGLBRACES, 5},
210 { "lbrace", TLBRACE, MS_LBRACE, TGLBRACES, 5},
211 { "lceil", TLCEIL, MS_LCEIL, TGLBRACES, 5},
212 { "ldbracket", TLDBRACKET, MS_LDBRACKET, TGLBRACES, 5},
213 { "ldline", TLDLINE, MS_DLINE, TGLBRACES, 5},
214 { "le", TLE, MS_LE, TGRELATION, 0},
215 { "left", TLEFT, '\0', 0, 5},
216 { "leftarrow" , TLEFTARROW, MS_LEFTARROW, TGSTANDALONE, 5},
217 { "leslant", TLESLANT, MS_LESLANT, TGRELATION, 0 },
218 { "lfloor", TLFLOOR, MS_LFLOOR, TGLBRACES, 5},
219 { "lim", TLIM, '\0', TGOPER, 5},
220 { "liminf", TLIMINF, '\0', TGOPER, 5},
221 { "limsup", TLIMSUP, '\0', TGOPER, 5},
222 { "lint", TLINT, MS_LINT, TGOPER, 5},
223 { "ll", TLL, MS_LL, TGRELATION, 0},
224 { "lline", TLLINE, MS_LINE, TGLBRACES, 5},
225 { "llint", TLLINT, MS_LLINT, TGOPER, 5},
226 { "lllint", TLLLINT, MS_LLLINT, TGOPER, 5},
227 { "ln", TLN, '\0', TGFUNCTION, 5},
228 { "log", TLOG, '\0', TGFUNCTION, 5},
229 { "lsub", TLSUB, '\0', TGPOWER, 0},
230 { "lsup", TLSUP, '\0', TGPOWER, 0},
231 { "lt", TLT, MS_LT, TGRELATION, 0},
232 { "magenta", TMAGENTA, '\0', TGCOLOR, 0},
233 { "matrix", TMATRIX, '\0', 0, 5},
234 { "minusplus", TMINUSPLUS, MS_MINUSPLUS, TGUNOPER | TGSUM, 5},
235 { "mline", TMLINE, MS_LINE, 0, 0}, //! nicht in TGRBRACES, Level 0
236 { "nabla", TNABLA, MS_NABLA, TGSTANDALONE, 5},
237 { "nbold", TNBOLD, '\0', TGFONTATTR, 5},
238 { "ndivides", TNDIVIDES, MS_NDIVIDES, TGRELATION, 0},
239 { "neg", TNEG, MS_NEG, TGUNOPER, 5 },
240 { "neq", TNEQ, MS_NEQ, TGRELATION, 0},
241 { "newline", TNEWLINE, '\0', 0, 0},
242 { "ni", TNI, MS_NI, TGRELATION, 0},
243 { "nitalic", TNITALIC, '\0', TGFONTATTR, 5},
244 { "none", TNONE, '\0', TGLBRACES | TGRBRACES, 0},
245 { "nospace", TNOSPACE, '\0', TGSTANDALONE, 5},
246 { "notin", TNOTIN, MS_NOTIN, TGRELATION, 0},
247 { "nroot", TNROOT, MS_SQRT, TGUNOPER, 5},
248 { "nsubset", TNSUBSET, MS_NSUBSET, TGRELATION, 0 },
249 { "nsupset", TNSUPSET, MS_NSUPSET, TGRELATION, 0 },
250 { "nsubseteq", TNSUBSETEQ, MS_NSUBSETEQ, TGRELATION, 0 },
251 { "nsupseteq", TNSUPSETEQ, MS_NSUPSETEQ, TGRELATION, 0 },
252 { "odivide", TODIVIDE, MS_ODIVIDE, TGPRODUCT, 0},
253 { "odot", TODOT, MS_ODOT, TGPRODUCT, 0},
254 { "ominus", TOMINUS, MS_OMINUS, TGSUM, 0},
255 { "oper", TOPER, '\0', TGOPER, 5},
256 { "oplus", TOPLUS, MS_OPLUS, TGSUM, 0},
257 { "or", TOR, MS_OR, TGSUM, 0},
258 { "ortho", TORTHO, MS_ORTHO, TGRELATION, 0},
259 { "otimes", TOTIMES, MS_OTIMES, TGPRODUCT, 0},
260 { "over", TOVER, '\0', TGPRODUCT, 0},
261 { "overbrace", TOVERBRACE, MS_OVERBRACE, TGPRODUCT, 5},
262 { "overline", TOVERLINE, '\0', TGATTRIBUT, 5},
263 { "overstrike", TOVERSTRIKE, '\0', TGATTRIBUT, 5},
264 { "owns", TNI, MS_NI, TGRELATION, 0},
265 { "parallel", TPARALLEL, MS_DLINE, TGRELATION, 0},
266 { "partial", TPARTIAL, MS_PARTIAL, TGSTANDALONE, 5 },
267 { "phantom", TPHANTOM, '\0', TGFONTATTR, 5},
268 { "plusminus", TPLUSMINUS, MS_PLUSMINUS, TGUNOPER | TGSUM, 5},
269 { "prod", TPROD, MS_PROD, TGOPER, 5},
270 { "prop", TPROP, MS_PROP, TGRELATION, 0},
271 { "rangle", TRANGLE, MS_RANGLE, TGRBRACES, 0}, //! 0 to terminate expression
272 { "rbrace", TRBRACE, MS_RBRACE, TGRBRACES, 0}, //
273 { "rceil", TRCEIL, MS_RCEIL, TGRBRACES, 0}, //
274 { "rdbracket", TRDBRACKET, MS_RDBRACKET, TGRBRACES, 0}, //
275 { "rdline", TRDLINE, MS_DLINE, TGRBRACES, 0}, //
276 { "red", TRED, '\0', TGCOLOR, 0},
277 { "rfloor", TRFLOOR, MS_RFLOOR, TGRBRACES, 0}, //! 0 to terminate expression
278 { "right", TRIGHT, '\0', 0, 0},
279 { "rightarrow" , TRIGHTARROW, MS_RIGHTARROW, TGSTANDALONE, 5},
280 { "rline", TRLINE, MS_LINE, TGRBRACES, 0}, //! 0 to terminate expression
281 { "rsub", TRSUB, '\0', TGPOWER, 0},
282 { "rsup", TRSUP, '\0', TGPOWER, 0},
283 { "sans", TSANS, '\0', TGFONT, 0},
284 { "serif", TSERIF, '\0', TGFONT, 0},
285 { "setC" , TSETC, MS_SETC, TGSTANDALONE, 5},
286 { "setN" , TSETN, MS_SETN, TGSTANDALONE, 5},
287 { "setQ" , TSETQ, MS_SETQ, TGSTANDALONE, 5},
288 { "setR" , TSETR, MS_SETR, TGSTANDALONE, 5},
289 { "setZ" , TSETZ, MS_SETZ, TGSTANDALONE, 5},
290 { "setminus", TBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 },
291 { "sim", TSIM, MS_SIM, TGRELATION, 0},
292 { "simeq", TSIMEQ, MS_SIMEQ, TGRELATION, 0},
293 { "sin", TSIN, '\0', TGFUNCTION, 5},
294 { "sinh", TSINH, '\0', TGFUNCTION, 5},
295 { "size", TSIZE, '\0', TGFONTATTR, 5},
296 { "slash", TSLASH, MS_SLASH, TGPRODUCT, 0 },
297 { "sqrt", TSQRT, MS_SQRT, TGUNOPER, 5},
298 { "stack", TSTACK, '\0', 0, 5},
299 { "sub", TRSUB, '\0', TGPOWER, 0},
300 { "subset", TSUBSET, MS_SUBSET, TGRELATION, 0},
301 { "subseteq", TSUBSETEQ, MS_SUBSETEQ, TGRELATION, 0},
302 { "sum", TSUM, MS_SUM, TGOPER, 5},
303 { "sup", TRSUP, '\0', TGPOWER, 0},
304 { "supset", TSUPSET, MS_SUPSET, TGRELATION, 0},
305 { "supseteq", TSUPSETEQ, MS_SUPSETEQ, TGRELATION, 0},
306 { "tan", TTAN, '\0', TGFUNCTION, 5},
307 { "tanh", TTANH, '\0', TGFUNCTION, 5},
308 { "tilde", TTILDE, MS_TILDE, TGATTRIBUT, 5},
309 { "times", TTIMES, MS_TIMES, TGPRODUCT, 0},
310 { "to", TTO, '\0', TGLIMIT, 0},
311 { "toward", TTOWARD, MS_RIGHTARROW, TGRELATION, 0},
312 { "transl", TTRANSL, MS_TRANSL, TGRELATION, 0},
313 { "transr", TTRANSR, MS_TRANSR, TGRELATION, 0},
314 { "underbrace", TUNDERBRACE, MS_UNDERBRACE, TGPRODUCT, 5},
315 { "underline", TUNDERLINE, '\0', TGATTRIBUT, 5},
316 { "union", TUNION, MS_UNION, TGSUM, 0},
317 { "uoper", TUOPER, '\0', TGUNOPER, 5},
318 { "uparrow" , TUPARROW, MS_UPARROW, TGSTANDALONE, 5},
319 { "vec", TVEC, MS_VEC, TGATTRIBUT, 5},
320 { "white", TWHITE, '\0', TGCOLOR, 0},
321 { "widebslash", TWIDEBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 },
322 { "widehat", TWIDEHAT, MS_HAT, TGATTRIBUT, 5},
323 { "widetilde", TWIDETILDE, MS_TILDE, TGATTRIBUT, 5},
324 { "wideslash", TWIDESLASH, MS_SLASH, TGPRODUCT, 0 },
325 { "widevec", TWIDEVEC, MS_VEC, TGATTRIBUT, 5},
326 { "wp" , TWP, MS_WP, TGSTANDALONE, 5},
327 { "yellow", TYELLOW, '\0', TGCOLOR, 0},
328 // { "[", TLBRACKET, MS_LBRACKET, TGLBRACES, 5}, //! 5 to continue expression
329 // { "\\", TESCAPE, '\0', 0, 5},
330 // { "]", TRBRACKET, MS_RBRACKET, TGRBRACES, 0}, //! 0 to terminate expression
331 // { "^", TRSUP, '\0', TGPOWER, 0},
332 // { "_", TRSUB, '\0', TGPOWER, 0},
333 // { "`", TSBLANK, '\0', TGBLANK, 5},
334 // { "{", TLGROUP, MS_LBRACE, 0, 5}, //! 5 to continue expression
335 // { "|", TOR, MS_OR, TGSUM, 0},
336 // { "}", TRGROUP, MS_RBRACE, 0, 0}, //! 0 to terminate expression
337 // { "~", TBLANK, '\0', TGBLANK, 5},
338 { "", TEND, '\0', 0, 0}
342 static const SmTokenTableEntry * GetTokenTableEntry( const String &rName )
344 const SmTokenTableEntry * pRes = 0;
345 if (rName.Len())
347 sal_Int32 nEntries = sizeof( aTokenTable ) / sizeof( aTokenTable[0] );
348 for (sal_Int32 i = 0; i < nEntries; ++i)
350 if (rName.EqualsIgnoreCaseAscii( aTokenTable[i].pIdent ))
352 pRes = &aTokenTable[i];
353 break;
359 return pRes;
363 ///////////////////////////////////////////////////////////////////////////
365 #if OSL_DEBUG_LEVEL
367 sal_Bool SmParser::IsDelimiter( const String &rTxt, xub_StrLen nPos )
368 // returns 'sal_True' iff cChar is '\0' or a delimeter
370 DBG_ASSERT( nPos <= rTxt.Len(), "index out of range" );
372 sal_Unicode cChar = rTxt.GetChar( nPos );
373 if(!cChar)
374 return sal_True;
376 // check if 'cChar' is in the delimeter table
377 const sal_Unicode *pDelim = &aDelimiterTable[0];
378 for ( ; *pDelim != 0; pDelim++)
379 if (*pDelim == cChar)
380 break;
382 sal_Bool bIsDelim = *pDelim != 0;
384 sal_Int16 nTypJp = SM_MOD()->GetSysLocale().GetCharClass().getType( rTxt, nPos );
385 bIsDelim |= nTypJp == com::sun::star::i18n::UnicodeType::SPACE_SEPARATOR ||
386 nTypJp == com::sun::star::i18n::UnicodeType::CONTROL;
388 return bIsDelim;
391 #endif
393 void SmParser::Insert(const String &rText, sal_uInt16 nPos)
395 m_aBufferString.Insert(rText, nPos);
397 xub_StrLen nLen = rText.Len();
398 m_nBufferIndex = m_nBufferIndex + nLen;
399 m_nTokenIndex = m_nTokenIndex + nLen;
403 void SmParser::Replace( sal_uInt16 nPos, sal_uInt16 nLen, const String &rText )
405 DBG_ASSERT( nPos + nLen <= m_aBufferString.Len(), "argument mismatch" );
407 m_aBufferString.Replace( nPos, nLen, rText );
408 sal_Int16 nChg = rText.Len() - nLen;
409 m_nBufferIndex = m_nBufferIndex + nChg;
410 m_nTokenIndex = m_nTokenIndex + nChg;
414 // First character may be any alphabetic
415 const sal_Int32 coStartFlags =
416 KParseTokens::ANY_LETTER_OR_NUMBER |
417 KParseTokens::IGNORE_LEADING_WS;
419 // Continuing characters may be any alphanumeric or dot.
420 const sal_Int32 coContFlags =
421 ((coStartFlags | KParseTokens::ASC_DOT) & ~KParseTokens::IGNORE_LEADING_WS)
422 | KParseTokens::TWO_DOUBLE_QUOTES_BREAK_STRING;
424 // First character for numbers, may be any numeric or dot
425 const sal_Int32 coNumStartFlags =
426 KParseTokens::ASC_DIGIT |
427 KParseTokens::ASC_DOT |
428 KParseTokens::IGNORE_LEADING_WS;
429 // Continuing characters for numbers, may be any numeric or dot.
430 const sal_Int32 coNumContFlags =
431 (coNumStartFlags | KParseTokens::ASC_DOT) & ~KParseTokens::IGNORE_LEADING_WS;
433 void SmParser::NextToken()
435 static const String aEmptyStr;
437 xub_StrLen nBufLen = m_aBufferString.Len();
438 ParseResult aRes;
439 xub_StrLen nRealStart;
440 sal_Bool bCont;
441 sal_Bool bNumStart = sal_False;
442 CharClass aCC(SM_MOD()->GetSysLocale().GetCharClass().getLocale());
445 // skip white spaces
446 while (UnicodeType::SPACE_SEPARATOR ==
447 aCC.getType( m_aBufferString, m_nBufferIndex ))
448 ++m_nBufferIndex;
450 sal_Int32 nStartFlags = coStartFlags;
451 sal_Int32 nContFlags = coContFlags;
452 sal_Unicode cFirstChar = m_aBufferString.GetChar( m_nBufferIndex );
454 removed because of #i11752#
455 bNumStart = cFirstChar == '.' || ('0' <= cFirstChar && cFirstChar <= '9');
456 if (bNumStart)
458 nStartFlags = coNumStartFlags;
459 nContFlags = coNumContFlags;
462 aRes = aCC.parseAnyToken( m_aBufferString, m_nBufferIndex,
463 nStartFlags, aEmptyStr,
464 nContFlags, aEmptyStr );
466 // #i45779# parse numbers correctly
467 // i.e. independent from the locale setting.
468 // (note that #i11752# remains fixed)
469 if ((aRes.TokenType & KParseType::IDENTNAME) && IsDigit( cFirstChar ))
471 //! locale where '.' is decimal seperator!
472 static lang::Locale aDotLoc( SvxCreateLocale( LANGUAGE_ENGLISH_US ) );
474 ParseResult aTmpRes;
475 lang::Locale aOldLoc( aCC.getLocale() );
476 aCC.setLocale( aDotLoc );
477 aTmpRes = aCC.parsePredefinedToken(
478 KParseType::ASC_NUMBER,
479 m_aBufferString, m_nBufferIndex,
480 KParseTokens::ASC_DIGIT, aEmptyStr,
481 KParseTokens::ASC_DIGIT | KParseTokens::ASC_DOT, aEmptyStr );
482 aCC.setLocale( aOldLoc );
483 if (aTmpRes.TokenType & KParseType::ASC_NUMBER)
484 aRes.TokenType = aTmpRes.TokenType;
487 nRealStart = m_nBufferIndex + sal::static_int_cast< xub_StrLen >(aRes.LeadingWhiteSpace);
488 m_nBufferIndex = nRealStart;
490 bCont = sal_False;
491 if ( aRes.TokenType == 0 &&
492 nRealStart < nBufLen &&
493 '\n' == m_aBufferString.GetChar( nRealStart ) )
495 // keep data needed for tokens row and col entry up to date
496 ++m_Row;
497 m_nBufferIndex = m_nColOff = nRealStart + 1;
498 bCont = sal_True;
500 else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR)
502 String aName( m_aBufferString.Copy( nRealStart, 2 ));
503 if ( aName.EqualsAscii( "%%" ))
505 //SkipComment
506 m_nBufferIndex = nRealStart + 2;
507 while (m_nBufferIndex < nBufLen &&
508 '\n' != m_aBufferString.GetChar( m_nBufferIndex ))
509 ++m_nBufferIndex;
510 bCont = sal_True;
514 } while (bCont);
516 // set index of current token
517 m_nTokenIndex = m_nBufferIndex;
519 m_aCurToken.nRow = m_Row;
520 m_aCurToken.nCol = nRealStart - m_nColOff + 1;
522 sal_Bool bHandled = sal_True;
523 if (nRealStart >= nBufLen)
525 m_aCurToken.eType = TEND;
526 m_aCurToken.cMathChar = '\0';
527 m_aCurToken.nGroup = 0;
528 m_aCurToken.nLevel = 0;
529 m_aCurToken.aText.Erase();
531 else if ((aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER))
532 || (bNumStart && (aRes.TokenType & KParseType::IDENTNAME)))
534 sal_Int32 n = aRes.EndPos - nRealStart;
535 DBG_ASSERT( n >= 0, "length < 0" );
536 m_aCurToken.eType = TNUMBER;
537 m_aCurToken.cMathChar = '\0';
538 m_aCurToken.nGroup = 0;
539 m_aCurToken.nLevel = 5;
540 m_aCurToken.aText = m_aBufferString.Copy( nRealStart, sal::static_int_cast< xub_StrLen >(n) );
542 #if OSL_DEBUG_LEVEL > 1
543 if (!IsDelimiter( m_aBufferString, static_cast< xub_StrLen >(aRes.EndPos) ))
545 DBG_WARNING( "identifier really finished? (compatibility!)" );
547 #endif
549 else if (aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING)
551 m_aCurToken.eType = TTEXT;
552 m_aCurToken.cMathChar = '\0';
553 m_aCurToken.nGroup = 0;
554 m_aCurToken.nLevel = 5;
555 m_aCurToken.aText = aRes.DequotedNameOrString;
556 m_aCurToken.nRow = m_Row;
557 m_aCurToken.nCol = nRealStart - m_nColOff + 2;
559 else if (aRes.TokenType & KParseType::IDENTNAME)
561 sal_Int32 n = aRes.EndPos - nRealStart;
562 DBG_ASSERT( n >= 0, "length < 0" );
563 String aName( m_aBufferString.Copy( nRealStart, sal::static_int_cast< xub_StrLen >(n) ) );
564 const SmTokenTableEntry *pEntry = GetTokenTableEntry( aName );
566 if (pEntry)
568 m_aCurToken.eType = pEntry->eType;
569 m_aCurToken.cMathChar = pEntry->cMathChar;
570 m_aCurToken.nGroup = pEntry->nGroup;
571 m_aCurToken.nLevel = pEntry->nLevel;
572 m_aCurToken.aText.AssignAscii( pEntry->pIdent );
574 else
576 m_aCurToken.eType = TIDENT;
577 m_aCurToken.cMathChar = '\0';
578 m_aCurToken.nGroup = 0;
579 m_aCurToken.nLevel = 5;
580 m_aCurToken.aText = aName;
582 #if OSL_DEBUG_LEVEL > 1
583 if (!IsDelimiter( m_aBufferString, static_cast< xub_StrLen >(aRes.EndPos) ))
585 DBG_WARNING( "identifier really finished? (compatibility!)" );
587 #endif
590 else if (aRes.TokenType == 0 && '_' == m_aBufferString.GetChar( nRealStart ))
592 m_aCurToken.eType = TRSUB;
593 m_aCurToken.cMathChar = '\0';
594 m_aCurToken.nGroup = TGPOWER;
595 m_aCurToken.nLevel = 0;
596 m_aCurToken.aText.AssignAscii( "_" );
598 aRes.EndPos = nRealStart + 1;
600 else if (aRes.TokenType & KParseType::BOOLEAN)
602 sal_Int32 &rnEndPos = aRes.EndPos;
603 String aName( m_aBufferString.Copy( nRealStart,
604 sal::static_int_cast< xub_StrLen >(rnEndPos - nRealStart) ));
605 if (2 >= aName.Len())
607 sal_Unicode ch = aName.GetChar( 0 );
608 switch (ch)
610 case '<':
612 if (m_aBufferString.Copy( nRealStart, 2 ).
613 EqualsAscii( "<<" ))
615 m_aCurToken.eType = TLL;
616 m_aCurToken.cMathChar = MS_LL;
617 m_aCurToken.nGroup = TGRELATION;
618 m_aCurToken.nLevel = 0;
619 m_aCurToken.aText.AssignAscii( "<<" );
621 rnEndPos = nRealStart + 2;
623 else if (m_aBufferString.Copy( nRealStart, 2 ).
624 EqualsAscii( "<=" ))
626 m_aCurToken.eType = TLE;
627 m_aCurToken.cMathChar = MS_LE;
628 m_aCurToken.nGroup = TGRELATION;
629 m_aCurToken.nLevel = 0;
630 m_aCurToken.aText.AssignAscii( "<=" );
632 rnEndPos = nRealStart + 2;
634 else if (m_aBufferString.Copy( nRealStart, 2 ).
635 EqualsAscii( "<>" ))
637 m_aCurToken.eType = TNEQ;
638 m_aCurToken.cMathChar = MS_NEQ;
639 m_aCurToken.nGroup = TGRELATION;
640 m_aCurToken.nLevel = 0;
641 m_aCurToken.aText.AssignAscii( "<>" );
643 rnEndPos = nRealStart + 2;
645 else if (m_aBufferString.Copy( nRealStart, 3 ).
646 EqualsAscii( "<?>" ))
648 m_aCurToken.eType = TPLACE;
649 m_aCurToken.cMathChar = MS_PLACE;
650 m_aCurToken.nGroup = 0;
651 m_aCurToken.nLevel = 5;
652 m_aCurToken.aText.AssignAscii( "<?>" );
654 rnEndPos = nRealStart + 3;
656 else
658 m_aCurToken.eType = TLT;
659 m_aCurToken.cMathChar = MS_LT;
660 m_aCurToken.nGroup = TGRELATION;
661 m_aCurToken.nLevel = 0;
662 m_aCurToken.aText.AssignAscii( "<" );
665 break;
666 case '>':
668 if (m_aBufferString.Copy( nRealStart, 2 ).
669 EqualsAscii( ">=" ))
671 m_aCurToken.eType = TGE;
672 m_aCurToken.cMathChar = MS_GE;
673 m_aCurToken.nGroup = TGRELATION;
674 m_aCurToken.nLevel = 0;
675 m_aCurToken.aText.AssignAscii( ">=" );
677 rnEndPos = nRealStart + 2;
679 else if (m_aBufferString.Copy( nRealStart, 2 ).
680 EqualsAscii( ">>" ))
682 m_aCurToken.eType = TGG;
683 m_aCurToken.cMathChar = MS_GG;
684 m_aCurToken.nGroup = TGRELATION;
685 m_aCurToken.nLevel = 0;
686 m_aCurToken.aText.AssignAscii( ">>" );
688 rnEndPos = nRealStart + 2;
690 else
692 m_aCurToken.eType = TGT;
693 m_aCurToken.cMathChar = MS_GT;
694 m_aCurToken.nGroup = TGRELATION;
695 m_aCurToken.nLevel = 0;
696 m_aCurToken.aText.AssignAscii( ">" );
699 break;
700 default:
701 bHandled = sal_False;
705 else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR)
707 sal_Int32 &rnEndPos = aRes.EndPos;
708 String aName( m_aBufferString.Copy( nRealStart,
709 sal::static_int_cast< xub_StrLen >(rnEndPos - nRealStart) ) );
711 if (1 == aName.Len())
713 sal_Unicode ch = aName.GetChar( 0 );
714 switch (ch)
716 case '%':
718 //! modifies aRes.EndPos
720 DBG_ASSERT( rnEndPos >= nBufLen ||
721 '%' != m_aBufferString.GetChar( sal::static_int_cast< xub_StrLen >(rnEndPos) ),
722 "unexpected comment start" );
724 // get identifier of user-defined character
725 ParseResult aTmpRes = aCC.parseAnyToken(
726 m_aBufferString, rnEndPos,
727 KParseTokens::ANY_LETTER,
728 aEmptyStr,
729 coContFlags,
730 aEmptyStr );
732 xub_StrLen nTmpStart = sal::static_int_cast< xub_StrLen >(rnEndPos +
733 aTmpRes.LeadingWhiteSpace);
735 // default setting for the case that no identifier
736 // i.e. a valid symbol-name is following the '%'
737 // character
738 m_aCurToken.eType = TTEXT;
739 m_aCurToken.cMathChar = '\0';
740 m_aCurToken.nGroup = 0;
741 m_aCurToken.nLevel = 5;
742 m_aCurToken.aText = String();
743 m_aCurToken.nRow = sal::static_int_cast< xub_StrLen >(m_Row);
744 m_aCurToken.nCol = nTmpStart - m_nColOff;
746 if (aTmpRes.TokenType & KParseType::IDENTNAME)
749 xub_StrLen n = sal::static_int_cast< xub_StrLen >(aTmpRes.EndPos - nTmpStart);
750 m_aCurToken.eType = TSPECIAL;
751 m_aCurToken.aText = m_aBufferString.Copy( sal::static_int_cast< xub_StrLen >(nTmpStart-1), n+1 );
753 DBG_ASSERT( aTmpRes.EndPos > rnEndPos,
754 "empty identifier" );
755 if (aTmpRes.EndPos > rnEndPos)
756 rnEndPos = aTmpRes.EndPos;
757 else
758 ++rnEndPos;
761 // if no symbol-name was found we start-over with
762 // finding the next token right afer the '%' sign.
763 // I.e. we leave rnEndPos unmodified.
765 break;
766 case '[':
768 m_aCurToken.eType = TLBRACKET;
769 m_aCurToken.cMathChar = MS_LBRACKET;
770 m_aCurToken.nGroup = TGLBRACES;
771 m_aCurToken.nLevel = 5;
772 m_aCurToken.aText.AssignAscii( "[" );
774 break;
775 case '\\':
777 m_aCurToken.eType = TESCAPE;
778 m_aCurToken.cMathChar = '\0';
779 m_aCurToken.nGroup = 0;
780 m_aCurToken.nLevel = 5;
781 m_aCurToken.aText.AssignAscii( "\\" );
783 break;
784 case ']':
786 m_aCurToken.eType = TRBRACKET;
787 m_aCurToken.cMathChar = MS_RBRACKET;
788 m_aCurToken.nGroup = TGRBRACES;
789 m_aCurToken.nLevel = 0;
790 m_aCurToken.aText.AssignAscii( "]" );
792 break;
793 case '^':
795 m_aCurToken.eType = TRSUP;
796 m_aCurToken.cMathChar = '\0';
797 m_aCurToken.nGroup = TGPOWER;
798 m_aCurToken.nLevel = 0;
799 m_aCurToken.aText.AssignAscii( "^" );
801 break;
802 case '`':
804 m_aCurToken.eType = TSBLANK;
805 m_aCurToken.cMathChar = '\0';
806 m_aCurToken.nGroup = TGBLANK;
807 m_aCurToken.nLevel = 5;
808 m_aCurToken.aText.AssignAscii( "`" );
810 break;
811 case '{':
813 m_aCurToken.eType = TLGROUP;
814 m_aCurToken.cMathChar = MS_LBRACE;
815 m_aCurToken.nGroup = 0;
816 m_aCurToken.nLevel = 5;
817 m_aCurToken.aText.AssignAscii( "{" );
819 break;
820 case '|':
822 m_aCurToken.eType = TOR;
823 m_aCurToken.cMathChar = MS_OR;
824 m_aCurToken.nGroup = TGSUM;
825 m_aCurToken.nLevel = 0;
826 m_aCurToken.aText.AssignAscii( "|" );
828 break;
829 case '}':
831 m_aCurToken.eType = TRGROUP;
832 m_aCurToken.cMathChar = MS_RBRACE;
833 m_aCurToken.nGroup = 0;
834 m_aCurToken.nLevel = 0;
835 m_aCurToken.aText.AssignAscii( "}" );
837 break;
838 case '~':
840 m_aCurToken.eType = TBLANK;
841 m_aCurToken.cMathChar = '\0';
842 m_aCurToken.nGroup = TGBLANK;
843 m_aCurToken.nLevel = 5;
844 m_aCurToken.aText.AssignAscii( "~" );
846 break;
847 case '#':
849 if (m_aBufferString.Copy( nRealStart, 2 ).
850 EqualsAscii( "##" ))
852 m_aCurToken.eType = TDPOUND;
853 m_aCurToken.cMathChar = '\0';
854 m_aCurToken.nGroup = 0;
855 m_aCurToken.nLevel = 0;
856 m_aCurToken.aText.AssignAscii( "##" );
858 rnEndPos = nRealStart + 2;
860 else
862 m_aCurToken.eType = TPOUND;
863 m_aCurToken.cMathChar = '\0';
864 m_aCurToken.nGroup = 0;
865 m_aCurToken.nLevel = 0;
866 m_aCurToken.aText.AssignAscii( "#" );
869 break;
870 case '&':
872 m_aCurToken.eType = TAND;
873 m_aCurToken.cMathChar = MS_AND;
874 m_aCurToken.nGroup = TGPRODUCT;
875 m_aCurToken.nLevel = 0;
876 m_aCurToken.aText.AssignAscii( "&" );
878 break;
879 case '(':
881 m_aCurToken.eType = TLPARENT;
882 m_aCurToken.cMathChar = MS_LPARENT;
883 m_aCurToken.nGroup = TGLBRACES;
884 m_aCurToken.nLevel = 5; //! 0 to continue expression
885 m_aCurToken.aText.AssignAscii( "(" );
887 break;
888 case ')':
890 m_aCurToken.eType = TRPARENT;
891 m_aCurToken.cMathChar = MS_RPARENT;
892 m_aCurToken.nGroup = TGRBRACES;
893 m_aCurToken.nLevel = 0; //! 0 to terminate expression
894 m_aCurToken.aText.AssignAscii( ")" );
896 break;
897 case '*':
899 m_aCurToken.eType = TMULTIPLY;
900 m_aCurToken.cMathChar = MS_MULTIPLY;
901 m_aCurToken.nGroup = TGPRODUCT;
902 m_aCurToken.nLevel = 0;
903 m_aCurToken.aText.AssignAscii( "*" );
905 break;
906 case '+':
908 if (m_aBufferString.Copy( nRealStart, 2 ).
909 EqualsAscii( "+-" ))
911 m_aCurToken.eType = TPLUSMINUS;
912 m_aCurToken.cMathChar = MS_PLUSMINUS;
913 m_aCurToken.nGroup = TGUNOPER | TGSUM;
914 m_aCurToken.nLevel = 5;
915 m_aCurToken.aText.AssignAscii( "+-" );
917 rnEndPos = nRealStart + 2;
919 else
921 m_aCurToken.eType = TPLUS;
922 m_aCurToken.cMathChar = MS_PLUS;
923 m_aCurToken.nGroup = TGUNOPER | TGSUM;
924 m_aCurToken.nLevel = 5;
925 m_aCurToken.aText.AssignAscii( "+" );
928 break;
929 case '-':
931 if (m_aBufferString.Copy( nRealStart, 2 ).
932 EqualsAscii( "-+" ))
934 m_aCurToken.eType = TMINUSPLUS;
935 m_aCurToken.cMathChar = MS_MINUSPLUS;
936 m_aCurToken.nGroup = TGUNOPER | TGSUM;
937 m_aCurToken.nLevel = 5;
938 m_aCurToken.aText.AssignAscii( "-+" );
940 rnEndPos = nRealStart + 2;
942 else
944 m_aCurToken.eType = TMINUS;
945 m_aCurToken.cMathChar = MS_MINUS;
946 m_aCurToken.nGroup = TGUNOPER | TGSUM;
947 m_aCurToken.nLevel = 5;
948 m_aCurToken.aText.AssignAscii( "-" );
951 break;
952 case '.':
954 // for compatibility with SO5.2
955 // texts like .34 ...56 ... h ...78..90
956 // will be treated as numbers
957 m_aCurToken.eType = TNUMBER;
958 m_aCurToken.cMathChar = '\0';
959 m_aCurToken.nGroup = 0;
960 m_aCurToken.nLevel = 5;
962 xub_StrLen nTxtStart = m_nBufferIndex;
963 sal_Unicode cChar;
966 cChar = m_aBufferString.GetChar( ++m_nBufferIndex );
968 while ( cChar == '.' || IsDigit( cChar ) );
970 m_aCurToken.aText = m_aBufferString.Copy( sal::static_int_cast< xub_StrLen >(nTxtStart),
971 sal::static_int_cast< xub_StrLen >(m_nBufferIndex - nTxtStart) );
972 aRes.EndPos = m_nBufferIndex;
974 break;
975 case '/':
977 m_aCurToken.eType = TDIVIDEBY;
978 m_aCurToken.cMathChar = MS_SLASH;
979 m_aCurToken.nGroup = TGPRODUCT;
980 m_aCurToken.nLevel = 0;
981 m_aCurToken.aText.AssignAscii( "/" );
983 break;
984 case '=':
986 m_aCurToken.eType = TASSIGN;
987 m_aCurToken.cMathChar = MS_ASSIGN;
988 m_aCurToken.nGroup = TGRELATION;
989 m_aCurToken.nLevel = 0;
990 m_aCurToken.aText.AssignAscii( "=" );
992 break;
993 default:
994 bHandled = sal_False;
998 else
999 bHandled = sal_False;
1001 if (!bHandled)
1003 m_aCurToken.eType = TCHARACTER;
1004 m_aCurToken.cMathChar = '\0';
1005 m_aCurToken.nGroup = 0;
1006 m_aCurToken.nLevel = 5;
1007 m_aCurToken.aText = m_aBufferString.Copy( nRealStart, 1 );
1009 aRes.EndPos = nRealStart + 1;
1012 if (TEND != m_aCurToken.eType)
1013 m_nBufferIndex = sal::static_int_cast< xub_StrLen >(aRes.EndPos);
1017 ////////////////////////////////////////
1018 // grammar
1022 void SmParser::Table()
1024 SmNodeArray LineArray;
1026 Line();
1027 while (m_aCurToken.eType == TNEWLINE)
1029 NextToken();
1030 Line();
1033 if (m_aCurToken.eType != TEND)
1034 Error(PE_UNEXPECTED_CHAR);
1036 sal_uLong n = m_aNodeStack.Count();
1038 LineArray.resize(n);
1040 for (sal_uLong i = 0; i < n; i++)
1041 LineArray[n - (i + 1)] = m_aNodeStack.Pop();
1043 SmStructureNode *pSNode = new SmTableNode(m_aCurToken);
1044 pSNode->SetSubNodes(LineArray);
1045 m_aNodeStack.Push(pSNode);
1049 void SmParser::Align()
1050 // parse alignment info (if any), then go on with rest of expression
1052 SmStructureNode *pSNode = 0;
1053 sal_Bool bNeedGroupClose = sal_False;
1055 if (TokenInGroup(TGALIGN))
1057 if (CONVERT_40_TO_50 == GetConversion())
1058 // encapsulate expression to be aligned in group braces
1059 // (here group-open brace)
1060 { Insert('{', GetTokenIndex());
1061 bNeedGroupClose = sal_True;
1063 // get first valid align statement in sequence
1064 // (the dominant one in 4.0) and erase all others (especially old
1065 // discarded tokens) from command string.
1066 while (TokenInGroup(TGALIGN))
1068 if (TokenInGroup(TGDISCARDED) || pSNode)
1070 m_nBufferIndex = GetTokenIndex();
1071 m_aBufferString.Erase(m_nBufferIndex, m_aCurToken.aText.Len());
1073 else
1074 pSNode = new SmAlignNode(m_aCurToken);
1076 NextToken();
1079 else
1081 pSNode = new SmAlignNode(m_aCurToken);
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(m_aNodeStack.Pop(), 0);
1100 m_aNodeStack.Push(pSNode);
1105 void SmParser::Line()
1107 sal_uInt16 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 (m_aCurToken.eType != TEND && m_aCurToken.eType != TNEWLINE)
1116 { Align();
1117 ExpressionArray.resize(++n);
1118 ExpressionArray[n - 1] = m_aNodeStack.Pop();
1121 while (m_aCurToken.eType != TEND && m_aCurToken.eType != TNEWLINE)
1122 { if (CONVERT_40_TO_50 != GetConversion())
1123 Expression();
1124 else
1125 Align();
1126 ExpressionArray.resize(++n);
1127 ExpressionArray[n - 1] = m_aNodeStack.Pop();
1130 SmStructureNode *pSNode = new SmLineNode(m_aCurToken);
1131 pSNode->SetSubNodes(ExpressionArray);
1132 m_aNodeStack.Push(pSNode);
1136 void SmParser::Expression()
1138 sal_Bool bUseExtraSpaces = sal_True;
1139 SmNode *pNode = m_aNodeStack.Pop();
1140 if (pNode)
1142 if (pNode->GetToken().eType == TNOSPACE)
1143 bUseExtraSpaces = sal_False;
1144 else
1145 m_aNodeStack.Push(pNode); // push the node from above again (now to be used as argument to this current 'nospace' node)
1148 sal_uInt16 n = 0;
1149 SmNodeArray RelationArray;
1151 RelationArray.resize(n);
1153 Relation();
1154 RelationArray.resize(++n);
1155 RelationArray[n - 1] = m_aNodeStack.Pop();
1157 while (m_aCurToken.nLevel >= 4)
1158 { Relation();
1159 RelationArray.resize(++n);
1160 RelationArray[n - 1] = m_aNodeStack.Pop();
1163 SmExpressionNode *pSNode = new SmExpressionNode(m_aCurToken);
1164 pSNode->SetSubNodes(RelationArray);
1165 pSNode->SetUseExtraSpaces(bUseExtraSpaces);
1166 m_aNodeStack.Push(pSNode);
1170 void SmParser::Relation()
1172 Sum();
1173 while (TokenInGroup(TGRELATION))
1175 SmStructureNode *pSNode = new SmBinHorNode(m_aCurToken);
1176 SmNode *pFirst = m_aNodeStack.Pop();
1178 OpSubSup();
1179 SmNode *pSecond = m_aNodeStack.Pop();
1181 Sum();
1183 pSNode->SetSubNodes(pFirst, pSecond, m_aNodeStack.Pop());
1184 m_aNodeStack.Push(pSNode);
1189 void SmParser::Sum()
1191 Product();
1192 while (TokenInGroup(TGSUM))
1194 SmStructureNode *pSNode = new SmBinHorNode(m_aCurToken);
1195 SmNode *pFirst = m_aNodeStack.Pop();
1197 OpSubSup();
1198 SmNode *pSecond = m_aNodeStack.Pop();
1200 Product();
1202 pSNode->SetSubNodes(pFirst, pSecond, m_aNodeStack.Pop());
1203 m_aNodeStack.Push(pSNode);
1208 void SmParser::Product()
1210 Power();
1212 while (TokenInGroup(TGPRODUCT))
1213 { SmStructureNode *pSNode;
1214 SmNode *pFirst = m_aNodeStack.Pop(),
1215 *pOper;
1216 sal_Bool bSwitchArgs = sal_False;
1218 SmTokenType eType = m_aCurToken.eType;
1219 switch (eType)
1221 case TOVER:
1222 pSNode = new SmBinVerNode(m_aCurToken);
1223 pOper = new SmRectangleNode(m_aCurToken);
1224 NextToken();
1225 break;
1227 case TBOPER:
1228 pSNode = new SmBinHorNode(m_aCurToken);
1230 NextToken();
1232 GlyphSpecial();
1233 pOper = m_aNodeStack.Pop();
1234 break;
1236 case TOVERBRACE :
1237 case TUNDERBRACE :
1238 pSNode = new SmVerticalBraceNode(m_aCurToken);
1239 pOper = new SmMathSymbolNode(m_aCurToken);
1241 NextToken();
1242 break;
1244 case TWIDEBACKSLASH:
1245 case TWIDESLASH:
1247 SmBinDiagonalNode *pSTmp = new SmBinDiagonalNode(m_aCurToken);
1248 pSTmp->SetAscending(eType == TWIDESLASH);
1249 pSNode = pSTmp;
1251 pOper = new SmPolyLineNode(m_aCurToken);
1252 NextToken();
1254 bSwitchArgs =sal_True;
1255 break;
1258 default:
1259 pSNode = new SmBinHorNode(m_aCurToken);
1261 OpSubSup();
1262 pOper = m_aNodeStack.Pop();
1265 Power();
1267 if (bSwitchArgs)
1268 //! vgl siehe SmBinDiagonalNode::Arrange
1269 pSNode->SetSubNodes(pFirst, m_aNodeStack.Pop(), pOper);
1270 else
1271 pSNode->SetSubNodes(pFirst, pOper, m_aNodeStack.Pop());
1272 m_aNodeStack.Push(pSNode);
1277 void SmParser::SubSup(sal_uLong nActiveGroup)
1279 DBG_ASSERT(nActiveGroup == TGPOWER || nActiveGroup == TGLIMIT,
1280 "Sm: falsche Tokengruppe");
1282 if (!TokenInGroup(nActiveGroup))
1283 // already finish
1284 return;
1286 SmSubSupNode *pNode = new SmSubSupNode(m_aCurToken);
1287 //! Of course 'm_aCurToken' is just the first sub-/supscript token.
1288 //! It should be of no further interest. The positions of the
1289 //! sub-/supscripts will be identified by the corresponding subnodes
1290 //! index in the 'aSubNodes' array (enum value from 'SmSubSup').
1292 pNode->SetUseLimits(nActiveGroup == TGLIMIT);
1294 // initialize subnodes array
1295 SmNodeArray aSubNodes;
1296 aSubNodes.resize(1 + SUBSUP_NUM_ENTRIES);
1297 aSubNodes[0] = m_aNodeStack.Pop();
1298 for (sal_uInt16 i = 1; i < aSubNodes.size(); i++)
1299 aSubNodes[i] = NULL;
1301 // process all sub-/supscripts
1302 int nIndex = 0;
1303 while (TokenInGroup(nActiveGroup))
1304 { SmTokenType eType (m_aCurToken.eType);
1306 // skip sub-/supscript token
1307 NextToken();
1309 // get sub-/supscript node on top of stack
1310 if (eType == TFROM || eType == TTO)
1312 // parse limits in old 4.0 and 5.0 style
1313 Relation();
1315 else
1316 Term();
1318 switch (eType)
1319 { case TRSUB : nIndex = (int) RSUB; break;
1320 case TRSUP : nIndex = (int) RSUP; break;
1321 case TFROM :
1322 case TCSUB : nIndex = (int) CSUB; break;
1323 case TTO :
1324 case TCSUP : nIndex = (int) CSUP; break;
1325 case TLSUB : nIndex = (int) LSUB; break;
1326 case TLSUP : nIndex = (int) LSUP; break;
1327 default :
1328 DBG_ASSERT(sal_False, "Sm: unbekannter Fall");
1330 nIndex++;
1331 DBG_ASSERT(1 <= nIndex && nIndex <= 1 + SUBSUP_NUM_ENTRIES,
1332 "SmParser::Power() : sub-/supscript index falsch");
1334 // set sub-/supscript if not already done
1335 if (aSubNodes[nIndex] != NULL)
1336 Error(PE_DOUBLE_SUBSUPSCRIPT);
1337 aSubNodes[nIndex] = m_aNodeStack.Pop();
1340 pNode->SetSubNodes(aSubNodes);
1341 m_aNodeStack.Push(pNode);
1345 void SmParser::OpSubSup()
1347 // push operator symbol
1348 m_aNodeStack.Push(new SmMathSymbolNode(m_aCurToken));
1349 // skip operator token
1350 NextToken();
1351 // get sub- supscripts if any
1352 if (TokenInGroup(TGPOWER))
1353 SubSup(TGPOWER);
1357 void SmParser::Power()
1359 // get body for sub- supscripts on top of stack
1360 Term();
1362 SubSup(TGPOWER);
1366 void SmParser::Blank()
1368 DBG_ASSERT(TokenInGroup(TGBLANK), "Sm : falsches Token");
1369 SmBlankNode *pBlankNode = new SmBlankNode(m_aCurToken);
1371 while (TokenInGroup(TGBLANK))
1373 pBlankNode->IncreaseBy(m_aCurToken);
1374 NextToken();
1377 // Blanks am Zeilenende ignorieren wenn die entsprechende Option gesetzt ist
1378 if ( m_aCurToken.eType == TNEWLINE ||
1379 (m_aCurToken.eType == TEND && SM_MOD()->GetConfig()->IsIgnoreSpacesRight()) )
1381 pBlankNode->Clear();
1384 m_aNodeStack.Push(pBlankNode);
1388 void SmParser::Term()
1390 switch (m_aCurToken.eType)
1392 case TESCAPE :
1393 Escape();
1394 break;
1396 case TNOSPACE :
1397 case TLGROUP :
1399 bool bNoSpace = m_aCurToken.eType == TNOSPACE;
1400 if (bNoSpace) // push 'no space' node and continue to parse expression
1402 m_aNodeStack.Push(new SmExpressionNode(m_aCurToken));
1403 NextToken();
1405 if (m_aCurToken.eType != TLGROUP)
1407 m_aNodeStack.Pop(); // get rid of the 'no space' node pushed above
1408 Term();
1410 else
1412 NextToken();
1414 // allow for empty group
1415 if (m_aCurToken.eType == TRGROUP)
1417 if (bNoSpace) // get rid of the 'no space' node pushed above
1418 m_aNodeStack.Pop();
1419 SmStructureNode *pSNode = new SmExpressionNode(m_aCurToken);
1420 pSNode->SetSubNodes(NULL, NULL);
1421 m_aNodeStack.Push(pSNode);
1423 NextToken();
1425 else // go as usual
1427 Align();
1428 if (m_aCurToken.eType != TRGROUP)
1429 Error(PE_RGROUP_EXPECTED);
1430 else
1431 NextToken();
1435 break;
1437 case TLEFT :
1438 Brace();
1439 break;
1441 case TBLANK :
1442 case TSBLANK :
1443 Blank();
1444 break;
1446 case TTEXT :
1447 m_aNodeStack.Push(new SmTextNode(m_aCurToken, FNT_TEXT));
1448 NextToken();
1449 break;
1450 case TIDENT :
1451 case TCHARACTER :
1452 m_aNodeStack.Push(new SmTextNode(m_aCurToken, FNT_VARIABLE));
1453 NextToken();
1454 break;
1455 case TNUMBER :
1456 m_aNodeStack.Push(new SmTextNode(m_aCurToken, FNT_NUMBER));
1457 NextToken();
1458 break;
1460 case TLEFTARROW :
1461 case TRIGHTARROW :
1462 case TUPARROW :
1463 case TDOWNARROW :
1464 case TSETN :
1465 case TSETZ :
1466 case TSETQ :
1467 case TSETR :
1468 case TSETC :
1469 case THBAR :
1470 case TLAMBDABAR :
1471 case TCIRC :
1472 case TDRARROW :
1473 case TDLARROW :
1474 case TDLRARROW :
1475 case TBACKEPSILON :
1476 case TALEPH :
1477 case TIM :
1478 case TRE :
1479 case TWP :
1480 case TEMPTYSET :
1481 case TINFINITY :
1482 case TEXISTS :
1483 case TFORALL :
1484 case TPARTIAL :
1485 case TNABLA :
1486 case TTOWARD :
1487 case TDOTSAXIS :
1488 case TDOTSDIAG :
1489 case TDOTSDOWN :
1490 case TDOTSLOW :
1491 case TDOTSUP :
1492 case TDOTSVERT :
1493 m_aNodeStack.Push(new SmMathSymbolNode(m_aCurToken));
1494 NextToken();
1495 break;
1497 case TPLACE:
1498 m_aNodeStack.Push(new SmPlaceNode(m_aCurToken));
1499 NextToken();
1500 break;
1502 case TSPECIAL:
1503 Special();
1504 break;
1506 case TBINOM:
1507 Binom();
1508 break;
1510 case TSTACK:
1511 Stack();
1512 break;
1514 case TMATRIX:
1515 Matrix();
1516 break;
1518 default:
1519 if (TokenInGroup(TGLBRACES))
1520 { Brace();
1522 else if (TokenInGroup(TGOPER))
1523 { Operator();
1525 else if (TokenInGroup(TGUNOPER))
1526 { UnOper();
1528 else if ( TokenInGroup(TGATTRIBUT)
1529 || TokenInGroup(TGFONTATTR))
1530 { SmStructureNodeArray aArray;
1532 sal_Bool bIsAttr;
1533 sal_uInt16 n = 0;
1534 while (sal_True == (bIsAttr = TokenInGroup(TGATTRIBUT))
1535 || TokenInGroup(TGFONTATTR))
1536 { aArray.resize(n + 1);
1538 if (bIsAttr)
1539 Attribut();
1540 else
1541 FontAttribut();
1543 // check if casting in following line is ok
1544 DBG_ASSERT(!m_aNodeStack.Top()->IsVisible(), "Sm : Ooops...");
1546 aArray[n] = (SmStructureNode *) m_aNodeStack.Pop();
1547 n++;
1550 Power();
1552 SmNode *pFirstNode = m_aNodeStack.Pop();
1553 while (n > 0)
1554 { aArray[n - 1]->SetSubNodes(0, pFirstNode);
1555 pFirstNode = aArray[n - 1];
1556 n--;
1558 m_aNodeStack.Push(pFirstNode);
1560 else if (TokenInGroup(TGFUNCTION))
1561 { if (CONVERT_40_TO_50 != GetConversion())
1562 { Function();
1564 else // encapsulate old 4.0 style parsing in braces
1566 // insert opening brace
1567 Insert('{', GetTokenIndex());
1570 // parse in 4.0 style
1572 Function();
1574 SmNode *pFunc = m_aNodeStack.Pop();
1576 if (m_aCurToken.eType == TLPARENT)
1577 { Term();
1579 else
1580 { Align();
1583 // insert closing brace
1584 Insert('}', GetTokenIndex());
1586 SmStructureNode *pSNode = new SmExpressionNode(pFunc->GetToken());
1587 pSNode->SetSubNodes(pFunc, m_aNodeStack.Pop());
1588 m_aNodeStack.Push(pSNode);
1591 else
1592 Error(PE_UNEXPECTED_CHAR);
1597 void SmParser::Escape()
1599 NextToken();
1601 sal_Unicode cChar;
1602 switch (m_aCurToken.eType)
1603 { case TLPARENT : cChar = MS_LPARENT; break;
1604 case TRPARENT : cChar = MS_RPARENT; break;
1605 case TLBRACKET : cChar = MS_LBRACKET; break;
1606 case TRBRACKET : cChar = MS_RBRACKET; break;
1607 case TLDBRACKET : cChar = MS_LDBRACKET; break;
1608 case TRDBRACKET : cChar = MS_RDBRACKET; break;
1609 case TLBRACE :
1610 case TLGROUP : cChar = MS_LBRACE; break;
1611 case TRBRACE :
1612 case TRGROUP : cChar = MS_RBRACE; break;
1613 case TLANGLE : cChar = MS_LANGLE; break;
1614 case TRANGLE : cChar = MS_RANGLE; break;
1615 case TLCEIL : cChar = MS_LCEIL; break;
1616 case TRCEIL : cChar = MS_RCEIL; break;
1617 case TLFLOOR : cChar = MS_LFLOOR; break;
1618 case TRFLOOR : cChar = MS_RFLOOR; break;
1619 case TLLINE :
1620 case TRLINE : cChar = MS_LINE; break;
1621 case TLDLINE :
1622 case TRDLINE : cChar = MS_DLINE; break;
1623 default:
1624 Error(PE_UNEXPECTED_TOKEN);
1627 SmNode *pNode = new SmMathSymbolNode(m_aCurToken);
1628 m_aNodeStack.Push(pNode);
1630 NextToken();
1634 void SmParser::Operator()
1636 if (TokenInGroup(TGOPER))
1637 { SmStructureNode *pSNode = new SmOperNode(m_aCurToken);
1639 // put operator on top of stack
1640 Oper();
1642 if (TokenInGroup(TGLIMIT) || TokenInGroup(TGPOWER))
1643 SubSup(m_aCurToken.nGroup);
1644 SmNode *pOperator = m_aNodeStack.Pop();
1646 // get argument
1647 Power();
1649 pSNode->SetSubNodes(pOperator, m_aNodeStack.Pop());
1650 m_aNodeStack.Push(pSNode);
1655 void SmParser::Oper()
1657 SmTokenType eType (m_aCurToken.eType);
1658 SmNode *pNode = NULL;
1660 switch (eType)
1662 case TSUM :
1663 case TPROD :
1664 case TCOPROD :
1665 case TINT :
1666 case TIINT :
1667 case TIIINT :
1668 case TLINT :
1669 case TLLINT :
1670 case TLLLINT :
1671 pNode = new SmMathSymbolNode(m_aCurToken);
1672 break;
1674 case TLIM :
1675 case TLIMSUP :
1676 case TLIMINF :
1678 const sal_Char* pLim = 0;
1679 switch (eType)
1681 case TLIM : pLim = "lim"; break;
1682 case TLIMSUP : pLim = "lim sup"; break;
1683 case TLIMINF : pLim = "lim inf"; break;
1684 default:
1685 break;
1687 if( pLim )
1688 m_aCurToken.aText.AssignAscii( pLim );
1689 pNode = new SmTextNode(m_aCurToken, FNT_TEXT);
1691 break;
1693 case TOVERBRACE :
1694 case TUNDERBRACE :
1695 pNode = new SmMathSymbolNode(m_aCurToken);
1696 break;
1698 case TOPER :
1699 NextToken();
1701 DBG_ASSERT(m_aCurToken.eType == TSPECIAL, "Sm: falsches Token");
1702 pNode = new SmGlyphSpecialNode(m_aCurToken);
1703 break;
1705 default :
1706 DBG_ASSERT(0, "Sm: unbekannter Fall");
1708 m_aNodeStack.Push(pNode);
1710 NextToken();
1714 void SmParser::UnOper()
1716 DBG_ASSERT(TokenInGroup(TGUNOPER), "Sm: falsches Token");
1718 SmToken aNodeToken = m_aCurToken;
1719 SmTokenType eType = m_aCurToken.eType;
1720 sal_Bool bIsPostfix = eType == TFACT;
1722 SmStructureNode *pSNode;
1723 SmNode *pOper = 0,
1724 *pExtra = 0,
1725 *pArg;
1727 switch (eType)
1729 case TABS :
1730 case TSQRT :
1731 NextToken();
1732 break;
1734 case TNROOT :
1735 NextToken();
1736 Power();
1737 pExtra = m_aNodeStack.Pop();
1738 break;
1740 case TUOPER :
1741 NextToken();
1742 GlyphSpecial();
1743 pOper = m_aNodeStack.Pop();
1744 break;
1746 case TPLUS :
1747 case TMINUS :
1748 case TPLUSMINUS :
1749 case TMINUSPLUS :
1750 case TNEG :
1751 case TFACT :
1752 OpSubSup();
1753 pOper = m_aNodeStack.Pop();
1754 break;
1756 default :
1757 Error(PE_UNOPER_EXPECTED);
1760 // get argument
1761 Power();
1762 pArg = m_aNodeStack.Pop();
1764 if (eType == TABS)
1765 { pSNode = new SmBraceNode(aNodeToken);
1766 pSNode->SetScaleMode(SCALE_HEIGHT);
1768 // build nodes for left & right lines
1769 // (text, group, level of the used token are of no interrest here)
1770 // we'll use row & column of the keyword for abs
1771 aNodeToken.eType = TABS;
1773 aNodeToken.cMathChar = MS_LINE;
1774 SmNode* pLeft = new SmMathSymbolNode(aNodeToken);
1776 aNodeToken.cMathChar = MS_LINE;
1777 SmNode* pRight = new SmMathSymbolNode(aNodeToken);
1779 pSNode->SetSubNodes(pLeft, pArg, pRight);
1781 else if (eType == TSQRT || eType == TNROOT)
1782 { pSNode = new SmRootNode(aNodeToken);
1783 pOper = new SmRootSymbolNode(aNodeToken);
1784 pSNode->SetSubNodes(pExtra, pOper, pArg);
1786 else
1787 { pSNode = new SmUnHorNode(aNodeToken);
1789 if (bIsPostfix)
1790 pSNode->SetSubNodes(pArg, pOper);
1791 else
1792 // prefix operator
1793 pSNode->SetSubNodes(pOper, pArg);
1796 m_aNodeStack.Push(pSNode);
1800 void SmParser::Attribut()
1802 DBG_ASSERT(TokenInGroup(TGATTRIBUT), "Sm: falsche Tokengruppe");
1804 SmStructureNode *pSNode = new SmAttributNode(m_aCurToken);
1805 SmNode *pAttr;
1806 SmScaleMode eScaleMode = SCALE_NONE;
1808 // get appropriate node for the attribut itself
1809 switch (m_aCurToken.eType)
1810 { case TUNDERLINE :
1811 case TOVERLINE :
1812 case TOVERSTRIKE :
1813 pAttr = new SmRectangleNode(m_aCurToken);
1814 eScaleMode = SCALE_WIDTH;
1815 break;
1817 case TWIDEVEC :
1818 case TWIDEHAT :
1819 case TWIDETILDE :
1820 pAttr = new SmMathSymbolNode(m_aCurToken);
1821 eScaleMode = SCALE_WIDTH;
1822 break;
1824 default :
1825 pAttr = new SmMathSymbolNode(m_aCurToken);
1828 NextToken();
1830 pSNode->SetSubNodes(pAttr, 0);
1831 pSNode->SetScaleMode(eScaleMode);
1832 m_aNodeStack.Push(pSNode);
1836 void SmParser::FontAttribut()
1838 DBG_ASSERT(TokenInGroup(TGFONTATTR), "Sm: falsche Tokengruppe");
1840 switch (m_aCurToken.eType)
1842 case TITALIC :
1843 case TNITALIC :
1844 case TBOLD :
1845 case TNBOLD :
1846 case TPHANTOM :
1847 m_aNodeStack.Push(new SmFontNode(m_aCurToken));
1848 NextToken();
1849 break;
1851 case TSIZE :
1852 FontSize();
1853 break;
1855 case TFONT :
1856 Font();
1857 break;
1859 case TCOLOR :
1860 Color();
1861 break;
1863 default :
1864 DBG_ASSERT(0, "Sm: unbekannter Fall");
1869 void SmParser::Color()
1871 DBG_ASSERT(m_aCurToken.eType == TCOLOR, "Sm : Ooops...");
1873 // last color rules, get that one
1874 SmToken aToken;
1876 { NextToken();
1878 if (TokenInGroup(TGCOLOR))
1879 { aToken = m_aCurToken;
1880 NextToken();
1882 else
1883 Error(PE_COLOR_EXPECTED);
1884 } while (m_aCurToken.eType == TCOLOR);
1886 m_aNodeStack.Push(new SmFontNode(aToken));
1890 void SmParser::Font()
1892 DBG_ASSERT(m_aCurToken.eType == TFONT, "Sm : Ooops...");
1894 // last font rules, get that one
1895 SmToken aToken;
1897 { NextToken();
1899 if (TokenInGroup(TGFONT))
1900 { aToken = m_aCurToken;
1901 NextToken();
1903 else
1904 Error(PE_FONT_EXPECTED);
1905 } while (m_aCurToken.eType == TFONT);
1907 m_aNodeStack.Push(new SmFontNode(aToken));
1911 // gets number used as arguments in Math formulas (e.g. 'size' command)
1912 // Format: no negative numbers, must start with a digit, no exponent notation, ...
1913 sal_Bool lcl_IsNumber(const UniString& rText)
1915 sal_Bool bPoint = sal_False;
1916 const sal_Unicode* pBuffer = rText.GetBuffer();
1917 for(xub_StrLen nPos = 0; nPos < rText.Len(); nPos++, pBuffer++)
1919 const sal_Unicode cChar = *pBuffer;
1920 if(cChar == '.')
1922 if(bPoint)
1923 return sal_False;
1924 else
1925 bPoint = sal_True;
1927 else if ( !IsDigit( cChar ) )
1928 return sal_False;
1930 return sal_True;
1933 void SmParser::FontSize()
1935 DBG_ASSERT(m_aCurToken.eType == TSIZE, "Sm : Ooops...");
1937 sal_uInt16 Type;
1938 SmFontNode *pFontNode = new SmFontNode(m_aCurToken);
1940 NextToken();
1942 switch (m_aCurToken.eType)
1944 case TNUMBER: Type = FNTSIZ_ABSOLUT; break;
1945 case TPLUS: Type = FNTSIZ_PLUS; break;
1946 case TMINUS: Type = FNTSIZ_MINUS; break;
1947 case TMULTIPLY: Type = FNTSIZ_MULTIPLY; break;
1948 case TDIVIDEBY: Type = FNTSIZ_DIVIDE; break;
1950 default:
1951 delete pFontNode;
1952 Error(PE_SIZE_EXPECTED);
1953 return;
1956 if (Type != FNTSIZ_ABSOLUT)
1958 NextToken();
1959 if (m_aCurToken.eType != TNUMBER)
1961 delete pFontNode;
1962 Error(PE_SIZE_EXPECTED);
1963 return;
1967 // get number argument
1968 Fraction aValue( 1L );
1969 if (lcl_IsNumber( m_aCurToken.aText ))
1971 double fTmp;
1972 if ((fTmp = m_aCurToken.aText.ToDouble()) != 0.0)
1974 aValue = fTmp;
1976 //!! keep the numerator and denominator from being to large
1977 //!! otherwise ongoing multiplications may result in overflows
1978 //!! (for example in SmNode::SetFontSize the font size calculated
1979 //!! may become 0 because of this!!! Happens e.g. for ftmp = 2.9 with Linux
1980 //!! or ftmp = 1.11111111111111111... (11/9) on every platform.)
1981 if (aValue.GetDenominator() > 1000)
1983 long nNum = aValue.GetNumerator();
1984 long nDenom = aValue.GetDenominator();
1985 while (nDenom > 1000)
1987 nNum /= 10;
1988 nDenom /= 10;
1990 aValue = Fraction( nNum, nDenom );
1995 NextToken();
1997 pFontNode->SetSizeParameter(aValue, Type);
1998 m_aNodeStack.Push(pFontNode);
2002 void SmParser::Brace()
2004 DBG_ASSERT(m_aCurToken.eType == TLEFT || TokenInGroup(TGLBRACES),
2005 "Sm: kein Klammer Ausdruck");
2007 SmStructureNode *pSNode = new SmBraceNode(m_aCurToken);
2008 SmNode *pBody = 0,
2009 *pLeft = 0,
2010 *pRight = 0;
2011 SmScaleMode eScaleMode = SCALE_NONE;
2012 SmParseError eError = PE_NONE;
2014 if (m_aCurToken.eType == TLEFT)
2015 { NextToken();
2017 eScaleMode = SCALE_HEIGHT;
2019 // check for left bracket
2020 if (TokenInGroup(TGLBRACES) || TokenInGroup(TGRBRACES))
2022 pLeft = new SmMathSymbolNode(m_aCurToken);
2024 NextToken();
2025 Bracebody(sal_True);
2026 pBody = m_aNodeStack.Pop();
2028 if (m_aCurToken.eType == TRIGHT)
2029 { NextToken();
2031 // check for right bracket
2032 if (TokenInGroup(TGLBRACES) || TokenInGroup(TGRBRACES))
2034 pRight = new SmMathSymbolNode(m_aCurToken);
2035 NextToken();
2037 else
2038 eError = PE_RBRACE_EXPECTED;
2040 else
2041 eError = PE_RIGHT_EXPECTED;
2043 else
2044 eError = PE_LBRACE_EXPECTED;
2046 else
2048 if (TokenInGroup(TGLBRACES))
2050 pLeft = new SmMathSymbolNode(m_aCurToken);
2052 NextToken();
2053 Bracebody(sal_False);
2054 pBody = m_aNodeStack.Pop();
2056 SmTokenType eExpectedType = TUNKNOWN;
2057 switch (pLeft->GetToken().eType)
2058 { case TLPARENT : eExpectedType = TRPARENT; break;
2059 case TLBRACKET : eExpectedType = TRBRACKET; break;
2060 case TLBRACE : eExpectedType = TRBRACE; break;
2061 case TLDBRACKET : eExpectedType = TRDBRACKET; break;
2062 case TLLINE : eExpectedType = TRLINE; break;
2063 case TLDLINE : eExpectedType = TRDLINE; break;
2064 case TLANGLE : eExpectedType = TRANGLE; break;
2065 case TLFLOOR : eExpectedType = TRFLOOR; break;
2066 case TLCEIL : eExpectedType = TRCEIL; break;
2067 default :
2068 DBG_ASSERT(0, "Sm: unbekannter Fall");
2071 if (m_aCurToken.eType == eExpectedType)
2073 pRight = new SmMathSymbolNode(m_aCurToken);
2074 NextToken();
2076 else
2077 eError = PE_PARENT_MISMATCH;
2079 else
2080 eError = PE_LBRACE_EXPECTED;
2083 if (eError == PE_NONE)
2084 { DBG_ASSERT(pLeft, "Sm: NULL pointer");
2085 DBG_ASSERT(pRight, "Sm: NULL pointer");
2086 pSNode->SetSubNodes(pLeft, pBody, pRight);
2087 pSNode->SetScaleMode(eScaleMode);
2088 m_aNodeStack.Push(pSNode);
2090 else
2091 { delete pSNode;
2092 delete pBody;
2093 delete pLeft;
2094 delete pRight;
2096 Error(eError);
2101 void SmParser::Bracebody(sal_Bool bIsLeftRight)
2103 SmStructureNode *pBody = new SmBracebodyNode(m_aCurToken);
2104 SmNodeArray aNodes;
2105 sal_uInt16 nNum = 0;
2107 // get body if any
2108 if (bIsLeftRight)
2112 if (m_aCurToken.eType == TMLINE)
2114 m_aNodeStack.Push(new SmMathSymbolNode(m_aCurToken));
2115 NextToken();
2116 nNum++;
2118 else if (m_aCurToken.eType != TRIGHT)
2119 { Align();
2120 nNum++;
2122 if (m_aCurToken.eType != TMLINE && m_aCurToken.eType != TRIGHT)
2123 Error(PE_RIGHT_EXPECTED);
2125 } while (m_aCurToken.eType != TEND && m_aCurToken.eType != TRIGHT);
2127 else
2131 if (m_aCurToken.eType == TMLINE)
2133 m_aNodeStack.Push(new SmMathSymbolNode(m_aCurToken));
2134 NextToken();
2135 nNum++;
2137 else if (!TokenInGroup(TGRBRACES))
2138 { Align();
2139 nNum++;
2141 if (m_aCurToken.eType != TMLINE && !TokenInGroup(TGRBRACES))
2142 Error(PE_RBRACE_EXPECTED);
2144 } while (m_aCurToken.eType != TEND && !TokenInGroup(TGRBRACES));
2147 // build argument vector in parsing order
2148 aNodes.resize(nNum);
2149 for (sal_uInt16 i = 0; i < nNum; i++)
2150 aNodes[nNum - 1 - i] = m_aNodeStack.Pop();
2152 pBody->SetSubNodes(aNodes);
2153 pBody->SetScaleMode(bIsLeftRight ? SCALE_HEIGHT : SCALE_NONE);
2154 m_aNodeStack.Push(pBody);
2158 void SmParser::Function()
2160 switch (m_aCurToken.eType)
2162 case TFUNC:
2163 NextToken(); // skip "FUNC"-statement
2164 // fall through
2166 case TSIN :
2167 case TCOS :
2168 case TTAN :
2169 case TCOT :
2170 case TASIN :
2171 case TACOS :
2172 case TATAN :
2173 case TACOT :
2174 case TSINH :
2175 case TCOSH :
2176 case TTANH :
2177 case TCOTH :
2178 case TASINH :
2179 case TACOSH :
2180 case TATANH :
2181 case TACOTH :
2182 case TLN :
2183 case TLOG :
2184 case TEXP :
2185 m_aNodeStack.Push(new SmTextNode(m_aCurToken, FNT_FUNCTION));
2186 NextToken();
2187 break;
2189 default:
2190 Error(PE_FUNC_EXPECTED);
2195 void SmParser::Binom()
2197 SmNodeArray ExpressionArray;
2198 SmStructureNode *pSNode = new SmTableNode(m_aCurToken);
2200 NextToken();
2202 Sum();
2203 Sum();
2205 ExpressionArray.resize(2);
2207 for (int i = 0; i < 2; i++)
2208 ExpressionArray[2 - (i + 1)] = m_aNodeStack.Pop();
2210 pSNode->SetSubNodes(ExpressionArray);
2211 m_aNodeStack.Push(pSNode);
2215 void SmParser::Stack()
2217 SmNodeArray ExpressionArray;
2218 NextToken();
2219 if (m_aCurToken.eType == TLGROUP)
2221 sal_uInt16 n = 0;
2225 NextToken();
2226 Align();
2227 n++;
2229 while (m_aCurToken.eType == TPOUND);
2231 ExpressionArray.resize(n);
2233 for (sal_uInt16 i = 0; i < n; i++)
2234 ExpressionArray[n - (i + 1)] = m_aNodeStack.Pop();
2236 if (m_aCurToken.eType != TRGROUP)
2237 Error(PE_RGROUP_EXPECTED);
2239 NextToken();
2241 SmStructureNode *pSNode = new SmTableNode(m_aCurToken);
2242 pSNode->SetSubNodes(ExpressionArray);
2243 m_aNodeStack.Push(pSNode);
2245 else
2246 Error(PE_LGROUP_EXPECTED);
2250 void SmParser::Matrix()
2252 SmNodeArray ExpressionArray;
2254 NextToken();
2255 if (m_aCurToken.eType == TLGROUP)
2257 sal_uInt16 c = 0;
2261 NextToken();
2262 Align();
2263 c++;
2265 while (m_aCurToken.eType == TPOUND);
2267 sal_uInt16 r = 1;
2269 while (m_aCurToken.eType == TDPOUND)
2271 NextToken();
2272 for (sal_uInt16 i = 0; i < c; i++)
2274 Align();
2275 if (i < (c - 1))
2277 if (m_aCurToken.eType == TPOUND)
2279 NextToken();
2281 else
2282 Error(PE_POUND_EXPECTED);
2286 r++;
2289 long nRC = r * c;
2291 ExpressionArray.resize(nRC);
2293 for (sal_uInt16 i = 0; i < (nRC); i++)
2294 ExpressionArray[(nRC) - (i + 1)] = m_aNodeStack.Pop();
2296 if (m_aCurToken.eType != TRGROUP)
2297 Error(PE_RGROUP_EXPECTED);
2299 NextToken();
2301 SmMatrixNode *pMNode = new SmMatrixNode(m_aCurToken);
2302 pMNode->SetSubNodes(ExpressionArray);
2303 pMNode->SetRowCol(r, c);
2304 m_aNodeStack.Push(pMNode);
2306 else
2307 Error(PE_LGROUP_EXPECTED);
2311 void SmParser::Special()
2313 sal_Bool bReplace = sal_False;
2314 String &rName = m_aCurToken.aText;
2315 String aNewName;
2317 if (CONVERT_NONE == GetConversion())
2319 // conversion of symbol names for 6.0 (XML) file format
2320 // (name change on import / export.
2321 // UI uses localized names XML file format does not.)
2322 if( rName.Len() && rName.GetChar( 0 ) == sal_Unicode( '%' ) )
2324 if (IsImportSymbolNames())
2326 const SmLocalizedSymbolData &rLSD = SM_MOD()->GetLocSymbolData();
2327 aNewName = rLSD.GetUiSymbolName( rName.Copy( 1 ) );
2328 bReplace = sal_True;
2330 else if (IsExportSymbolNames())
2332 const SmLocalizedSymbolData &rLSD = SM_MOD()->GetLocSymbolData();
2333 aNewName = rLSD.GetExportSymbolName( rName.Copy( 1 ) );
2334 bReplace = sal_True;
2337 if( aNewName.Len() )
2338 aNewName.Insert( '%', 0 );
2340 else // 5.0 <-> 6.0 formula text (symbol name) conversion
2342 LanguageType nLanguage = GetLanguage();
2343 SmLocalizedSymbolData &rData = SM_MOD()->GetLocSymbolData();
2344 const ResStringArray *pFrom = 0;
2345 const ResStringArray *pTo = 0;
2346 if (CONVERT_50_TO_60 == GetConversion())
2348 pFrom = rData.Get50NamesArray( nLanguage );
2349 pTo = rData.Get60NamesArray( nLanguage );
2351 else if (CONVERT_60_TO_50 == GetConversion())
2353 pFrom = rData.Get60NamesArray( nLanguage );
2354 pTo = rData.Get50NamesArray( nLanguage );
2356 if (pFrom && pTo)
2358 DBG_ASSERT( pFrom->Count() == pTo->Count(),
2359 "array length mismatch" );
2360 sal_uInt16 nCount = sal::static_int_cast< sal_uInt16 >(pFrom->Count());
2361 for (sal_uInt16 i = 0; i < nCount; ++i)
2363 if (pFrom->GetString(i) == rName)
2365 aNewName = pTo->GetString(i);
2366 bReplace = sal_True;
2370 // else:
2371 // conversion arrays not found or (usually)
2372 // conversion not necessary
2375 if (bReplace && aNewName.Len() && rName != aNewName)
2377 Replace( GetTokenIndex(), rName.Len(), aNewName );
2378 rName = aNewName;
2381 // add symbol name to list of used symbols
2382 const String aSymbolName( m_aCurToken.aText.Copy( 1 ) );
2383 if (aSymbolName.Len() > 0 )
2384 AddToUsedSymbols( aSymbolName );
2386 m_aNodeStack.Push(new SmSpecialNode(m_aCurToken));
2387 NextToken();
2391 void SmParser::GlyphSpecial()
2393 m_aNodeStack.Push(new SmGlyphSpecialNode(m_aCurToken));
2394 NextToken();
2398 void SmParser::Error(SmParseError eError)
2400 SmStructureNode *pSNode = new SmExpressionNode(m_aCurToken);
2401 SmErrorNode *pErr = new SmErrorNode(eError, m_aCurToken);
2402 pSNode->SetSubNodes(pErr, 0);
2404 //! put a structure node on the stack (instead of the error node itself)
2405 //! because sometimes such a node is expected in order to attach some
2406 //! subnodes
2407 m_aNodeStack.Push(pSNode);
2409 AddError(eError, pSNode);
2411 NextToken();
2415 // end gramar
2418 SmParser::SmParser()
2420 m_eConversion = CONVERT_NONE;
2421 m_bImportSymNames = m_bExportSymNames = sal_False;
2422 m_nLang = Application::GetSettings().GetUILanguage();
2426 SmNode *SmParser::Parse(const String &rBuffer)
2428 ClearUsedSymbols();
2430 m_aBufferString = rBuffer;
2431 m_aBufferString.ConvertLineEnd( LINEEND_LF );
2432 m_nBufferIndex =
2433 m_nTokenIndex = 0;
2434 m_Row = 1;
2435 m_nColOff = 0;
2436 m_nCurError = -1;
2438 for (sal_uInt16 i = 0; i < m_aErrDescList.Count(); i++)
2439 delete m_aErrDescList.Remove(i);
2441 m_aErrDescList.Clear();
2443 m_aNodeStack.Clear();
2445 SetLanguage( Application::GetSettings().GetUILanguage() );
2446 NextToken();
2447 Table();
2449 return m_aNodeStack.Pop();
2453 sal_uInt16 SmParser::AddError(SmParseError Type, SmNode *pNode)
2455 SmErrorDesc *pErrDesc = new SmErrorDesc;
2457 pErrDesc->Type = Type;
2458 pErrDesc->pNode = pNode;
2459 pErrDesc->Text = String(SmResId(RID_ERR_IDENT));
2461 sal_uInt16 nRID;
2462 switch (Type)
2464 case PE_UNEXPECTED_CHAR: nRID = RID_ERR_UNEXPECTEDCHARACTER; break;
2465 case PE_LGROUP_EXPECTED: nRID = RID_ERR_LGROUPEXPECTED; break;
2466 case PE_RGROUP_EXPECTED: nRID = RID_ERR_RGROUPEXPECTED; break;
2467 case PE_LBRACE_EXPECTED: nRID = RID_ERR_LBRACEEXPECTED; break;
2468 case PE_RBRACE_EXPECTED: nRID = RID_ERR_RBRACEEXPECTED; break;
2469 case PE_FUNC_EXPECTED: nRID = RID_ERR_FUNCEXPECTED; break;
2470 case PE_UNOPER_EXPECTED: nRID = RID_ERR_UNOPEREXPECTED; break;
2471 case PE_BINOPER_EXPECTED: nRID = RID_ERR_BINOPEREXPECTED; break;
2472 case PE_SYMBOL_EXPECTED: nRID = RID_ERR_SYMBOLEXPECTED; break;
2473 case PE_IDENTIFIER_EXPECTED: nRID = RID_ERR_IDENTEXPECTED; break;
2474 case PE_POUND_EXPECTED: nRID = RID_ERR_POUNDEXPECTED; break;
2475 case PE_COLOR_EXPECTED: nRID = RID_ERR_COLOREXPECTED; break;
2476 case PE_RIGHT_EXPECTED: nRID = RID_ERR_RIGHTEXPECTED; break;
2478 default:
2479 nRID = RID_ERR_UNKOWN;
2481 pErrDesc->Text += SmResId(nRID);
2483 m_aErrDescList.Insert(pErrDesc);
2485 return (sal_uInt16) m_aErrDescList.GetPos(pErrDesc);
2489 const SmErrorDesc *SmParser::NextError()
2491 if (m_aErrDescList.Count())
2492 if (m_nCurError > 0) return m_aErrDescList.Seek(--m_nCurError);
2493 else
2495 m_nCurError = 0;
2496 return m_aErrDescList.Seek(m_nCurError);
2498 else return 0;
2502 const SmErrorDesc *SmParser::PrevError()
2504 if (m_aErrDescList.Count())
2505 if (m_nCurError < (int) (m_aErrDescList.Count() - 1)) return m_aErrDescList.Seek(++m_nCurError);
2506 else
2508 m_nCurError = (int) (m_aErrDescList.Count() - 1);
2509 return m_aErrDescList.Seek(m_nCurError);
2511 else return 0;
2515 const SmErrorDesc *SmParser::GetError(sal_uInt16 i)
2517 return (/*i >= 0 &&*/ i < m_aErrDescList.Count())
2518 ? m_aErrDescList.Seek(i)
2519 : m_aErrDescList.Seek(m_nCurError);