LCOV - code coverage report
Current view: top level - slideshow/source/engine - smilfunctionparser.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 144 0.0 %
Date: 2012-08-25 Functions: 0 56 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*
       3                 :            :  * This file is part of the LibreOffice project.
       4                 :            :  *
       5                 :            :  * This Source Code Form is subject to the terms of the Mozilla Public
       6                 :            :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7                 :            :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8                 :            :  *
       9                 :            :  * This file incorporates work covered by the following license notice:
      10                 :            :  *
      11                 :            :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12                 :            :  *   contributor license agreements. See the NOTICE file distributed
      13                 :            :  *   with this work for additional information regarding copyright
      14                 :            :  *   ownership. The ASF licenses this file to you under the Apache
      15                 :            :  *   License, Version 2.0 (the "License"); you may not use this file
      16                 :            :  *   except in compliance with the License. You may obtain a copy of
      17                 :            :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18                 :            :  */
      19                 :            : 
      20                 :            : 
      21                 :            : // must be first
      22                 :            : #include <canvas/debug.hxx>
      23                 :            : #include <tools/diagnose_ex.h>
      24                 :            : 
      25                 :            : #include <rtl/math.hxx>
      26                 :            : 
      27                 :            : #include <smilfunctionparser.hxx>
      28                 :            : #include <expressionnodefactory.hxx>
      29                 :            : 
      30                 :            : #include <rtl/ustring.hxx>
      31                 :            : #include <canvas/verbosetrace.hxx>
      32                 :            : 
      33                 :            : #include <basegfx/matrix/b2dhommatrix.hxx>
      34                 :            : #include <basegfx/point/b2dpoint.hxx>
      35                 :            : 
      36                 :            : // Makes parser a static resource,
      37                 :            : // we're synchronized externally.
      38                 :            : // But watch out, the parser might have
      39                 :            : // state not visible to this code!
      40                 :            : #define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
      41                 :            : #if defined(VERBOSE) && defined(DBG_UTIL)
      42                 :            : #include <typeinfo>
      43                 :            : #define BOOST_SPIRIT_DEBUG
      44                 :            : #endif
      45                 :            : #include <boost/spirit/include/classic_core.hpp>
      46                 :            : 
      47                 :            : #if OSL_DEBUG_LEVEL > 0
      48                 :            : #include <iostream>
      49                 :            : #endif
      50                 :            : #include <functional>
      51                 :            : #include <algorithm>
      52                 :            : #include <stack>
      53                 :            : 
      54                 :            : 
      55                 :            : 
      56                 :            : /* Implementation of SmilFunctionParser class */
      57                 :            : 
      58                 :            : namespace slideshow
      59                 :            : {
      60                 :            :     namespace internal
      61                 :            :     {
      62                 :            :         namespace
      63                 :            :         {
      64                 :            :             typedef const sal_Char*                   StringIteratorT;
      65                 :            : 
      66                 :          0 :             struct ParserContext
      67                 :            :             {
      68                 :            :                 typedef ::std::stack< ExpressionNodeSharedPtr > OperandStack;
      69                 :            : 
      70                 :            :                 // stores a stack of not-yet-evaluated operands. This is used
      71                 :            :                 // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
      72                 :            :                 // arguments from. If all arguments to an operator are constant,
      73                 :            :                 // the operator pushes a precalculated result on the stack, and
      74                 :            :                 // a composite ExpressionNode otherwise.
      75                 :            :                 OperandStack                maOperandStack;
      76                 :            : 
      77                 :            :                 // bounds of the shape this expression is associated with
      78                 :            :                 ::basegfx::B2DRectangle     maShapeBounds;
      79                 :            : 
      80                 :            :                 // when true, enable usage of time-dependent variable '$'
      81                 :            :                 // in expressions
      82                 :            :                 bool                        mbParseAnimationFunction;
      83                 :            :             };
      84                 :            : 
      85                 :            :             typedef ::boost::shared_ptr< ParserContext > ParserContextSharedPtr;
      86                 :            : 
      87                 :            : 
      88                 :          0 :             template< typename Generator > class ShapeBoundsFunctor
      89                 :            :             {
      90                 :            :             public:
      91                 :          0 :                 ShapeBoundsFunctor( Generator                       aGenerator,
      92                 :            :                                     const ParserContextSharedPtr&   rContext ) :
      93                 :            :                     maGenerator( aGenerator ),
      94                 :          0 :                     mpContext( rContext )
      95                 :            :                 {
      96                 :          0 :                     ENSURE_OR_THROW( mpContext,
      97                 :            :                                       "ShapeBoundsFunctor::ShapeBoundsFunctor(): Invalid context" );
      98                 :          0 :                 }
      99                 :            : 
     100                 :          0 :                 void operator()( StringIteratorT, StringIteratorT ) const
     101                 :            :                 {
     102                 :          0 :                     mpContext->maOperandStack.push(
     103                 :            :                         ExpressionNodeFactory::createConstantValueExpression(
     104                 :            :                             maGenerator( mpContext->maShapeBounds ) ) );
     105                 :          0 :                 }
     106                 :            : 
     107                 :            :             private:
     108                 :            :                 Generator               maGenerator;
     109                 :            :                 ParserContextSharedPtr  mpContext;
     110                 :            :             };
     111                 :            : 
     112                 :            :             template< typename Generator > ShapeBoundsFunctor< Generator >
     113                 :          0 :                 makeShapeBoundsFunctor( const Generator&                rGenerator,
     114                 :            :                                         const ParserContextSharedPtr&   rContext )
     115                 :            :             {
     116                 :          0 :                 return ShapeBoundsFunctor<Generator>(rGenerator, rContext);
     117                 :            :             }
     118                 :            : 
     119                 :            :             /** Generate apriori constant value
     120                 :            :              */
     121                 :          0 :             class ConstantFunctor
     122                 :            :             {
     123                 :            :             public:
     124                 :          0 :                 ConstantFunctor( double                         rValue,
     125                 :            :                                  const ParserContextSharedPtr&  rContext ) :
     126                 :            :                     mnValue( rValue ),
     127                 :          0 :                     mpContext( rContext )
     128                 :            :                 {
     129                 :          0 :                     ENSURE_OR_THROW( mpContext,
     130                 :            :                                       "ConstantFunctor::ConstantFunctor(): Invalid context" );
     131                 :          0 :                 }
     132                 :            : 
     133                 :          0 :                 void operator()( StringIteratorT, StringIteratorT ) const
     134                 :            :                 {
     135                 :          0 :                     mpContext->maOperandStack.push(
     136                 :          0 :                         ExpressionNodeFactory::createConstantValueExpression( mnValue ) );
     137                 :          0 :                 }
     138                 :            : 
     139                 :            :             private:
     140                 :            :                 const double            mnValue;
     141                 :            :                 ParserContextSharedPtr  mpContext;
     142                 :            :             };
     143                 :            : 
     144                 :            :             /** Generate parse-dependent-but-then-constant value
     145                 :            :              */
     146                 :          0 :             class DoubleConstantFunctor
     147                 :            :             {
     148                 :            :             public:
     149                 :          0 :                 DoubleConstantFunctor( const ParserContextSharedPtr& rContext ) :
     150                 :          0 :                     mpContext( rContext )
     151                 :            :                 {
     152                 :          0 :                     ENSURE_OR_THROW( mpContext,
     153                 :            :                                       "DoubleConstantFunctor::DoubleConstantFunctor(): Invalid context" );
     154                 :          0 :                 }
     155                 :            : 
     156                 :          0 :                 void operator()( double n ) const
     157                 :            :                 {
     158                 :            :                     // push constant value expression to the stack
     159                 :          0 :                     mpContext->maOperandStack.push(
     160                 :          0 :                         ExpressionNodeFactory::createConstantValueExpression( n ) );
     161                 :          0 :                 }
     162                 :            : 
     163                 :            :             private:
     164                 :            :                 ParserContextSharedPtr  mpContext;
     165                 :            :             };
     166                 :            : 
     167                 :            :             /** Generate special t value expression node
     168                 :            :              */
     169                 :          0 :             class ValueTFunctor
     170                 :            :             {
     171                 :            :             public:
     172                 :          0 :                 ValueTFunctor( const ParserContextSharedPtr& rContext ) :
     173                 :          0 :                     mpContext( rContext )
     174                 :            :                 {
     175                 :          0 :                     ENSURE_OR_THROW( mpContext,
     176                 :            :                                       "ValueTFunctor::ValueTFunctor(): Invalid context" );
     177                 :          0 :                 }
     178                 :            : 
     179                 :          0 :                 void operator()( StringIteratorT, StringIteratorT ) const
     180                 :            :                 {
     181                 :          0 :                     if( !mpContext->mbParseAnimationFunction )
     182                 :            :                     {
     183                 :            :                         OSL_FAIL( "ValueTFunctor::operator(): variable encountered, but we're not parsing a function here" );
     184                 :          0 :                         throw ParseError();
     185                 :            :                     }
     186                 :            : 
     187                 :            :                     // push special t value expression to the stack
     188                 :          0 :                     mpContext->maOperandStack.push(
     189                 :          0 :                         ExpressionNodeFactory::createValueTExpression() );
     190                 :          0 :                 }
     191                 :            : 
     192                 :            :             private:
     193                 :            :                 ParserContextSharedPtr  mpContext;
     194                 :            :             };
     195                 :            : 
     196                 :          0 :             template< typename Functor > class UnaryFunctionFunctor
     197                 :            :             {
     198                 :            :             private:
     199                 :            :                 /** ExpressionNode implementation for unary
     200                 :            :                     function over one ExpressionNode
     201                 :            :                  */
     202                 :          0 :                 class UnaryFunctionExpression : public ExpressionNode
     203                 :            :                 {
     204                 :            :                 public:
     205                 :          0 :                     UnaryFunctionExpression( const Functor&                 rFunctor,
     206                 :            :                                              const ExpressionNodeSharedPtr& rArg ) :
     207                 :            :                         maFunctor( rFunctor ),
     208                 :          0 :                         mpArg( rArg )
     209                 :            :                     {
     210                 :          0 :                     }
     211                 :            : 
     212                 :          0 :                     virtual double operator()( double t ) const
     213                 :            :                     {
     214                 :          0 :                         return maFunctor( (*mpArg)(t) );
     215                 :            :                     }
     216                 :            : 
     217                 :          0 :                     virtual bool isConstant() const
     218                 :            :                     {
     219                 :          0 :                         return mpArg->isConstant();
     220                 :            :                     }
     221                 :            : 
     222                 :            :                 private:
     223                 :            :                     Functor                 maFunctor;
     224                 :            :                     ExpressionNodeSharedPtr mpArg;
     225                 :            :                 };
     226                 :            : 
     227                 :            :             public:
     228                 :          0 :                 UnaryFunctionFunctor( const Functor&                rFunctor,
     229                 :            :                                       const ParserContextSharedPtr& rContext ) :
     230                 :            :                     maFunctor( rFunctor ),
     231                 :          0 :                     mpContext( rContext )
     232                 :            :                 {
     233                 :          0 :                     ENSURE_OR_THROW( mpContext,
     234                 :            :                                       "UnaryFunctionFunctor::UnaryFunctionFunctor(): Invalid context" );
     235                 :          0 :                 }
     236                 :            : 
     237                 :          0 :                 void operator()( StringIteratorT, StringIteratorT ) const
     238                 :            :                 {
     239                 :          0 :                     ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
     240                 :            : 
     241                 :          0 :                     if( rNodeStack.size() < 1 )
     242                 :          0 :                         throw ParseError( "Not enough arguments for unary operator" );
     243                 :            : 
     244                 :            :                     // retrieve arguments
     245                 :          0 :                     ExpressionNodeSharedPtr pArg( rNodeStack.top() );
     246                 :          0 :                     rNodeStack.pop();
     247                 :            : 
     248                 :            :                     // check for constness
     249                 :          0 :                     if( pArg->isConstant() )
     250                 :            :                     {
     251                 :          0 :                         rNodeStack.push(
     252                 :            :                             ExpressionNodeFactory::createConstantValueExpression(
     253                 :            :                                 maFunctor( (*pArg)(0.0) ) ) );
     254                 :            :                     }
     255                 :            :                     else
     256                 :            :                     {
     257                 :            :                         // push complex node, that calcs the value on demand
     258                 :          0 :                         rNodeStack.push(
     259                 :            :                             ExpressionNodeSharedPtr(
     260                 :            :                                 new UnaryFunctionExpression(
     261                 :            :                                     maFunctor,
     262                 :            :                                     pArg ) ) );
     263                 :            :                     }
     264                 :          0 :                 }
     265                 :            : 
     266                 :            :             private:
     267                 :            :                 Functor                 maFunctor;
     268                 :            :                 ParserContextSharedPtr  mpContext;
     269                 :            :             };
     270                 :            : 
     271                 :            :             // TODO(Q2): Refactor makeUnaryFunctionFunctor,
     272                 :            :             // makeBinaryFunctionFunctor and the whole
     273                 :            :             // ExpressionNodeFactory, to use a generic
     274                 :            :             // makeFunctionFunctor template, which is overloaded for
     275                 :            :             // unary, binary, ternary, etc. function pointers.
     276                 :            :             template< typename Functor > UnaryFunctionFunctor<Functor>
     277                 :          0 :                 makeUnaryFunctionFunctor( const Functor&                rFunctor,
     278                 :            :                                           const ParserContextSharedPtr& rContext )
     279                 :            :             {
     280                 :          0 :                 return UnaryFunctionFunctor<Functor>( rFunctor, rContext );
     281                 :            :             }
     282                 :            : 
     283                 :            :             // MSVC has problems instantiating above template function with plain function
     284                 :            :             // pointers (doesn't like the const reference there). Thus, provide it with
     285                 :            :             // a dedicated overload here.
     286                 :            :             UnaryFunctionFunctor< double (*)(double) >
     287                 :          0 :                 makeUnaryFunctionFunctor( double (*pFunc)(double),
     288                 :            :                                           const ParserContextSharedPtr& rContext )
     289                 :            :             {
     290                 :          0 :                 return UnaryFunctionFunctor< double (*)(double) >( pFunc, rContext );
     291                 :            :             }
     292                 :            : 
     293                 :            :             /** Implements a binary function over two ExpressionNodes
     294                 :            : 
     295                 :            :                 @tpl Generator
     296                 :            :                 Generator functor, to generate an ExpressionNode of
     297                 :            :                 appropriate type
     298                 :            : 
     299                 :            :              */
     300                 :          0 :             template< class Generator > class BinaryFunctionFunctor
     301                 :            :             {
     302                 :            :             public:
     303                 :          0 :                 BinaryFunctionFunctor( const Generator&                 rGenerator,
     304                 :            :                                        const ParserContextSharedPtr&    rContext ) :
     305                 :            :                     maGenerator( rGenerator ),
     306                 :          0 :                     mpContext( rContext )
     307                 :            :                 {
     308                 :          0 :                     ENSURE_OR_THROW( mpContext,
     309                 :            :                                       "BinaryFunctionFunctor::BinaryFunctionFunctor(): Invalid context" );
     310                 :          0 :                 }
     311                 :            : 
     312                 :          0 :                 void operator()( StringIteratorT, StringIteratorT ) const
     313                 :            :                 {
     314                 :          0 :                     ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
     315                 :            : 
     316                 :          0 :                     if( rNodeStack.size() < 2 )
     317                 :          0 :                         throw ParseError( "Not enough arguments for binary operator" );
     318                 :            : 
     319                 :            :                     // retrieve arguments
     320                 :          0 :                     ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() );
     321                 :          0 :                     rNodeStack.pop();
     322                 :          0 :                     ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() );
     323                 :          0 :                     rNodeStack.pop();
     324                 :            : 
     325                 :            :                     // create combined ExpressionNode
     326                 :            :                     ExpressionNodeSharedPtr pNode( maGenerator( pFirstArg,
     327                 :          0 :                                                                 pSecondArg ) );
     328                 :            :                     // check for constness
     329                 :          0 :                     if( pFirstArg->isConstant() &&
     330                 :            :                         pSecondArg->isConstant() )
     331                 :            :                     {
     332                 :            :                         // call the operator() at pNode, store result
     333                 :            :                         // in constant value ExpressionNode.
     334                 :          0 :                         rNodeStack.push(
     335                 :            :                             ExpressionNodeFactory::createConstantValueExpression(
     336                 :            :                                 (*pNode)( 0.0 ) ) );
     337                 :            :                     }
     338                 :            :                     else
     339                 :            :                     {
     340                 :            :                         // push complex node, that calcs the value on demand
     341                 :          0 :                         rNodeStack.push( pNode );
     342                 :            :                     }
     343                 :          0 :                 }
     344                 :            : 
     345                 :            :             private:
     346                 :            :                 Generator               maGenerator;
     347                 :            :                 ParserContextSharedPtr  mpContext;
     348                 :            :             };
     349                 :            : 
     350                 :            :             template< typename Generator > BinaryFunctionFunctor<Generator>
     351                 :          0 :                 makeBinaryFunctionFunctor( const Generator&                 rGenerator,
     352                 :            :                                            const ParserContextSharedPtr&    rContext )
     353                 :            :             {
     354                 :          0 :                 return BinaryFunctionFunctor<Generator>( rGenerator, rContext );
     355                 :            :             }
     356                 :            : 
     357                 :            : 
     358                 :            :             // Workaround for MSVC compiler anomaly (stack trashing)
     359                 :            :             //
     360                 :            :             // The default ureal_parser_policies implementation of parse_exp
     361                 :            :             // triggers a really weird error in MSVC7 (Version 13.00.9466), in
     362                 :            :             // that the real_parser_impl::parse_main() call of parse_exp()
     363                 :            :             // overwrites the frame pointer _on the stack_ (EBP of the calling
     364                 :            :             // function gets overwritten while lying on the stack).
     365                 :            :             //
     366                 :            :             // For the time being, our parser thus can only read the 1.0E10
     367                 :            :             // notation, not the 1.0e10 one.
     368                 :            :             //
     369                 :            :             // TODO(F1): Also handle the 1.0e10 case here.
     370                 :            :             template< typename T > struct custom_real_parser_policies : public ::boost::spirit::ureal_parser_policies<T>
     371                 :            :             {
     372                 :            :                 template< typename ScannerT >
     373                 :            :                     static typename ::boost::spirit::parser_result< ::boost::spirit::chlit<>, ScannerT >::type
     374                 :          0 :                 parse_exp(ScannerT& scan)
     375                 :            :                 {
     376                 :            :                     // as_lower_d somehow breaks MSVC7
     377                 :          0 :                     return ::boost::spirit::ch_p('E').parse(scan);
     378                 :            :                 }
     379                 :            :             };
     380                 :            : 
     381                 :            :             /* This class implements the following grammar (more or
     382                 :            :                less literally written down below, only slightly
     383                 :            :                obfuscated by the parser actions):
     384                 :            : 
     385                 :            :                identifier = '$'|'pi'|'e'|'X'|'Y'|'Width'|'Height'
     386                 :            : 
     387                 :            :                function = 'abs'|'sqrt'|'sin'|'cos'|'tan'|'atan'|'acos'|'asin'|'exp'|'log'
     388                 :            : 
     389                 :            :                basic_expression =
     390                 :            :                                 number |
     391                 :            :                                 identifier |
     392                 :            :                                 function '(' additive_expression ')' |
     393                 :            :                                 '(' additive_expression ')'
     394                 :            : 
     395                 :            :                unary_expression =
     396                 :            :                                    '-' basic_expression |
     397                 :            :                                 basic_expression
     398                 :            : 
     399                 :            :                multiplicative_expression =
     400                 :            :                                    unary_expression ( ( '*' unary_expression )* |
     401                 :            :                                                    ( '/' unary_expression )* )
     402                 :            : 
     403                 :            :                additive_expression =
     404                 :            :                                    multiplicative_expression ( ( '+' multiplicative_expression )* |
     405                 :            :                                                                ( '-' multiplicative_expression )* )
     406                 :            : 
     407                 :            :              */
     408                 :          0 :             class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar >
     409                 :            :             {
     410                 :            :             public:
     411                 :            :                 /** Create an arithmetic expression grammar
     412                 :            : 
     413                 :            :                     @param rParserContext
     414                 :            :                     Contains context info for the parser
     415                 :            :                  */
     416                 :          0 :                 ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
     417                 :          0 :                     mpParserContext( rParserContext )
     418                 :            :                 {
     419                 :          0 :                 }
     420                 :            : 
     421                 :          0 :                 template< typename ScannerT > class definition
     422                 :            :                 {
     423                 :            :                 public:
     424                 :            :                     // grammar definition
     425                 :          0 :                     definition( const ExpressionGrammar& self )
     426                 :          0 :                     {
     427                 :            :                         using ::boost::spirit::str_p;
     428                 :            :                         using ::boost::spirit::real_parser;
     429                 :            : 
     430                 :          0 :                         identifier =
     431                 :            :                                     str_p( "$"      )[ ValueTFunctor(                                                              self.getContext()) ]
     432                 :            :                               |     str_p( "pi"     )[ ConstantFunctor(M_PI,                                                       self.getContext()) ]
     433                 :            :                               |     str_p( "e"      )[ ConstantFunctor(M_E,                                                        self.getContext()) ]
     434                 :            :                               |     str_p( "x"      )[ makeShapeBoundsFunctor(::std::mem_fun_ref(&::basegfx::B2DRange::getCenterX),self.getContext()) ]
     435                 :            :                               |     str_p( "y"      )[ makeShapeBoundsFunctor(::std::mem_fun_ref(&::basegfx::B2DRange::getCenterY),self.getContext()) ]
     436                 :            :                               |     str_p( "width"  )[ makeShapeBoundsFunctor(::std::mem_fun_ref(&::basegfx::B2DRange::getWidth),  self.getContext()) ]
     437                 :            :                               |     str_p( "height" )[ makeShapeBoundsFunctor(::std::mem_fun_ref(&::basegfx::B2DRange::getHeight), self.getContext()) ]
     438                 :            :                               ;
     439                 :            : 
     440                 :          0 :                         unaryFunction =
     441                 :            :                                 (str_p( "abs"  ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&fabs, self.getContext()) ]
     442                 :            :                             |   (str_p( "sqrt" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&sqrt, self.getContext()) ]
     443                 :            :                             |   (str_p( "sin"  ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&sin,  self.getContext()) ]
     444                 :            :                             |   (str_p( "cos"  ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&cos,  self.getContext()) ]
     445                 :            :                             |   (str_p( "tan"  ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&tan,  self.getContext()) ]
     446                 :            :                             |   (str_p( "atan" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&atan, self.getContext()) ]
     447                 :            :                             |   (str_p( "acos" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&acos, self.getContext()) ]
     448                 :            :                             |   (str_p( "asin" ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&asin, self.getContext()) ]
     449                 :            :                             |   (str_p( "exp"  ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&exp,  self.getContext()) ]
     450                 :            :                             |   (str_p( "log"  ) >> '(' >> additiveExpression >> ')' )[ makeUnaryFunctionFunctor(&log,  self.getContext()) ]
     451                 :            :                             ;
     452                 :            : 
     453                 :          0 :                         binaryFunction =
     454                 :            :                                 (str_p( "min"  ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createMinExpression, self.getContext()) ]
     455                 :            :                             |   (str_p( "max"  ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createMaxExpression, self.getContext()) ]
     456                 :            :                             ;
     457                 :            : 
     458                 :          0 :                         basicExpression =
     459                 :            :                                 real_parser<double, custom_real_parser_policies<double> >()[ DoubleConstantFunctor(self.getContext()) ]
     460                 :            :                             |   identifier
     461                 :            :                             |   unaryFunction
     462                 :            :                             |   binaryFunction
     463                 :            :                             |   '(' >> additiveExpression >> ')'
     464                 :            :                             ;
     465                 :            : 
     466                 :          0 :                         unaryExpression =
     467                 :            :                                 ('-' >> basicExpression)[ makeUnaryFunctionFunctor(::std::negate<double>(), self.getContext()) ]
     468                 :            :                             |   basicExpression
     469                 :            :                             ;
     470                 :            : 
     471                 :          0 :                         multiplicativeExpression =
     472                 :            :                                 unaryExpression
     473                 :            :                             >> *( ('*' >> unaryExpression)[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createMultipliesExpression, self.getContext()) ]
     474                 :            :                                 | ('/' >> unaryExpression)[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createDividesExpression,    self.getContext()) ]
     475                 :            :                                 )
     476                 :            :                             ;
     477                 :            : 
     478                 :          0 :                         additiveExpression =
     479                 :            :                                 multiplicativeExpression
     480                 :            :                             >> *( ('+' >> multiplicativeExpression)[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createPlusExpression,  self.getContext()) ]
     481                 :            :                                 | ('-' >> multiplicativeExpression)[ makeBinaryFunctionFunctor(&ExpressionNodeFactory::createMinusExpression, self.getContext()) ]
     482                 :            :                                 )
     483                 :            :                             ;
     484                 :            : 
     485                 :            :                         BOOST_SPIRIT_DEBUG_RULE(additiveExpression);
     486                 :            :                         BOOST_SPIRIT_DEBUG_RULE(multiplicativeExpression);
     487                 :            :                         BOOST_SPIRIT_DEBUG_RULE(unaryExpression);
     488                 :            :                         BOOST_SPIRIT_DEBUG_RULE(basicExpression);
     489                 :            :                         BOOST_SPIRIT_DEBUG_RULE(unaryFunction);
     490                 :            :                         BOOST_SPIRIT_DEBUG_RULE(binaryFunction);
     491                 :            :                         BOOST_SPIRIT_DEBUG_RULE(identifier);
     492                 :          0 :                     }
     493                 :            : 
     494                 :          0 :                     const ::boost::spirit::rule< ScannerT >& start() const
     495                 :            :                     {
     496                 :          0 :                         return additiveExpression;
     497                 :            :                     }
     498                 :            : 
     499                 :            :                 private:
     500                 :            :                     // the constituents of the Spirit arithmetic expression grammar.
     501                 :            :                     // For the sake of readability, without 'ma' prefix.
     502                 :            :                     ::boost::spirit::rule< ScannerT >   additiveExpression;
     503                 :            :                     ::boost::spirit::rule< ScannerT >   multiplicativeExpression;
     504                 :            :                     ::boost::spirit::rule< ScannerT >   unaryExpression;
     505                 :            :                     ::boost::spirit::rule< ScannerT >   basicExpression;
     506                 :            :                     ::boost::spirit::rule< ScannerT >   unaryFunction;
     507                 :            :                     ::boost::spirit::rule< ScannerT >   binaryFunction;
     508                 :            :                     ::boost::spirit::rule< ScannerT >   identifier;
     509                 :            :                 };
     510                 :            : 
     511                 :          0 :                 const ParserContextSharedPtr& getContext() const
     512                 :            :                 {
     513                 :          0 :                     return mpParserContext;
     514                 :            :                 }
     515                 :            : 
     516                 :            :             private:
     517                 :            :                 ParserContextSharedPtr  mpParserContext; // might get modified during parsing
     518                 :            :             };
     519                 :            : 
     520                 :            : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
     521                 :          0 :             const ParserContextSharedPtr& getParserContext()
     522                 :            :             {
     523                 :          0 :                 static ParserContextSharedPtr lcl_parserContext( new ParserContext() );
     524                 :            : 
     525                 :            :                 // clear node stack (since we reuse the static object, that's
     526                 :            :                 // the whole point here)
     527                 :          0 :                 while( !lcl_parserContext->maOperandStack.empty() )
     528                 :          0 :                     lcl_parserContext->maOperandStack.pop();
     529                 :            : 
     530                 :          0 :                 return lcl_parserContext;
     531                 :            :             }
     532                 :            : #endif
     533                 :            :         }
     534                 :            : 
     535                 :          0 :         ExpressionNodeSharedPtr SmilFunctionParser::parseSmilValue( const ::rtl::OUString&          rSmilValue,
     536                 :            :                                                                     const ::basegfx::B2DRectangle&  rRelativeShapeBounds )
     537                 :            :         {
     538                 :            :             // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
     539                 :            :             // gives better conversion robustness here (we might want to map space
     540                 :            :             // etc. to ASCII space here)
     541                 :            :             const ::rtl::OString& rAsciiSmilValue(
     542                 :          0 :                 rtl::OUStringToOString( rSmilValue, RTL_TEXTENCODING_ASCII_US ) );
     543                 :            : 
     544                 :          0 :             StringIteratorT aStart( rAsciiSmilValue.getStr() );
     545                 :          0 :             StringIteratorT aEnd( rAsciiSmilValue.getStr()+rAsciiSmilValue.getLength() );
     546                 :            : 
     547                 :          0 :             ParserContextSharedPtr pContext;
     548                 :            : 
     549                 :            : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
     550                 :            :             // static parser context, because the actual
     551                 :            :             // Spirit parser is also a static object
     552                 :          0 :             pContext = getParserContext();
     553                 :            : #else
     554                 :            :             pContext.reset( new ParserContext() );
     555                 :            : #endif
     556                 :            : 
     557                 :          0 :             pContext->maShapeBounds = rRelativeShapeBounds;
     558                 :          0 :             pContext->mbParseAnimationFunction = false; // parse with '$' disabled
     559                 :            : 
     560                 :            : 
     561                 :          0 :             ExpressionGrammar aExpressionGrammer( pContext );
     562                 :            :             const ::boost::spirit::parse_info<StringIteratorT> aParseInfo(
     563                 :            :                   ::boost::spirit::parse( aStart,
     564                 :            :                                           aEnd,
     565                 :            :                                           aExpressionGrammer,
     566                 :          0 :                                           ::boost::spirit::space_p ) );
     567                 :            :             OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync
     568                 :            : 
     569                 :            :             // input fully congested by the parser?
     570                 :          0 :             if( !aParseInfo.full )
     571                 :          0 :                 throw ParseError( "SmilFunctionParser::parseSmilValue(): string not fully parseable" );
     572                 :            : 
     573                 :            :             // parser's state stack now must contain exactly _one_ ExpressionNode,
     574                 :            :             // which represents our formula.
     575                 :          0 :             if( pContext->maOperandStack.size() != 1 )
     576                 :          0 :                 throw ParseError( "SmilFunctionParser::parseSmilValue(): incomplete or empty expression" );
     577                 :            : 
     578                 :          0 :             return pContext->maOperandStack.top();
     579                 :            :         }
     580                 :            : 
     581                 :          0 :         ExpressionNodeSharedPtr SmilFunctionParser::parseSmilFunction( const ::rtl::OUString&           rSmilFunction,
     582                 :            :                                                                        const ::basegfx::B2DRectangle&   rRelativeShapeBounds )
     583                 :            :         {
     584                 :            :             // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
     585                 :            :             // gives better conversion robustness here (we might want to map space
     586                 :            :             // etc. to ASCII space here)
     587                 :            :             const ::rtl::OString& rAsciiSmilFunction(
     588                 :          0 :                 rtl::OUStringToOString( rSmilFunction, RTL_TEXTENCODING_ASCII_US ) );
     589                 :            : 
     590                 :          0 :             StringIteratorT aStart( rAsciiSmilFunction.getStr() );
     591                 :          0 :             StringIteratorT aEnd( rAsciiSmilFunction.getStr()+rAsciiSmilFunction.getLength() );
     592                 :            : 
     593                 :          0 :             ParserContextSharedPtr pContext;
     594                 :            : 
     595                 :            : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
     596                 :            :             // static parser context, because the actual
     597                 :            :             // Spirit parser is also a static object
     598                 :          0 :             pContext = getParserContext();
     599                 :            : #else
     600                 :            :             pContext.reset( new ParserContext() );
     601                 :            : #endif
     602                 :            : 
     603                 :          0 :             pContext->maShapeBounds = rRelativeShapeBounds;
     604                 :          0 :             pContext->mbParseAnimationFunction = true; // parse with '$' enabled
     605                 :            : 
     606                 :            : 
     607                 :          0 :             ExpressionGrammar aExpressionGrammer( pContext );
     608                 :            :             const ::boost::spirit::parse_info<StringIteratorT> aParseInfo(
     609                 :            :                   ::boost::spirit::parse( aStart,
     610                 :            :                                           aEnd,
     611                 :            :                                           aExpressionGrammer >> ::boost::spirit::end_p,
     612                 :          0 :                                           ::boost::spirit::space_p ) );
     613                 :            :             OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync
     614                 :            : 
     615                 :            :             // input fully congested by the parser?
     616                 :          0 :             if( !aParseInfo.full )
     617                 :          0 :                 throw ParseError( "SmilFunctionParser::parseSmilFunction(): string not fully parseable" );
     618                 :            : 
     619                 :            :             // parser's state stack now must contain exactly _one_ ExpressionNode,
     620                 :            :             // which represents our formula.
     621                 :          0 :             if( pContext->maOperandStack.size() != 1 )
     622                 :          0 :                 throw ParseError( "SmilFunctionParser::parseSmilFunction(): incomplete or empty expression" );
     623                 :            : 
     624                 :          0 :             return pContext->maOperandStack.top();
     625                 :            :         }
     626                 :            :     }
     627                 :          0 : }
     628                 :            : 
     629                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10