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