update credits
[LibreOffice.git] / starmath / source / parse.cxx
blob9ae5dffb97f1097dd6f530d41c1b30f5703e9aea
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <stdio.h>
22 #include <com/sun/star/i18n/UnicodeType.hpp>
23 #include <i18nlangtag/lang.h>
24 #include <unotools/charclass.hxx>
25 #include <editeng/unolingu.hxx>
26 #include <unotools/syslocale.hxx>
27 #include <sal/macros.h>
28 #include "parse.hxx"
29 #include "starmath.hrc"
30 #include "smdll.hxx"
31 #include "smmod.hxx"
32 #include "config.hxx"
34 #include "node.hxx"
36 using namespace ::com::sun::star;
37 using namespace ::com::sun::star::i18n;
39 ///////////////////////////////////////////////////////////////////////////
41 namespace {
42 template < typename T >
43 T* lcl_popOrZero( ::std::stack<T*> & rStack )
45 if (rStack.empty())
46 return 0;
47 T* pTmp = rStack.top();
48 rStack.pop();
49 return pTmp;
53 static const sal_Unicode aDelimiterTable[] =
55 ' ', '\t', '\n', '\r', '+', '-', '*', '/', '=', '#',
56 '%', '\\', '"', '~', '`', '>', '<', '&', '|', '(',
57 ')', '{', '}', '[', ']', '^', '_',
58 '\0' // end of list symbol
61 SmToken::SmToken() :
62 eType (TUNKNOWN),
63 cMathChar ('\0')
65 nGroup = nCol = nRow = nLevel = 0;
68 SmToken::SmToken(SmTokenType eTokenType,
69 sal_Unicode cMath,
70 const sal_Char* pText,
71 sal_uLong nTokenGroup,
72 sal_uInt16 nTokenLevel) {
73 eType = eTokenType;
74 cMathChar = cMath;
75 aText = OUString::createFromAscii(pText);
76 nGroup = nTokenGroup;
77 nLevel = nTokenLevel;
78 nCol = nRow = 0;
81 ///////////////////////////////////////////////////////////////////////////
84 static const SmTokenTableEntry aTokenTable[] =
86 { "Im" , TIM, MS_IM, TGSTANDALONE, 5 },
87 { "MZ23", TDEBUG, '\0', TGATTRIBUT, 0 },
88 { "Re" , TRE, MS_RE, TGSTANDALONE, 5 },
89 { "abs", TABS, '\0', TGUNOPER, 13 },
90 { "arcosh", TACOSH, '\0', TGFUNCTION, 5 },
91 { "arcoth", TACOTH, '\0', TGFUNCTION, 5 },
92 { "acute", TACUTE, MS_ACUTE, TGATTRIBUT, 5 },
93 { "aleph" , TALEPH, MS_ALEPH, TGSTANDALONE, 5 },
94 { "alignb", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0},
95 { "alignc", TALIGNC, '\0', TGALIGN, 0},
96 { "alignl", TALIGNL, '\0', TGALIGN, 0},
97 { "alignm", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0},
98 { "alignr", TALIGNR, '\0', TGALIGN, 0},
99 { "alignt", TALIGNC, '\0', TGALIGN | TGDISCARDED, 0},
100 { "and", TAND, MS_AND, TGPRODUCT, 0},
101 { "approx", TAPPROX, MS_APPROX, TGRELATION, 0},
102 { "arccos", TACOS, '\0', TGFUNCTION, 5},
103 { "arccot", TACOT, '\0', TGFUNCTION, 5},
104 { "arcsin", TASIN, '\0', TGFUNCTION, 5},
105 { "arctan", TATAN, '\0', TGFUNCTION, 5},
106 { "arsinh", TASINH, '\0', TGFUNCTION, 5},
107 { "artanh", TATANH, '\0', TGFUNCTION, 5},
108 { "backepsilon" , TBACKEPSILON, MS_BACKEPSILON, TGSTANDALONE, 5},
109 { "bar", TBAR, MS_BAR, TGATTRIBUT, 5},
110 { "binom", TBINOM, '\0', 0, 5 },
111 { "black", TBLACK, '\0', TGCOLOR, 0},
112 { "blue", TBLUE, '\0', TGCOLOR, 0},
113 { "bold", TBOLD, '\0', TGFONTATTR, 5},
114 { "boper", TBOPER, '\0', TGPRODUCT, 0},
115 { "breve", TBREVE, MS_BREVE, TGATTRIBUT, 5},
116 { "bslash", TBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 },
117 { "cdot", TCDOT, MS_CDOT, TGPRODUCT, 0},
118 { "check", TCHECK, MS_CHECK, TGATTRIBUT, 5},
119 { "circ" , TCIRC, MS_CIRC, TGSTANDALONE, 5},
120 { "circle", TCIRCLE, MS_CIRCLE, TGATTRIBUT, 5},
121 { "color", TCOLOR, '\0', TGFONTATTR, 5},
122 { "coprod", TCOPROD, MS_COPROD, TGOPER, 5},
123 { "cos", TCOS, '\0', TGFUNCTION, 5},
124 { "cosh", TCOSH, '\0', TGFUNCTION, 5},
125 { "cot", TCOT, '\0', TGFUNCTION, 5},
126 { "coth", TCOTH, '\0', TGFUNCTION, 5},
127 { "csub", TCSUB, '\0', TGPOWER, 0},
128 { "csup", TCSUP, '\0', TGPOWER, 0},
129 { "cyan", TCYAN, '\0', TGCOLOR, 0},
130 { "dddot", TDDDOT, MS_DDDOT, TGATTRIBUT, 5},
131 { "ddot", TDDOT, MS_DDOT, TGATTRIBUT, 5},
132 { "def", TDEF, MS_DEF, TGRELATION, 0},
133 { "div", TDIV, MS_DIV, TGPRODUCT, 0},
134 { "divides", TDIVIDES, MS_LINE, TGRELATION, 0},
135 { "dlarrow" , TDLARROW, MS_DLARROW, TGSTANDALONE, 5},
136 { "dlrarrow" , TDLRARROW, MS_DLRARROW, TGSTANDALONE, 5},
137 { "dot", TDOT, MS_DOT, TGATTRIBUT, 5},
138 { "dotsaxis", TDOTSAXIS, MS_DOTSAXIS, TGSTANDALONE, 5}, // 5 to continue expression
139 { "dotsdiag", TDOTSDIAG, MS_DOTSUP, TGSTANDALONE, 5}, //
140 { "dotsdown", TDOTSDOWN, MS_DOTSDOWN, TGSTANDALONE, 5}, //
141 { "dotslow", TDOTSLOW, MS_DOTSLOW, TGSTANDALONE, 5}, //
142 { "dotsup", TDOTSUP, MS_DOTSUP, TGSTANDALONE, 5}, //
143 { "dotsvert", TDOTSVERT, MS_DOTSVERT, TGSTANDALONE, 5}, //
144 { "downarrow" , TDOWNARROW, MS_DOWNARROW, TGSTANDALONE, 5},
145 { "drarrow" , TDRARROW, MS_DRARROW, TGSTANDALONE, 5},
146 { "emptyset" , TEMPTYSET, MS_EMPTYSET, TGSTANDALONE, 5},
147 { "equiv", TEQUIV, MS_EQUIV, TGRELATION, 0},
148 { "exists", TEXISTS, MS_EXISTS, TGSTANDALONE, 5},
149 { "notexists", TNOTEXISTS, MS_NOTEXISTS, TGSTANDALONE, 5},
150 { "exp", TEXP, '\0', TGFUNCTION, 5},
151 { "fact", TFACT, MS_FACT, TGUNOPER, 5},
152 { "fixed", TFIXED, '\0', TGFONT, 0},
153 { "font", TFONT, '\0', TGFONTATTR, 5},
154 { "forall", TFORALL, MS_FORALL, TGSTANDALONE, 5},
155 { "from", TFROM, '\0', TGLIMIT, 0},
156 { "func", TFUNC, '\0', TGFUNCTION, 5},
157 { "ge", TGE, MS_GE, TGRELATION, 0},
158 { "geslant", TGESLANT, MS_GESLANT, TGRELATION, 0 },
159 { "gg", TGG, MS_GG, TGRELATION, 0},
160 { "grave", TGRAVE, MS_GRAVE, TGATTRIBUT, 5},
161 { "green", TGREEN, '\0', TGCOLOR, 0},
162 { "gt", TGT, MS_GT, TGRELATION, 0},
163 { "hat", THAT, MS_HAT, TGATTRIBUT, 5},
164 { "hbar" , THBAR, MS_HBAR, TGSTANDALONE, 5},
165 { "iiint", TIIINT, MS_IIINT, TGOPER, 5},
166 { "iint", TIINT, MS_IINT, TGOPER, 5},
167 { "in", TIN, MS_IN, TGRELATION, 0},
168 { "infinity" , TINFINITY, MS_INFINITY, TGSTANDALONE, 5},
169 { "infty" , TINFINITY, MS_INFINITY, TGSTANDALONE, 5},
170 { "int", TINT, MS_INT, TGOPER, 5},
171 { "intersection", TINTERSECT, MS_INTERSECT, TGPRODUCT, 0},
172 { "ital", TITALIC, '\0', TGFONTATTR, 5},
173 { "italic", TITALIC, '\0', TGFONTATTR, 5},
174 { "lambdabar" , TLAMBDABAR, MS_LAMBDABAR, TGSTANDALONE, 5},
175 { "langle", TLANGLE, MS_LANGLE, TGLBRACES, 5},
176 { "lbrace", TLBRACE, MS_LBRACE, TGLBRACES, 5},
177 { "lceil", TLCEIL, MS_LCEIL, TGLBRACES, 5},
178 { "ldbracket", TLDBRACKET, MS_LDBRACKET, TGLBRACES, 5},
179 { "ldline", TLDLINE, MS_DLINE, TGLBRACES, 5},
180 { "le", TLE, MS_LE, TGRELATION, 0},
181 { "left", TLEFT, '\0', 0, 5},
182 { "leftarrow" , TLEFTARROW, MS_LEFTARROW, TGSTANDALONE, 5},
183 { "leslant", TLESLANT, MS_LESLANT, TGRELATION, 0 },
184 { "lfloor", TLFLOOR, MS_LFLOOR, TGLBRACES, 5},
185 { "lim", TLIM, '\0', TGOPER, 5},
186 { "liminf", TLIMINF, '\0', TGOPER, 5},
187 { "limsup", TLIMSUP, '\0', TGOPER, 5},
188 { "lint", TLINT, MS_LINT, TGOPER, 5},
189 { "ll", TLL, MS_LL, TGRELATION, 0},
190 { "lline", TLLINE, MS_LINE, TGLBRACES, 5},
191 { "llint", TLLINT, MS_LLINT, TGOPER, 5},
192 { "lllint", TLLLINT, MS_LLLINT, TGOPER, 5},
193 { "ln", TLN, '\0', TGFUNCTION, 5},
194 { "log", TLOG, '\0', TGFUNCTION, 5},
195 { "lsub", TLSUB, '\0', TGPOWER, 0},
196 { "lsup", TLSUP, '\0', TGPOWER, 0},
197 { "lt", TLT, MS_LT, TGRELATION, 0},
198 { "magenta", TMAGENTA, '\0', TGCOLOR, 0},
199 { "matrix", TMATRIX, '\0', 0, 5},
200 { "minusplus", TMINUSPLUS, MS_MINUSPLUS, TGUNOPER | TGSUM, 5},
201 { "mline", TMLINE, MS_LINE, 0, 0}, //! nicht in TGRBRACES, Level 0
202 { "nabla", TNABLA, MS_NABLA, TGSTANDALONE, 5},
203 { "nbold", TNBOLD, '\0', TGFONTATTR, 5},
204 { "ndivides", TNDIVIDES, MS_NDIVIDES, TGRELATION, 0},
205 { "neg", TNEG, MS_NEG, TGUNOPER, 5 },
206 { "neq", TNEQ, MS_NEQ, TGRELATION, 0},
207 { "newline", TNEWLINE, '\0', 0, 0},
208 { "ni", TNI, MS_NI, TGRELATION, 0},
209 { "nitalic", TNITALIC, '\0', TGFONTATTR, 5},
210 { "none", TNONE, '\0', TGLBRACES | TGRBRACES, 0},
211 { "nospace", TNOSPACE, '\0', TGSTANDALONE, 5},
212 { "notin", TNOTIN, MS_NOTIN, TGRELATION, 0},
213 { "nroot", TNROOT, MS_SQRT, TGUNOPER, 5},
214 { "nsubset", TNSUBSET, MS_NSUBSET, TGRELATION, 0 },
215 { "nsupset", TNSUPSET, MS_NSUPSET, TGRELATION, 0 },
216 { "nsubseteq", TNSUBSETEQ, MS_NSUBSETEQ, TGRELATION, 0 },
217 { "nsupseteq", TNSUPSETEQ, MS_NSUPSETEQ, TGRELATION, 0 },
218 { "odivide", TODIVIDE, MS_ODIVIDE, TGPRODUCT, 0},
219 { "odot", TODOT, MS_ODOT, TGPRODUCT, 0},
220 { "ominus", TOMINUS, MS_OMINUS, TGSUM, 0},
221 { "oper", TOPER, '\0', TGOPER, 5},
222 { "oplus", TOPLUS, MS_OPLUS, TGSUM, 0},
223 { "or", TOR, MS_OR, TGSUM, 0},
224 { "ortho", TORTHO, MS_ORTHO, TGRELATION, 0},
225 { "otimes", TOTIMES, MS_OTIMES, TGPRODUCT, 0},
226 { "over", TOVER, '\0', TGPRODUCT, 0},
227 { "overbrace", TOVERBRACE, MS_OVERBRACE, TGPRODUCT, 5},
228 { "overline", TOVERLINE, '\0', TGATTRIBUT, 5},
229 { "overstrike", TOVERSTRIKE, '\0', TGATTRIBUT, 5},
230 { "owns", TNI, MS_NI, TGRELATION, 0},
231 { "parallel", TPARALLEL, MS_DLINE, TGRELATION, 0},
232 { "partial", TPARTIAL, MS_PARTIAL, TGSTANDALONE, 5 },
233 { "phantom", TPHANTOM, '\0', TGFONTATTR, 5},
234 { "plusminus", TPLUSMINUS, MS_PLUSMINUS, TGUNOPER | TGSUM, 5},
235 { "prec", TPRECEDES, MS_PRECEDES, TGRELATION, 0 },
236 { "preccurlyeq", TPRECEDESEQUAL, MS_PRECEDESEQUAL, TGRELATION, 0 },
237 { "precsim", TPRECEDESEQUIV, MS_PRECEDESEQUIV, TGRELATION, 0 },
238 { "nprec", TNOTPRECEDES, MS_NOTPRECEDES, TGRELATION, 0 },
239 { "prod", TPROD, MS_PROD, TGOPER, 5},
240 { "prop", TPROP, MS_PROP, TGRELATION, 0},
241 { "rangle", TRANGLE, MS_RANGLE, TGRBRACES, 0}, //! 0 to terminate expression
242 { "rbrace", TRBRACE, MS_RBRACE, TGRBRACES, 0}, //
243 { "rceil", TRCEIL, MS_RCEIL, TGRBRACES, 0}, //
244 { "rdbracket", TRDBRACKET, MS_RDBRACKET, TGRBRACES, 0}, //
245 { "rdline", TRDLINE, MS_DLINE, TGRBRACES, 0}, //
246 { "red", TRED, '\0', TGCOLOR, 0},
247 { "rfloor", TRFLOOR, MS_RFLOOR, TGRBRACES, 0}, //! 0 to terminate expression
248 { "right", TRIGHT, '\0', 0, 0},
249 { "rightarrow" , TRIGHTARROW, MS_RIGHTARROW, TGSTANDALONE, 5},
250 { "rline", TRLINE, MS_LINE, TGRBRACES, 0}, //! 0 to terminate expression
251 { "rsub", TRSUB, '\0', TGPOWER, 0},
252 { "rsup", TRSUP, '\0', TGPOWER, 0},
253 { "sans", TSANS, '\0', TGFONT, 0},
254 { "serif", TSERIF, '\0', TGFONT, 0},
255 { "setC" , TSETC, MS_SETC, TGSTANDALONE, 5},
256 { "setN" , TSETN, MS_SETN, TGSTANDALONE, 5},
257 { "setQ" , TSETQ, MS_SETQ, TGSTANDALONE, 5},
258 { "setR" , TSETR, MS_SETR, TGSTANDALONE, 5},
259 { "setZ" , TSETZ, MS_SETZ, TGSTANDALONE, 5},
260 { "setminus", TBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 },
261 { "sim", TSIM, MS_SIM, TGRELATION, 0},
262 { "simeq", TSIMEQ, MS_SIMEQ, TGRELATION, 0},
263 { "sin", TSIN, '\0', TGFUNCTION, 5},
264 { "sinh", TSINH, '\0', TGFUNCTION, 5},
265 { "size", TSIZE, '\0', TGFONTATTR, 5},
266 { "slash", TSLASH, MS_SLASH, TGPRODUCT, 0 },
267 { "sqrt", TSQRT, MS_SQRT, TGUNOPER, 5},
268 { "stack", TSTACK, '\0', 0, 5},
269 { "sub", TRSUB, '\0', TGPOWER, 0},
270 { "subset", TSUBSET, MS_SUBSET, TGRELATION, 0},
271 { "succ", TSUCCEEDS, MS_SUCCEEDS, TGRELATION, 0 },
272 { "succcurlyeq", TSUCCEEDSEQUAL, MS_SUCCEEDSEQUAL, TGRELATION, 0 },
273 { "succsim", TSUCCEEDSEQUIV, MS_SUCCEEDSEQUIV, TGRELATION, 0 },
274 { "nsucc", TNOTSUCCEEDS, MS_NOTSUCCEEDS, TGRELATION, 0 },
275 { "subseteq", TSUBSETEQ, MS_SUBSETEQ, TGRELATION, 0},
276 { "sum", TSUM, MS_SUM, TGOPER, 5},
277 { "sup", TRSUP, '\0', TGPOWER, 0},
278 { "supset", TSUPSET, MS_SUPSET, TGRELATION, 0},
279 { "supseteq", TSUPSETEQ, MS_SUPSETEQ, TGRELATION, 0},
280 { "tan", TTAN, '\0', TGFUNCTION, 5},
281 { "tanh", TTANH, '\0', TGFUNCTION, 5},
282 { "tilde", TTILDE, MS_TILDE, TGATTRIBUT, 5},
283 { "times", TTIMES, MS_TIMES, TGPRODUCT, 0},
284 { "to", TTO, '\0', TGLIMIT, 0},
285 { "toward", TTOWARD, MS_RIGHTARROW, TGRELATION, 0},
286 { "transl", TTRANSL, MS_TRANSL, TGRELATION, 0},
287 { "transr", TTRANSR, MS_TRANSR, TGRELATION, 0},
288 { "underbrace", TUNDERBRACE, MS_UNDERBRACE, TGPRODUCT, 5},
289 { "underline", TUNDERLINE, '\0', TGATTRIBUT, 5},
290 { "union", TUNION, MS_UNION, TGSUM, 0},
291 { "uoper", TUOPER, '\0', TGUNOPER, 5},
292 { "uparrow" , TUPARROW, MS_UPARROW, TGSTANDALONE, 5},
293 { "vec", TVEC, MS_VEC, TGATTRIBUT, 5},
294 { "white", TWHITE, '\0', TGCOLOR, 0},
295 { "widebslash", TWIDEBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 },
296 { "widehat", TWIDEHAT, MS_HAT, TGATTRIBUT, 5},
297 { "widetilde", TWIDETILDE, MS_TILDE, TGATTRIBUT, 5},
298 { "wideslash", TWIDESLASH, MS_SLASH, TGPRODUCT, 0 },
299 { "widevec", TWIDEVEC, MS_VEC, TGATTRIBUT, 5},
300 { "wp" , TWP, MS_WP, TGSTANDALONE, 5},
301 { "yellow", TYELLOW, '\0', TGCOLOR, 0},
302 { "", TEND, '\0', 0, 0}
305 const SmTokenTableEntry * SmParser::GetTokenTableEntry( const String &rName )
307 const SmTokenTableEntry * pRes = 0;
308 if (rName.Len())
310 for (size_t i = 0; i < SAL_N_ELEMENTS(aTokenTable); ++i)
312 if (rName.EqualsIgnoreCaseAscii( aTokenTable[i].pIdent ))
314 pRes = &aTokenTable[i];
315 break;
320 return pRes;
324 ///////////////////////////////////////////////////////////////////////////
326 #if OSL_DEBUG_LEVEL > 1
328 bool SmParser::IsDelimiter( const String &rTxt, xub_StrLen nPos )
329 // returns 'true' iff cChar is '\0' or a delimeter
331 OSL_ENSURE( nPos <= rTxt.Len(), "index out of range" );
333 sal_Unicode cChar = rTxt.GetChar( nPos );
334 if(!cChar)
335 return true;
337 // check if 'cChar' is in the delimeter table
338 const sal_Unicode *pDelim = &aDelimiterTable[0];
339 for ( ; *pDelim != 0; pDelim++)
340 if (*pDelim == cChar)
341 break;
344 sal_Int16 nTypJp = SM_MOD()->GetSysLocale().GetCharClass().getType( rTxt, nPos );
345 bool bIsDelim = (*pDelim != 0 ||
346 nTypJp == com::sun::star::i18n::UnicodeType::SPACE_SEPARATOR ||
347 nTypJp == com::sun::star::i18n::UnicodeType::CONTROL);
349 return bIsDelim;
352 #endif
354 void SmParser::Insert(const String &rText, sal_uInt16 nPos)
356 m_aBufferString.Insert(rText, nPos);
358 xub_StrLen nLen = rText.Len();
359 m_nBufferIndex = m_nBufferIndex + nLen;
360 m_nTokenIndex = m_nTokenIndex + nLen;
364 void SmParser::Replace( sal_uInt16 nPos, sal_uInt16 nLen, const String &rText )
366 OSL_ENSURE( nPos + nLen <= m_aBufferString.Len(), "argument mismatch" );
368 m_aBufferString.Replace( nPos, nLen, rText );
369 sal_Int16 nChg = rText.Len() - nLen;
370 m_nBufferIndex = m_nBufferIndex + nChg;
371 m_nTokenIndex = m_nTokenIndex + nChg;
375 // First character may be any alphabetic
376 const sal_Int32 coStartFlags =
377 KParseTokens::ANY_LETTER_OR_NUMBER |
378 KParseTokens::IGNORE_LEADING_WS;
380 // Continuing characters may be any alphanumeric or dot.
381 const sal_Int32 coContFlags =
382 ((coStartFlags | KParseTokens::ASC_DOT) & ~KParseTokens::IGNORE_LEADING_WS)
383 | KParseTokens::TWO_DOUBLE_QUOTES_BREAK_STRING;
385 // First character for numbers, may be any numeric or dot
386 const sal_Int32 coNumStartFlags =
387 KParseTokens::ASC_DIGIT |
388 KParseTokens::ASC_DOT |
389 KParseTokens::IGNORE_LEADING_WS;
390 // Continuing characters for numbers, may be any numeric or dot.
391 const sal_Int32 coNumContFlags =
392 (coNumStartFlags | KParseTokens::ASC_DOT) & ~KParseTokens::IGNORE_LEADING_WS;
394 void SmParser::NextToken()
396 static const String aEmptyStr;
398 xub_StrLen nBufLen = m_aBufferString.Len();
399 ParseResult aRes;
400 xub_StrLen nRealStart;
401 bool bCont;
402 bool bNumStart = false;
403 CharClass aCC(SM_MOD()->GetSysLocale().GetLanguageTag());
406 // skip white spaces
407 while (UnicodeType::SPACE_SEPARATOR ==
408 aCC.getType( m_aBufferString, m_nBufferIndex ))
409 ++m_nBufferIndex;
411 sal_Int32 nStartFlags = coStartFlags;
412 sal_Int32 nContFlags = coContFlags;
413 sal_Unicode cFirstChar = m_aBufferString.GetChar( m_nBufferIndex );
414 aRes = aCC.parseAnyToken( m_aBufferString, m_nBufferIndex,
415 nStartFlags, aEmptyStr,
416 nContFlags, aEmptyStr );
418 // #i45779# parse numbers correctly
419 // i.e. independent from the locale setting.
420 // (note that #i11752# remains fixed)
421 if ((aRes.TokenType & KParseType::IDENTNAME) && CharClass::isAsciiDigit( cFirstChar ))
423 ParseResult aTmpRes;
424 LanguageTag aOldLoc( aCC.getLanguageTag() );
425 aCC.setLanguageTag( LanguageTag( m_aDotLoc ));
426 aTmpRes = aCC.parsePredefinedToken(
427 KParseType::ASC_NUMBER,
428 m_aBufferString, m_nBufferIndex,
429 KParseTokens::ASC_DIGIT, aEmptyStr,
430 KParseTokens::ASC_DIGIT | KParseTokens::ASC_DOT, aEmptyStr );
431 aCC.setLanguageTag( aOldLoc );
432 if (aTmpRes.TokenType & KParseType::ASC_NUMBER)
433 aRes.TokenType = aTmpRes.TokenType;
436 nRealStart = m_nBufferIndex + sal::static_int_cast< xub_StrLen >(aRes.LeadingWhiteSpace);
437 m_nBufferIndex = nRealStart;
439 bCont = false;
440 if ( aRes.TokenType == 0 &&
441 nRealStart < nBufLen &&
442 '\n' == m_aBufferString.GetChar( nRealStart ) )
444 // keep data needed for tokens row and col entry up to date
445 ++m_Row;
446 m_nBufferIndex = m_nColOff = nRealStart + 1;
447 bCont = true;
449 else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR)
451 String aName( m_aBufferString.Copy( nRealStart, 2 ));
452 if ( aName.EqualsAscii( "%%" ))
454 //SkipComment
455 m_nBufferIndex = nRealStart + 2;
456 while (m_nBufferIndex < nBufLen &&
457 '\n' != m_aBufferString.GetChar( m_nBufferIndex ))
458 ++m_nBufferIndex;
459 bCont = true;
463 } while (bCont);
465 // set index of current token
466 m_nTokenIndex = m_nBufferIndex;
468 m_aCurToken.nRow = m_Row;
469 m_aCurToken.nCol = nRealStart - m_nColOff + 1;
471 bool bHandled = true;
472 if (nRealStart >= nBufLen)
474 m_aCurToken.eType = TEND;
475 m_aCurToken.cMathChar = '\0';
476 m_aCurToken.nGroup = 0;
477 m_aCurToken.nLevel = 0;
478 m_aCurToken.aText = "";
480 else if ((aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER))
481 || (bNumStart && (aRes.TokenType & KParseType::IDENTNAME)))
483 sal_Int32 n = aRes.EndPos - nRealStart;
484 OSL_ENSURE( n >= 0, "length < 0" );
485 m_aCurToken.eType = TNUMBER;
486 m_aCurToken.cMathChar = '\0';
487 m_aCurToken.nGroup = 0;
488 m_aCurToken.nLevel = 5;
489 m_aCurToken.aText = m_aBufferString.Copy( nRealStart, sal::static_int_cast< xub_StrLen >(n) );
491 #if OSL_DEBUG_LEVEL > 1
492 if (!IsDelimiter( m_aBufferString, static_cast< xub_StrLen >(aRes.EndPos) ))
494 OSL_FAIL( "identifier really finished? (compatibility!)" );
496 #endif
498 else if (aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING)
500 m_aCurToken.eType = TTEXT;
501 m_aCurToken.cMathChar = '\0';
502 m_aCurToken.nGroup = 0;
503 m_aCurToken.nLevel = 5;
504 m_aCurToken.aText = aRes.DequotedNameOrString;
505 m_aCurToken.nRow = m_Row;
506 m_aCurToken.nCol = nRealStart - m_nColOff + 2;
508 else if (aRes.TokenType & KParseType::IDENTNAME)
510 sal_Int32 n = aRes.EndPos - nRealStart;
511 OSL_ENSURE( n >= 0, "length < 0" );
512 String aName( m_aBufferString.Copy( nRealStart, sal::static_int_cast< xub_StrLen >(n) ) );
513 const SmTokenTableEntry *pEntry = GetTokenTableEntry( aName );
515 if (pEntry)
517 m_aCurToken.eType = pEntry->eType;
518 m_aCurToken.cMathChar = pEntry->cMathChar;
519 m_aCurToken.nGroup = pEntry->nGroup;
520 m_aCurToken.nLevel = pEntry->nLevel;
521 m_aCurToken.aText = OUString::createFromAscii( pEntry->pIdent );
523 else
525 m_aCurToken.eType = TIDENT;
526 m_aCurToken.cMathChar = '\0';
527 m_aCurToken.nGroup = 0;
528 m_aCurToken.nLevel = 5;
529 m_aCurToken.aText = aName;
531 #if OSL_DEBUG_LEVEL > 1
532 if (!IsDelimiter( m_aBufferString, static_cast< xub_StrLen >(aRes.EndPos) ))
534 OSL_FAIL( "identifier really finished? (compatibility!)" );
536 #endif
539 else if (aRes.TokenType == 0 && '_' == m_aBufferString.GetChar( nRealStart ))
541 m_aCurToken.eType = TRSUB;
542 m_aCurToken.cMathChar = '\0';
543 m_aCurToken.nGroup = TGPOWER;
544 m_aCurToken.nLevel = 0;
545 m_aCurToken.aText = "_";
547 aRes.EndPos = nRealStart + 1;
549 else if (aRes.TokenType & KParseType::BOOLEAN)
551 sal_Int32 &rnEndPos = aRes.EndPos;
552 String aName( m_aBufferString.Copy( nRealStart,
553 sal::static_int_cast< xub_StrLen >(rnEndPos - nRealStart) ));
554 if (2 >= aName.Len())
556 sal_Unicode ch = aName.GetChar( 0 );
557 switch (ch)
559 case '<':
561 if (m_aBufferString.Copy( nRealStart, 2 ).
562 EqualsAscii( "<<" ))
564 m_aCurToken.eType = TLL;
565 m_aCurToken.cMathChar = MS_LL;
566 m_aCurToken.nGroup = TGRELATION;
567 m_aCurToken.nLevel = 0;
568 m_aCurToken.aText = "<<";
570 rnEndPos = nRealStart + 2;
572 else if (m_aBufferString.Copy( nRealStart, 2 ).
573 EqualsAscii( "<=" ))
575 m_aCurToken.eType = TLE;
576 m_aCurToken.cMathChar = MS_LE;
577 m_aCurToken.nGroup = TGRELATION;
578 m_aCurToken.nLevel = 0;
579 m_aCurToken.aText = "<=";
581 rnEndPos = nRealStart + 2;
583 else if (m_aBufferString.Copy( nRealStart, 2 ).
584 EqualsAscii( "<>" ))
586 m_aCurToken.eType = TNEQ;
587 m_aCurToken.cMathChar = MS_NEQ;
588 m_aCurToken.nGroup = TGRELATION;
589 m_aCurToken.nLevel = 0;
590 m_aCurToken.aText = "<>";
592 rnEndPos = nRealStart + 2;
594 else if (m_aBufferString.Copy( nRealStart, 3 ).
595 EqualsAscii( "<?>" ))
597 m_aCurToken.eType = TPLACE;
598 m_aCurToken.cMathChar = MS_PLACE;
599 m_aCurToken.nGroup = 0;
600 m_aCurToken.nLevel = 5;
601 m_aCurToken.aText = "<?>";
603 rnEndPos = nRealStart + 3;
605 else
607 m_aCurToken.eType = TLT;
608 m_aCurToken.cMathChar = MS_LT;
609 m_aCurToken.nGroup = TGRELATION;
610 m_aCurToken.nLevel = 0;
611 m_aCurToken.aText = "<";
614 break;
615 case '>':
617 if (m_aBufferString.Copy( nRealStart, 2 ).
618 EqualsAscii( ">=" ))
620 m_aCurToken.eType = TGE;
621 m_aCurToken.cMathChar = MS_GE;
622 m_aCurToken.nGroup = TGRELATION;
623 m_aCurToken.nLevel = 0;
624 m_aCurToken.aText = ">=";
626 rnEndPos = nRealStart + 2;
628 else if (m_aBufferString.Copy( nRealStart, 2 ).
629 EqualsAscii( ">>" ))
631 m_aCurToken.eType = TGG;
632 m_aCurToken.cMathChar = MS_GG;
633 m_aCurToken.nGroup = TGRELATION;
634 m_aCurToken.nLevel = 0;
635 m_aCurToken.aText = ">>";
637 rnEndPos = nRealStart + 2;
639 else
641 m_aCurToken.eType = TGT;
642 m_aCurToken.cMathChar = MS_GT;
643 m_aCurToken.nGroup = TGRELATION;
644 m_aCurToken.nLevel = 0;
645 m_aCurToken.aText = ">";
648 break;
649 default:
650 bHandled = false;
654 else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR)
656 sal_Int32 &rnEndPos = aRes.EndPos;
657 String aName( m_aBufferString.Copy( nRealStart,
658 sal::static_int_cast< xub_StrLen >(rnEndPos - nRealStart) ) );
660 if (1 == aName.Len())
662 sal_Unicode ch = aName.GetChar( 0 );
663 switch (ch)
665 case '%':
667 //! modifies aRes.EndPos
669 OSL_ENSURE( rnEndPos >= nBufLen ||
670 '%' != m_aBufferString.GetChar( sal::static_int_cast< xub_StrLen >(rnEndPos) ),
671 "unexpected comment start" );
673 // get identifier of user-defined character
674 ParseResult aTmpRes = aCC.parseAnyToken(
675 m_aBufferString, rnEndPos,
676 KParseTokens::ANY_LETTER,
677 aEmptyStr,
678 coContFlags,
679 aEmptyStr );
681 xub_StrLen nTmpStart = sal::static_int_cast< xub_StrLen >(rnEndPos +
682 aTmpRes.LeadingWhiteSpace);
684 // default setting for the case that no identifier
685 // i.e. a valid symbol-name is following the '%'
686 // character
687 m_aCurToken.eType = TTEXT;
688 m_aCurToken.cMathChar = '\0';
689 m_aCurToken.nGroup = 0;
690 m_aCurToken.nLevel = 5;
691 m_aCurToken.aText = String();
692 m_aCurToken.nRow = sal::static_int_cast< xub_StrLen >(m_Row);
693 m_aCurToken.nCol = nTmpStart - m_nColOff;
695 if (aTmpRes.TokenType & KParseType::IDENTNAME)
698 xub_StrLen n = sal::static_int_cast< xub_StrLen >(aTmpRes.EndPos - nTmpStart);
699 m_aCurToken.eType = TSPECIAL;
700 m_aCurToken.aText = m_aBufferString.Copy( sal::static_int_cast< xub_StrLen >(nTmpStart-1), n+1 );
702 OSL_ENSURE( aTmpRes.EndPos > rnEndPos,
703 "empty identifier" );
704 if (aTmpRes.EndPos > rnEndPos)
705 rnEndPos = aTmpRes.EndPos;
706 else
707 ++rnEndPos;
710 // if no symbol-name was found we start-over with
711 // finding the next token right afer the '%' sign.
712 // I.e. we leave rnEndPos unmodified.
714 break;
715 case '[':
717 m_aCurToken.eType = TLBRACKET;
718 m_aCurToken.cMathChar = MS_LBRACKET;
719 m_aCurToken.nGroup = TGLBRACES;
720 m_aCurToken.nLevel = 5;
721 m_aCurToken.aText = "[";
723 break;
724 case '\\':
726 m_aCurToken.eType = TESCAPE;
727 m_aCurToken.cMathChar = '\0';
728 m_aCurToken.nGroup = 0;
729 m_aCurToken.nLevel = 5;
730 m_aCurToken.aText = "\\";
732 break;
733 case ']':
735 m_aCurToken.eType = TRBRACKET;
736 m_aCurToken.cMathChar = MS_RBRACKET;
737 m_aCurToken.nGroup = TGRBRACES;
738 m_aCurToken.nLevel = 0;
739 m_aCurToken.aText = "]";
741 break;
742 case '^':
744 m_aCurToken.eType = TRSUP;
745 m_aCurToken.cMathChar = '\0';
746 m_aCurToken.nGroup = TGPOWER;
747 m_aCurToken.nLevel = 0;
748 m_aCurToken.aText = "^";
750 break;
751 case '`':
753 m_aCurToken.eType = TSBLANK;
754 m_aCurToken.cMathChar = '\0';
755 m_aCurToken.nGroup = TGBLANK;
756 m_aCurToken.nLevel = 5;
757 m_aCurToken.aText = "`";
759 break;
760 case '{':
762 m_aCurToken.eType = TLGROUP;
763 m_aCurToken.cMathChar = MS_LBRACE;
764 m_aCurToken.nGroup = 0;
765 m_aCurToken.nLevel = 5;
766 m_aCurToken.aText = "{";
768 break;
769 case '|':
771 m_aCurToken.eType = TOR;
772 m_aCurToken.cMathChar = MS_OR;
773 m_aCurToken.nGroup = TGSUM;
774 m_aCurToken.nLevel = 0;
775 m_aCurToken.aText = "|";
777 break;
778 case '}':
780 m_aCurToken.eType = TRGROUP;
781 m_aCurToken.cMathChar = MS_RBRACE;
782 m_aCurToken.nGroup = 0;
783 m_aCurToken.nLevel = 0;
784 m_aCurToken.aText = "}";
786 break;
787 case '~':
789 m_aCurToken.eType = TBLANK;
790 m_aCurToken.cMathChar = '\0';
791 m_aCurToken.nGroup = TGBLANK;
792 m_aCurToken.nLevel = 5;
793 m_aCurToken.aText = "~";
795 break;
796 case '#':
798 if (m_aBufferString.Copy( nRealStart, 2 ).
799 EqualsAscii( "##" ))
801 m_aCurToken.eType = TDPOUND;
802 m_aCurToken.cMathChar = '\0';
803 m_aCurToken.nGroup = 0;
804 m_aCurToken.nLevel = 0;
805 m_aCurToken.aText = "##";
807 rnEndPos = nRealStart + 2;
809 else
811 m_aCurToken.eType = TPOUND;
812 m_aCurToken.cMathChar = '\0';
813 m_aCurToken.nGroup = 0;
814 m_aCurToken.nLevel = 0;
815 m_aCurToken.aText = "#";
818 break;
819 case '&':
821 m_aCurToken.eType = TAND;
822 m_aCurToken.cMathChar = MS_AND;
823 m_aCurToken.nGroup = TGPRODUCT;
824 m_aCurToken.nLevel = 0;
825 m_aCurToken.aText = "&";
827 break;
828 case '(':
830 m_aCurToken.eType = TLPARENT;
831 m_aCurToken.cMathChar = MS_LPARENT;
832 m_aCurToken.nGroup = TGLBRACES;
833 m_aCurToken.nLevel = 5; //! 0 to continue expression
834 m_aCurToken.aText = "(";
836 break;
837 case ')':
839 m_aCurToken.eType = TRPARENT;
840 m_aCurToken.cMathChar = MS_RPARENT;
841 m_aCurToken.nGroup = TGRBRACES;
842 m_aCurToken.nLevel = 0; //! 0 to terminate expression
843 m_aCurToken.aText = ")";
845 break;
846 case '*':
848 m_aCurToken.eType = TMULTIPLY;
849 m_aCurToken.cMathChar = MS_MULTIPLY;
850 m_aCurToken.nGroup = TGPRODUCT;
851 m_aCurToken.nLevel = 0;
852 m_aCurToken.aText = "*";
854 break;
855 case '+':
857 if (m_aBufferString.Copy( nRealStart, 2 ).
858 EqualsAscii( "+-" ))
860 m_aCurToken.eType = TPLUSMINUS;
861 m_aCurToken.cMathChar = MS_PLUSMINUS;
862 m_aCurToken.nGroup = TGUNOPER | TGSUM;
863 m_aCurToken.nLevel = 5;
864 m_aCurToken.aText = "+-";
866 rnEndPos = nRealStart + 2;
868 else
870 m_aCurToken.eType = TPLUS;
871 m_aCurToken.cMathChar = MS_PLUS;
872 m_aCurToken.nGroup = TGUNOPER | TGSUM;
873 m_aCurToken.nLevel = 5;
874 m_aCurToken.aText = "+";
877 break;
878 case '-':
880 if (m_aBufferString.Copy( nRealStart, 2 ).
881 EqualsAscii( "-+" ))
883 m_aCurToken.eType = TMINUSPLUS;
884 m_aCurToken.cMathChar = MS_MINUSPLUS;
885 m_aCurToken.nGroup = TGUNOPER | TGSUM;
886 m_aCurToken.nLevel = 5;
887 m_aCurToken.aText = "-+";
889 rnEndPos = nRealStart + 2;
891 else
893 m_aCurToken.eType = TMINUS;
894 m_aCurToken.cMathChar = MS_MINUS;
895 m_aCurToken.nGroup = TGUNOPER | TGSUM;
896 m_aCurToken.nLevel = 5;
897 m_aCurToken.aText = "-";
900 break;
901 case '.':
903 // for compatibility with SO5.2
904 // texts like .34 ...56 ... h ...78..90
905 // will be treated as numbers
906 m_aCurToken.eType = TNUMBER;
907 m_aCurToken.cMathChar = '\0';
908 m_aCurToken.nGroup = 0;
909 m_aCurToken.nLevel = 5;
911 xub_StrLen nTxtStart = m_nBufferIndex;
912 sal_Unicode cChar;
915 cChar = m_aBufferString.GetChar( ++m_nBufferIndex );
917 while ( cChar == '.' || CharClass::isAsciiDigit( cChar ) );
919 m_aCurToken.aText = m_aBufferString.Copy( sal::static_int_cast< xub_StrLen >(nTxtStart),
920 sal::static_int_cast< xub_StrLen >(m_nBufferIndex - nTxtStart) );
921 aRes.EndPos = m_nBufferIndex;
923 break;
924 case '/':
926 m_aCurToken.eType = TDIVIDEBY;
927 m_aCurToken.cMathChar = MS_SLASH;
928 m_aCurToken.nGroup = TGPRODUCT;
929 m_aCurToken.nLevel = 0;
930 m_aCurToken.aText = "/";
932 break;
933 case '=':
935 m_aCurToken.eType = TASSIGN;
936 m_aCurToken.cMathChar = MS_ASSIGN;
937 m_aCurToken.nGroup = TGRELATION;
938 m_aCurToken.nLevel = 0;
939 m_aCurToken.aText = "=";
941 break;
942 default:
943 bHandled = false;
947 else
948 bHandled = false;
950 if (!bHandled)
952 m_aCurToken.eType = TCHARACTER;
953 m_aCurToken.cMathChar = '\0';
954 m_aCurToken.nGroup = 0;
955 m_aCurToken.nLevel = 5;
956 m_aCurToken.aText = m_aBufferString.Copy( nRealStart, 1 );
958 aRes.EndPos = nRealStart + 1;
961 if (TEND != m_aCurToken.eType)
962 m_nBufferIndex = sal::static_int_cast< xub_StrLen >(aRes.EndPos);
966 ////////////////////////////////////////
967 // grammar
971 void SmParser::Table()
973 SmNodeArray LineArray;
975 Line();
976 while (m_aCurToken.eType == TNEWLINE)
978 NextToken();
979 Line();
982 if (m_aCurToken.eType != TEND)
983 Error(PE_UNEXPECTED_CHAR);
985 sal_uLong n = m_aNodeStack.size();
987 LineArray.resize(n);
989 for (sal_uLong i = 0; i < n; i++)
991 LineArray[n - (i + 1)] = m_aNodeStack.top();
992 m_aNodeStack.pop();
995 SmStructureNode *pSNode = new SmTableNode(m_aCurToken);
996 pSNode->SetSubNodes(LineArray);
997 m_aNodeStack.push(pSNode);
1001 void SmParser::Align()
1002 // parse alignment info (if any), then go on with rest of expression
1004 SmStructureNode *pSNode = 0;
1005 bool bNeedGroupClose = false;
1007 if (TokenInGroup(TGALIGN))
1009 if (CONVERT_40_TO_50 == GetConversion())
1010 // encapsulate expression to be aligned in group braces
1011 // (here group-open brace)
1012 { Insert(OUString('{'), GetTokenIndex());
1013 bNeedGroupClose = true;
1015 // get first valid align statement in sequence
1016 // (the dominant one in 4.0) and erase all others (especially old
1017 // discarded tokens) from command string.
1018 while (TokenInGroup(TGALIGN))
1020 if (TokenInGroup(TGDISCARDED) || pSNode)
1022 m_nBufferIndex = GetTokenIndex();
1023 m_aBufferString.Erase(m_nBufferIndex, m_aCurToken.aText.getLength());
1025 else
1026 pSNode = new SmAlignNode(m_aCurToken);
1028 NextToken();
1031 else
1033 pSNode = new SmAlignNode(m_aCurToken);
1035 NextToken();
1037 // allow for just one align statement in 5.0
1038 if (CONVERT_40_TO_50 != GetConversion() && TokenInGroup(TGALIGN))
1040 Error(PE_DOUBLE_ALIGN);
1041 delete pSNode;
1042 return;
1047 Expression();
1049 if (bNeedGroupClose)
1050 Insert(OUString('}'), GetTokenIndex());
1052 if (pSNode)
1054 pSNode->SetSubNodes(lcl_popOrZero(m_aNodeStack), 0);
1055 m_aNodeStack.push(pSNode);
1060 void SmParser::Line()
1062 sal_uInt16 n = 0;
1063 SmNodeArray ExpressionArray;
1065 ExpressionArray.resize(n);
1067 // start with single expression that may have an alignment statement
1068 // (and go on with expressions that must not have alignment
1069 // statements in 'while' loop below. See also 'Expression()'.)
1070 if (m_aCurToken.eType != TEND && m_aCurToken.eType != TNEWLINE)
1071 { Align();
1072 ExpressionArray.resize(++n);
1073 ExpressionArray[n - 1] = lcl_popOrZero(m_aNodeStack);
1076 while (m_aCurToken.eType != TEND && m_aCurToken.eType != TNEWLINE)
1077 { if (CONVERT_40_TO_50 != GetConversion())
1078 Expression();
1079 else
1080 Align();
1081 ExpressionArray.resize(++n);
1082 ExpressionArray[n - 1] = lcl_popOrZero(m_aNodeStack);
1085 //If there's no expression, add an empty one.
1086 //this is to avoid a formula tree without any caret
1087 //positions, in visual formula editor.
1088 if(ExpressionArray.empty())
1089 ExpressionArray.push_back(new SmExpressionNode(SmToken()));
1091 SmStructureNode *pSNode = new SmLineNode(m_aCurToken);
1092 pSNode->SetSubNodes(ExpressionArray);
1093 m_aNodeStack.push(pSNode);
1097 void SmParser::Expression()
1099 bool bUseExtraSpaces = true;
1100 if (!m_aNodeStack.empty())
1102 SmNode *pNode = m_aNodeStack.top();
1103 m_aNodeStack.pop();
1104 if (pNode->GetToken().eType == TNOSPACE)
1105 bUseExtraSpaces = false;
1106 else
1107 m_aNodeStack.push(pNode); // push the node from above again (now to be used as argument to this current 'nospace' node)
1110 sal_uInt16 n = 0;
1111 SmNodeArray RelationArray;
1113 RelationArray.resize(n);
1115 Relation();
1116 RelationArray.resize(++n);
1117 RelationArray[n - 1] = lcl_popOrZero(m_aNodeStack);
1119 while (m_aCurToken.nLevel >= 4)
1120 { Relation();
1121 RelationArray.resize(++n);
1122 RelationArray[n - 1] = lcl_popOrZero(m_aNodeStack);
1125 SmExpressionNode *pSNode = new SmExpressionNode(m_aCurToken);
1126 pSNode->SetSubNodes(RelationArray);
1127 pSNode->SetUseExtraSpaces(bUseExtraSpaces);
1128 m_aNodeStack.push(pSNode);
1132 void SmParser::Relation()
1134 Sum();
1135 while (TokenInGroup(TGRELATION))
1137 SmStructureNode *pSNode = new SmBinHorNode(m_aCurToken);
1138 SmNode *pFirst = lcl_popOrZero(m_aNodeStack);
1140 OpSubSup();
1141 SmNode *pSecond = lcl_popOrZero(m_aNodeStack);
1143 Sum();
1145 pSNode->SetSubNodes(pFirst, pSecond, lcl_popOrZero(m_aNodeStack));
1146 m_aNodeStack.push(pSNode);
1151 void SmParser::Sum()
1153 Product();
1154 while (TokenInGroup(TGSUM))
1156 SmStructureNode *pSNode = new SmBinHorNode(m_aCurToken);
1157 SmNode *pFirst = lcl_popOrZero(m_aNodeStack);
1159 OpSubSup();
1160 SmNode *pSecond = lcl_popOrZero(m_aNodeStack);
1162 Product();
1164 pSNode->SetSubNodes(pFirst, pSecond, lcl_popOrZero(m_aNodeStack));
1165 m_aNodeStack.push(pSNode);
1170 void SmParser::Product()
1172 Power();
1174 while (TokenInGroup(TGPRODUCT))
1175 { SmStructureNode *pSNode;
1176 SmNode *pFirst = lcl_popOrZero(m_aNodeStack),
1177 *pOper;
1178 bool bSwitchArgs = false;
1180 SmTokenType eType = m_aCurToken.eType;
1181 switch (eType)
1183 case TOVER:
1184 pSNode = new SmBinVerNode(m_aCurToken);
1185 pOper = new SmRectangleNode(m_aCurToken);
1186 NextToken();
1187 break;
1189 case TBOPER:
1190 pSNode = new SmBinHorNode(m_aCurToken);
1192 NextToken();
1194 //Let the glyph node know it's a binary operation
1195 m_aCurToken.eType = TBOPER;
1196 m_aCurToken.nGroup = TGPRODUCT;
1198 GlyphSpecial();
1199 pOper = lcl_popOrZero(m_aNodeStack);
1200 break;
1202 case TOVERBRACE :
1203 case TUNDERBRACE :
1204 pSNode = new SmVerticalBraceNode(m_aCurToken);
1205 pOper = new SmMathSymbolNode(m_aCurToken);
1207 NextToken();
1208 break;
1210 case TWIDEBACKSLASH:
1211 case TWIDESLASH:
1213 SmBinDiagonalNode *pSTmp = new SmBinDiagonalNode(m_aCurToken);
1214 pSTmp->SetAscending(eType == TWIDESLASH);
1215 pSNode = pSTmp;
1217 pOper = new SmPolyLineNode(m_aCurToken);
1218 NextToken();
1220 bSwitchArgs = true;
1221 break;
1224 default:
1225 pSNode = new SmBinHorNode(m_aCurToken);
1227 OpSubSup();
1228 pOper = lcl_popOrZero(m_aNodeStack);
1231 Power();
1233 if (bSwitchArgs)
1235 //! vgl siehe SmBinDiagonalNode::Arrange
1236 pSNode->SetSubNodes(pFirst, lcl_popOrZero(m_aNodeStack), pOper);
1238 else
1240 pSNode->SetSubNodes(pFirst, pOper, lcl_popOrZero(m_aNodeStack));
1242 m_aNodeStack.push(pSNode);
1247 void SmParser::SubSup(sal_uLong nActiveGroup)
1249 OSL_ENSURE(nActiveGroup == TGPOWER || nActiveGroup == TGLIMIT,
1250 "Sm: wrong token group");
1252 if (!TokenInGroup(nActiveGroup))
1253 // already finish
1254 return;
1256 SmSubSupNode *pNode = new SmSubSupNode(m_aCurToken);
1257 //! Of course 'm_aCurToken' is just the first sub-/supscript token.
1258 //! It should be of no further interest. The positions of the
1259 //! sub-/supscripts will be identified by the corresponding subnodes
1260 //! index in the 'aSubNodes' array (enum value from 'SmSubSup').
1262 pNode->SetUseLimits(nActiveGroup == TGLIMIT);
1264 // initialize subnodes array
1265 SmNodeArray aSubNodes;
1266 aSubNodes.resize(1 + SUBSUP_NUM_ENTRIES);
1267 aSubNodes[0] = lcl_popOrZero(m_aNodeStack);
1268 for (sal_uInt16 i = 1; i < aSubNodes.size(); i++)
1269 aSubNodes[i] = NULL;
1271 // process all sub-/supscripts
1272 int nIndex = 0;
1273 while (TokenInGroup(nActiveGroup))
1274 { SmTokenType eType (m_aCurToken.eType);
1276 // skip sub-/supscript token
1277 NextToken();
1279 // get sub-/supscript node on top of stack
1280 if (eType == TFROM || eType == TTO)
1282 // parse limits in old 4.0 and 5.0 style
1283 Relation();
1285 else
1286 Term();
1288 switch (eType)
1289 { case TRSUB : nIndex = (int) RSUB; break;
1290 case TRSUP : nIndex = (int) RSUP; break;
1291 case TFROM :
1292 case TCSUB : nIndex = (int) CSUB; break;
1293 case TTO :
1294 case TCSUP : nIndex = (int) CSUP; break;
1295 case TLSUB : nIndex = (int) LSUB; break;
1296 case TLSUP : nIndex = (int) LSUP; break;
1297 default :
1298 OSL_FAIL("Sm: unknown case");
1300 nIndex++;
1301 OSL_ENSURE(1 <= nIndex && nIndex <= 1 + SUBSUP_NUM_ENTRIES,
1302 "SmParser::Power() : sub-/supscript index falsch");
1304 // set sub-/supscript if not already done
1305 if (aSubNodes[nIndex] != NULL)
1306 Error(PE_DOUBLE_SUBSUPSCRIPT);
1307 aSubNodes[nIndex] = lcl_popOrZero(m_aNodeStack);
1310 pNode->SetSubNodes(aSubNodes);
1311 m_aNodeStack.push(pNode);
1315 void SmParser::OpSubSup()
1317 // push operator symbol
1318 m_aNodeStack.push(new SmMathSymbolNode(m_aCurToken));
1319 // skip operator token
1320 NextToken();
1321 // get sub- supscripts if any
1322 if (TokenInGroup(TGPOWER))
1323 SubSup(TGPOWER);
1327 void SmParser::Power()
1329 // get body for sub- supscripts on top of stack
1330 Term();
1332 SubSup(TGPOWER);
1336 void SmParser::Blank()
1338 OSL_ENSURE(TokenInGroup(TGBLANK), "Sm : wrong token");
1339 SmBlankNode *pBlankNode = new SmBlankNode(m_aCurToken);
1341 while (TokenInGroup(TGBLANK))
1343 pBlankNode->IncreaseBy(m_aCurToken);
1344 NextToken();
1347 // Blanks am Zeilenende ignorieren wenn die entsprechende Option gesetzt ist
1348 if ( m_aCurToken.eType == TNEWLINE ||
1349 (m_aCurToken.eType == TEND && SM_MOD()->GetConfig()->IsIgnoreSpacesRight()) )
1351 pBlankNode->Clear();
1354 m_aNodeStack.push(pBlankNode);
1358 void SmParser::Term()
1360 switch (m_aCurToken.eType)
1362 case TESCAPE :
1363 Escape();
1364 break;
1366 case TNOSPACE :
1367 case TLGROUP :
1369 bool bNoSpace = m_aCurToken.eType == TNOSPACE;
1370 if (bNoSpace) // push 'no space' node and continue to parse expression
1372 m_aNodeStack.push(new SmExpressionNode(m_aCurToken));
1373 NextToken();
1375 if (m_aCurToken.eType != TLGROUP)
1377 m_aNodeStack.pop(); // get rid of the 'no space' node pushed above
1378 Term();
1380 else
1382 NextToken();
1384 // allow for empty group
1385 if (m_aCurToken.eType == TRGROUP)
1387 if (bNoSpace) // get rid of the 'no space' node pushed above
1388 m_aNodeStack.pop();
1389 SmStructureNode *pSNode = new SmExpressionNode(m_aCurToken);
1390 pSNode->SetSubNodes(NULL, NULL);
1391 m_aNodeStack.push(pSNode);
1393 NextToken();
1395 else // go as usual
1397 Align();
1398 if (m_aCurToken.eType != TRGROUP)
1399 Error(PE_RGROUP_EXPECTED);
1400 else
1401 NextToken();
1405 break;
1407 case TLEFT :
1408 Brace();
1409 break;
1411 case TBLANK :
1412 case TSBLANK :
1413 Blank();
1414 break;
1416 case TTEXT :
1417 m_aNodeStack.push(new SmTextNode(m_aCurToken, FNT_TEXT));
1418 NextToken();
1419 break;
1420 case TIDENT :
1421 case TCHARACTER :
1422 m_aNodeStack.push(new SmTextNode(m_aCurToken, FNT_VARIABLE));
1423 NextToken();
1424 break;
1425 case TNUMBER :
1426 m_aNodeStack.push(new SmTextNode(m_aCurToken, FNT_NUMBER));
1427 NextToken();
1428 break;
1430 case TLEFTARROW :
1431 case TRIGHTARROW :
1432 case TUPARROW :
1433 case TDOWNARROW :
1434 case TSETN :
1435 case TSETZ :
1436 case TSETQ :
1437 case TSETR :
1438 case TSETC :
1439 case THBAR :
1440 case TLAMBDABAR :
1441 case TCIRC :
1442 case TDRARROW :
1443 case TDLARROW :
1444 case TDLRARROW :
1445 case TBACKEPSILON :
1446 case TALEPH :
1447 case TIM :
1448 case TRE :
1449 case TWP :
1450 case TEMPTYSET :
1451 case TINFINITY :
1452 case TEXISTS :
1453 case TNOTEXISTS :
1454 case TFORALL :
1455 case TPARTIAL :
1456 case TNABLA :
1457 case TTOWARD :
1458 case TDOTSAXIS :
1459 case TDOTSDIAG :
1460 case TDOTSDOWN :
1461 case TDOTSLOW :
1462 case TDOTSUP :
1463 case TDOTSVERT :
1464 m_aNodeStack.push(new SmMathSymbolNode(m_aCurToken));
1465 NextToken();
1466 break;
1468 case TPLACE:
1469 m_aNodeStack.push(new SmPlaceNode(m_aCurToken));
1470 NextToken();
1471 break;
1473 case TSPECIAL:
1474 Special();
1475 break;
1477 case TBINOM:
1478 Binom();
1479 break;
1481 case TSTACK:
1482 Stack();
1483 break;
1485 case TMATRIX:
1486 Matrix();
1487 break;
1489 default:
1490 if (TokenInGroup(TGLBRACES))
1491 { Brace();
1493 else if (TokenInGroup(TGOPER))
1494 { Operator();
1496 else if (TokenInGroup(TGUNOPER))
1497 { UnOper();
1499 else if ( TokenInGroup(TGATTRIBUT)
1500 || TokenInGroup(TGFONTATTR))
1501 { SmStructureNodeArray aArray;
1503 bool bIsAttr;
1504 sal_uInt16 n = 0;
1505 while (true == (bIsAttr = TokenInGroup(TGATTRIBUT))
1506 || TokenInGroup(TGFONTATTR))
1507 { aArray.resize(n + 1);
1509 if (bIsAttr)
1510 Attribut();
1511 else
1512 FontAttribut();
1514 SmNode* pTmp = lcl_popOrZero(m_aNodeStack);
1516 // check if casting in following line is ok
1517 OSL_ENSURE(pTmp && !pTmp->IsVisible(), "Sm : Ooops...");
1519 aArray[n] = (SmStructureNode *) pTmp;
1520 n++;
1523 Power();
1525 SmNode *pFirstNode = lcl_popOrZero(m_aNodeStack);
1526 while (n > 0)
1527 { aArray[n - 1]->SetSubNodes(0, pFirstNode);
1528 pFirstNode = aArray[n - 1];
1529 n--;
1531 m_aNodeStack.push(pFirstNode);
1533 else if (TokenInGroup(TGFUNCTION))
1534 { if (CONVERT_40_TO_50 != GetConversion())
1535 { Function();
1537 else // encapsulate old 4.0 style parsing in braces
1539 // insert opening brace
1540 Insert(OUString('{'), GetTokenIndex());
1543 // parse in 4.0 style
1545 Function();
1547 SmNode *pFunc = lcl_popOrZero(m_aNodeStack);
1549 if (m_aCurToken.eType == TLPARENT)
1550 { Term();
1552 else
1553 { Align();
1556 // insert closing brace
1557 Insert(OUString('}'), GetTokenIndex());
1559 SmStructureNode *pSNode = new SmExpressionNode(pFunc->GetToken());
1560 pSNode->SetSubNodes(pFunc, lcl_popOrZero(m_aNodeStack));
1561 m_aNodeStack.push(pSNode);
1564 else
1565 Error(PE_UNEXPECTED_CHAR);
1570 void SmParser::Escape()
1572 NextToken();
1574 switch (m_aCurToken.eType)
1576 case TLPARENT :
1577 case TRPARENT :
1578 case TLBRACKET :
1579 case TRBRACKET :
1580 case TLDBRACKET :
1581 case TRDBRACKET :
1582 case TLBRACE :
1583 case TLGROUP :
1584 case TRBRACE :
1585 case TRGROUP :
1586 case TLANGLE :
1587 case TRANGLE :
1588 case TLCEIL :
1589 case TRCEIL :
1590 case TLFLOOR :
1591 case TRFLOOR :
1592 case TLLINE :
1593 case TRLINE :
1594 case TLDLINE :
1595 case TRDLINE :
1596 break;
1597 default:
1598 Error(PE_UNEXPECTED_TOKEN);
1601 SmNode *pNode = new SmMathSymbolNode(m_aCurToken);
1602 m_aNodeStack.push(pNode);
1604 NextToken();
1608 void SmParser::Operator()
1610 if (TokenInGroup(TGOPER))
1611 { SmStructureNode *pSNode = new SmOperNode(m_aCurToken);
1613 // put operator on top of stack
1614 Oper();
1616 if (TokenInGroup(TGLIMIT) || TokenInGroup(TGPOWER))
1617 SubSup(m_aCurToken.nGroup);
1618 SmNode *pOperator = lcl_popOrZero(m_aNodeStack);
1620 // get argument
1621 Power();
1623 pSNode->SetSubNodes(pOperator, lcl_popOrZero(m_aNodeStack));
1624 m_aNodeStack.push(pSNode);
1629 void SmParser::Oper()
1631 SmTokenType eType (m_aCurToken.eType);
1632 SmNode *pNode = NULL;
1634 switch (eType)
1636 case TSUM :
1637 case TPROD :
1638 case TCOPROD :
1639 case TINT :
1640 case TIINT :
1641 case TIIINT :
1642 case TLINT :
1643 case TLLINT :
1644 case TLLLINT :
1645 pNode = new SmMathSymbolNode(m_aCurToken);
1646 break;
1648 case TLIM :
1649 case TLIMSUP :
1650 case TLIMINF :
1652 const sal_Char* pLim = 0;
1653 switch (eType)
1655 case TLIM : pLim = "lim"; break;
1656 case TLIMSUP : pLim = "lim sup"; break;
1657 case TLIMINF : pLim = "lim inf"; break;
1658 default:
1659 break;
1661 if( pLim )
1662 m_aCurToken.aText = OUString::createFromAscii(pLim);
1663 pNode = new SmTextNode(m_aCurToken, FNT_TEXT);
1665 break;
1667 case TOVERBRACE :
1668 case TUNDERBRACE :
1669 pNode = new SmMathSymbolNode(m_aCurToken);
1670 break;
1672 case TOPER :
1673 NextToken();
1675 OSL_ENSURE(m_aCurToken.eType == TSPECIAL, "Sm: wrong token");
1676 pNode = new SmGlyphSpecialNode(m_aCurToken);
1677 break;
1679 default :
1680 OSL_FAIL("Sm: unknown case");
1682 m_aNodeStack.push(pNode);
1684 NextToken();
1688 void SmParser::UnOper()
1690 OSL_ENSURE(TokenInGroup(TGUNOPER), "Sm: wrong token");
1692 SmToken aNodeToken = m_aCurToken;
1693 SmTokenType eType = m_aCurToken.eType;
1694 bool bIsPostfix = eType == TFACT;
1696 SmStructureNode *pSNode;
1697 SmNode *pOper = 0,
1698 *pExtra = 0,
1699 *pArg;
1701 switch (eType)
1703 case TABS :
1704 case TSQRT :
1705 NextToken();
1706 break;
1708 case TNROOT :
1709 NextToken();
1710 Power();
1711 pExtra = lcl_popOrZero(m_aNodeStack);
1712 break;
1714 case TUOPER :
1715 NextToken();
1716 //Let the glyph know what it is...
1717 m_aCurToken.eType = TUOPER;
1718 m_aCurToken.nGroup = TGUNOPER;
1719 GlyphSpecial();
1720 pOper = lcl_popOrZero(m_aNodeStack);
1721 break;
1723 case TPLUS :
1724 case TMINUS :
1725 case TPLUSMINUS :
1726 case TMINUSPLUS :
1727 case TNEG :
1728 case TFACT :
1729 OpSubSup();
1730 pOper = lcl_popOrZero(m_aNodeStack);
1731 break;
1733 default :
1734 Error(PE_UNOPER_EXPECTED);
1737 // get argument
1738 Power();
1739 pArg = lcl_popOrZero(m_aNodeStack);
1741 if (eType == TABS)
1742 { pSNode = new SmBraceNode(aNodeToken);
1743 pSNode->SetScaleMode(SCALE_HEIGHT);
1745 // build nodes for left & right lines
1746 // (text, group, level of the used token are of no interrest here)
1747 // we'll use row & column of the keyword for abs
1748 aNodeToken.eType = TABS;
1750 aNodeToken.cMathChar = MS_LINE;
1751 SmNode* pLeft = new SmMathSymbolNode(aNodeToken);
1753 aNodeToken.cMathChar = MS_LINE;
1754 SmNode* pRight = new SmMathSymbolNode(aNodeToken);
1756 pSNode->SetSubNodes(pLeft, pArg, pRight);
1758 else if (eType == TSQRT || eType == TNROOT)
1759 { pSNode = new SmRootNode(aNodeToken);
1760 pOper = new SmRootSymbolNode(aNodeToken);
1761 pSNode->SetSubNodes(pExtra, pOper, pArg);
1763 else
1764 { pSNode = new SmUnHorNode(aNodeToken);
1766 if (bIsPostfix)
1767 pSNode->SetSubNodes(pArg, pOper);
1768 else
1769 // prefix operator
1770 pSNode->SetSubNodes(pOper, pArg);
1773 m_aNodeStack.push(pSNode);
1777 void SmParser::Attribut()
1779 OSL_ENSURE(TokenInGroup(TGATTRIBUT), "Sm: wrong token group");
1781 SmStructureNode *pSNode = new SmAttributNode(m_aCurToken);
1782 SmNode *pAttr;
1783 SmScaleMode eScaleMode = SCALE_NONE;
1785 // get appropriate node for the attribut itself
1786 switch (m_aCurToken.eType)
1787 { case TUNDERLINE :
1788 case TOVERLINE :
1789 case TOVERSTRIKE :
1790 pAttr = new SmRectangleNode(m_aCurToken);
1791 eScaleMode = SCALE_WIDTH;
1792 break;
1794 case TWIDEVEC :
1795 case TWIDEHAT :
1796 case TWIDETILDE :
1797 pAttr = new SmMathSymbolNode(m_aCurToken);
1798 eScaleMode = SCALE_WIDTH;
1799 break;
1801 default :
1802 pAttr = new SmMathSymbolNode(m_aCurToken);
1805 NextToken();
1807 pSNode->SetSubNodes(pAttr, 0);
1808 pSNode->SetScaleMode(eScaleMode);
1809 m_aNodeStack.push(pSNode);
1813 void SmParser::FontAttribut()
1815 OSL_ENSURE(TokenInGroup(TGFONTATTR), "Sm: wrong token group");
1817 switch (m_aCurToken.eType)
1819 case TITALIC :
1820 case TNITALIC :
1821 case TBOLD :
1822 case TNBOLD :
1823 case TPHANTOM :
1824 m_aNodeStack.push(new SmFontNode(m_aCurToken));
1825 NextToken();
1826 break;
1828 case TSIZE :
1829 FontSize();
1830 break;
1832 case TFONT :
1833 Font();
1834 break;
1836 case TCOLOR :
1837 Color();
1838 break;
1840 default :
1841 OSL_FAIL("Sm: unknown case");
1846 void SmParser::Color()
1848 OSL_ENSURE(m_aCurToken.eType == TCOLOR, "Sm : Ooops...");
1850 // last color rules, get that one
1851 SmToken aToken;
1853 { NextToken();
1855 if (TokenInGroup(TGCOLOR))
1856 { aToken = m_aCurToken;
1857 NextToken();
1859 else
1860 Error(PE_COLOR_EXPECTED);
1861 } while (m_aCurToken.eType == TCOLOR);
1863 m_aNodeStack.push(new SmFontNode(aToken));
1867 void SmParser::Font()
1869 OSL_ENSURE(m_aCurToken.eType == TFONT, "Sm : Ooops...");
1871 // last font rules, get that one
1872 SmToken aToken;
1874 { NextToken();
1876 if (TokenInGroup(TGFONT))
1877 { aToken = m_aCurToken;
1878 NextToken();
1880 else
1881 Error(PE_FONT_EXPECTED);
1882 } while (m_aCurToken.eType == TFONT);
1884 m_aNodeStack.push(new SmFontNode(aToken));
1888 // gets number used as arguments in Math formulas (e.g. 'size' command)
1889 // Format: no negative numbers, must start with a digit, no exponent notation, ...
1890 static bool lcl_IsNumber(const OUString& rText)
1892 bool bPoint = false;
1893 const sal_Unicode* pBuffer = rText.getStr();
1894 for(sal_Int32 nPos = 0; nPos < rText.getLength(); nPos++, pBuffer++)
1896 const sal_Unicode cChar = *pBuffer;
1897 if(cChar == '.')
1899 if(bPoint)
1900 return false;
1901 else
1902 bPoint = true;
1904 else if ( !CharClass::isAsciiDigit( cChar ) )
1905 return false;
1907 return true;
1910 void SmParser::FontSize()
1912 OSL_ENSURE(m_aCurToken.eType == TSIZE, "Sm : Ooops...");
1914 sal_uInt16 Type;
1915 SmFontNode *pFontNode = new SmFontNode(m_aCurToken);
1917 NextToken();
1919 switch (m_aCurToken.eType)
1921 case TNUMBER: Type = FNTSIZ_ABSOLUT; break;
1922 case TPLUS: Type = FNTSIZ_PLUS; break;
1923 case TMINUS: Type = FNTSIZ_MINUS; break;
1924 case TMULTIPLY: Type = FNTSIZ_MULTIPLY; break;
1925 case TDIVIDEBY: Type = FNTSIZ_DIVIDE; break;
1927 default:
1928 delete pFontNode;
1929 Error(PE_SIZE_EXPECTED);
1930 return;
1933 if (Type != FNTSIZ_ABSOLUT)
1935 NextToken();
1936 if (m_aCurToken.eType != TNUMBER)
1938 delete pFontNode;
1939 Error(PE_SIZE_EXPECTED);
1940 return;
1944 // get number argument
1945 Fraction aValue( 1L );
1946 if (lcl_IsNumber( m_aCurToken.aText ))
1948 double fTmp = OUString(m_aCurToken.aText).toDouble();
1949 if (fTmp != 0.0)
1951 aValue = fTmp;
1953 //!! keep the numerator and denominator from being to large
1954 //!! otherwise ongoing multiplications may result in overflows
1955 //!! (for example in SmNode::SetFontSize the font size calculated
1956 //!! may become 0 because of this!!! Happens e.g. for ftmp = 2.9 with Linux
1957 //!! or ftmp = 1.11111111111111111... (11/9) on every platform.)
1958 if (aValue.GetDenominator() > 1000)
1960 long nNum = aValue.GetNumerator();
1961 long nDenom = aValue.GetDenominator();
1962 while (nDenom > 1000)
1964 nNum /= 10;
1965 nDenom /= 10;
1967 aValue = Fraction( nNum, nDenom );
1972 NextToken();
1974 pFontNode->SetSizeParameter(aValue, Type);
1975 m_aNodeStack.push(pFontNode);
1979 void SmParser::Brace()
1981 OSL_ENSURE(m_aCurToken.eType == TLEFT || TokenInGroup(TGLBRACES),
1982 "Sm: kein Klammer Ausdruck");
1984 SmStructureNode *pSNode = new SmBraceNode(m_aCurToken);
1985 SmNode *pBody = 0,
1986 *pLeft = 0,
1987 *pRight = 0;
1988 SmScaleMode eScaleMode = SCALE_NONE;
1989 SmParseError eError = PE_NONE;
1991 if (m_aCurToken.eType == TLEFT)
1992 { NextToken();
1994 eScaleMode = SCALE_HEIGHT;
1996 // check for left bracket
1997 if (TokenInGroup(TGLBRACES) || TokenInGroup(TGRBRACES))
1999 pLeft = new SmMathSymbolNode(m_aCurToken);
2001 NextToken();
2002 Bracebody(true);
2003 pBody = lcl_popOrZero(m_aNodeStack);
2005 if (m_aCurToken.eType == TRIGHT)
2006 { NextToken();
2008 // check for right bracket
2009 if (TokenInGroup(TGLBRACES) || TokenInGroup(TGRBRACES))
2011 pRight = new SmMathSymbolNode(m_aCurToken);
2012 NextToken();
2014 else
2015 eError = PE_RBRACE_EXPECTED;
2017 else
2018 eError = PE_RIGHT_EXPECTED;
2020 else
2021 eError = PE_LBRACE_EXPECTED;
2023 else
2025 if (TokenInGroup(TGLBRACES))
2027 pLeft = new SmMathSymbolNode(m_aCurToken);
2029 NextToken();
2030 Bracebody(false);
2031 pBody = lcl_popOrZero(m_aNodeStack);
2033 SmTokenType eExpectedType = TUNKNOWN;
2034 switch (pLeft->GetToken().eType)
2035 { case TLPARENT : eExpectedType = TRPARENT; break;
2036 case TLBRACKET : eExpectedType = TRBRACKET; break;
2037 case TLBRACE : eExpectedType = TRBRACE; break;
2038 case TLDBRACKET : eExpectedType = TRDBRACKET; break;
2039 case TLLINE : eExpectedType = TRLINE; break;
2040 case TLDLINE : eExpectedType = TRDLINE; break;
2041 case TLANGLE : eExpectedType = TRANGLE; break;
2042 case TLFLOOR : eExpectedType = TRFLOOR; break;
2043 case TLCEIL : eExpectedType = TRCEIL; break;
2044 default :
2045 OSL_FAIL("Sm: unknown case");
2048 if (m_aCurToken.eType == eExpectedType)
2050 pRight = new SmMathSymbolNode(m_aCurToken);
2051 NextToken();
2053 else
2054 eError = PE_PARENT_MISMATCH;
2056 else
2057 eError = PE_LBRACE_EXPECTED;
2060 if (eError == PE_NONE)
2061 { OSL_ENSURE(pLeft, "Sm: NULL pointer");
2062 OSL_ENSURE(pRight, "Sm: NULL pointer");
2063 pSNode->SetSubNodes(pLeft, pBody, pRight);
2064 pSNode->SetScaleMode(eScaleMode);
2065 m_aNodeStack.push(pSNode);
2067 else
2068 { delete pSNode;
2069 delete pBody;
2070 delete pLeft;
2071 delete pRight;
2073 Error(eError);
2078 void SmParser::Bracebody(bool bIsLeftRight)
2080 SmStructureNode *pBody = new SmBracebodyNode(m_aCurToken);
2081 SmNodeArray aNodes;
2082 sal_uInt16 nNum = 0;
2084 // get body if any
2085 if (bIsLeftRight)
2089 if (m_aCurToken.eType == TMLINE)
2091 m_aNodeStack.push(new SmMathSymbolNode(m_aCurToken));
2092 NextToken();
2093 nNum++;
2095 else if (m_aCurToken.eType != TRIGHT)
2096 { Align();
2097 nNum++;
2099 if (m_aCurToken.eType != TMLINE && m_aCurToken.eType != TRIGHT)
2100 Error(PE_RIGHT_EXPECTED);
2102 } while (m_aCurToken.eType != TEND && m_aCurToken.eType != TRIGHT);
2104 else
2108 if (m_aCurToken.eType == TMLINE)
2110 m_aNodeStack.push(new SmMathSymbolNode(m_aCurToken));
2111 NextToken();
2112 nNum++;
2114 else if (!TokenInGroup(TGRBRACES))
2115 { Align();
2116 nNum++;
2118 if (m_aCurToken.eType != TMLINE && !TokenInGroup(TGRBRACES))
2119 Error(PE_RBRACE_EXPECTED);
2121 } while (m_aCurToken.eType != TEND && !TokenInGroup(TGRBRACES));
2124 // build argument vector in parsing order
2125 aNodes.resize(nNum);
2126 for (sal_uInt16 i = 0; i < nNum; i++)
2128 aNodes[nNum - 1 - i] = lcl_popOrZero(m_aNodeStack);
2131 pBody->SetSubNodes(aNodes);
2132 pBody->SetScaleMode(bIsLeftRight ? SCALE_HEIGHT : SCALE_NONE);
2133 m_aNodeStack.push(pBody);
2137 void SmParser::Function()
2139 switch (m_aCurToken.eType)
2141 case TFUNC:
2142 NextToken(); // skip "FUNC"-statement
2143 // fall through
2145 case TSIN :
2146 case TCOS :
2147 case TTAN :
2148 case TCOT :
2149 case TASIN :
2150 case TACOS :
2151 case TATAN :
2152 case TACOT :
2153 case TSINH :
2154 case TCOSH :
2155 case TTANH :
2156 case TCOTH :
2157 case TASINH :
2158 case TACOSH :
2159 case TATANH :
2160 case TACOTH :
2161 case TLN :
2162 case TLOG :
2163 case TEXP :
2164 m_aNodeStack.push(new SmTextNode(m_aCurToken, FNT_FUNCTION));
2165 NextToken();
2166 break;
2168 default:
2169 Error(PE_FUNC_EXPECTED);
2174 void SmParser::Binom()
2176 SmNodeArray ExpressionArray;
2177 SmStructureNode *pSNode = new SmTableNode(m_aCurToken);
2179 NextToken();
2181 Sum();
2182 Sum();
2184 ExpressionArray.resize(2);
2186 for (int i = 0; i < 2; i++)
2188 ExpressionArray[2 - (i + 1)] = lcl_popOrZero(m_aNodeStack);
2191 pSNode->SetSubNodes(ExpressionArray);
2192 m_aNodeStack.push(pSNode);
2196 void SmParser::Stack()
2198 SmNodeArray ExpressionArray;
2199 NextToken();
2200 if (m_aCurToken.eType == TLGROUP)
2202 sal_uInt16 n = 0;
2206 NextToken();
2207 Align();
2208 n++;
2210 while (m_aCurToken.eType == TPOUND);
2212 ExpressionArray.resize(n);
2214 for (sal_uInt16 i = 0; i < n; i++)
2216 ExpressionArray[n - (i + 1)] = lcl_popOrZero(m_aNodeStack);
2219 if (m_aCurToken.eType != TRGROUP)
2220 Error(PE_RGROUP_EXPECTED);
2222 NextToken();
2224 //We need to let the table node know it context
2225 //it's used in SmNodeToTextVisitor
2226 SmToken aTok = m_aCurToken;
2227 aTok.eType = TSTACK;
2228 SmStructureNode *pSNode = new SmTableNode(aTok);
2229 pSNode->SetSubNodes(ExpressionArray);
2230 m_aNodeStack.push(pSNode);
2232 else
2233 Error(PE_LGROUP_EXPECTED);
2237 void SmParser::Matrix()
2239 SmNodeArray ExpressionArray;
2241 NextToken();
2242 if (m_aCurToken.eType == TLGROUP)
2244 sal_uInt16 c = 0;
2248 NextToken();
2249 Align();
2250 c++;
2252 while (m_aCurToken.eType == TPOUND);
2254 sal_uInt16 r = 1;
2256 while (m_aCurToken.eType == TDPOUND)
2258 NextToken();
2259 for (sal_uInt16 i = 0; i < c; i++)
2261 Align();
2262 if (i < (c - 1))
2264 if (m_aCurToken.eType == TPOUND)
2266 NextToken();
2268 else
2269 Error(PE_POUND_EXPECTED);
2273 r++;
2276 long nRC = r * c;
2278 ExpressionArray.resize(nRC);
2280 for (sal_uInt16 i = 0; i < (nRC); i++)
2282 ExpressionArray[(nRC) - (i + 1)] = lcl_popOrZero(m_aNodeStack);
2285 if (m_aCurToken.eType != TRGROUP)
2286 Error(PE_RGROUP_EXPECTED);
2288 NextToken();
2290 SmMatrixNode *pMNode = new SmMatrixNode(m_aCurToken);
2291 pMNode->SetSubNodes(ExpressionArray);
2292 pMNode->SetRowCol(r, c);
2293 m_aNodeStack.push(pMNode);
2295 else
2296 Error(PE_LGROUP_EXPECTED);
2300 void SmParser::Special()
2302 bool bReplace = false;
2303 OUString &rName = m_aCurToken.aText;
2304 OUString aNewName;
2306 if (CONVERT_NONE == GetConversion())
2308 // conversion of symbol names for 6.0 (XML) file format
2309 // (name change on import / export.
2310 // UI uses localized names XML file format does not.)
2311 if (!rName.isEmpty() && rName[0] == '%')
2313 if (IsImportSymbolNames())
2315 const SmLocalizedSymbolData &rLSD = SM_MOD()->GetLocSymbolData();
2316 aNewName = rLSD.GetUiSymbolName(rName.copy(1));
2317 bReplace = true;
2319 else if (IsExportSymbolNames())
2321 const SmLocalizedSymbolData &rLSD = SM_MOD()->GetLocSymbolData();
2322 aNewName = rLSD.GetExportSymbolName(rName.copy(1));
2323 bReplace = true;
2326 if (!aNewName.isEmpty())
2327 aNewName = "%" + aNewName;
2329 else // 5.0 <-> 6.0 formula text (symbol name) conversion
2331 LanguageType nLanguage = GetLanguage();
2332 SmLocalizedSymbolData &rData = SM_MOD()->GetLocSymbolData();
2333 const ResStringArray *pFrom = 0;
2334 const ResStringArray *pTo = 0;
2335 if (CONVERT_50_TO_60 == GetConversion())
2337 pFrom = rData.Get50NamesArray( nLanguage );
2338 pTo = rData.Get60NamesArray( nLanguage );
2340 else if (CONVERT_60_TO_50 == GetConversion())
2342 pFrom = rData.Get60NamesArray( nLanguage );
2343 pTo = rData.Get50NamesArray( nLanguage );
2345 if (pFrom && pTo)
2347 OSL_ENSURE( pFrom->Count() == pTo->Count(),
2348 "array length mismatch" );
2349 sal_uInt16 nCount = sal::static_int_cast< sal_uInt16 >(pFrom->Count());
2350 for (sal_uInt16 i = 0; i < nCount; ++i)
2352 if (pFrom->GetString(i).equals(rName))
2354 aNewName = pTo->GetString(i);
2355 bReplace = true;
2359 // else:
2360 // conversion arrays not found or (usually)
2361 // conversion not necessary
2364 if (bReplace && !aNewName.isEmpty() && rName != aNewName)
2366 Replace(GetTokenIndex(), rName.getLength(), aNewName);
2367 rName = aNewName;
2370 // add symbol name to list of used symbols
2371 const OUString aSymbolName(m_aCurToken.aText.copy(1));
2372 if (!aSymbolName.isEmpty())
2373 AddToUsedSymbols( aSymbolName );
2375 m_aNodeStack.push(new SmSpecialNode(m_aCurToken));
2376 NextToken();
2380 void SmParser::GlyphSpecial()
2382 m_aNodeStack.push(new SmGlyphSpecialNode(m_aCurToken));
2383 NextToken();
2387 void SmParser::Error(SmParseError eError)
2389 SmStructureNode *pSNode = new SmExpressionNode(m_aCurToken);
2390 SmErrorNode *pErr = new SmErrorNode(eError, m_aCurToken);
2391 pSNode->SetSubNodes(pErr, 0);
2393 //! put a structure node on the stack (instead of the error node itself)
2394 //! because sometimes such a node is expected in order to attach some
2395 //! subnodes
2396 m_aNodeStack.push(pSNode);
2398 AddError(eError, pSNode);
2400 NextToken();
2404 // end gramar
2407 SmParser::SmParser()
2408 : m_aDotLoc( LanguageTag( LANGUAGE_ENGLISH_US ).getLocale() )
2410 m_eConversion = CONVERT_NONE;
2411 bImportSymNames = m_bExportSymNames = false;
2412 m_nLang = Application::GetSettings().GetUILanguageTag().getLanguageType();
2415 SmNode *SmParser::Parse(const String &rBuffer)
2417 ClearUsedSymbols();
2419 m_aBufferString = convertLineEnd(rBuffer, LINEEND_LF);
2420 m_nBufferIndex = 0;
2421 m_nTokenIndex = 0;
2422 m_Row = 1;
2423 m_nColOff = 0;
2424 m_nCurError = -1;
2426 for ( size_t i = 0, n = m_aErrDescList.size(); i < n; ++i )
2427 delete m_aErrDescList[ i ];
2428 m_aErrDescList.clear();
2430 while ( !m_aNodeStack.empty() )
2431 m_aNodeStack.pop();
2433 SetLanguage( Application::GetSettings().GetUILanguageTag().getLanguageType() );
2434 NextToken();
2435 Table();
2437 SmNode* result = lcl_popOrZero(m_aNodeStack);
2438 return result;
2441 SmNode *SmParser::ParseExpression(const OUString &rBuffer)
2443 m_aBufferString = convertLineEnd(rBuffer, LINEEND_LF);
2444 m_nBufferIndex = 0;
2445 m_nTokenIndex = 0;
2446 m_Row = 1;
2447 m_nColOff = 0;
2448 m_nCurError = -1;
2450 for ( size_t i = 0, n = m_aErrDescList.size(); i < n; ++i )
2451 delete m_aErrDescList[ i ];
2452 m_aErrDescList.clear();
2454 while ( !m_aNodeStack.empty() )
2455 m_aNodeStack.pop();
2457 SetLanguage( Application::GetSettings().GetUILanguageTag().getLanguageType() );
2458 NextToken();
2459 Expression();
2461 SmNode* result = lcl_popOrZero(m_aNodeStack);
2462 return result;
2466 size_t SmParser::AddError(SmParseError Type, SmNode *pNode)
2468 SmErrorDesc *pErrDesc = new SmErrorDesc;
2470 pErrDesc->Type = Type;
2471 pErrDesc->pNode = pNode;
2472 pErrDesc->Text = String(SmResId(RID_ERR_IDENT));
2474 sal_uInt16 nRID;
2475 switch (Type)
2477 case PE_UNEXPECTED_CHAR: nRID = RID_ERR_UNEXPECTEDCHARACTER; break;
2478 case PE_LGROUP_EXPECTED: nRID = RID_ERR_LGROUPEXPECTED; break;
2479 case PE_RGROUP_EXPECTED: nRID = RID_ERR_RGROUPEXPECTED; break;
2480 case PE_LBRACE_EXPECTED: nRID = RID_ERR_LBRACEEXPECTED; break;
2481 case PE_RBRACE_EXPECTED: nRID = RID_ERR_RBRACEEXPECTED; break;
2482 case PE_FUNC_EXPECTED: nRID = RID_ERR_FUNCEXPECTED; break;
2483 case PE_UNOPER_EXPECTED: nRID = RID_ERR_UNOPEREXPECTED; break;
2484 case PE_BINOPER_EXPECTED: nRID = RID_ERR_BINOPEREXPECTED; break;
2485 case PE_SYMBOL_EXPECTED: nRID = RID_ERR_SYMBOLEXPECTED; break;
2486 case PE_IDENTIFIER_EXPECTED: nRID = RID_ERR_IDENTEXPECTED; break;
2487 case PE_POUND_EXPECTED: nRID = RID_ERR_POUNDEXPECTED; break;
2488 case PE_COLOR_EXPECTED: nRID = RID_ERR_COLOREXPECTED; break;
2489 case PE_RIGHT_EXPECTED: nRID = RID_ERR_RIGHTEXPECTED; break;
2491 default:
2492 nRID = RID_ERR_UNKNOWN;
2494 pErrDesc->Text += SM_RESSTR(nRID);
2496 m_aErrDescList.push_back( pErrDesc );
2498 return m_aErrDescList.size()-1;
2502 const SmErrorDesc *SmParser::NextError()
2504 if ( !m_aErrDescList.empty() )
2505 if (m_nCurError > 0) return m_aErrDescList[ --m_nCurError ];
2506 else
2508 m_nCurError = 0;
2509 return m_aErrDescList[ m_nCurError ];
2511 else return NULL;
2515 const SmErrorDesc *SmParser::PrevError()
2517 if ( !m_aErrDescList.empty() )
2518 if (m_nCurError < (int) (m_aErrDescList.size() - 1)) return m_aErrDescList[ ++m_nCurError ];
2519 else
2521 m_nCurError = (int) (m_aErrDescList.size() - 1);
2522 return m_aErrDescList[ m_nCurError ];
2524 else return NULL;
2528 const SmErrorDesc *SmParser::GetError(size_t i)
2530 if ( i < m_aErrDescList.size() )
2531 return m_aErrDescList[ i ];
2533 if ( (size_t)m_nCurError < m_aErrDescList.size() )
2534 return m_aErrDescList[ m_nCurError ];
2536 return NULL;
2539 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */