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