diff options
Diffstat (limited to 'svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx')
-rw-r--r-- | svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx | 1212 |
1 files changed, 1212 insertions, 0 deletions
diff --git a/svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx b/svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx new file mode 100644 index 000000000000..a00a625693c4 --- /dev/null +++ b/svx/source/customshapes/EnhancedCustomShapeFunctionParser.cxx @@ -0,0 +1,1212 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include "EnhancedCustomShape2d.hxx" +#include <rtl/ustring.hxx> +#include <tools/fract.hxx> + +// Makes parser a static resource, +// we're synchronized externally. +// But watch out, the parser might have +// state not visible to this code! + +#define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE +#if defined(VERBOSE) && defined(DBG_UTIL) +#include <typeinfo> +#define BOOST_SPIRIT_DEBUG +#endif +#include <boost/spirit/include/classic_core.hpp> + +#if (OSL_DEBUG_LEVEL > 0) +#include <iostream> +#endif +#include <functional> +#include <algorithm> +#include <stack> + +#include <math.h> // fabs, sqrt, sin, cos, tan, atan, atan2 +using namespace EnhancedCustomShape; +using namespace com::sun::star; +using namespace com::sun::star::drawing; + +void EnhancedCustomShape::FillEquationParameter( const EnhancedCustomShapeParameter& rSource, const sal_Int32 nDestPara, EnhancedCustomShapeEquation& rDest ) +{ + sal_Int32 nValue = 0; + if ( rSource.Value.getValueTypeClass() == uno::TypeClass_DOUBLE ) + { + double fValue; + if ( rSource.Value >>= fValue ) + nValue = (sal_Int32)fValue; + } + else + rSource.Value >>= nValue; + + switch( rSource.Type ) + { + case com::sun::star::drawing::EnhancedCustomShapeParameterType::EQUATION : + { + if ( nValue & 0x40000000 ) + { + nValue ^= 0x40000000; + rDest.nOperation |= 0x20000000 << nDestPara; // the bit is indicating that this value has to be adjusted later + } + nValue |= 0x400; + } + break; + case com::sun::star::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT : nValue += DFF_Prop_adjustValue; break; + case com::sun::star::drawing::EnhancedCustomShapeParameterType::BOTTOM : nValue = DFF_Prop_geoBottom; break; + case com::sun::star::drawing::EnhancedCustomShapeParameterType::RIGHT : nValue = DFF_Prop_geoRight; break; + case com::sun::star::drawing::EnhancedCustomShapeParameterType::TOP : nValue = DFF_Prop_geoTop; break; + case com::sun::star::drawing::EnhancedCustomShapeParameterType::LEFT : nValue = DFF_Prop_geoLeft; break; + } + if ( rSource.Type != com::sun::star::drawing::EnhancedCustomShapeParameterType::NORMAL ) + rDest.nOperation |= ( 0x2000 << nDestPara ); + rDest.nPara[ nDestPara ] = nValue; +} + +ExpressionNode::~ExpressionNode() +{} + +namespace +{ + +////////////////////// +////////////////////// +// EXPRESSION NODES +////////////////////// +////////////////////// +class ConstantValueExpression : public ExpressionNode +{ + double maValue; + +public: + + ConstantValueExpression( double rValue ) : + maValue( rValue ) + { + } + virtual double operator()() const + { + return maValue; + } + virtual bool isConstant() const + { + return true; + } + virtual ExpressionFunct getType() const + { + return FUNC_CONST; + } + virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ ) + { + EnhancedCustomShapeParameter aRet; + Fraction aFract( maValue ); + if ( aFract.GetDenominator() == 1 ) + { + aRet.Type = EnhancedCustomShapeParameterType::NORMAL; + aRet.Value <<= (sal_Int32)aFract.GetNumerator(); + } + else + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation = 1; + aEquation.nPara[ 0 ] = 1; + aEquation.nPara[ 1 ] = (sal_Int16)aFract.GetNumerator(); + aEquation.nPara[ 2 ] = (sal_Int16)aFract.GetDenominator(); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + return aRet; + } +}; + +class AdjustmentExpression : public ExpressionNode +{ + sal_Int32 mnIndex; + const EnhancedCustomShape2d& mrCustoShape; + +public: + + AdjustmentExpression( const EnhancedCustomShape2d& rCustoShape, sal_Int32 nIndex ) + : mnIndex ( nIndex ) + , mrCustoShape( rCustoShape ) + + { + } + virtual double operator()() const + { + return mrCustoShape.GetAdjustValueAsDouble( mnIndex ); + } + virtual bool isConstant() const + { + return false; + } + virtual ExpressionFunct getType() const + { + return ENUM_FUNC_ADJUSTMENT; + } + virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ ) + { + EnhancedCustomShapeParameter aRet; + aRet.Type = EnhancedCustomShapeParameterType::ADJUSTMENT; + aRet.Value <<= mnIndex; + return aRet; + } +}; + +class EquationExpression : public ExpressionNode +{ + sal_Int32 mnIndex; + const EnhancedCustomShape2d& mrCustoShape; + +public: + + EquationExpression( const EnhancedCustomShape2d& rCustoShape, sal_Int32 nIndex ) + : mnIndex ( nIndex ) + , mrCustoShape( rCustoShape ) + { + } + virtual double operator()() const + { + return mrCustoShape.GetEquationValueAsDouble( mnIndex ); + } + virtual bool isConstant() const + { + return false; + } + virtual ExpressionFunct getType() const + { + return ENUM_FUNC_EQUATION; + } + virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ ) + { + EnhancedCustomShapeParameter aRet; + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= mnIndex | 0x40000000; // the bit is indicating that this equation needs to be adjusted later + return aRet; + } +}; + +class EnumValueExpression : public ExpressionNode +{ + const ExpressionFunct meFunct; + const EnhancedCustomShape2d& mrCustoShape; + +public: + + EnumValueExpression( const EnhancedCustomShape2d& rCustoShape, const ExpressionFunct eFunct ) + : meFunct ( eFunct ) + , mrCustoShape ( rCustoShape ) + { + } + static double getValue( const EnhancedCustomShape2d& rCustoShape, const ExpressionFunct eFunc ) + { + EnhancedCustomShape2d::EnumFunc eF; + switch( eFunc ) + { + case ENUM_FUNC_PI : eF = EnhancedCustomShape2d::ENUM_FUNC_PI; break; + case ENUM_FUNC_LEFT : eF = EnhancedCustomShape2d::ENUM_FUNC_LEFT; break; + case ENUM_FUNC_TOP : eF = EnhancedCustomShape2d::ENUM_FUNC_TOP; break; + case ENUM_FUNC_RIGHT : eF = EnhancedCustomShape2d::ENUM_FUNC_RIGHT; break; + case ENUM_FUNC_BOTTOM : eF = EnhancedCustomShape2d::ENUM_FUNC_BOTTOM; break; + case ENUM_FUNC_XSTRETCH : eF = EnhancedCustomShape2d::ENUM_FUNC_XSTRETCH; break; + case ENUM_FUNC_YSTRETCH : eF = EnhancedCustomShape2d::ENUM_FUNC_YSTRETCH; break; + case ENUM_FUNC_HASSTROKE : eF = EnhancedCustomShape2d::ENUM_FUNC_HASSTROKE; break; + case ENUM_FUNC_HASFILL : eF = EnhancedCustomShape2d::ENUM_FUNC_HASFILL; break; + case ENUM_FUNC_WIDTH : eF = EnhancedCustomShape2d::ENUM_FUNC_WIDTH; break; + case ENUM_FUNC_HEIGHT : eF = EnhancedCustomShape2d::ENUM_FUNC_HEIGHT; break; + case ENUM_FUNC_LOGWIDTH : eF = EnhancedCustomShape2d::ENUM_FUNC_LOGWIDTH; break; + case ENUM_FUNC_LOGHEIGHT : eF = EnhancedCustomShape2d::ENUM_FUNC_LOGHEIGHT; break; + + default : + return 0.0; + } + return rCustoShape.GetEnumFunc( eF ); + } + virtual double operator()() const + { + return getValue( mrCustoShape, meFunct ); + } + virtual bool isConstant() const + { + return false; + } + virtual ExpressionFunct getType() const + { + return meFunct; + } + virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /*pOptionalArg*/, sal_uInt32 nFlags ) + { + EnhancedCustomShapeParameter aRet; + + sal_Int32 nDummy = 1; + aRet.Value <<= nDummy; + + switch( meFunct ) + { + case ENUM_FUNC_WIDTH : // TODO: do not use this as constant value + case ENUM_FUNC_HEIGHT : + case ENUM_FUNC_LOGWIDTH : + case ENUM_FUNC_LOGHEIGHT : + case ENUM_FUNC_PI : + { + ConstantValueExpression aConstantValue( getValue( mrCustoShape, meFunct ) ); + aRet = aConstantValue.fillNode( rEquations, NULL, nFlags ); + } + break; + case ENUM_FUNC_LEFT : aRet.Type = EnhancedCustomShapeParameterType::LEFT; break; + case ENUM_FUNC_TOP : aRet.Type = EnhancedCustomShapeParameterType::TOP; break; + case ENUM_FUNC_RIGHT : aRet.Type = EnhancedCustomShapeParameterType::RIGHT; break; + case ENUM_FUNC_BOTTOM : aRet.Type = EnhancedCustomShapeParameterType::BOTTOM; break; + + // not implemented so far + case ENUM_FUNC_XSTRETCH : + case ENUM_FUNC_YSTRETCH : + case ENUM_FUNC_HASSTROKE : + case ENUM_FUNC_HASFILL : aRet.Type = EnhancedCustomShapeParameterType::NORMAL; break; + + default: + break; + } + return aRet; + } +}; + +/** ExpressionNode implementation for unary + function over one ExpressionNode + */ +class UnaryFunctionExpression : public ExpressionNode +{ + const ExpressionFunct meFunct; + ExpressionNodeSharedPtr mpArg; + +public: + UnaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) : + meFunct( eFunct ), + mpArg( rArg ) + { + } + static double getValue( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) + { + double fRet = 0; + switch( eFunct ) + { + case UNARY_FUNC_ABS : fRet = fabs( (*rArg)() ); break; + case UNARY_FUNC_SQRT: fRet = sqrt( (*rArg)() ); break; + case UNARY_FUNC_SIN : fRet = sin( (*rArg)() ); break; + case UNARY_FUNC_COS : fRet = cos( (*rArg)() ); break; + case UNARY_FUNC_TAN : fRet = tan( (*rArg)() ); break; + case UNARY_FUNC_ATAN: fRet = atan( (*rArg)() ); break; + case UNARY_FUNC_NEG : fRet = ::std::negate<double>()( (*rArg)() ); break; + default: + break; + } + return fRet; + } + virtual double operator()() const + { + return getValue( meFunct, mpArg ); + } + virtual bool isConstant() const + { + return mpArg->isConstant(); + } + virtual ExpressionFunct getType() const + { + return meFunct; + } + virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* pOptionalArg, sal_uInt32 nFlags ) + { + EnhancedCustomShapeParameter aRet; + switch( meFunct ) + { + case UNARY_FUNC_ABS : + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 3; + FillEquationParameter( mpArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case UNARY_FUNC_SQRT: + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 13; + FillEquationParameter( mpArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case UNARY_FUNC_SIN : + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 9; + if ( pOptionalArg ) + FillEquationParameter( pOptionalArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + else + aEquation.nPara[ 0 ] = 1; + + EnhancedCustomShapeParameter aSource( mpArg->fillNode( rEquations, NULL, nFlags | EXPRESSION_FLAG_SUMANGLE_MODE ) ); + if ( aSource.Type == EnhancedCustomShapeParameterType::NORMAL ) + { // sumangle needed :-( + EnhancedCustomShapeEquation _aEquation; + _aEquation.nOperation |= 0xe; // sumangle + FillEquationParameter( aSource, 1, _aEquation ); + aSource.Type = EnhancedCustomShapeParameterType::EQUATION; + aSource.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( _aEquation ); + } + FillEquationParameter( aSource, 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case UNARY_FUNC_COS : + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 10; + if ( pOptionalArg ) + FillEquationParameter( pOptionalArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + else + aEquation.nPara[ 0 ] = 1; + + EnhancedCustomShapeParameter aSource( mpArg->fillNode( rEquations, NULL, nFlags | EXPRESSION_FLAG_SUMANGLE_MODE ) ); + if ( aSource.Type == EnhancedCustomShapeParameterType::NORMAL ) + { // sumangle needed :-( + EnhancedCustomShapeEquation aTmpEquation; + aTmpEquation.nOperation |= 0xe; // sumangle + FillEquationParameter( aSource, 1, aTmpEquation ); + aSource.Type = EnhancedCustomShapeParameterType::EQUATION; + aSource.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aTmpEquation ); + } + FillEquationParameter( aSource, 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case UNARY_FUNC_TAN : + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 16; + if ( pOptionalArg ) + FillEquationParameter( pOptionalArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + else + aEquation.nPara[ 0 ] = 1; + + EnhancedCustomShapeParameter aSource( mpArg->fillNode( rEquations, NULL, nFlags | EXPRESSION_FLAG_SUMANGLE_MODE ) ); + if ( aSource.Type == EnhancedCustomShapeParameterType::NORMAL ) + { // sumangle needed :-( + EnhancedCustomShapeEquation aTmpEquation; + aTmpEquation.nOperation |= 0xe; // sumangle + FillEquationParameter( aSource, 1, aTmpEquation ); + aSource.Type = EnhancedCustomShapeParameterType::EQUATION; + aSource.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aTmpEquation ); + } + FillEquationParameter( aSource, 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case UNARY_FUNC_ATAN: + { +// TODO: + aRet.Type = EnhancedCustomShapeParameterType::NORMAL; + } + break; + case UNARY_FUNC_NEG: + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 1; + aEquation.nPara[ 1 ] = -1; + aEquation.nPara[ 2 ] = 1; + FillEquationParameter( mpArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + default: + break; + } + return aRet; + } +}; + +/** ExpressionNode implementation for unary + function over two ExpressionNodes + */ +class BinaryFunctionExpression : public ExpressionNode +{ + const ExpressionFunct meFunct; + ExpressionNodeSharedPtr mpFirstArg; + ExpressionNodeSharedPtr mpSecondArg; + +public: + + BinaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rFirstArg, const ExpressionNodeSharedPtr& rSecondArg ) : + meFunct( eFunct ), + mpFirstArg( rFirstArg ), + mpSecondArg( rSecondArg ) + { + } + static double getValue( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rFirstArg, const ExpressionNodeSharedPtr& rSecondArg ) + { + double fRet = 0; + switch( eFunct ) + { + case BINARY_FUNC_PLUS : fRet = (*rFirstArg)() + (*rSecondArg)(); break; + case BINARY_FUNC_MINUS: fRet = (*rFirstArg)() - (*rSecondArg)(); break; + case BINARY_FUNC_MUL : fRet = (*rFirstArg)() * (*rSecondArg)(); break; + case BINARY_FUNC_DIV : fRet = (*rFirstArg)() / (*rSecondArg)(); break; + case BINARY_FUNC_MIN : fRet = ::std::min( (*rFirstArg)(), (*rSecondArg)() ); break; + case BINARY_FUNC_MAX : fRet = ::std::max( (*rFirstArg)(), (*rSecondArg)() ); break; + case BINARY_FUNC_ATAN2: fRet = atan2( (*rFirstArg)(), (*rSecondArg)() ); break; + default: + break; + } + return fRet; + } + virtual double operator()() const + { + return getValue( meFunct, mpFirstArg, mpSecondArg ); + } + virtual bool isConstant() const + { + return mpFirstArg->isConstant() && mpSecondArg->isConstant(); + } + virtual ExpressionFunct getType() const + { + return meFunct; + } + virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /*pOptionalArg*/, sal_uInt32 nFlags ) + { + EnhancedCustomShapeParameter aRet; + switch( meFunct ) + { + case BINARY_FUNC_PLUS : + { + if ( nFlags & EXPRESSION_FLAG_SUMANGLE_MODE ) + { + if ( mpFirstArg->getType() == ENUM_FUNC_ADJUSTMENT ) + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 0xe; // sumangle + FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + else if ( mpSecondArg->getType() == ENUM_FUNC_ADJUSTMENT ) + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 0xe; // sumangle + FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + else + { + EnhancedCustomShapeEquation aSumangle1; + aSumangle1.nOperation |= 0xe; // sumangle + FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags &~EXPRESSION_FLAG_SUMANGLE_MODE ), 1, aSumangle1 ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aSumangle1 ); + + EnhancedCustomShapeEquation aSumangle2; + aSumangle2.nOperation |= 0xe; // sumangle + FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags &~EXPRESSION_FLAG_SUMANGLE_MODE ), 1, aSumangle2 ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aSumangle2 ); + + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 0; + aEquation.nPara[ 0 ] = ( rEquations.size() - 2 ) | 0x400; + aEquation.nPara[ 1 ] = ( rEquations.size() - 1 ) | 0x400; + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + } + else + { + sal_Bool bFirstIsEmpty = mpFirstArg->isConstant() && ( (*mpFirstArg)() == 0 ); + sal_Bool bSecondIsEmpty = mpSecondArg->isConstant() && ( (*mpSecondArg)() == 0 ); + + if ( bFirstIsEmpty ) + aRet = mpSecondArg->fillNode( rEquations, NULL, nFlags ); + else if ( bSecondIsEmpty ) + aRet = mpFirstArg->fillNode( rEquations, NULL, nFlags ); + else + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 0; + FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + } + } + break; + case BINARY_FUNC_MINUS: + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 0; + FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 2, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case BINARY_FUNC_MUL : + { + // in the dest. format the cos function is using integer as result :-( + // so we can't use the generic algorithm + if ( ( mpFirstArg->getType() == UNARY_FUNC_SIN ) || ( mpFirstArg->getType() == UNARY_FUNC_COS ) || ( mpFirstArg->getType() == UNARY_FUNC_TAN ) ) + aRet = mpFirstArg->fillNode( rEquations, mpSecondArg.get(), nFlags ); + else if ( ( mpSecondArg->getType() == UNARY_FUNC_SIN ) || ( mpSecondArg->getType() == UNARY_FUNC_COS ) || ( mpSecondArg->getType() == UNARY_FUNC_TAN ) ) + aRet = mpSecondArg->fillNode( rEquations, mpFirstArg.get(), nFlags ); + else + { + if ( mpFirstArg->isConstant() && (*mpFirstArg)() == 1 ) + aRet = mpSecondArg->fillNode( rEquations, NULL, nFlags ); + else if ( mpSecondArg->isConstant() && (*mpSecondArg)() == 1 ) + aRet = mpFirstArg->fillNode( rEquations, NULL, nFlags ); + else if ( ( mpFirstArg->getType() == BINARY_FUNC_DIV ) // don't care of (pi/180) + && ( ((BinaryFunctionExpression*)((BinaryFunctionExpression*)mpFirstArg.get())->mpFirstArg.get())->getType() == ENUM_FUNC_PI ) + && ( ((BinaryFunctionExpression*)((BinaryFunctionExpression*)mpFirstArg.get())->mpSecondArg.get())->getType() == FUNC_CONST ) ) + { + aRet = mpSecondArg->fillNode( rEquations, NULL, nFlags ); + } + else if ( ( mpSecondArg->getType() == BINARY_FUNC_DIV ) // don't care of (pi/180) + && ( ((BinaryFunctionExpression*)((BinaryFunctionExpression*)mpSecondArg.get())->mpFirstArg.get())->getType() == ENUM_FUNC_PI ) + && ( ((BinaryFunctionExpression*)((BinaryFunctionExpression*)mpSecondArg.get())->mpSecondArg.get())->getType() == FUNC_CONST ) ) + { + aRet = mpFirstArg->fillNode( rEquations, NULL, nFlags ); + } + else + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 1; + FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation ); + aEquation.nPara[ 2 ] = 1; + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + } + } + break; + case BINARY_FUNC_DIV : + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 1; + FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + aEquation.nPara[ 1 ] = 1; + FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 2, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case BINARY_FUNC_MIN : + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 4; + FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case BINARY_FUNC_MAX : + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 5; + FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + case BINARY_FUNC_ATAN2: + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 8; + FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation ); + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + rEquations.push_back( aEquation ); + } + break; + default: + break; + } + return aRet; + } +}; + +class IfExpression : public ExpressionNode +{ + ExpressionNodeSharedPtr mpFirstArg; + ExpressionNodeSharedPtr mpSecondArg; + ExpressionNodeSharedPtr mpThirdArg; + +public: + + IfExpression( const ExpressionNodeSharedPtr& rFirstArg, + const ExpressionNodeSharedPtr& rSecondArg, + const ExpressionNodeSharedPtr& rThirdArg ) : + mpFirstArg( rFirstArg ), + mpSecondArg( rSecondArg ), + mpThirdArg( rThirdArg ) + { + } + virtual bool isConstant() const + { + return + mpFirstArg->isConstant() && + mpSecondArg->isConstant() && + mpThirdArg->isConstant(); + } + virtual double operator()() const + { + return (*mpFirstArg)() > 0 ? (*mpSecondArg)() : (*mpThirdArg)(); + } + virtual ExpressionFunct getType() const + { + return TERNARY_FUNC_IF; + } + virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /*pOptionalArg*/, sal_uInt32 nFlags ) + { + EnhancedCustomShapeParameter aRet; + aRet.Type = EnhancedCustomShapeParameterType::EQUATION; + aRet.Value <<= (sal_Int32)rEquations.size(); + { + EnhancedCustomShapeEquation aEquation; + aEquation.nOperation |= 6; + FillEquationParameter( mpFirstArg->fillNode( rEquations, NULL, nFlags ), 0, aEquation ); + FillEquationParameter( mpSecondArg->fillNode( rEquations, NULL, nFlags ), 1, aEquation ); + FillEquationParameter( mpThirdArg->fillNode( rEquations, NULL, nFlags ), 2, aEquation ); + rEquations.push_back( aEquation ); + } + return aRet; + } +}; + +//////////////////////// +//////////////////////// +// FUNCTION PARSER +//////////////////////// +//////////////////////// + +typedef const sal_Char* StringIteratorT; + +struct ParserContext +{ + typedef ::std::stack< ExpressionNodeSharedPtr > OperandStack; + + // stores a stack of not-yet-evaluated operands. This is used + // by the operators (i.e. '+', '*', 'sin' etc.) to pop their + // arguments from. If all arguments to an operator are constant, + // the operator pushes a precalculated result on the stack, and + // a composite ExpressionNode otherwise. + OperandStack maOperandStack; + + const EnhancedCustomShape2d* mpCustoShape; + +}; + +typedef ::boost::shared_ptr< ParserContext > ParserContextSharedPtr; + +/** Generate apriori constant value + */ + +class ConstantFunctor +{ + const double mnValue; + ParserContextSharedPtr mpContext; + +public: + + ConstantFunctor( double rValue, const ParserContextSharedPtr& rContext ) : + mnValue( rValue ), + mpContext( rContext ) + { + } + void operator()( StringIteratorT /*rFirst*/, StringIteratorT /*rSecond*/ ) const + { + mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( mnValue ) ) ); + } +}; + +/** Generate parse-dependent-but-then-constant value + */ +class DoubleConstantFunctor +{ + ParserContextSharedPtr mpContext; + +public: + DoubleConstantFunctor( const ParserContextSharedPtr& rContext ) : + mpContext( rContext ) + { + } + void operator()( double n ) const + { + mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( n ) ) ); + } +}; + +class EnumFunctor +{ + const ExpressionFunct meFunct; + double mnValue; + ParserContextSharedPtr mpContext; + +public: + + EnumFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) + : meFunct( eFunct ) + , mnValue( 0 ) + , mpContext( rContext ) + { + } + void operator()( StringIteratorT rFirst, StringIteratorT rSecond ) const + { + /*double nVal = mnValue;*/ + switch( meFunct ) + { + case ENUM_FUNC_ADJUSTMENT : + { + rtl::OUString aVal( rFirst + 1, rSecond - rFirst, RTL_TEXTENCODING_UTF8 ); + mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new AdjustmentExpression( *mpContext->mpCustoShape, aVal.toInt32() ) ) ); + } + break; + case ENUM_FUNC_EQUATION : + { + rtl::OUString aVal( rFirst + 1, rSecond - rFirst, RTL_TEXTENCODING_UTF8 ); + mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new EquationExpression( *mpContext->mpCustoShape, aVal.toInt32() ) ) ); + } + break; + default: + mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new EnumValueExpression( *mpContext->mpCustoShape, meFunct ) ) ); + } + } +}; + +class UnaryFunctionFunctor +{ + const ExpressionFunct meFunct; + ParserContextSharedPtr mpContext; + +public : + + UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) : + meFunct( eFunct ), + mpContext( rContext ) + { + } + void operator()( StringIteratorT, StringIteratorT ) const + { + ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); + + if( rNodeStack.size() < 1 ) + throw ParseError( "Not enough arguments for unary operator" ); + + // retrieve arguments + ExpressionNodeSharedPtr pArg( rNodeStack.top() ); + rNodeStack.pop(); + + if( pArg->isConstant() ) // check for constness + rNodeStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( UnaryFunctionExpression::getValue( meFunct, pArg ) ) ) ); + else // push complex node, that calcs the value on demand + rNodeStack.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct, pArg ) ) ); + } +}; + +/** Implements a binary function over two ExpressionNodes + + @tpl Generator + Generator functor, to generate an ExpressionNode of + appropriate type + + */ +class BinaryFunctionFunctor +{ + const ExpressionFunct meFunct; + ParserContextSharedPtr mpContext; + +public: + + BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) : + meFunct( eFunct ), + mpContext( rContext ) + { + } + + void operator()( StringIteratorT, StringIteratorT ) const + { + ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); + + if( rNodeStack.size() < 2 ) + throw ParseError( "Not enough arguments for binary operator" ); + + // retrieve arguments + ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() ); + rNodeStack.pop(); + ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() ); + rNodeStack.pop(); + + // create combined ExpressionNode + ExpressionNodeSharedPtr pNode = ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct, pFirstArg, pSecondArg ) ); + // check for constness + if( pFirstArg->isConstant() && pSecondArg->isConstant() ) // call the operator() at pNode, store result in constant value ExpressionNode. + rNodeStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( (*pNode)() ) ) ); + else // push complex node, that calcs the value on demand + rNodeStack.push( pNode ); + } +}; + +class IfFunctor +{ + ParserContextSharedPtr mpContext; + +public : + + IfFunctor( const ParserContextSharedPtr& rContext ) : + mpContext( rContext ) + { + } + void operator()( StringIteratorT, StringIteratorT ) const + { + ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); + + if( rNodeStack.size() < 3 ) + throw ParseError( "Not enough arguments for ternary operator" ); + + // retrieve arguments + ExpressionNodeSharedPtr pThirdArg( rNodeStack.top() ); + rNodeStack.pop(); + ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() ); + rNodeStack.pop(); + ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() ); + rNodeStack.pop(); + + // create combined ExpressionNode + ExpressionNodeSharedPtr pNode( new IfExpression( pFirstArg, pSecondArg, pThirdArg ) ); + // check for constness + if( pFirstArg->isConstant() && pSecondArg->isConstant() && pThirdArg->isConstant() ) + rNodeStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( (*pNode)() ) ) ); // call the operator() at pNode, store result in constant value ExpressionNode. + else + rNodeStack.push( pNode ); // push complex node, that calcs the value on demand + } +}; + +// Workaround for MSVC compiler anomaly (stack trashing) +// +// The default ureal_parser_policies implementation of parse_exp +// triggers a really weird error in MSVC7 (Version 13.00.9466), in +// that the real_parser_impl::parse_main() call of parse_exp() +// overwrites the frame pointer _on the stack_ (EBP of the calling +// function gets overwritten while lying on the stack). +// +// For the time being, our parser thus can only read the 1.0E10 +// notation, not the 1.0e10 one. +// +// TODO(F1): Also handle the 1.0e10 case here. +template< typename T > struct custom_real_parser_policies : public ::boost::spirit::ureal_parser_policies<T> +{ + template< typename ScannerT > + static typename ::boost::spirit::parser_result< ::boost::spirit::chlit<>, ScannerT >::type + parse_exp(ScannerT& scan) + { + // as_lower_d somehow breaks MSVC7 + return ::boost::spirit::ch_p('E').parse(scan); + } +}; + +/* This class implements the following grammar (more or + less literally written down below, only slightly + obfuscated by the parser actions): + + identifier = '$'|'pi'|'e'|'X'|'Y'|'Width'|'Height' + + function = 'abs'|'sqrt'|'sin'|'cos'|'tan'|'atan'|'acos'|'asin'|'exp'|'log' + + basic_expression = + number | + identifier | + function '(' additive_expression ')' | + '(' additive_expression ')' + + unary_expression = + '-' basic_expression | + basic_expression + + multiplicative_expression = + unary_expression ( ( '*' unary_expression )* | + ( '/' unary_expression )* ) + + additive_expression = + multiplicative_expression ( ( '+' multiplicative_expression )* | + ( '-' multiplicative_expression )* ) + + */ + +class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar > +{ +public: + /** Create an arithmetic expression grammar + + @param rParserContext + Contains context info for the parser + */ + ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) : + mpParserContext( rParserContext ) + { + } + + template< typename ScannerT > class definition + { + public: + // grammar definition + definition( const ExpressionGrammar& self ) + { + using ::boost::spirit::str_p; + using ::boost::spirit::range_p; + using ::boost::spirit::lexeme_d; + using ::boost::spirit::real_parser; + using ::boost::spirit::chseq_p; + + identifier = + str_p( "pi" )[ EnumFunctor(ENUM_FUNC_PI, self.getContext() ) ] + | str_p( "left" )[ EnumFunctor(ENUM_FUNC_LEFT, self.getContext() ) ] + | str_p( "top" )[ EnumFunctor(ENUM_FUNC_TOP, self.getContext() ) ] + | str_p( "right" )[ EnumFunctor(ENUM_FUNC_RIGHT, self.getContext() ) ] + | str_p( "bottom" )[ EnumFunctor(ENUM_FUNC_BOTTOM, self.getContext() ) ] + | str_p( "xstretch" )[ EnumFunctor(ENUM_FUNC_XSTRETCH, self.getContext() ) ] + | str_p( "ystretch" )[ EnumFunctor(ENUM_FUNC_YSTRETCH, self.getContext() ) ] + | str_p( "hasstroke" )[ EnumFunctor(ENUM_FUNC_HASSTROKE, self.getContext() ) ] + | str_p( "hasfill" )[ EnumFunctor(ENUM_FUNC_HASFILL, self.getContext() ) ] + | str_p( "width" )[ EnumFunctor(ENUM_FUNC_WIDTH, self.getContext() ) ] + | str_p( "height" )[ EnumFunctor(ENUM_FUNC_HEIGHT, self.getContext() ) ] + | str_p( "logwidth" )[ EnumFunctor(ENUM_FUNC_LOGWIDTH, self.getContext() ) ] + | str_p( "logheight" )[ EnumFunctor(ENUM_FUNC_LOGHEIGHT, self.getContext() ) ] + ; + + unaryFunction = + (str_p( "abs" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_ABS, self.getContext()) ] + | (str_p( "sqrt" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_SQRT, self.getContext()) ] + | (str_p( "sin" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_SIN, self.getContext()) ] + | (str_p( "cos" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_COS, self.getContext()) ] + | (str_p( "tan" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_TAN, self.getContext()) ] + | (str_p( "atan" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( UNARY_FUNC_ATAN, self.getContext()) ] + ; + + binaryFunction = + (str_p( "min" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( BINARY_FUNC_MIN, self.getContext()) ] + | (str_p( "max" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( BINARY_FUNC_MAX, self.getContext()) ] + | (str_p( "atan2") >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( BINARY_FUNC_ATAN2,self.getContext()) ] + ; + + ternaryFunction = + (str_p( "if" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ IfFunctor( self.getContext() ) ] + ; + + funcRef_decl = + lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]; + + functionReference = + (str_p( "?" ) >> funcRef_decl )[ EnumFunctor( ENUM_FUNC_EQUATION, self.getContext() ) ]; + + modRef_decl = + lexeme_d[ +( range_p('0','9') ) ]; + + modifierReference = + (str_p( "$" ) >> modRef_decl )[ EnumFunctor( ENUM_FUNC_ADJUSTMENT, self.getContext() ) ]; + + basicExpression = + real_parser<double, custom_real_parser_policies<double> >()[ DoubleConstantFunctor(self.getContext()) ] + | identifier + | functionReference + | modifierReference + | unaryFunction + | binaryFunction + | ternaryFunction + | '(' >> additiveExpression >> ')' + ; + + unaryExpression = + ('-' >> basicExpression)[ UnaryFunctionFunctor( UNARY_FUNC_NEG, self.getContext()) ] + | basicExpression + ; + + multiplicativeExpression = + unaryExpression + >> *( ('*' >> unaryExpression)[ BinaryFunctionFunctor( BINARY_FUNC_MUL, self.getContext()) ] + | ('/' >> unaryExpression)[ BinaryFunctionFunctor( BINARY_FUNC_DIV, self.getContext()) ] + ) + ; + + additiveExpression = + multiplicativeExpression + >> *( ('+' >> multiplicativeExpression)[ BinaryFunctionFunctor( BINARY_FUNC_PLUS, self.getContext()) ] + | ('-' >> multiplicativeExpression)[ BinaryFunctionFunctor( BINARY_FUNC_MINUS, self.getContext()) ] + ) + ; + + BOOST_SPIRIT_DEBUG_RULE(additiveExpression); + BOOST_SPIRIT_DEBUG_RULE(multiplicativeExpression); + BOOST_SPIRIT_DEBUG_RULE(unaryExpression); + BOOST_SPIRIT_DEBUG_RULE(basicExpression); + BOOST_SPIRIT_DEBUG_RULE(unaryFunction); + BOOST_SPIRIT_DEBUG_RULE(binaryFunction); + BOOST_SPIRIT_DEBUG_RULE(ternaryFunction); + BOOST_SPIRIT_DEBUG_RULE(identifier); + } + + const ::boost::spirit::rule< ScannerT >& start() const + { + return additiveExpression; + } + + private: + // the constituents of the Spirit arithmetic expression grammar. + // For the sake of readability, without 'ma' prefix. + ::boost::spirit::rule< ScannerT > additiveExpression; + ::boost::spirit::rule< ScannerT > multiplicativeExpression; + ::boost::spirit::rule< ScannerT > unaryExpression; + ::boost::spirit::rule< ScannerT > basicExpression; + ::boost::spirit::rule< ScannerT > unaryFunction; + ::boost::spirit::rule< ScannerT > binaryFunction; + ::boost::spirit::rule< ScannerT > ternaryFunction; + ::boost::spirit::rule< ScannerT > funcRef_decl; + ::boost::spirit::rule< ScannerT > functionReference; + ::boost::spirit::rule< ScannerT > modRef_decl; + ::boost::spirit::rule< ScannerT > modifierReference; + ::boost::spirit::rule< ScannerT > identifier; + }; + + const ParserContextSharedPtr& getContext() const + { + return mpParserContext; + } + +private: + ParserContextSharedPtr mpParserContext; // might get modified during parsing +}; + +#ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE +const ParserContextSharedPtr& getParserContext() +{ + static ParserContextSharedPtr lcl_parserContext( new ParserContext() ); + + // clear node stack (since we reuse the static object, that's + // the whole point here) + while( !lcl_parserContext->maOperandStack.empty() ) + lcl_parserContext->maOperandStack.pop(); + + return lcl_parserContext; +} +#endif + +} + +namespace EnhancedCustomShape { + + + +ExpressionNodeSharedPtr FunctionParser::parseFunction( const ::rtl::OUString& rFunction, const EnhancedCustomShape2d& rCustoShape ) +{ + // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_* + // gives better conversion robustness here (we might want to map space + // etc. to ASCII space here) + const ::rtl::OString& rAsciiFunction( + rtl::OUStringToOString( rFunction, RTL_TEXTENCODING_ASCII_US ) ); + + StringIteratorT aStart( rAsciiFunction.getStr() ); + StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() ); + + ParserContextSharedPtr pContext; + +#ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE + // static parser context, because the actual + // Spirit parser is also a static object + pContext = getParserContext(); +#else + pContext.reset( new ParserContext() ); +#endif + pContext->mpCustoShape = &rCustoShape; + + ExpressionGrammar aExpressionGrammer( pContext ); + const ::boost::spirit::parse_info<StringIteratorT> aParseInfo( + ::boost::spirit::parse( aStart, + aEnd, + aExpressionGrammer >> ::boost::spirit::end_p, + ::boost::spirit::space_p ) ); + OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync + + + + // input fully congested by the parser? + if( !aParseInfo.full ) + throw ParseError( "EnhancedCustomShapeFunctionParser::parseFunction(): string not fully parseable" ); + + // parser's state stack now must contain exactly _one_ ExpressionNode, + // which represents our formula. + if( pContext->maOperandStack.size() != 1 ) + throw ParseError( "EnhancedCustomShapeFunctionParser::parseFunction(): incomplete or empty expression" ); + + + return pContext->maOperandStack.top(); +} + + +} + |