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