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