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