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