| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_svx.hxx" |
| #include "svx/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(); |
| } |
| |
| |
| } |
| |