starmath/Library_sm.mk | 2 starmath/inc/parse.hxx | 181 -- starmath/inc/parse5.hxx | 123 ++ starmath/inc/parsebase.hxx | 122 ++ starmath/source/parse.cxx | 2683 -------------------------------------------- starmath/source/parse5.cxx | 2739 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 2986 insertions(+), 2864 deletions(-)
New commits: commit 1d529ad0bd59cbbf029e45a715db5db87541d5c1 Author: dante <[email protected]> AuthorDate: Fri Feb 19 20:52:30 2021 +0100 Commit: Noel Grandin <[email protected]> CommitDate: Wed Feb 24 09:19:05 2021 +0100 Starmath now allows multiple parsers second part Uses AbstractSmParser as base for SmParser Renames parse._xx as parse5._xx rename of parse._xx is not recognized, so clang-formated New parse.hxx as a future mean to get the parser. Change-Id: I122c1fda0144a24316948fcc125e60ed1a130bcb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111243 Tested-by: Jenkins Reviewed-by: Noel Grandin <[email protected]> diff --git a/starmath/Library_sm.mk b/starmath/Library_sm.mk index 1ccbf48896f7..77fd47d1bfed 100644 --- a/starmath/Library_sm.mk +++ b/starmath/Library_sm.mk @@ -80,7 +80,7 @@ $(eval $(call gb_Library_add_exception_objects,sm,\ starmath/source/ooxmlexport \ starmath/source/ooxmlimport \ starmath/source/rtfexport \ - starmath/source/parse \ + starmath/source/parse5 \ starmath/source/rect \ starmath/source/scrwin \ starmath/source/smdll \ diff --git a/starmath/inc/parse.hxx b/starmath/inc/parse.hxx index 752cde6b23e5..d033faa2bf06 100644 --- a/starmath/inc/parse.hxx +++ b/starmath/inc/parse.hxx @@ -24,186 +24,7 @@ #ifndef INCLUDED_STARMATH_INC_PARSE_HXX #define INCLUDED_STARMATH_INC_PARSE_HXX -#include <unotools/charclass.hxx> -#include <memory> -#include <set> -#include <vector> - -#include "token.hxx" - -class SmBlankNode; -class SmBinVerNode; -class SmBracebodyNode; -class SmExpressionNode; -class SmGlyphSpecialNode; -class SmNode; -class SmOperNode; -class SmSpecialNode; -class SmStructureNode; -class SmTableNode; -class SmTextNode; - -#define DEPTH_LIMIT 1024 - -// Those are the errors that the parser may encounter. -enum class SmParseError : uint_fast8_t -{ - None = 0, - UnexpectedChar = 1, - UnexpectedToken = 2, - PoundExpected = 3, - ColorExpected = 4, - LgroupExpected = 5, - RgroupExpected = 6, - LbraceExpected = 7, - RbraceExpected = 8, - ParentMismatch = 9, - RightExpected = 10, - FontExpected = 11, - SizeExpected = 12, - DoubleAlign = 13, - DoubleSubsupscript = 14, - NumberExpected = 15 -}; - -struct SmErrorDesc -{ - SmParseError m_eType; - SmNode* m_pNode; - OUString m_aText; - - SmErrorDesc(SmParseError eType, SmNode* pNode, OUString aText) - : m_eType(eType) - , m_pNode(pNode) - , m_aText(aText) - {} - -}; - -namespace starmathdatabase{ - -// Must be in sync with SmParseError list -extern const char* SmParseErrorDesc[16]; - -OUString getParseErrorDesc(SmParseError err); - -} - -class SmParser -{ - OUString m_aBufferString; - SmToken m_aCurToken; - std::vector<SmErrorDesc> m_aErrDescList; - int m_nCurError; - sal_Int32 m_nBufferIndex, - m_nTokenIndex; - sal_Int32 m_nRow, // 1-based - m_nColOff; // 0-based - bool m_bImportSymNames, - m_bExportSymNames; - sal_Int32 m_nParseDepth; - - class DepthProtect - { - private: - sal_Int32& m_rParseDepth; - public: - DepthProtect(sal_Int32& rParseDepth) - : m_rParseDepth(rParseDepth) - { - ++m_rParseDepth; - if(m_rParseDepth > DEPTH_LIMIT) - throw std::range_error("parser depth limit"); - } - ~DepthProtect() - { - --m_rParseDepth; - } - }; - - // map of used symbols (used to reduce file size by exporting only actually used symbols) - std::set< OUString > m_aUsedSymbols; - - // CharClass representing a locale for parsing numbers - CharClass m_aNumCC; - // pointer to System locale's CharClass, which is alive inside SM_MOD() - const CharClass* m_pSysCC; - - SmParser(const SmParser&) = delete; - SmParser& operator=(const SmParser&) = delete; - - // Moves between tokens inside starmath code. - void NextToken(); - void NextTokenColor(SmTokenType dvipload); - void NextTokenFontSize(); - sal_Int32 GetTokenIndex() const { return m_nTokenIndex; } - void Replace( sal_Int32 nPos, sal_Int32 nLen, const OUString &rText ); - - inline bool TokenInGroup( TG nGroup ); - - // grammar - std::unique_ptr<SmTableNode> DoTable(); - std::unique_ptr<SmNode> DoLine(); - std::unique_ptr<SmNode> DoExpression(bool bUseExtraSpaces = true); - std::unique_ptr<SmNode> DoRelation(); - std::unique_ptr<SmNode> DoSum(); - std::unique_ptr<SmNode> DoProduct(); - std::unique_ptr<SmNode> DoSubSup(TG nActiveGroup, std::unique_ptr<SmNode> xGivenNode); - std::unique_ptr<SmNode> DoSubSupEvaluate(std::unique_ptr<SmNode> xGivenNode); - std::unique_ptr<SmNode> DoOpSubSup(); - std::unique_ptr<SmNode> DoPower(); - std::unique_ptr<SmBlankNode> DoBlank(); - std::unique_ptr<SmNode> DoTerm(bool bGroupNumberIdent); - std::unique_ptr<SmNode> DoEscape(); - std::unique_ptr<SmOperNode> DoOperator(); - std::unique_ptr<SmNode> DoOper(); - std::unique_ptr<SmStructureNode> DoUnOper(); - std::unique_ptr<SmNode> DoAlign(bool bUseExtraSpaces = true); - std::unique_ptr<SmStructureNode> DoFontAttribute(); - std::unique_ptr<SmStructureNode> DoAttribute(); - std::unique_ptr<SmStructureNode> DoFont(); - std::unique_ptr<SmStructureNode> DoFontSize(); - std::unique_ptr<SmStructureNode> DoColor(); - std::unique_ptr<SmStructureNode> DoBrace(); - std::unique_ptr<SmBracebodyNode> DoBracebody(bool bIsLeftRight); - std::unique_ptr<SmNode> DoEvaluate(); - std::unique_ptr<SmTextNode> DoFunction(); - std::unique_ptr<SmTableNode> DoBinom(); - std::unique_ptr<SmBinVerNode> DoFrac(); - std::unique_ptr<SmStructureNode> DoStack(); - std::unique_ptr<SmStructureNode> DoMatrix(); - std::unique_ptr<SmSpecialNode> DoSpecial(); - std::unique_ptr<SmGlyphSpecialNode> DoGlyphSpecial(); - std::unique_ptr<SmExpressionNode> DoError(SmParseError Error); - // end of grammar - -public: - SmParser(); - - /** Parse rBuffer to formula tree */ - std::unique_ptr<SmTableNode> Parse(const OUString &rBuffer); - /** Parse rBuffer to formula subtree that constitutes an expression */ - std::unique_ptr<SmNode> ParseExpression(const OUString &rBuffer); - - const OUString & GetText() const { return m_aBufferString; }; - - bool IsImportSymbolNames() const { return m_bImportSymNames; } - void SetImportSymbolNames(bool bVal) { m_bImportSymNames = bVal; } - bool IsExportSymbolNames() const { return m_bExportSymNames; } - void SetExportSymbolNames(bool bVal) { m_bExportSymNames = bVal; } - - const SmErrorDesc* NextError(); - const SmErrorDesc* PrevError(); - const SmErrorDesc* GetError() const; - const std::set< OUString >& GetUsedSymbols() const { return m_aUsedSymbols; } -}; - - -inline bool SmParser::TokenInGroup( TG nGroup) -{ - return bool(m_aCurToken.nGroup & nGroup); -} - +#include "parse5.hxx" #endif diff --git a/starmath/inc/parse5.hxx b/starmath/inc/parse5.hxx new file mode 100644 index 000000000000..f3c72a655626 --- /dev/null +++ b/starmath/inc/parse5.hxx @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +/** Parses the starmath code and creates the nodes. + * + */ + +#ifndef INCLUDED_STARMATH_INC_PARSE5_HXX +#define INCLUDED_STARMATH_INC_PARSE5_HXX + +#include "parsebase.hxx" + +class SmParser : public AbstractSmParser +{ + OUString m_aBufferString; + SmToken m_aCurToken; + std::vector<SmErrorDesc> m_aErrDescList; + int m_nCurError; + sal_Int32 m_nBufferIndex, m_nTokenIndex; + sal_Int32 m_nRow, // 1-based + m_nColOff; // 0-based + bool m_bImportSymNames, m_bExportSymNames; + sal_Int32 m_nParseDepth; + + // map of used symbols (used to reduce file size by exporting only actually used symbols) + std::set<OUString> m_aUsedSymbols; + + // CharClass representing a locale for parsing numbers + CharClass m_aNumCC; + // pointer to System locale's CharClass, which is alive inside SM_MOD() + const CharClass* m_pSysCC; + + SmParser(const SmParser&) = delete; + SmParser& operator=(const SmParser&) = delete; + + // Moves between tokens inside starmath code. + void NextToken(); + void NextTokenColor(SmTokenType dvipload); + void NextTokenFontSize(); + sal_Int32 GetTokenIndex() const { return m_nTokenIndex; } + void Replace(sal_Int32 nPos, sal_Int32 nLen, const OUString& rText); + + inline bool TokenInGroup(TG nGroup); + + // grammar + std::unique_ptr<SmTableNode> DoTable(); + std::unique_ptr<SmNode> DoLine(); + std::unique_ptr<SmNode> DoExpression(bool bUseExtraSpaces = true); + std::unique_ptr<SmNode> DoRelation(); + std::unique_ptr<SmNode> DoSum(); + std::unique_ptr<SmNode> DoProduct(); + std::unique_ptr<SmNode> DoSubSup(TG nActiveGroup, std::unique_ptr<SmNode> xGivenNode); + std::unique_ptr<SmNode> DoSubSupEvaluate(std::unique_ptr<SmNode> xGivenNode); + std::unique_ptr<SmNode> DoOpSubSup(); + std::unique_ptr<SmNode> DoPower(); + std::unique_ptr<SmBlankNode> DoBlank(); + std::unique_ptr<SmNode> DoTerm(bool bGroupNumberIdent); + std::unique_ptr<SmNode> DoEscape(); + std::unique_ptr<SmOperNode> DoOperator(); + std::unique_ptr<SmNode> DoOper(); + std::unique_ptr<SmStructureNode> DoUnOper(); + std::unique_ptr<SmNode> DoAlign(bool bUseExtraSpaces = true); + std::unique_ptr<SmStructureNode> DoFontAttribute(); + std::unique_ptr<SmStructureNode> DoAttribute(); + std::unique_ptr<SmStructureNode> DoFont(); + std::unique_ptr<SmStructureNode> DoFontSize(); + std::unique_ptr<SmStructureNode> DoColor(); + std::unique_ptr<SmStructureNode> DoBrace(); + std::unique_ptr<SmBracebodyNode> DoBracebody(bool bIsLeftRight); + std::unique_ptr<SmNode> DoEvaluate(); + std::unique_ptr<SmTextNode> DoFunction(); + std::unique_ptr<SmTableNode> DoBinom(); + std::unique_ptr<SmBinVerNode> DoFrac(); + std::unique_ptr<SmStructureNode> DoStack(); + std::unique_ptr<SmStructureNode> DoMatrix(); + std::unique_ptr<SmSpecialNode> DoSpecial(); + std::unique_ptr<SmGlyphSpecialNode> DoGlyphSpecial(); + std::unique_ptr<SmExpressionNode> DoError(SmParseError Error); + // end of grammar + +public: + SmParser(); + virtual ~SmParser(); + + /** Parse rBuffer to formula tree */ + std::unique_ptr<SmTableNode> Parse(const OUString& rBuffer); + /** Parse rBuffer to formula subtree that constitutes an expression */ + std::unique_ptr<SmNode> ParseExpression(const OUString& rBuffer); + + const OUString& GetText() const { return m_aBufferString; }; + + bool IsImportSymbolNames() const { return m_bImportSymNames; } + void SetImportSymbolNames(bool bVal) { m_bImportSymNames = bVal; } + bool IsExportSymbolNames() const { return m_bExportSymNames; } + void SetExportSymbolNames(bool bVal) { m_bExportSymNames = bVal; } + + const SmErrorDesc* NextError(); + const SmErrorDesc* PrevError(); + const SmErrorDesc* GetError() const; + const std::set<OUString>& GetUsedSymbols() const { return m_aUsedSymbols; } +}; + +inline bool SmParser::TokenInGroup(TG nGroup) { return bool(m_aCurToken.nGroup & nGroup); } + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/starmath/inc/parsebase.hxx b/starmath/inc/parsebase.hxx new file mode 100644 index 000000000000..ee6a0621b0d6 --- /dev/null +++ b/starmath/inc/parsebase.hxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +/** Parses the starmath code and creates the nodes. + * + */ + +#ifndef INCLUDED_STARMATH_INC_PARSEBASE_HXX +#define INCLUDED_STARMATH_INC_PARSEBASE_HXX + +#include <unotools/charclass.hxx> +#include <memory> +#include <set> +#include <vector> + +#include "token.hxx" +#include "node.hxx" + +#define DEPTH_LIMIT 1024 + +// Those are the errors that the parser may encounter. +enum class SmParseError : uint_fast8_t +{ + None = 0, + UnexpectedChar = 1, + UnexpectedToken = 2, + PoundExpected = 3, + ColorExpected = 4, + LgroupExpected = 5, + RgroupExpected = 6, + LbraceExpected = 7, + RbraceExpected = 8, + ParentMismatch = 9, + RightExpected = 10, + FontExpected = 11, + SizeExpected = 12, + DoubleAlign = 13, + DoubleSubsupscript = 14, + NumberExpected = 15 +}; + +struct SmErrorDesc +{ + SmParseError m_eType; + SmNode* m_pNode; + OUString m_aText; + + SmErrorDesc(SmParseError eType, SmNode* pNode, OUString aText) + : m_eType(eType) + , m_pNode(pNode) + , m_aText(aText) + { + } +}; + +class DepthProtect +{ +private: + sal_Int32& m_rParseDepth; + +public: + DepthProtect(sal_Int32& rParseDepth) + : m_rParseDepth(rParseDepth) + { + ++m_rParseDepth; + if (m_rParseDepth > DEPTH_LIMIT) + throw std::range_error("parser depth limit"); + } + ~DepthProtect() { --m_rParseDepth; } +}; + +namespace starmathdatabase +{ +// Must be in sync with SmParseError list +extern const char* SmParseErrorDesc[16]; + +OUString getParseErrorDesc(SmParseError err); +} + +class AbstractSmParser +{ +public: + AbstractSmParser() {} + virtual ~AbstractSmParser() {} + + /** Parse rBuffer to formula tree */ + virtual std::unique_ptr<SmTableNode> Parse(const OUString& rBuffer) = 0; + /** Parse rBuffer to formula subtree that constitutes an expression */ + virtual std::unique_ptr<SmNode> ParseExpression(const OUString& rBuffer) = 0; + + virtual const OUString& GetText() const = 0; + + virtual bool IsImportSymbolNames() const = 0; + virtual void SetImportSymbolNames(bool bVal) = 0; + virtual bool IsExportSymbolNames() const = 0; + virtual void SetExportSymbolNames(bool bVal) = 0; + + virtual const SmErrorDesc* NextError() = 0; + virtual const SmErrorDesc* PrevError() = 0; + virtual const SmErrorDesc* GetError() const = 0; + virtual const std::set<OUString>& GetUsedSymbols() const = 0; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/starmath/source/parse.cxx b/starmath/source/parse.cxx deleted file mode 100644 index 1de0a0518eef..000000000000 --- a/starmath/source/parse.cxx +++ /dev/null @@ -1,2683 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <memory> -#include <com/sun/star/i18n/UnicodeType.hpp> -#include <com/sun/star/i18n/KParseTokens.hpp> -#include <com/sun/star/i18n/KParseType.hpp> -#include <i18nlangtag/lang.h> -#include <tools/lineend.hxx> -#include <unotools/syslocale.hxx> -#include <sal/log.hxx> -#include <osl/diagnose.h> -#include <rtl/character.hxx> -#include <node.hxx> -#include <parse.hxx> -#include <strings.hrc> -#include <smmod.hxx> -#include <cfgitem.hxx> -#include <cassert> -#include <stack> -#include <starmathdatabase.hxx> - -using namespace ::com::sun::star::i18n; - -const char* starmathdatabase::SmParseErrorDesc[] = { - // clang-format off - RID_ERR_NONE, - RID_ERR_UNEXPECTEDCHARACTER, - RID_ERR_UNEXPECTEDTOKEN, - RID_ERR_POUNDEXPECTED, - RID_ERR_COLOREXPECTED, - RID_ERR_LGROUPEXPECTED, - RID_ERR_RGROUPEXPECTED, - RID_ERR_LBRACEEXPECTED, - RID_ERR_RBRACEEXPECTED, - RID_ERR_PARENTMISMATCH, - RID_ERR_RIGHTEXPECTED, - RID_ERR_FONTEXPECTED, - RID_ERR_SIZEEXPECTED, - RID_ERR_DOUBLEALIGN, - RID_ERR_DOUBLESUBSUPSCRIPT, - RID_ERR_NUMBEREXPECTED - // clang-format on -}; - -OUString starmathdatabase::getParseErrorDesc(SmParseError err){ - return SmResId(starmathdatabase::SmParseErrorDesc[static_cast<uint_fast8_t>(err)]); -} - -//Definition of math keywords -const SmTokenTableEntry aTokenTable[] = -{ - { u"abs", TABS, '\0', TG::UnOper, 13 }, - { u"acute", TACUTE, MS_ACUTE, TG::Attribute, 5 }, - { u"aleph" , TALEPH, MS_ALEPH, TG::Standalone, 5 }, - { u"alignb", TALIGNC, '\0', TG::Align, 0}, - { u"alignc", TALIGNC, '\0', TG::Align, 0}, - { u"alignl", TALIGNL, '\0', TG::Align, 0}, - { u"alignm", TALIGNC, '\0', TG::Align, 0}, - { u"alignr", TALIGNR, '\0', TG::Align, 0}, - { u"alignt", TALIGNC, '\0', TG::Align, 0}, - { u"and", TAND, MS_AND, TG::Product, 0}, - { u"approx", TAPPROX, MS_APPROX, TG::Relation, 0}, - { u"arccos", TACOS, '\0', TG::Function, 5}, - { u"arccot", TACOT, '\0', TG::Function, 5}, - { u"arcosh", TACOSH, '\0', TG::Function, 5 }, - { u"arcoth", TACOTH, '\0', TG::Function, 5 }, - { u"arcsin", TASIN, '\0', TG::Function, 5}, - { u"arctan", TATAN, '\0', TG::Function, 5}, - { u"arsinh", TASINH, '\0', TG::Function, 5}, - { u"artanh", TATANH, '\0', TG::Function, 5}, - { u"backepsilon" , TBACKEPSILON, MS_BACKEPSILON, TG::Standalone, 5}, - { u"bar", TBAR, MS_BAR, TG::Attribute, 5}, - { u"binom", TBINOM, '\0', TG::NONE, 5 }, - { u"bold", TBOLD, '\0', TG::FontAttr, 5}, - { u"boper", TBOPER, '\0', TG::Product, 0}, - { u"breve", TBREVE, MS_BREVE, TG::Attribute, 5}, - { u"bslash", TBACKSLASH, MS_BACKSLASH, TG::Product, 0 }, - { u"cdot", TCDOT, MS_CDOT, TG::Product, 0}, - { u"check", TCHECK, MS_CHECK, TG::Attribute, 5}, - { u"circ" , TCIRC, MS_CIRC, TG::Standalone, 5}, - { u"circle", TCIRCLE, MS_CIRCLE, TG::Attribute, 5}, - { u"color", TCOLOR, '\0', TG::FontAttr, 5}, - { u"coprod", TCOPROD, MS_COPROD, TG::Oper, 5}, - { u"cos", TCOS, '\0', TG::Function, 5}, - { u"cosh", TCOSH, '\0', TG::Function, 5}, - { u"cot", TCOT, '\0', TG::Function, 5}, - { u"coth", TCOTH, '\0', TG::Function, 5}, - { u"csub", TCSUB, '\0', TG::Power, 0}, - { u"csup", TCSUP, '\0', TG::Power, 0}, - { u"dddot", TDDDOT, MS_DDDOT, TG::Attribute, 5}, - { u"ddot", TDDOT, MS_DDOT, TG::Attribute, 5}, - { u"def", TDEF, MS_DEF, TG::Relation, 0}, - { u"div", TDIV, MS_DIV, TG::Product, 0}, - { u"divides", TDIVIDES, MS_LINE, TG::Relation, 0}, - { u"dlarrow" , TDLARROW, MS_DLARROW, TG::Standalone, 5}, - { u"dlrarrow" , TDLRARROW, MS_DLRARROW, TG::Standalone, 5}, - { u"dot", TDOT, MS_DOT, TG::Attribute, 5}, - { u"dotsaxis", TDOTSAXIS, MS_DOTSAXIS, TG::Standalone, 5}, // 5 to continue expression - { u"dotsdiag", TDOTSDIAG, MS_DOTSUP, TG::Standalone, 5}, - { u"dotsdown", TDOTSDOWN, MS_DOTSDOWN, TG::Standalone, 5}, - { u"dotslow", TDOTSLOW, MS_DOTSLOW, TG::Standalone, 5}, - { u"dotsup", TDOTSUP, MS_DOTSUP, TG::Standalone, 5}, - { u"dotsvert", TDOTSVERT, MS_DOTSVERT, TG::Standalone, 5}, - { u"downarrow" , TDOWNARROW, MS_DOWNARROW, TG::Standalone, 5}, - { u"drarrow" , TDRARROW, MS_DRARROW, TG::Standalone, 5}, - { u"emptyset" , TEMPTYSET, MS_EMPTYSET, TG::Standalone, 5}, - { u"equiv", TEQUIV, MS_EQUIV, TG::Relation, 0}, - { u"evaluate", TEVALUATE, '\0', TG::NONE, 0}, - { u"exists", TEXISTS, MS_EXISTS, TG::Standalone, 5}, - { u"exp", TEXP, '\0', TG::Function, 5}, - { u"fact", TFACT, MS_FACT, TG::UnOper, 5}, - { u"fixed", TFIXED, '\0', TG::Font, 0}, - { u"font", TFONT, '\0', TG::FontAttr, 5}, - { u"forall", TFORALL, MS_FORALL, TG::Standalone, 5}, - { u"fourier", TFOURIER, MS_FOURIER, TG::Standalone, 5}, - { u"frac", TFRAC, '\0', TG::NONE, 5}, - { u"from", TFROM, '\0', TG::Limit, 0}, - { u"func", TFUNC, '\0', TG::Function, 5}, - { u"ge", TGE, MS_GE, TG::Relation, 0}, - { u"geslant", TGESLANT, MS_GESLANT, TG::Relation, 0 }, - { u"gg", TGG, MS_GG, TG::Relation, 0}, - { u"grave", TGRAVE, MS_GRAVE, TG::Attribute, 5}, - { u"gt", TGT, MS_GT, TG::Relation, 0}, - { u"harpoon", THARPOON, MS_HARPOON, TG::Attribute, 5}, - { u"hat", THAT, MS_HAT, TG::Attribute, 5}, - { u"hbar" , THBAR, MS_HBAR, TG::Standalone, 5}, - { u"hex" , THEX, '\0', TG::NONE, 5}, - { u"iiint", TIIINT, MS_IIINT, TG::Oper, 5}, - { u"iint", TIINT, MS_IINT, TG::Oper, 5}, - { u"im" , TIM, MS_IM, TG::Standalone, 5 }, - { u"in", TIN, MS_IN, TG::Relation, 0}, - { u"infinity" , TINFINITY, MS_INFINITY, TG::Standalone, 5}, - { u"infty" , TINFINITY, MS_INFINITY, TG::Standalone, 5}, - { u"int", TINT, MS_INT, TG::Oper, 5}, - { u"intd", TINTD, MS_INT, TG::Oper, 5}, - { u"intersection", TINTERSECT, MS_INTERSECT, TG::Product, 0}, - { u"it", TIT, '\0', TG::Product, 0}, - { u"ital", TITALIC, '\0', TG::FontAttr, 5}, - { u"italic", TITALIC, '\0', TG::FontAttr, 5}, - { u"lambdabar" , TLAMBDABAR, MS_LAMBDABAR, TG::Standalone, 5}, - { u"langle", TLANGLE, MS_LMATHANGLE, TG::LBrace, 5}, - { u"laplace", TLAPLACE, MS_LAPLACE, TG::Standalone, 5}, - { u"lbrace", TLBRACE, MS_LBRACE, TG::LBrace, 5}, - { u"lceil", TLCEIL, MS_LCEIL, TG::LBrace, 5}, - { u"ldbracket", TLDBRACKET, MS_LDBRACKET, TG::LBrace, 5}, - { u"ldline", TLDLINE, MS_DVERTLINE, TG::LBrace, 5}, - { u"le", TLE, MS_LE, TG::Relation, 0}, - { u"left", TLEFT, '\0', TG::NONE, 5}, - { u"leftarrow" , TLEFTARROW, MS_LEFTARROW, TG::Standalone, 5}, - { u"leslant", TLESLANT, MS_LESLANT, TG::Relation, 0 }, - { u"lfloor", TLFLOOR, MS_LFLOOR, TG::LBrace, 5}, - { u"lim", TLIM, '\0', TG::Oper, 5}, - { u"liminf", TLIMINF, '\0', TG::Oper, 5}, - { u"limsup", TLIMSUP, '\0', TG::Oper, 5}, - { u"lint", TLINT, MS_LINT, TG::Oper, 5}, - { u"ll", TLL, MS_LL, TG::Relation, 0}, - { u"lline", TLLINE, MS_VERTLINE, TG::LBrace, 5}, - { u"llint", TLLINT, MS_LLINT, TG::Oper, 5}, - { u"lllint", TLLLINT, MS_LLLINT, TG::Oper, 5}, - { u"ln", TLN, '\0', TG::Function, 5}, - { u"log", TLOG, '\0', TG::Function, 5}, - { u"lrline", TLRLINE, MS_VERTLINE, TG::LBrace | TG::RBrace, 5}, - { u"lrdline", TLRDLINE, MS_VERTLINE, TG::LBrace | TG::RBrace, 5}, - { u"lsub", TLSUB, '\0', TG::Power, 0}, - { u"lsup", TLSUP, '\0', TG::Power, 0}, - { u"lt", TLT, MS_LT, TG::Relation, 0}, - { u"matrix", TMATRIX, '\0', TG::NONE, 5}, - { u"minusplus", TMINUSPLUS, MS_MINUSPLUS, TG::UnOper | TG::Sum, 5}, - { u"mline", TMLINE, MS_VERTLINE, TG::NONE, 0}, //! not in TG::RBrace, Level 0 - { u"nabla", TNABLA, MS_NABLA, TG::Standalone, 5}, - { u"nbold", TNBOLD, '\0', TG::FontAttr, 5}, - { u"ndivides", TNDIVIDES, MS_NDIVIDES, TG::Relation, 0}, - { u"neg", TNEG, MS_NEG, TG::UnOper, 5 }, - { u"neq", TNEQ, MS_NEQ, TG::Relation, 0}, - { u"newline", TNEWLINE, '\0', TG::NONE, 0}, - { u"ni", TNI, MS_NI, TG::Relation, 0}, - { u"nitalic", TNITALIC, '\0', TG::FontAttr, 5}, - { u"none", TNONE, '\0', TG::LBrace | TG::RBrace, 0}, - { u"nospace", TNOSPACE, '\0', TG::Standalone, 5}, - { u"notexists", TNOTEXISTS, MS_NOTEXISTS, TG::Standalone, 5}, - { u"notin", TNOTIN, MS_NOTIN, TG::Relation, 0}, - { u"nprec", TNOTPRECEDES, MS_NOTPRECEDES, TG::Relation, 0 }, - { u"nroot", TNROOT, MS_SQRT, TG::UnOper, 5}, - { u"nsubset", TNSUBSET, MS_NSUBSET, TG::Relation, 0 }, - { u"nsubseteq", TNSUBSETEQ, MS_NSUBSETEQ, TG::Relation, 0 }, - { u"nsucc", TNOTSUCCEEDS, MS_NOTSUCCEEDS, TG::Relation, 0 }, - { u"nsupset", TNSUPSET, MS_NSUPSET, TG::Relation, 0 }, - { u"nsupseteq", TNSUPSETEQ, MS_NSUPSETEQ, TG::Relation, 0 }, - { u"odivide", TODIVIDE, MS_ODIVIDE, TG::Product, 0}, - { u"odot", TODOT, MS_ODOT, TG::Product, 0}, - { u"ominus", TOMINUS, MS_OMINUS, TG::Sum, 0}, - { u"oper", TOPER, '\0', TG::Oper, 5}, - { u"oplus", TOPLUS, MS_OPLUS, TG::Sum, 0}, - { u"or", TOR, MS_OR, TG::Sum, 0}, - { u"ortho", TORTHO, MS_ORTHO, TG::Relation, 0}, - { u"otimes", TOTIMES, MS_OTIMES, TG::Product, 0}, - { u"over", TOVER, '\0', TG::Product, 0}, - { u"overbrace", TOVERBRACE, MS_OVERBRACE, TG::Product, 5}, - { u"overline", TOVERLINE, '\0', TG::Attribute, 5}, - { u"overstrike", TOVERSTRIKE, '\0', TG::Attribute, 5}, - { u"owns", TNI, MS_NI, TG::Relation, 0}, - { u"parallel", TPARALLEL, MS_DLINE, TG::Relation, 0}, - { u"partial", TPARTIAL, MS_PARTIAL, TG::Standalone, 5 }, - { u"phantom", TPHANTOM, '\0', TG::FontAttr, 5}, - { u"plusminus", TPLUSMINUS, MS_PLUSMINUS, TG::UnOper | TG::Sum, 5}, - { u"prec", TPRECEDES, MS_PRECEDES, TG::Relation, 0 }, - { u"preccurlyeq", TPRECEDESEQUAL, MS_PRECEDESEQUAL, TG::Relation, 0 }, - { u"precsim", TPRECEDESEQUIV, MS_PRECEDESEQUIV, TG::Relation, 0 }, - { u"prod", TPROD, MS_PROD, TG::Oper, 5}, - { u"prop", TPROP, MS_PROP, TG::Relation, 0}, - { u"rangle", TRANGLE, MS_RMATHANGLE, TG::RBrace, 0}, //! 0 to terminate expression - { u"rbrace", TRBRACE, MS_RBRACE, TG::RBrace, 0}, - { u"rceil", TRCEIL, MS_RCEIL, TG::RBrace, 0}, - { u"rdbracket", TRDBRACKET, MS_RDBRACKET, TG::RBrace, 0}, - { u"rdline", TRDLINE, MS_DVERTLINE, TG::RBrace, 0}, - { u"re" , TRE, MS_RE, TG::Standalone, 5 }, - { u"rfloor", TRFLOOR, MS_RFLOOR, TG::RBrace, 0}, //! 0 to terminate expression - { u"right", TRIGHT, '\0', TG::NONE, 0}, - { u"rightarrow" , TRIGHTARROW, MS_RIGHTARROW, TG::Standalone, 5}, - { u"rline", TRLINE, MS_VERTLINE, TG::RBrace, 0}, //! 0 to terminate expression - { u"rsub", TRSUB, '\0', TG::Power, 0}, - { u"rsup", TRSUP, '\0', TG::Power, 0}, - { u"sans", TSANS, '\0', TG::Font, 0}, - { u"serif", TSERIF, '\0', TG::Font, 0}, - { u"setC" , TSETC, MS_SETC, TG::Standalone, 5}, - { u"setminus", TSETMINUS, MS_BACKSLASH, TG::Product, 0 }, - { u"setN" , TSETN, MS_SETN, TG::Standalone, 5}, - { u"setQ" , TSETQ, MS_SETQ, TG::Standalone, 5}, - { u"setquotient", TSETQUOTIENT, MS_SLASH, TG::Product, 0 }, - { u"setR" , TSETR, MS_SETR, TG::Standalone, 5}, - { u"setZ" , TSETZ, MS_SETZ, TG::Standalone, 5}, - { u"sim", TSIM, MS_SIM, TG::Relation, 0}, - { u"simeq", TSIMEQ, MS_SIMEQ, TG::Relation, 0}, - { u"sin", TSIN, '\0', TG::Function, 5}, - { u"sinh", TSINH, '\0', TG::Function, 5}, - { u"size", TSIZE, '\0', TG::FontAttr, 5}, - { u"slash", TSLASH, MS_SLASH, TG::Product, 0 }, - { u"sqrt", TSQRT, MS_SQRT, TG::UnOper, 5}, - { u"stack", TSTACK, '\0', TG::NONE, 5}, - { u"sub", TRSUB, '\0', TG::Power, 0}, - { u"subset", TSUBSET, MS_SUBSET, TG::Relation, 0}, - { u"subseteq", TSUBSETEQ, MS_SUBSETEQ, TG::Relation, 0}, - { u"succ", TSUCCEEDS, MS_SUCCEEDS, TG::Relation, 0 }, - { u"succcurlyeq", TSUCCEEDSEQUAL, MS_SUCCEEDSEQUAL, TG::Relation, 0 }, - { u"succsim", TSUCCEEDSEQUIV, MS_SUCCEEDSEQUIV, TG::Relation, 0 }, - { u"sum", TSUM, MS_SUM, TG::Oper, 5}, - { u"sup", TRSUP, '\0', TG::Power, 0}, - { u"supset", TSUPSET, MS_SUPSET, TG::Relation, 0}, - { u"supseteq", TSUPSETEQ, MS_SUPSETEQ, TG::Relation, 0}, - { u"tan", TTAN, '\0', TG::Function, 5}, - { u"tanh", TTANH, '\0', TG::Function, 5}, - { u"tilde", TTILDE, MS_TILDE, TG::Attribute, 5}, - { u"times", TTIMES, MS_TIMES, TG::Product, 0}, - { u"to", TTO, '\0', TG::Limit, 0}, - { u"toward", TTOWARD, MS_RIGHTARROW, TG::Relation, 0}, - { u"transl", TTRANSL, MS_TRANSL, TG::Relation, 0}, - { u"transr", TTRANSR, MS_TRANSR, TG::Relation, 0}, - { u"underbrace", TUNDERBRACE, MS_UNDERBRACE, TG::Product, 5}, - { u"underline", TUNDERLINE, '\0', TG::Attribute, 5}, - { u"union", TUNION, MS_UNION, TG::Sum, 0}, - { u"uoper", TUOPER, '\0', TG::UnOper, 5}, - { u"uparrow" , TUPARROW, MS_UPARROW, TG::Standalone, 5}, - { u"vec", TVEC, MS_VEC, TG::Attribute, 5}, - { u"widebslash", TWIDEBACKSLASH, MS_BACKSLASH, TG::Product, 0 }, - { u"wideharpoon", TWIDEHARPOON, MS_HARPOON, TG::Attribute, 5}, - { u"widehat", TWIDEHAT, MS_HAT, TG::Attribute, 5}, - { u"wideslash", TWIDESLASH, MS_SLASH, TG::Product, 0 }, - { u"widetilde", TWIDETILDE, MS_TILDE, TG::Attribute, 5}, - { u"widevec", TWIDEVEC, MS_VEC, TG::Attribute, 5}, - { u"wp" , TWP, MS_WP, TG::Standalone, 5} -}; - -// First character may be any alphabetic -const sal_Int32 coStartFlags = KParseTokens::ANY_LETTER | KParseTokens::IGNORE_LEADING_WS; - -// Continuing characters may be any alphabetic -const sal_Int32 coContFlags = (coStartFlags & ~KParseTokens::IGNORE_LEADING_WS) - | KParseTokens::TWO_DOUBLE_QUOTES_BREAK_STRING; -// First character for numbers, may be any numeric or dot -const sal_Int32 coNumStartFlags = KParseTokens::ASC_DIGIT | KParseTokens::ASC_DOT - | KParseTokens::IGNORE_LEADING_WS; -// Continuing characters for numbers, may be any numeric or dot or comma. -// tdf#127873: additionally accept ',' comma group separator as too many -// existing documents unwittingly may have used that as decimal separator -// in such locales (though it never was as this is always the en-US locale -// and the group separator is only parsed away). -const sal_Int32 coNumContFlags = (coNumStartFlags & ~KParseTokens::IGNORE_LEADING_WS) - | KParseTokens::GROUP_SEPARATOR_IN_NUMBER; -// First character for numbers hexadecimal -const sal_Int32 coNum16StartFlags = KParseTokens::ASC_DIGIT | KParseTokens::ASC_UPALPHA - | KParseTokens::IGNORE_LEADING_WS; - -// Continuing characters for numbers hexadecimal -const sal_Int32 coNum16ContFlags = (coNum16StartFlags & ~KParseTokens::IGNORE_LEADING_WS); -// user-defined char continuing characters may be any alphanumeric or dot. -const sal_Int32 coUserDefinedCharContFlags = KParseTokens::ANY_LETTER_OR_NUMBER - | KParseTokens::ASC_DOT - | KParseTokens::TWO_DOUBLE_QUOTES_BREAK_STRING; - -//Checks if keyword is in the list. -static inline bool findCompare(const SmTokenTableEntry & lhs, const OUString & s) -{ - return s.compareToIgnoreAsciiCase(lhs.pIdent) > 0; -} - -//Returns the SmTokenTableEntry for a keyword -static const SmTokenTableEntry * GetTokenTableEntry( const OUString &rName ) -{ - if (rName.isEmpty())return nullptr; //avoid null pointer exceptions - //Looks for the first keyword after or equal to rName in alphabetical order. - auto findIter = std::lower_bound( std::begin(aTokenTable), - std::end(aTokenTable), rName, findCompare ); - if ( findIter != std::end(aTokenTable) && rName.equalsIgnoreAsciiCase( findIter->pIdent )) - return &*findIter; //check is equal - return nullptr; //not found -} - -static bool IsDelimiter( const OUString &rTxt, sal_Int32 nPos ) -{ // returns 'true' iff cChar is '\0' or a delimiter - - assert(nPos <= rTxt.getLength()); //index out of range - if (nPos == rTxt.getLength())return true; //This is EOF - sal_Unicode cChar = rTxt[nPos]; - - // check if 'cChar' is in the delimiter table - static const sal_Unicode aDelimiterTable[] = - { - ' ', '{', '}', '(', ')', '\t', '\n', '\r', '+', '-', - '*', '/', '=', '[', ']', '^', '_', '#', - '%', '>', '<', '&', '|', '\\', '"', '~', '`' - };//reordered by usage (by eye) for nanoseconds saving. - - //checks the array - for (auto const &cDelimiter : aDelimiterTable) - { - if (cDelimiter == cChar)return true; - } - - //special chars support - sal_Int16 nTypJp = SM_MOD()->GetSysLocale().GetCharClass().getType( rTxt, nPos ); - return ( nTypJp == css::i18n::UnicodeType::SPACE_SEPARATOR || - nTypJp == css::i18n::UnicodeType::CONTROL); -} - -// checks number used as arguments in Math formulas (e.g. 'size' command) -// Format: no negative numbers, must start with a digit, no exponent notation, ... -static bool lcl_IsNumber(const OUString& rText) -{ - bool bPoint = false; - const sal_Unicode* pBuffer = rText.getStr(); - for(sal_Int32 nPos = 0; nPos < rText.getLength(); nPos++, pBuffer++) - { - const sal_Unicode cChar = *pBuffer; - if(cChar == '.') - { - if(bPoint) return false; - else bPoint = true; - } - else if ( !rtl::isAsciiDigit( cChar ) ) return false; - } - return true; -} -// checks number used as arguments in Math formulas (e.g. 'size' command) -// Format: no negative numbers, must start with a digit, no exponent notation, ... -static bool lcl_IsNotWholeNumber(const OUString& rText) -{ - const sal_Unicode* pBuffer = rText.getStr(); - for(sal_Int32 nPos = 0; nPos < rText.getLength(); nPos++, pBuffer++) - if ( !rtl::isAsciiDigit( *pBuffer ) ) return true; - return false; -} -// checks hex number used as arguments in Math formulas (e.g. 'hex' command) -// Format: no negative numbers, must start with a digit, no exponent notation, ... -static bool lcl_IsNotWholeNumber16(const OUString& rText) -{ - const sal_Unicode* pBuffer = rText.getStr(); - for(sal_Int32 nPos = 0; nPos < rText.getLength(); nPos++, pBuffer++) - if ( !rtl::isAsciiCanonicHexDigit( *pBuffer ) ) return true; - return false; -} - -//Text replace onto m_aBufferString -void SmParser::Replace( sal_Int32 nPos, sal_Int32 nLen, const OUString &rText ) -{ - assert( nPos + nLen <= m_aBufferString.getLength() ); //checks if length allows text replace - - m_aBufferString = m_aBufferString.replaceAt( nPos, nLen, rText ); //replace and reindex - sal_Int32 nChg = rText.getLength() - nLen; - m_nBufferIndex = m_nBufferIndex + nChg; - m_nTokenIndex = m_nTokenIndex + nChg; -} - -void SmParser::NextToken() //Central part of the parser -{ - - sal_Int32 nBufLen = m_aBufferString.getLength(); - ParseResult aRes; - sal_Int32 nRealStart; - bool bCont; - do - { - // skip white spaces - while (UnicodeType::SPACE_SEPARATOR == - m_pSysCC->getType( m_aBufferString, m_nBufferIndex )) - ++m_nBufferIndex; - - // Try to parse a number in a locale-independent manner using - // '.' as decimal separator. - // See https://bz.apache.org/ooo/show_bug.cgi?id=45779 - aRes = m_aNumCC.parsePredefinedToken(KParseType::ASC_NUMBER, - m_aBufferString, m_nBufferIndex, - coNumStartFlags, "", - coNumContFlags, ""); - - if (aRes.TokenType == 0) - { - // Try again with the default token parsing. - aRes = m_pSysCC->parseAnyToken(m_aBufferString, m_nBufferIndex, - coStartFlags, "", - coContFlags, ""); - } - - nRealStart = m_nBufferIndex + aRes.LeadingWhiteSpace; - m_nBufferIndex = nRealStart; - - bCont = false; - if ( aRes.TokenType == 0 && - nRealStart < nBufLen && - '\n' == m_aBufferString[ nRealStart ] ) - { - // keep data needed for tokens row and col entry up to date - ++m_nRow; - m_nBufferIndex = m_nColOff = nRealStart + 1; - bCont = true; - } - else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR) - { - if (nRealStart + 2 <= nBufLen && m_aBufferString.match("%%", nRealStart)) - { - //SkipComment - m_nBufferIndex = nRealStart + 2; - while (m_nBufferIndex < nBufLen && - '\n' != m_aBufferString[ m_nBufferIndex ]) - ++m_nBufferIndex; - bCont = true; - } - } - - } while (bCont); - - // set index of current token - m_nTokenIndex = m_nBufferIndex; - - m_aCurToken.nRow = m_nRow; - m_aCurToken.nCol = nRealStart - m_nColOff + 1; - - bool bHandled = true; - if (nRealStart >= nBufLen) - { - m_aCurToken.eType = TEND; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::NONE; - m_aCurToken.nLevel = 0; - m_aCurToken.aText.clear(); - } - else if (aRes.TokenType & KParseType::ANY_NUMBER) - { - assert(aRes.EndPos > 0); - if ( m_aBufferString[aRes.EndPos-1] == ',' && - aRes.EndPos < nBufLen && - m_pSysCC->getType( m_aBufferString, aRes.EndPos ) != UnicodeType::SPACE_SEPARATOR ) - { - // Comma followed by a non-space char is unlikely for decimal/thousands separator. - --aRes.EndPos; - } - sal_Int32 n = aRes.EndPos - nRealStart; - assert(n >= 0); - m_aCurToken.eType = TNUMBER; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::NONE; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = m_aBufferString.copy( nRealStart, n ); - - SAL_WARN_IF( !IsDelimiter( m_aBufferString, aRes.EndPos ), "starmath", "identifier really finished? (compatibility!)" ); - } - else if (aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING) - { - m_aCurToken.eType = TTEXT; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::NONE; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = aRes.DequotedNameOrString; - m_aCurToken.nRow = m_nRow; - m_aCurToken.nCol = nRealStart - m_nColOff + 2; - } - else if (aRes.TokenType & KParseType::IDENTNAME) - { - sal_Int32 n = aRes.EndPos - nRealStart; - assert(n >= 0); - OUString aName( m_aBufferString.copy( nRealStart, n ) ); - const SmTokenTableEntry *pEntry = GetTokenTableEntry( aName ); - - if (pEntry) - { - m_aCurToken.eType = pEntry->eType; - m_aCurToken.setChar(pEntry->cMathChar); - m_aCurToken.nGroup = pEntry->nGroup; - m_aCurToken.nLevel = pEntry->nLevel; - m_aCurToken.aText = pEntry->pIdent; - } - else - { - m_aCurToken.eType = TIDENT; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::NONE; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = aName; - - SAL_WARN_IF(!IsDelimiter(m_aBufferString, aRes.EndPos),"starmath", "identifier really finished? (compatibility!)"); - } - } - else if (aRes.TokenType == 0 && '_' == m_aBufferString[ nRealStart ]) - { - m_aCurToken.eType = TRSUB; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::Power; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "_"; - - aRes.EndPos = nRealStart + 1; - } - else if (aRes.TokenType & KParseType::BOOLEAN) - { - sal_Int32 &rnEndPos = aRes.EndPos; - if (rnEndPos - nRealStart <= 2) - { - sal_Unicode ch = m_aBufferString[ nRealStart ]; - switch (ch) - { - case '<': - { - if (m_aBufferString.match("<<", nRealStart)) - { - m_aCurToken.eType = TLL; - m_aCurToken.setChar(MS_LL); - m_aCurToken.nGroup = TG::Relation; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "<<"; - - rnEndPos = nRealStart + 2; - } - else if (m_aBufferString.match("<=", nRealStart)) - { - m_aCurToken.eType = TLE; - m_aCurToken.setChar(MS_LE); - m_aCurToken.nGroup = TG::Relation; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "<="; - - rnEndPos = nRealStart + 2; - } - else if (m_aBufferString.match("<-", nRealStart)) - { - m_aCurToken.eType = TLEFTARROW; - m_aCurToken.setChar(MS_LEFTARROW); - m_aCurToken.nGroup = TG::Standalone; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = "<-"; - - rnEndPos = nRealStart + 2; - } - else if (m_aBufferString.match("<>", nRealStart)) - { - m_aCurToken.eType = TNEQ; - m_aCurToken.setChar(MS_NEQ); - m_aCurToken.nGroup = TG::Relation; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "<>"; - - rnEndPos = nRealStart + 2; - } - else if (m_aBufferString.match("<?>", nRealStart)) - { - m_aCurToken.eType = TPLACE; - m_aCurToken.setChar(MS_PLACE); - m_aCurToken.nGroup = TG::NONE; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = "<?>"; - - rnEndPos = nRealStart + 3; - } - else - { - m_aCurToken.eType = TLT; - m_aCurToken.setChar(MS_LT); - m_aCurToken.nGroup = TG::Relation; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "<"; - } - } - break; - case '>': - { - if (m_aBufferString.match(">=", nRealStart)) - { - m_aCurToken.eType = TGE; - m_aCurToken.setChar(MS_GE); - m_aCurToken.nGroup = TG::Relation; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = ">="; - - rnEndPos = nRealStart + 2; - } - else if (m_aBufferString.match(">>", nRealStart)) - { - m_aCurToken.eType = TGG; - m_aCurToken.setChar(MS_GG); - m_aCurToken.nGroup = TG::Relation; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = ">>"; - - rnEndPos = nRealStart + 2; - } - else - { - m_aCurToken.eType = TGT; - m_aCurToken.setChar(MS_GT); - m_aCurToken.nGroup = TG::Relation; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = ">"; - } - } - break; - default: - bHandled = false; - } - } - } - else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR) - { - sal_Int32 &rnEndPos = aRes.EndPos; - if (rnEndPos - nRealStart == 1) - { - sal_Unicode ch = m_aBufferString[ nRealStart ]; - switch (ch) - { - case '%': - { - //! modifies aRes.EndPos - - OSL_ENSURE( rnEndPos >= nBufLen || - '%' != m_aBufferString[ rnEndPos ], - "unexpected comment start" ); - - // get identifier of user-defined character - ParseResult aTmpRes = m_pSysCC->parseAnyToken( - m_aBufferString, rnEndPos, - KParseTokens::ANY_LETTER, - "", - coUserDefinedCharContFlags, - "" ); - - sal_Int32 nTmpStart = rnEndPos + aTmpRes.LeadingWhiteSpace; - - // default setting for the case that no identifier - // i.e. a valid symbol-name is following the '%' - // character - m_aCurToken.eType = TTEXT; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::NONE; - m_aCurToken.nLevel = 5; - m_aCurToken.aText ="%"; - m_aCurToken.nRow = m_nRow; - m_aCurToken.nCol = nTmpStart - m_nColOff; - - if (aTmpRes.TokenType & KParseType::IDENTNAME) - { - - sal_Int32 n = aTmpRes.EndPos - nTmpStart; - m_aCurToken.eType = TSPECIAL; - m_aCurToken.aText = m_aBufferString.copy( nTmpStart-1, n+1 ); - - OSL_ENSURE( aTmpRes.EndPos > rnEndPos, - "empty identifier" ); - if (aTmpRes.EndPos > rnEndPos) - rnEndPos = aTmpRes.EndPos; - else - ++rnEndPos; - } - - // if no symbol-name was found we start-over with - // finding the next token right after the '%' sign. - // I.e. we leave rnEndPos unmodified. - } - break; - case '[': - { - m_aCurToken.eType = TLBRACKET; - m_aCurToken.setChar(MS_LBRACKET); - m_aCurToken.nGroup = TG::LBrace; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = "["; - } - break; - case '\\': - { - m_aCurToken.eType = TESCAPE; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::NONE; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = "\\"; - } - break; - case ']': - { - m_aCurToken.eType = TRBRACKET; - m_aCurToken.setChar(MS_RBRACKET); - m_aCurToken.nGroup = TG::RBrace; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "]"; - } - break; - case '^': - { - m_aCurToken.eType = TRSUP; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::Power; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "^"; - } - break; - case '`': - { - m_aCurToken.eType = TSBLANK; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::Blank; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = "`"; - } - break; - case '{': - { - m_aCurToken.eType = TLGROUP; - m_aCurToken.setChar(MS_LBRACE); - m_aCurToken.nGroup = TG::NONE; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = "{"; - } - break; - case '|': - { - m_aCurToken.eType = TOR; - m_aCurToken.setChar(MS_OR); - m_aCurToken.nGroup = TG::Sum; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "|"; - } - break; - case '}': - { - m_aCurToken.eType = TRGROUP; - m_aCurToken.setChar(MS_RBRACE); - m_aCurToken.nGroup = TG::NONE; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "}"; - } - break; - case '~': - { - m_aCurToken.eType = TBLANK; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::Blank; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = "~"; - } - break; - case '#': - { - if (m_aBufferString.match("##", nRealStart)) - { - m_aCurToken.eType = TDPOUND; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::NONE; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "##"; - - rnEndPos = nRealStart + 2; - } - else - { - m_aCurToken.eType = TPOUND; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::NONE; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "#"; - } - } - break; - case '&': - { - m_aCurToken.eType = TAND; - m_aCurToken.setChar(MS_AND); - m_aCurToken.nGroup = TG::Product; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "&"; - } - break; - case '(': - { - m_aCurToken.eType = TLPARENT; - m_aCurToken.setChar(MS_LPARENT); - m_aCurToken.nGroup = TG::LBrace; - m_aCurToken.nLevel = 5; //! 0 to continue expression - m_aCurToken.aText = "("; - } - break; - case ')': - { - m_aCurToken.eType = TRPARENT; - m_aCurToken.setChar(MS_RPARENT); - m_aCurToken.nGroup = TG::RBrace; - m_aCurToken.nLevel = 0; //! 0 to terminate expression - m_aCurToken.aText = ")"; - } - break; - case '*': - { - m_aCurToken.eType = TMULTIPLY; - m_aCurToken.setChar(MS_MULTIPLY); - m_aCurToken.nGroup = TG::Product; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "*"; - } - break; - case '+': - { - if (m_aBufferString.match("+-", nRealStart)) - { - m_aCurToken.eType = TPLUSMINUS; - m_aCurToken.setChar(MS_PLUSMINUS); - m_aCurToken.nGroup = TG::UnOper | TG::Sum; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = "+-"; - - rnEndPos = nRealStart + 2; - } - else - { - m_aCurToken.eType = TPLUS; - m_aCurToken.setChar(MS_PLUS); - m_aCurToken.nGroup = TG::UnOper | TG::Sum; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = "+"; - } - } - break; - case '-': - { - if (m_aBufferString.match("-+", nRealStart)) - { - m_aCurToken.eType = TMINUSPLUS; - m_aCurToken.setChar(MS_MINUSPLUS); - m_aCurToken.nGroup = TG::UnOper | TG::Sum; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = "-+"; - - rnEndPos = nRealStart + 2; - } - else if (m_aBufferString.match("->", nRealStart)) - { - m_aCurToken.eType = TRIGHTARROW; - m_aCurToken.setChar(MS_RIGHTARROW); - m_aCurToken.nGroup = TG::Standalone; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = "->"; - - rnEndPos = nRealStart + 2; - } - else - { - m_aCurToken.eType = TMINUS; - m_aCurToken.setChar(MS_MINUS); - m_aCurToken.nGroup = TG::UnOper | TG::Sum; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = "-"; - } - } - break; - case '.': - { - // Only one character? Then it can't be a number. - if (m_nBufferIndex < m_aBufferString.getLength() - 1) - { - // for compatibility with SO5.2 - // texts like .34 ...56 ... h ...78..90 - // will be treated as numbers - m_aCurToken.eType = TNUMBER; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::NONE; - m_aCurToken.nLevel = 5; - - sal_Int32 nTxtStart = m_nBufferIndex; - sal_Unicode cChar; - // if the equation ends with dot(.) then increment m_nBufferIndex till end of string only - do - { - cChar = m_aBufferString[ ++m_nBufferIndex ]; - } - while ( (cChar == '.' || rtl::isAsciiDigit( cChar )) && - ( m_nBufferIndex < m_aBufferString.getLength() - 1 ) ); - - m_aCurToken.aText = m_aBufferString.copy( nTxtStart, m_nBufferIndex - nTxtStart ); - aRes.EndPos = m_nBufferIndex; - } - else - bHandled = false; - } - break; - case '/': - { - m_aCurToken.eType = TDIVIDEBY; - m_aCurToken.setChar(MS_SLASH); - m_aCurToken.nGroup = TG::Product; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "/"; - } - break; - case '=': - { - m_aCurToken.eType = TASSIGN; - m_aCurToken.setChar(MS_ASSIGN); - m_aCurToken.nGroup = TG::Relation; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "="; - } - break; - default: - bHandled = false; - } - } - } - else - bHandled = false; - - if (!bHandled) - { - m_aCurToken.eType = TCHARACTER; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::NONE; - m_aCurToken.nLevel = 5; - - // tdf#129372: we may have to deal with surrogate pairs - // (see https://en.wikipedia.org/wiki/Universal_Character_Set_characters#Surrogates) - // in this case, we must read 2 sal_Unicode instead of 1 - int nOffset(rtl::isSurrogate(m_aBufferString[nRealStart])? 2 : 1); - m_aCurToken.aText = m_aBufferString.copy( nRealStart, nOffset ); - - aRes.EndPos = nRealStart + nOffset; - } - - if (TEND != m_aCurToken.eType) - m_nBufferIndex = aRes.EndPos; -} - -void SmParser::NextTokenColor(SmTokenType dvipload) -{ - - sal_Int32 nBufLen = m_aBufferString.getLength(); - ParseResult aRes; - sal_Int32 nRealStart; - bool bCont; - - do - { - // skip white spaces - while (UnicodeType::SPACE_SEPARATOR == - m_pSysCC->getType( m_aBufferString, m_nBufferIndex )) - ++m_nBufferIndex; - //parse, there are few options, so less strict. - aRes = m_pSysCC->parseAnyToken(m_aBufferString, m_nBufferIndex, - coStartFlags, "", coContFlags, ""); - nRealStart = m_nBufferIndex + aRes.LeadingWhiteSpace; - m_nBufferIndex = nRealStart; - bCont = false; - if ( aRes.TokenType == 0 && - nRealStart < nBufLen && - '\n' == m_aBufferString[ nRealStart ] ) - { - // keep data needed for tokens row and col entry up to date - ++m_nRow; - m_nBufferIndex = m_nColOff = nRealStart + 1; - bCont = true; - } - else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR) - { - if (nRealStart + 2 <= nBufLen && m_aBufferString.match("%%", nRealStart)) - { - //SkipComment - m_nBufferIndex = nRealStart + 2; - while (m_nBufferIndex < nBufLen && - '\n' != m_aBufferString[ m_nBufferIndex ]) - ++m_nBufferIndex; - bCont = true; - } - } - } while (bCont); - - // set index of current token - m_nTokenIndex = m_nBufferIndex; - m_aCurToken.nRow = m_nRow; - m_aCurToken.nCol = nRealStart - m_nColOff + 1; - if (nRealStart >= nBufLen) m_aCurToken.eType = TEND; - else if (aRes.TokenType & KParseType::IDENTNAME) - { - sal_Int32 n = aRes.EndPos - nRealStart; - assert(n >= 0); - OUString aName( m_aBufferString.copy( nRealStart, n ) ); - switch(dvipload) - { - case TCOLOR: - m_aCurToken = starmathdatabase::Identify_ColorName_Parser( aName ); - break; - case TDVIPSNAMESCOL: - m_aCurToken = starmathdatabase::Identify_ColorName_DVIPSNAMES( aName ); - break; - default: - m_aCurToken = starmathdatabase::Identify_ColorName_Parser( aName ); - break; - } - } - else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR) - { - if( m_aBufferString[ nRealStart ] == '#' && !m_aBufferString.match("##", nRealStart) ) - { - m_aCurToken.eType = THEX; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::Color; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "hex"; - } - } - else m_aCurToken.eType = TNONE; - if (TEND != m_aCurToken.eType) m_nBufferIndex = aRes.EndPos; -} - -void SmParser::NextTokenFontSize() -{ - - sal_Int32 nBufLen = m_aBufferString.getLength(); - ParseResult aRes; - sal_Int32 nRealStart; - bool bCont; - bool hex = false; - - do - { - // skip white spaces - while (UnicodeType::SPACE_SEPARATOR == - m_pSysCC->getType( m_aBufferString, m_nBufferIndex )) - ++m_nBufferIndex; - //hexadecimal parser - aRes = m_pSysCC->parseAnyToken(m_aBufferString, m_nBufferIndex, - coNum16StartFlags, ".", coNum16ContFlags, ".,"); - if (aRes.TokenType == 0) - { - // Try again with the default token parsing. - aRes = m_pSysCC->parseAnyToken(m_aBufferString, m_nBufferIndex, - coStartFlags, "", coContFlags, ""); - } - else hex = true; - nRealStart = m_nBufferIndex + aRes.LeadingWhiteSpace; - m_nBufferIndex = nRealStart; - bCont = false; - if ( aRes.TokenType == 0 && - nRealStart < nBufLen && - '\n' == m_aBufferString[ nRealStart ] ) - { - // keep data needed for tokens row and col entry up to date - ++m_nRow; - m_nBufferIndex = m_nColOff = nRealStart + 1; - bCont = true; - } - else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR) - { - if (nRealStart + 2 <= nBufLen && m_aBufferString.match("%%", nRealStart)) - { - //SkipComment - m_nBufferIndex = nRealStart + 2; - while (m_nBufferIndex < nBufLen && - '\n' != m_aBufferString[ m_nBufferIndex ]) - ++m_nBufferIndex; - bCont = true; - } - } - } while (bCont); - - // set index of current token - m_nTokenIndex = m_nBufferIndex; - m_aCurToken.nRow = m_nRow; - m_aCurToken.nCol = nRealStart - m_nColOff + 1; - if (nRealStart >= nBufLen) m_aCurToken.eType = TEND; - else if (aRes.TokenType & KParseType::ONE_SINGLE_CHAR) - { - if ( aRes.EndPos - nRealStart == 1 ) - { - switch ( m_aBufferString[ nRealStart ] ) - { - case '*': - m_aCurToken.eType = TMULTIPLY; - m_aCurToken.setChar(MS_MULTIPLY); - m_aCurToken.nGroup = TG::Product; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "*"; - break; - case '+': - m_aCurToken.eType = TPLUS; - m_aCurToken.setChar(MS_PLUS); - m_aCurToken.nGroup = TG::UnOper | TG::Sum; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = "+"; - break; - case '-': - m_aCurToken.eType = TMINUS; - m_aCurToken.setChar(MS_MINUS); - m_aCurToken.nGroup = TG::UnOper | TG::Sum; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = "-"; - break; - case '/': - m_aCurToken.eType = TDIVIDEBY; - m_aCurToken.setChar(MS_SLASH); - m_aCurToken.nGroup = TG::Product; - m_aCurToken.nLevel = 0; - m_aCurToken.aText = "/"; - break; - default: - m_aCurToken.eType = TNONE; - break; - } - } - else m_aCurToken.eType = TNONE; - } - else if(hex) - { - assert(aRes.EndPos > 0); - sal_Int32 n = aRes.EndPos - nRealStart; - assert(n >= 0); - m_aCurToken.eType = THEX; - m_aCurToken.cMathChar = u""; - m_aCurToken.nGroup = TG::NONE; - m_aCurToken.nLevel = 5; - m_aCurToken.aText = m_aBufferString.copy( nRealStart, n ); - } - else m_aCurToken.eType = TNONE; - if (TEND != m_aCurToken.eType) m_nBufferIndex = aRes.EndPos; -} - -namespace -{ - SmNodeArray buildNodeArray(std::vector<std::unique_ptr<SmNode>>& rSubNodes) - { - SmNodeArray aSubArray(rSubNodes.size()); - for (size_t i = 0; i < rSubNodes.size(); ++i) - aSubArray[i] = rSubNodes[i].release(); - return aSubArray; - } -} //end namespace - -// grammar -/*************************************************************************************************/ - -std::unique_ptr<SmTableNode> SmParser::DoTable() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - std::vector<std::unique_ptr<SmNode>> aLineArray; - aLineArray.push_back(DoLine()); - while (m_aCurToken.eType == TNEWLINE) - { - NextToken(); - aLineArray.push_back(DoLine()); - } - assert(m_aCurToken.eType == TEND); - std::unique_ptr<SmTableNode> xSNode(new SmTableNode(m_aCurToken)); - xSNode->SetSubNodes(buildNodeArray(aLineArray)); - return xSNode; -} - -std::unique_ptr<SmNode> SmParser::DoAlign(bool bUseExtraSpaces) - // parse alignment info (if any), then go on with rest of expression -{ - DepthProtect aDepthGuard(m_nParseDepth); - - std::unique_ptr<SmStructureNode> xSNode; - - if (TokenInGroup(TG::Align)) - { - xSNode.reset(new SmAlignNode(m_aCurToken)); - - NextToken(); - - // allow for just one align statement in 5.0 - if (TokenInGroup(TG::Align)) - return DoError(SmParseError::DoubleAlign); - } - - auto pNode = DoExpression(bUseExtraSpaces); - - if (xSNode) - { - xSNode->SetSubNode(0, pNode.release()); - return xSNode; - } - return pNode; -} - -// Postcondition: m_aCurToken.eType == TEND || m_aCurToken.eType == TNEWLINE -std::unique_ptr<SmNode> SmParser::DoLine() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - std::vector<std::unique_ptr<SmNode>> ExpressionArray; - - // start with single expression that may have an alignment statement - // (and go on with expressions that must not have alignment - // statements in 'while' loop below. See also 'Expression()'.) - if (m_aCurToken.eType != TEND && m_aCurToken.eType != TNEWLINE) - ExpressionArray.push_back(DoAlign()); - - while (m_aCurToken.eType != TEND && m_aCurToken.eType != TNEWLINE) - ExpressionArray.push_back(DoExpression()); - - //If there's no expression, add an empty one. - //this is to avoid a formula tree without any caret - //positions, in visual formula editor. - if(ExpressionArray.empty()) - { - SmToken aTok; - aTok.eType = TNEWLINE; - ExpressionArray.emplace_back(std::unique_ptr<SmNode>(new SmExpressionNode(aTok))); - } - - auto xSNode = std::make_unique<SmLineNode>(m_aCurToken); - xSNode->SetSubNodes(buildNodeArray(ExpressionArray)); - return xSNode; -} - -std::unique_ptr<SmNode> SmParser::DoExpression(bool bUseExtraSpaces) -{ - DepthProtect aDepthGuard(m_nParseDepth); - - std::vector<std::unique_ptr<SmNode>> RelationArray; - RelationArray.push_back(DoRelation()); - while (m_aCurToken.nLevel >= 4) - RelationArray.push_back(DoRelation()); - - if (RelationArray.size() > 1) - { - std::unique_ptr<SmExpressionNode> xSNode(new SmExpressionNode(m_aCurToken)); - xSNode->SetSubNodes(buildNodeArray(RelationArray)); - xSNode->SetUseExtraSpaces(bUseExtraSpaces); - return xSNode; - } - else - { - // This expression has only one node so just push this node. - return std::move(RelationArray[0]); - } -} - -std::unique_ptr<SmNode> SmParser::DoRelation() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - int nDepthLimit = m_nParseDepth; - - auto xFirst = DoSum(); - while (TokenInGroup(TG::Relation)) - { - std::unique_ptr<SmStructureNode> xSNode(new SmBinHorNode(m_aCurToken)); - auto xSecond = DoOpSubSup(); - auto xThird = DoSum(); - xSNode->SetSubNodes(std::move(xFirst), std::move(xSecond), std::move(xThird)); - xFirst = std::move(xSNode); - - ++m_nParseDepth; - DepthProtect bDepthGuard(m_nParseDepth); - } - - m_nParseDepth = nDepthLimit; - - return xFirst; -} - -std::unique_ptr<SmNode> SmParser::DoSum() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - int nDepthLimit = m_nParseDepth; - - auto xFirst = DoProduct(); - while (TokenInGroup(TG::Sum)) - { - std::unique_ptr<SmStructureNode> xSNode(new SmBinHorNode(m_aCurToken)); - auto xSecond = DoOpSubSup(); - auto xThird = DoProduct(); - xSNode->SetSubNodes(std::move(xFirst), std::move(xSecond), std::move(xThird)); - xFirst = std::move(xSNode); - - ++m_nParseDepth; - DepthProtect bDepthGuard(m_nParseDepth); - } - - m_nParseDepth = nDepthLimit; - - return xFirst; -} - -std::unique_ptr<SmNode> SmParser::DoProduct() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - auto xFirst = DoPower(); - - int nDepthLimit = 0; - - while (TokenInGroup(TG::Product)) - { - //this linear loop builds a recursive structure, if it gets - //too deep then later processing, e.g. releasing the tree, - //can exhaust stack - if (m_nParseDepth + nDepthLimit > DEPTH_LIMIT) - throw std::range_error("parser depth limit"); - - std::unique_ptr<SmStructureNode> xSNode; - std::unique_ptr<SmNode> xOper; - - SmTokenType eType = m_aCurToken.eType; - switch (eType) - { - case TOVER: - xSNode.reset(new SmBinVerNode(m_aCurToken)); - xOper.reset(new SmRectangleNode(m_aCurToken)); - NextToken(); - break; - - case TBOPER: - xSNode.reset(new SmBinHorNode(m_aCurToken)); - - NextToken(); - - //Let the glyph node know it's a binary operation - m_aCurToken.eType = TBOPER; - m_aCurToken.nGroup = TG::Product; - xOper = DoGlyphSpecial(); - break; - - case TOVERBRACE : - case TUNDERBRACE : - xSNode.reset(new SmVerticalBraceNode(m_aCurToken)); - xOper.reset(new SmMathSymbolNode(m_aCurToken)); - - NextToken(); - break; - - case TWIDEBACKSLASH: - case TWIDESLASH: - { - SmBinDiagonalNode *pSTmp = new SmBinDiagonalNode(m_aCurToken); - pSTmp->SetAscending(eType == TWIDESLASH); - xSNode.reset(pSTmp); - - xOper.reset(new SmPolyLineNode(m_aCurToken)); - NextToken(); - - break; - } - - default: - xSNode.reset(new SmBinHorNode(m_aCurToken)); - - xOper = DoOpSubSup(); - } - - auto xArg = DoPower(); - xSNode->SetSubNodesBinMo(std::move(xFirst), std::move(xOper), std::move(xArg)); - xFirst = std::move(xSNode); - ++nDepthLimit; - } - return xFirst; -} - -std::unique_ptr<SmNode> SmParser::DoSubSup(TG nActiveGroup, std::unique_ptr<SmNode> xGivenNode) -{ - DepthProtect aDepthGuard(m_nParseDepth); - - assert(nActiveGroup == TG::Power || nActiveGroup == TG::Limit); - assert(m_aCurToken.nGroup == nActiveGroup); - - std::unique_ptr<SmSubSupNode> pNode(new SmSubSupNode(m_aCurToken)); - //! Of course 'm_aCurToken' is just the first sub-/supscript token. - //! It should be of no further interest. The positions of the - //! sub-/supscripts will be identified by the corresponding subnodes - //! index in the 'aSubNodes' array (enum value from 'SmSubSup'). - - pNode->SetUseLimits(nActiveGroup == TG::Limit); - - // initialize subnodes array - std::vector<std::unique_ptr<SmNode>> aSubNodes(1 + SUBSUP_NUM_ENTRIES); - aSubNodes[0] = std::move(xGivenNode); - - // process all sub-/supscripts - int nIndex = 0; - while (TokenInGroup(nActiveGroup)) - { - SmTokenType eType (m_aCurToken.eType); - - switch (eType) - { - case TRSUB : nIndex = static_cast<int>(RSUB); break; - case TRSUP : nIndex = static_cast<int>(RSUP); break; - case TFROM : - case TCSUB : nIndex = static_cast<int>(CSUB); break; - case TTO : - case TCSUP : nIndex = static_cast<int>(CSUP); break; - case TLSUB : nIndex = static_cast<int>(LSUB); break; - case TLSUP : nIndex = static_cast<int>(LSUP); break; - default : - SAL_WARN( "starmath", "unknown case"); - } - nIndex++; - assert(1 <= nIndex && nIndex <= SUBSUP_NUM_ENTRIES); - - std::unique_ptr<SmNode> xENode; - if (aSubNodes[nIndex]) // if already occupied at earlier iteration - { - // forget the earlier one, remember an error instead - aSubNodes[nIndex].reset(); - xENode = DoError(SmParseError::DoubleSubsupscript); // this also skips current token. - } - else - { - // skip sub-/supscript token - NextToken(); - } - - // get sub-/supscript node - // (even when we saw a double-sub/supscript error in the above - // in order to minimize mess and continue parsing.) - std::unique_ptr<SmNode> xSNode; - if (eType == TFROM || eType == TTO) - { - // parse limits in old 4.0 and 5.0 style - xSNode = DoRelation(); - } - else - xSNode = DoTerm(true); - - aSubNodes[nIndex] = std::move(xENode ? xENode : xSNode); - } - - pNode->SetSubNodes(buildNodeArray(aSubNodes)); - return pNode; -} - -std::unique_ptr<SmNode> SmParser::DoSubSupEvaluate(std::unique_ptr<SmNode> xGivenNode) -{ - DepthProtect aDepthGuard(m_nParseDepth); - - std::unique_ptr<SmSubSupNode> pNode(new SmSubSupNode(m_aCurToken)); - pNode->SetUseLimits(true); - - // initialize subnodes array - std::vector<std::unique_ptr<SmNode>> aSubNodes(1 + SUBSUP_NUM_ENTRIES); - aSubNodes[0] = std::move(xGivenNode); - - // process all sub-/supscripts - int nIndex = 0; - while (TokenInGroup(TG::Limit)) - { - SmTokenType eType (m_aCurToken.eType); - - switch (eType) - { - case TFROM : nIndex = static_cast<int>(RSUB); break; - case TTO : nIndex = static_cast<int>(RSUP); break; - default : - SAL_WARN( "starmath", "unknown case"); - } - nIndex++; - assert(1 <= nIndex && nIndex <= SUBSUP_NUM_ENTRIES); - - std::unique_ptr<SmNode> xENode; - if (aSubNodes[nIndex]) // if already occupied at earlier iteration - { - // forget the earlier one, remember an error instead - aSubNodes[nIndex].reset(); - xENode = DoError(SmParseError::DoubleSubsupscript); // this also skips current token. - } - else NextToken(); // skip sub-/supscript token - - // get sub-/supscript node - std::unique_ptr<SmNode> xSNode; - xSNode = DoTerm(true); - - aSubNodes[nIndex] = std::move(xENode ? xENode : xSNode); - } - - pNode->SetSubNodes(buildNodeArray(aSubNodes)); - return pNode; -} - -std::unique_ptr<SmNode> SmParser::DoOpSubSup() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - // get operator symbol - auto xNode = std::make_unique<SmMathSymbolNode>(m_aCurToken); - // skip operator token - NextToken(); - // get sub- supscripts if any - if (m_aCurToken.nGroup == TG::Power) - return DoSubSup(TG::Power, std::move(xNode)); - return xNode; -} - -std::unique_ptr<SmNode> SmParser::DoPower() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - // get body for sub- supscripts on top of stack - std::unique_ptr<SmNode> xNode(DoTerm(false)); - - if (m_aCurToken.nGroup == TG::Power) - return DoSubSup(TG::Power, std::move(xNode)); - return xNode; -} - -std::unique_ptr<SmBlankNode> SmParser::DoBlank() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - assert(TokenInGroup(TG::Blank)); - std::unique_ptr<SmBlankNode> pBlankNode(new SmBlankNode(m_aCurToken)); - - do - { - pBlankNode->IncreaseBy(m_aCurToken); - NextToken(); - } - while (TokenInGroup(TG::Blank)); - - // Ignore trailing spaces, if corresponding option is set - if ( m_aCurToken.eType == TNEWLINE || - (m_aCurToken.eType == TEND && SM_MOD()->GetConfig()->IsIgnoreSpacesRight()) ) - { - pBlankNode->Clear(); - } - return pBlankNode; -} - -std::unique_ptr<SmNode> SmParser::DoTerm(bool bGroupNumberIdent) -{ - DepthProtect aDepthGuard(m_nParseDepth); - - switch (m_aCurToken.eType) - { - case TESCAPE : - return DoEscape(); - - case TNOSPACE : - case TLGROUP : - { - bool bNoSpace = m_aCurToken.eType == TNOSPACE; - if (bNoSpace) - NextToken(); - if (m_aCurToken.eType != TLGROUP) - return DoTerm(false); // nospace is no longer concerned - - NextToken(); - - // allow for empty group - if (m_aCurToken.eType == TRGROUP) - { - std::unique_ptr<SmStructureNode> xSNode(new SmExpressionNode(m_aCurToken)); - xSNode->SetSubNodes(nullptr, nullptr); - - NextToken(); - return std::unique_ptr<SmNode>(xSNode.release()); - } - - auto pNode = DoAlign(!bNoSpace); - if (m_aCurToken.eType == TRGROUP) { - NextToken(); - return pNode; - } - auto xSNode = std::make_unique<SmExpressionNode>(m_aCurToken); - std::unique_ptr<SmNode> xError(DoError(SmParseError::RgroupExpected)); - xSNode->SetSubNodes(std::move(pNode), std::move(xError)); - return std::unique_ptr<SmNode>(xSNode.release()); - } - - case TLEFT : - return DoBrace(); - case TEVALUATE: - return DoEvaluate(); - - case TBLANK : - case TSBLANK : - return DoBlank(); - - case TTEXT : - { - auto pNode = std::make_unique<SmTextNode>(m_aCurToken, FNT_TEXT); - NextToken(); - return std::unique_ptr<SmNode>(pNode.release()); - } - case TCHARACTER : - { - auto pNode = std::make_unique<SmTextNode>(m_aCurToken, FNT_VARIABLE); - NextToken(); - return std::unique_ptr<SmNode>(pNode.release()); - } - case TIDENT : - case TNUMBER : - { - auto pTextNode = std::make_unique<SmTextNode>(m_aCurToken, - m_aCurToken.eType == TNUMBER ? - FNT_NUMBER : - FNT_VARIABLE); - if (!bGroupNumberIdent) - { - NextToken(); - return std::unique_ptr<SmNode>(pTextNode.release()); - } - std::vector<std::unique_ptr<SmNode>> aNodes; - // Some people want to be able to write "x_2n" for "x_{2n}" - // although e.g. LaTeX or AsciiMath interpret that as "x_2 n". - // The tokenizer skips whitespaces so we need some additional - // work to distinguish from "x_2 n". - // See https://bz.apache.org/ooo/show_bug.cgi?id=11752 and - // https://bugs.libreoffice.org/show_bug.cgi?id=55853 - sal_Int32 nBufLen = m_aBufferString.getLength(); - - // We need to be careful to call NextToken() only after having - // tested for a whitespace separator (otherwise it will be - // skipped!) - bool moveToNextToken = true; - while (m_nBufferIndex < nBufLen && - m_pSysCC->getType(m_aBufferString, m_nBufferIndex) != - UnicodeType::SPACE_SEPARATOR) - { - NextToken(); - if (m_aCurToken.eType != TNUMBER && - m_aCurToken.eType != TIDENT) - { - // Neither a number nor an identifier. We just moved to - // the next token, so no need to do that again. - moveToNextToken = false; - break; - } - aNodes.emplace_back(std::unique_ptr<SmNode>(new SmTextNode(m_aCurToken, - m_aCurToken.eType == - TNUMBER ? - FNT_NUMBER : - FNT_VARIABLE))); - } - if (moveToNextToken) - NextToken(); - if (aNodes.empty()) - return std::unique_ptr<SmNode>(pTextNode.release()); - // We have several concatenated identifiers and numbers. - // Let's group them into one SmExpressionNode. - aNodes.insert(aNodes.begin(), std::move(pTextNode)); - std::unique_ptr<SmExpressionNode> xNode(new SmExpressionNode(SmToken())); - xNode->SetSubNodes(buildNodeArray(aNodes)); - return std::unique_ptr<SmNode>(xNode.release()); - } - case TLEFTARROW : - case TRIGHTARROW : - case TUPARROW : - case TDOWNARROW : - case TCIRC : - case TDRARROW : - case TDLARROW : - case TDLRARROW : - case TEXISTS : - case TNOTEXISTS : - case TFORALL : - case TPARTIAL : - case TNABLA : - case TLAPLACE : - case TFOURIER : - case TTOWARD : - case TDOTSAXIS : - case TDOTSDIAG : - case TDOTSDOWN : - case TDOTSLOW : - case TDOTSUP : - case TDOTSVERT : - { - auto pNode = std::make_unique<SmMathSymbolNode>(m_aCurToken); - NextToken(); - return std::unique_ptr<SmNode>(pNode.release()); - } - - case TSETN : - case TSETZ : - case TSETQ : - case TSETR : - case TSETC : - case THBAR : - case TLAMBDABAR : - case TBACKEPSILON : - case TALEPH : - case TIM : - case TRE : - case TWP : - case TEMPTYSET : - case TINFINITY : - { - auto pNode = std::make_unique<SmMathIdentifierNode>(m_aCurToken); - NextToken(); - return std::unique_ptr<SmNode>(pNode.release()); - } - - case TPLACE: - { - auto pNode = std::make_unique<SmPlaceNode>(m_aCurToken); - NextToken(); - return std::unique_ptr<SmNode>(pNode.release()); - } - - case TSPECIAL: - return DoSpecial(); - - case TBINOM: - return DoBinom(); - - case TFRAC: - return DoFrac(); - - case TSTACK: - return DoStack(); - - case TMATRIX: - return DoMatrix(); - - case THEX: - NextTokenFontSize(); - if( m_aCurToken.eType == THEX ) - { - auto pTextNode = std::make_unique<SmTextNode>(m_aCurToken, FNT_NUMBER ); - NextToken(); - return pTextNode; - } - else return DoError(SmParseError::NumberExpected); - default: - if (TokenInGroup(TG::LBrace)) return DoBrace(); - if (TokenInGroup(TG::Oper)) return DoOperator(); - if (TokenInGroup(TG::UnOper)) return DoUnOper(); - if ( TokenInGroup(TG::Attribute) || TokenInGroup(TG::FontAttr) ) - { - std::stack<std::unique_ptr<SmStructureNode>> aStack; - bool bIsAttr; - for (;;) - { - bIsAttr = TokenInGroup(TG::Attribute); - if (!bIsAttr && !TokenInGroup(TG::FontAttr)) - break; - aStack.push(bIsAttr ? DoAttribute() : DoFontAttribute()); - } - - auto xFirstNode = DoPower(); - while (!aStack.empty()) - { - std::unique_ptr<SmStructureNode> xNode = std::move(aStack.top()); - aStack.pop(); - xNode->SetSubNodes(nullptr, std::move(xFirstNode)); - xFirstNode = std::move(xNode); - } - return xFirstNode; - } - if (TokenInGroup(TG::Function)) - return DoFunction(); - return DoError(SmParseError::UnexpectedChar); - } -} - -std::unique_ptr<SmNode> SmParser::DoEscape() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - NextToken(); - - switch (m_aCurToken.eType) - { - case TLPARENT : - case TRPARENT : - case TLBRACKET : - case TRBRACKET : - case TLDBRACKET : - case TRDBRACKET : - case TLBRACE : - case TLGROUP : - case TRBRACE : - case TRGROUP : - case TLANGLE : - case TRANGLE : - case TLCEIL : - case TRCEIL : - case TLFLOOR : - case TRFLOOR : - case TLLINE : - case TRLINE : - case TLDLINE : - case TRDLINE : - { - auto pNode = std::make_unique<SmMathSymbolNode>(m_aCurToken); - NextToken(); - return std::unique_ptr<SmNode>(pNode.release()); - } - default: - return DoError(SmParseError::UnexpectedToken); - } -} - -std::unique_ptr<SmOperNode> SmParser::DoOperator() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - assert(TokenInGroup(TG::Oper)); - - auto xSNode = std::make_unique<SmOperNode>(m_aCurToken); - - // get operator - auto xOperator = DoOper(); - - if (m_aCurToken.nGroup == TG::Limit || m_aCurToken.nGroup == TG::Power) - xOperator = DoSubSup(m_aCurToken.nGroup, std::move(xOperator)); - - // get argument - auto xArg = DoPower(); - - xSNode->SetSubNodes(std::move(xOperator), std::move(xArg)); - return xSNode; -} - -std::unique_ptr<SmNode> SmParser::DoOper() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - SmTokenType eType (m_aCurToken.eType); - std::unique_ptr<SmNode> pNode; - - switch (eType) - { - case TSUM : - case TPROD : - case TCOPROD : - case TINT : - case TINTD : - case TIINT : - case TIIINT : - case TLINT : - case TLLINT : - case TLLLINT : - pNode.reset(new SmMathSymbolNode(m_aCurToken)); - break; - - case TLIM : - case TLIMSUP : - case TLIMINF : - m_aCurToken.aText = eType == TLIMSUP ? u"lim sup" - : eType == TLIMINF ? u"lim inf" : u"lim"; - pNode.reset(new SmTextNode(m_aCurToken, FNT_TEXT)); - break; - - case TOPER : - NextToken(); - OSL_ENSURE(m_aCurToken.eType == TSPECIAL, "Sm: wrong token"); - m_aCurToken.eType = TOPER; - pNode.reset(new SmGlyphSpecialNode(m_aCurToken)); - break; - - default : - assert(false && "unknown case"); - } - - NextToken(); - return pNode; -} - -std::unique_ptr<SmStructureNode> SmParser::DoUnOper() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - assert(TokenInGroup(TG::UnOper)); - - SmToken aNodeToken = m_aCurToken; - SmTokenType eType = m_aCurToken.eType; - bool bIsPostfix = eType == TFACT; - - std::unique_ptr<SmStructureNode> xSNode; - std::unique_ptr<SmNode> xOper; - std::unique_ptr<SmNode> xExtra; - std::unique_ptr<SmNode> xArg; - - switch (eType) - { - case TABS : - case TSQRT : - NextToken(); - break; - - case TNROOT : - NextToken(); - xExtra = DoPower(); - break; - - case TUOPER : - NextToken(); - //Let the glyph know what it is... - m_aCurToken.eType = TUOPER; - m_aCurToken.nGroup = TG::UnOper; - xOper = DoGlyphSpecial(); - break; - - case TPLUS : - case TMINUS : - case TPLUSMINUS : - case TMINUSPLUS : - case TNEG : - case TFACT : - xOper = DoOpSubSup(); - break; - - default : - assert(false); - } - - // get argument - xArg = DoPower(); - - if (eType == TABS) - { - xSNode.reset(new SmBraceNode(aNodeToken)); - xSNode->SetScaleMode(SmScaleMode::Height); - - // build nodes for left & right lines - // (text, group, level of the used token are of no interest here) - // we'll use row & column of the keyword for abs - aNodeToken.eType = TABS; - - aNodeToken.setChar(MS_VERTLINE); - std::unique_ptr<SmNode> xLeft(new SmMathSymbolNode(aNodeToken)); - std::unique_ptr<SmNode> xRight(new SmMathSymbolNode(aNodeToken)); - - xSNode->SetSubNodes(std::move(xLeft), std::move(xArg), std::move(xRight)); - } - else if (eType == TSQRT || eType == TNROOT) - { - xSNode.reset(new SmRootNode(aNodeToken)); - xOper.reset(new SmRootSymbolNode(aNodeToken)); - xSNode->SetSubNodes(std::move(xExtra), std::move(xOper), std::move(xArg)); - } - else - { - xSNode.reset(new SmUnHorNode(aNodeToken)); - if (bIsPostfix) - xSNode->SetSubNodes(std::move(xArg), std::move(xOper)); - else - { - // prefix operator - xSNode->SetSubNodes(std::move(xOper), std::move(xArg)); - } - } - return xSNode; -} - -std::unique_ptr<SmStructureNode> SmParser::DoAttribute() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - assert(TokenInGroup(TG::Attribute)); - - auto xSNode = std::make_unique<SmAttributeNode>(m_aCurToken); - std::unique_ptr<SmNode> xAttr; - SmScaleMode eScaleMode = SmScaleMode::None; - - // get appropriate node for the attribute itself - switch (m_aCurToken.eType) - { case TUNDERLINE : - case TOVERLINE : - case TOVERSTRIKE : - xAttr.reset(new SmRectangleNode(m_aCurToken)); - eScaleMode = SmScaleMode::Width; - break; - - case TWIDEVEC : - case TWIDEHARPOON : - case TWIDEHAT : - case TWIDETILDE : - xAttr.reset(new SmMathSymbolNode(m_aCurToken)); - eScaleMode = SmScaleMode::Width; - break; - - default : - xAttr.reset(new SmMathSymbolNode(m_aCurToken)); - } - - NextToken(); - - xSNode->SetSubNodes(std::move(xAttr), nullptr); // the body will be filled later - xSNode->SetScaleMode(eScaleMode); - return xSNode; -} - -std::unique_ptr<SmStructureNode> SmParser::DoFontAttribute() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - assert(TokenInGroup(TG::FontAttr)); - - switch (m_aCurToken.eType) - { - case TITALIC : - case TNITALIC : - case TBOLD : - case TNBOLD : - case TPHANTOM : - { - auto pNode = std::make_unique<SmFontNode>(m_aCurToken); - NextToken(); - return pNode; - } - - case TSIZE : - return DoFontSize(); - - case TFONT : - return DoFont(); - - case TCOLOR : - return DoColor(); - - default : - assert(false); - return {}; - } -} - -std::unique_ptr<SmStructureNode> SmParser::DoColor() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - assert(m_aCurToken.eType == TCOLOR); - sal_Int32 nBufferIndex = m_nBufferIndex; - NextTokenColor(TCOLOR); - SmToken aToken; - - if( m_aCurToken.eType == TDVIPSNAMESCOL ) NextTokenColor(TDVIPSNAMESCOL); - if( m_aCurToken.eType == TERROR ) return DoError(SmParseError::ColorExpected); - if (TokenInGroup(TG::Color)) - { - aToken = m_aCurToken; - if( m_aCurToken.eType == TRGB ) //loads r, g and b - { - sal_uInt32 nr, ng, nb, nc; - NextTokenFontSize(); - if( lcl_IsNotWholeNumber(m_aCurToken.aText) ) - return DoError(SmParseError::ColorExpected); - nr = m_aCurToken.aText.toUInt32(); - if( nr > 255 )return DoError(SmParseError::ColorExpected); - NextTokenFontSize(); - if( lcl_IsNotWholeNumber(m_aCurToken.aText) ) - return DoError(SmParseError::ColorExpected); - ng = m_aCurToken.aText.toUInt32(); - if( ng > 255 )return DoError(SmParseError::ColorExpected); - NextTokenFontSize(); - if( lcl_IsNotWholeNumber(m_aCurToken.aText) ) - return DoError(SmParseError::ColorExpected); - nb = m_aCurToken.aText.toUInt32(); - if( nb > 255 )return DoError(SmParseError::ColorExpected); - nc = nb | ng << 8 | nr << 16 | sal_uInt32(0) << 24; - aToken.cMathChar = OUString::number(nc, 16); - } - else if( m_aCurToken.eType == TRGBA ) //loads r, g and b - { - sal_uInt32 nr, na, ng, nb, nc; - NextTokenFontSize(); - if( lcl_IsNotWholeNumber(m_aCurToken.aText) ) - return DoError(SmParseError::ColorExpected); - nr = m_aCurToken.aText.toUInt32(); - if( nr > 255 )return DoError(SmParseError::ColorExpected); - NextTokenFontSize(); - if( lcl_IsNotWholeNumber(m_aCurToken.aText) ) - return DoError(SmParseError::ColorExpected); - ng = m_aCurToken.aText.toUInt32(); - if( ng > 255 )return DoError(SmParseError::ColorExpected); - NextTokenFontSize(); - if( lcl_IsNotWholeNumber(m_aCurToken.aText) ) - return DoError(SmParseError::ColorExpected); - nb = m_aCurToken.aText.toUInt32(); - if( nb > 255 )return DoError(SmParseError::ColorExpected); - NextTokenFontSize(); - if( lcl_IsNotWholeNumber(m_aCurToken.aText) ) - return DoError(SmParseError::ColorExpected); - na = m_aCurToken.aText.toUInt32(); - if( na > 255 )return DoError(SmParseError::ColorExpected); - nc = nb | ng << 8 | nr << 16 | na << 24; - aToken.cMathChar = OUString::number(nc, 16); - } - else if( m_aCurToken.eType == THEX ) //loads hex code - { - sal_uInt32 nc; - NextTokenFontSize(); - if( lcl_IsNotWholeNumber16(m_aCurToken.aText) ) - return DoError(SmParseError::ColorExpected); - nc = m_aCurToken.aText.toUInt32(16); - aToken.cMathChar = OUString::number(nc, 16); - } - aToken.aText = m_aBufferString.subView(nBufferIndex, m_nBufferIndex - nBufferIndex); - NextToken(); - } - else return DoError(SmParseError::ColorExpected); - - std::unique_ptr<SmStructureNode> xNode; - xNode.reset(new SmFontNode(aToken)); - return xNode; -} - -std::unique_ptr<SmStructureNode> SmParser::DoFont() -{ - DepthProtect aDepthGuard(m_nParseDepth); - - assert(m_aCurToken.eType == TFONT); - - std::unique_ptr<SmStructureNode> xNode; - // last font rules, get that one - SmToken aToken; - do - { NextToken(); - - if (TokenInGroup(TG::Font)) - { aToken = m_aCurToken; - NextToken(); - } - else - { - return DoError(SmParseError::FontExpected); - } - } while (m_aCurToken.eType == TFONT); - - xNode.reset(new SmFontNode(aToken)); - return xNode; -} - -std::unique_ptr<SmStructureNode> SmParser::DoFontSize() -{ - DepthProtect aDepthGuard(m_nParseDepth); - std::unique_ptr<SmFontNode> pFontNode(new SmFontNode(m_aCurToken)); - NextTokenFontSize(); - FontSizeType Type; - - switch (m_aCurToken.eType) - { - case THEX: Type = FontSizeType::ABSOLUT; break; - case TPLUS: Type = FontSizeType::PLUS; break; - case TMINUS: Type = FontSizeType::MINUS; break; - case TMULTIPLY: Type = FontSizeType::MULTIPLY; break; - case TDIVIDEBY: Type = FontSizeType::DIVIDE; break; - - default: - return DoError(SmParseError::SizeExpected); - } - - if (Type != FontSizeType::ABSOLUT) - { ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
