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: */
|