Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / svx / source / customshapes / EnhancedCustomShapeFunctionParser.cxx
blob2ef6b040e6ce7b1ea2e307119fd4a12d43b0b3e4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <svx/EnhancedCustomShape2d.hxx>
23 #include <rtl/ustring.hxx>
24 #include <sal/log.hxx>
25 #include <tools/fract.hxx>
27 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
29 // Makes parser a static resource,
30 // we're synchronized externally.
31 // But watch out, the parser might have
32 // state not visible to this code!
34 #define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
36 #if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
37 #define BOOST_SPIRIT_DEBUG
38 #endif
39 #include <boost/spirit/include/classic_core.hpp>
41 #include <functional>
42 #include <algorithm>
43 #include <stack>
45 #include <math.h>
46 using namespace EnhancedCustomShape;
47 using namespace com::sun::star;
48 using namespace com::sun::star::drawing;
50 void EnhancedCustomShape::FillEquationParameter( const EnhancedCustomShapeParameter& rSource, const sal_Int32 nDestPara, EnhancedCustomShapeEquation& rDest )
52 sal_Int32 nValue = 0;
53 if ( rSource.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
55 double fValue(0.0);
56 if ( rSource.Value >>= fValue )
57 nValue = static_cast<sal_Int32>(fValue);
59 else
60 rSource.Value >>= nValue;
62 switch( rSource.Type )
64 case css::drawing::EnhancedCustomShapeParameterType::EQUATION :
66 if ( nValue & 0x40000000 )
68 nValue ^= 0x40000000;
69 rDest.nOperation |= 0x20000000 << nDestPara; // the bit is indicating that this value has to be adjusted later
71 nValue |= 0x400;
73 break;
74 case css::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT : nValue += DFF_Prop_adjustValue; break;
75 case css::drawing::EnhancedCustomShapeParameterType::BOTTOM : nValue = DFF_Prop_geoBottom; break;
76 case css::drawing::EnhancedCustomShapeParameterType::RIGHT : nValue = DFF_Prop_geoRight; break;
77 case css::drawing::EnhancedCustomShapeParameterType::TOP : nValue = DFF_Prop_geoTop; break;
78 case css::drawing::EnhancedCustomShapeParameterType::LEFT : nValue = DFF_Prop_geoLeft; break;
80 if ( rSource.Type != css::drawing::EnhancedCustomShapeParameterType::NORMAL )
81 rDest.nOperation |= ( 0x2000 << nDestPara );
82 rDest.nPara[ nDestPara ] = nValue;
85 ExpressionNode::~ExpressionNode()
88 namespace
92 // EXPRESSION NODES
95 class ConstantValueExpression : public ExpressionNode
97 double maValue;
99 public:
101 explicit ConstantValueExpression( double rValue ) :
102 maValue( rValue )
105 virtual double operator()() const override
107 return maValue;
109 virtual bool isConstant() const override
111 return true;
113 virtual ExpressionFunct getType() const override
115 return ExpressionFunct::Const;
117 virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ ) override
119 EnhancedCustomShapeParameter aRet;
120 Fraction aFract( maValue );
121 if ( aFract.GetDenominator() == 1 )
123 aRet.Type = EnhancedCustomShapeParameterType::NORMAL;
124 aRet.Value <<= aFract.GetNumerator();
126 else
128 EnhancedCustomShapeEquation aEquation;
129 aEquation.nOperation = 1;
130 aEquation.nPara[ 0 ] = 1;
131 aEquation.nPara[ 1 ] = static_cast<sal_Int16>(aFract.GetNumerator());
132 aEquation.nPara[ 2 ] = static_cast<sal_Int16>(aFract.GetDenominator());
133 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
134 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
135 rEquations.push_back( aEquation );
137 return aRet;
141 class AdjustmentExpression : public ExpressionNode
143 sal_Int32 mnIndex;
144 const EnhancedCustomShape2d& mrCustoShape;
146 public:
148 AdjustmentExpression( const EnhancedCustomShape2d& rCustoShape, sal_Int32 nIndex )
149 : mnIndex ( nIndex )
150 , mrCustoShape( rCustoShape )
154 virtual double operator()() const override
156 SAL_INFO(
157 "svx",
158 "$" << mnIndex << " --> "
159 << mrCustoShape.GetAdjustValueAsDouble(mnIndex) << " (angle: "
160 << 180.0*mrCustoShape.GetAdjustValueAsDouble(mnIndex)/10800000.0
161 << ")");
162 return mrCustoShape.GetAdjustValueAsDouble( mnIndex );
164 virtual bool isConstant() const override
166 return false;
168 virtual ExpressionFunct getType() const override
170 return ExpressionFunct::EnumAdjustment;
172 virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ ) override
174 EnhancedCustomShapeParameter aRet;
175 aRet.Type = EnhancedCustomShapeParameterType::ADJUSTMENT;
176 aRet.Value <<= mnIndex;
177 return aRet;
181 class EquationExpression : public ExpressionNode
183 const sal_Int32 mnIndex;
184 const EnhancedCustomShape2d& mrCustoShape;
185 mutable bool mbGettingValueGuard;
187 public:
189 EquationExpression( const EnhancedCustomShape2d& rCustoShape, sal_Int32 nIndex )
190 : mnIndex ( nIndex )
191 , mrCustoShape( rCustoShape )
192 , mbGettingValueGuard(false)
195 virtual double operator()() const override
197 if (mbGettingValueGuard)
198 throw ParseError("Loop in Expression");
199 mbGettingValueGuard = true;
200 double fRet = mrCustoShape.GetEquationValueAsDouble(mnIndex);
201 mbGettingValueGuard = false;
202 return fRet;
204 virtual bool isConstant() const override
206 return false;
208 virtual ExpressionFunct getType() const override
210 return ExpressionFunct::EnumEquation;
212 virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ ) override
214 EnhancedCustomShapeParameter aRet;
215 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
216 aRet.Value <<= mnIndex | 0x40000000; // the bit is indicating that this equation needs to be adjusted later
217 return aRet;
221 class EnumValueExpression : public ExpressionNode
223 const ExpressionFunct meFunct;
224 const EnhancedCustomShape2d& mrCustoShape;
226 public:
228 EnumValueExpression( const EnhancedCustomShape2d& rCustoShape, const ExpressionFunct eFunct )
229 : meFunct ( eFunct )
230 , mrCustoShape ( rCustoShape )
233 virtual double operator()() const override
235 SAL_INFO("svx", meFunct << " --> " << mrCustoShape.GetEnumFunc(meFunct) << "(angle: " <<
236 180.0 * mrCustoShape.GetEnumFunc(meFunct) / 10800000.0 << ")");
238 return mrCustoShape.GetEnumFunc( meFunct );
240 virtual bool isConstant() const override
242 return false;
244 virtual ExpressionFunct getType() const override
246 return meFunct;
248 virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /*pOptionalArg*/, sal_uInt32 nFlags ) override
250 EnhancedCustomShapeParameter aRet;
252 aRet.Value <<= sal_Int32(1);
254 switch( meFunct )
256 case ExpressionFunct::EnumWidth : // TODO: do not use this as constant value
257 case ExpressionFunct::EnumHeight :
258 case ExpressionFunct::EnumLogWidth :
259 case ExpressionFunct::EnumLogHeight :
260 case ExpressionFunct::EnumPi :
262 ConstantValueExpression aConstantValue( mrCustoShape.GetEnumFunc( meFunct ) );
263 aRet = aConstantValue.fillNode( rEquations, nullptr, nFlags );
265 break;
266 case ExpressionFunct::EnumLeft : aRet.Type = EnhancedCustomShapeParameterType::LEFT; break;
267 case ExpressionFunct::EnumTop : aRet.Type = EnhancedCustomShapeParameterType::TOP; break;
268 case ExpressionFunct::EnumRight : aRet.Type = EnhancedCustomShapeParameterType::RIGHT; break;
269 case ExpressionFunct::EnumBottom : aRet.Type = EnhancedCustomShapeParameterType::BOTTOM; break;
271 // not implemented so far
272 case ExpressionFunct::EnumXStretch :
273 case ExpressionFunct::EnumYStretch :
274 case ExpressionFunct::EnumHasStroke :
275 case ExpressionFunct::EnumHasFill : aRet.Type = EnhancedCustomShapeParameterType::NORMAL; break;
277 default:
278 break;
280 return aRet;
284 /** ExpressionNode implementation for unary
285 function over one ExpressionNode
287 class UnaryFunctionExpression : public ExpressionNode
289 const ExpressionFunct meFunct;
290 std::shared_ptr<ExpressionNode> mpArg;
292 public:
293 UnaryFunctionExpression( const ExpressionFunct eFunct, const std::shared_ptr<ExpressionNode>& rArg ) :
294 meFunct( eFunct ),
295 mpArg( rArg )
298 static double getValue( const ExpressionFunct eFunct, const std::shared_ptr<ExpressionNode>& rArg )
300 double fRet = 0;
301 switch( eFunct )
303 case ExpressionFunct::UnaryAbs : fRet = fabs( (*rArg)() ); break;
304 case ExpressionFunct::UnarySqrt: fRet = sqrt( (*rArg)() ); break;
305 case ExpressionFunct::UnarySin : fRet = sin( (*rArg)() ); break;
306 case ExpressionFunct::UnaryCos : fRet = cos( (*rArg)() ); break;
307 case ExpressionFunct::UnaryTan : fRet = tan( (*rArg)() ); break;
308 case ExpressionFunct::UnaryAtan: fRet = atan( (*rArg)() ); break;
309 case ExpressionFunct::UnaryNeg : fRet = ::std::negate<double>()( (*rArg)() ); break;
310 default:
311 break;
313 return fRet;
315 virtual double operator()() const override
317 return getValue( meFunct, mpArg );
319 virtual bool isConstant() const override
321 return mpArg->isConstant();
323 virtual ExpressionFunct getType() const override
325 return meFunct;
327 virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* pOptionalArg, sal_uInt32 nFlags ) override
329 EnhancedCustomShapeParameter aRet;
330 switch( meFunct )
332 case ExpressionFunct::UnaryAbs :
334 EnhancedCustomShapeEquation aEquation;
335 aEquation.nOperation |= 3;
336 FillEquationParameter( mpArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
337 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
338 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
339 rEquations.push_back( aEquation );
341 break;
342 case ExpressionFunct::UnarySqrt:
344 EnhancedCustomShapeEquation aEquation;
345 aEquation.nOperation |= 13;
346 FillEquationParameter( mpArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
347 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
348 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
349 rEquations.push_back( aEquation );
351 break;
352 case ExpressionFunct::UnarySin :
354 EnhancedCustomShapeEquation aEquation;
355 aEquation.nOperation |= 9;
356 if ( pOptionalArg )
357 FillEquationParameter( pOptionalArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
358 else
359 aEquation.nPara[ 0 ] = 1;
361 EnhancedCustomShapeParameter aSource( mpArg->fillNode( rEquations, nullptr, nFlags | EXPRESSION_FLAG_SUMANGLE_MODE ) );
362 if ( aSource.Type == EnhancedCustomShapeParameterType::NORMAL )
363 { // sumangle needed :-(
364 EnhancedCustomShapeEquation _aEquation;
365 _aEquation.nOperation |= 0xe; // sumangle
366 FillEquationParameter( aSource, 1, _aEquation );
367 aSource.Type = EnhancedCustomShapeParameterType::EQUATION;
368 aSource.Value <<= static_cast<sal_Int32>(rEquations.size());
369 rEquations.push_back( _aEquation );
371 FillEquationParameter( aSource, 1, aEquation );
372 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
373 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
374 rEquations.push_back( aEquation );
376 break;
377 case ExpressionFunct::UnaryCos :
379 EnhancedCustomShapeEquation aEquation;
380 aEquation.nOperation |= 10;
381 if ( pOptionalArg )
382 FillEquationParameter( pOptionalArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
383 else
384 aEquation.nPara[ 0 ] = 1;
386 EnhancedCustomShapeParameter aSource( mpArg->fillNode( rEquations, nullptr, nFlags | EXPRESSION_FLAG_SUMANGLE_MODE ) );
387 if ( aSource.Type == EnhancedCustomShapeParameterType::NORMAL )
388 { // sumangle needed :-(
389 EnhancedCustomShapeEquation aTmpEquation;
390 aTmpEquation.nOperation |= 0xe; // sumangle
391 FillEquationParameter( aSource, 1, aTmpEquation );
392 aSource.Type = EnhancedCustomShapeParameterType::EQUATION;
393 aSource.Value <<= static_cast<sal_Int32>(rEquations.size());
394 rEquations.push_back( aTmpEquation );
396 FillEquationParameter( aSource, 1, aEquation );
397 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
398 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
399 rEquations.push_back( aEquation );
401 break;
402 case ExpressionFunct::UnaryTan :
404 EnhancedCustomShapeEquation aEquation;
405 aEquation.nOperation |= 16;
406 if ( pOptionalArg )
407 FillEquationParameter( pOptionalArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
408 else
409 aEquation.nPara[ 0 ] = 1;
411 EnhancedCustomShapeParameter aSource( mpArg->fillNode( rEquations, nullptr, nFlags | EXPRESSION_FLAG_SUMANGLE_MODE ) );
412 if ( aSource.Type == EnhancedCustomShapeParameterType::NORMAL )
413 { // sumangle needed :-(
414 EnhancedCustomShapeEquation aTmpEquation;
415 aTmpEquation.nOperation |= 0xe; // sumangle
416 FillEquationParameter( aSource, 1, aTmpEquation );
417 aSource.Type = EnhancedCustomShapeParameterType::EQUATION;
418 aSource.Value <<= static_cast<sal_Int32>(rEquations.size());
419 rEquations.push_back( aTmpEquation );
421 FillEquationParameter( aSource, 1, aEquation );
422 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
423 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
424 rEquations.push_back( aEquation );
426 break;
427 case ExpressionFunct::UnaryAtan:
429 // TODO:
430 aRet.Type = EnhancedCustomShapeParameterType::NORMAL;
432 break;
433 case ExpressionFunct::UnaryNeg:
435 EnhancedCustomShapeEquation aEquation;
436 aEquation.nOperation |= 1;
437 aEquation.nPara[ 1 ] = -1;
438 aEquation.nPara[ 2 ] = 1;
439 FillEquationParameter( mpArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
440 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
441 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
442 rEquations.push_back( aEquation );
444 break;
445 default:
446 break;
448 return aRet;
452 /** ExpressionNode implementation for unary
453 function over two ExpressionNodes
455 class BinaryFunctionExpression : public ExpressionNode
457 const ExpressionFunct meFunct;
458 std::shared_ptr<ExpressionNode> mpFirstArg;
459 std::shared_ptr<ExpressionNode> mpSecondArg;
461 public:
463 BinaryFunctionExpression( const ExpressionFunct eFunct, const std::shared_ptr<ExpressionNode>& rFirstArg, const std::shared_ptr<ExpressionNode>& rSecondArg ) :
464 meFunct( eFunct ),
465 mpFirstArg( rFirstArg ),
466 mpSecondArg( rSecondArg )
469 #if defined(__clang__) || (defined (__GNUC__) && __GNUC__ >= 8)
470 //GetEquationValueAsDouble calls isFinite on the result
471 __attribute__((no_sanitize("float-divide-by-zero")))
472 #endif
473 static double getValue( const ExpressionFunct eFunct, const std::shared_ptr<ExpressionNode>& rFirstArg, const std::shared_ptr<ExpressionNode>& rSecondArg )
475 double fRet = 0;
476 switch( eFunct )
478 case ExpressionFunct::BinaryPlus : fRet = (*rFirstArg)() + (*rSecondArg)(); break;
479 case ExpressionFunct::BinaryMinus: fRet = (*rFirstArg)() - (*rSecondArg)(); break;
480 case ExpressionFunct::BinaryMul : fRet = (*rFirstArg)() * (*rSecondArg)(); break;
481 case ExpressionFunct::BinaryDiv : fRet = (*rFirstArg)() / (*rSecondArg)(); break;
482 case ExpressionFunct::BinaryMin : fRet = ::std::min( (*rFirstArg)(), (*rSecondArg)() ); break;
483 case ExpressionFunct::BinaryMax : fRet = ::std::max( (*rFirstArg)(), (*rSecondArg)() ); break;
484 case ExpressionFunct::BinaryAtan2: fRet = atan2( (*rFirstArg)(), (*rSecondArg)() ); break;
485 default:
486 break;
488 return fRet;
490 virtual double operator()() const override
492 return getValue( meFunct, mpFirstArg, mpSecondArg );
494 virtual bool isConstant() const override
496 return mpFirstArg->isConstant() && mpSecondArg->isConstant();
498 virtual ExpressionFunct getType() const override
500 return meFunct;
502 virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /*pOptionalArg*/, sal_uInt32 nFlags ) override
504 EnhancedCustomShapeParameter aRet;
505 switch( meFunct )
507 case ExpressionFunct::BinaryPlus :
509 if ( nFlags & EXPRESSION_FLAG_SUMANGLE_MODE )
511 if ( mpFirstArg->getType() == ExpressionFunct::EnumAdjustment )
513 EnhancedCustomShapeEquation aEquation;
514 aEquation.nOperation |= 0xe; // sumangle
515 FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
516 FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
517 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
518 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
519 rEquations.push_back( aEquation );
521 else if ( mpSecondArg->getType() == ExpressionFunct::EnumAdjustment )
523 EnhancedCustomShapeEquation aEquation;
524 aEquation.nOperation |= 0xe; // sumangle
525 FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
526 FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
527 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
528 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
529 rEquations.push_back( aEquation );
531 else
533 EnhancedCustomShapeEquation aSumangle1;
534 aSumangle1.nOperation |= 0xe; // sumangle
535 FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags &~EXPRESSION_FLAG_SUMANGLE_MODE ), 1, aSumangle1 );
536 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
537 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
538 rEquations.push_back( aSumangle1 );
540 EnhancedCustomShapeEquation aSumangle2;
541 aSumangle2.nOperation |= 0xe; // sumangle
542 FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags &~EXPRESSION_FLAG_SUMANGLE_MODE ), 1, aSumangle2 );
543 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
544 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
545 rEquations.push_back( aSumangle2 );
547 EnhancedCustomShapeEquation aEquation;
548 aEquation.nOperation |= 0;
549 aEquation.nPara[ 0 ] = ( rEquations.size() - 2 ) | 0x400;
550 aEquation.nPara[ 1 ] = ( rEquations.size() - 1 ) | 0x400;
551 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
552 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
553 rEquations.push_back( aEquation );
556 else
558 bool bFirstIsEmpty = mpFirstArg->isConstant() && ( (*mpFirstArg)() == 0 );
559 bool bSecondIsEmpty = mpSecondArg->isConstant() && ( (*mpSecondArg)() == 0 );
561 if ( bFirstIsEmpty )
562 aRet = mpSecondArg->fillNode( rEquations, nullptr, nFlags );
563 else if ( bSecondIsEmpty )
564 aRet = mpFirstArg->fillNode( rEquations, nullptr, nFlags );
565 else
567 EnhancedCustomShapeEquation aEquation;
568 aEquation.nOperation |= 0;
569 FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
570 FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
571 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
572 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
573 rEquations.push_back( aEquation );
577 break;
578 case ExpressionFunct::BinaryMinus:
580 EnhancedCustomShapeEquation aEquation;
581 aEquation.nOperation |= 0;
582 FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
583 FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 2, aEquation );
584 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
585 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
586 rEquations.push_back( aEquation );
588 break;
589 case ExpressionFunct::BinaryMul :
591 // in the dest. format the cos function is using integer as result :-(
592 // so we can't use the generic algorithm
593 if ( ( mpFirstArg->getType() == ExpressionFunct::UnarySin ) || ( mpFirstArg->getType() == ExpressionFunct::UnaryCos ) || ( mpFirstArg->getType() == ExpressionFunct::UnaryTan ) )
594 aRet = mpFirstArg->fillNode( rEquations, mpSecondArg.get(), nFlags );
595 else if ( ( mpSecondArg->getType() == ExpressionFunct::UnarySin ) || ( mpSecondArg->getType() == ExpressionFunct::UnaryCos ) || ( mpSecondArg->getType() == ExpressionFunct::UnaryTan ) )
596 aRet = mpSecondArg->fillNode( rEquations, mpFirstArg.get(), nFlags );
597 else
599 if ( mpFirstArg->isConstant() && (*mpFirstArg)() == 1 )
600 aRet = mpSecondArg->fillNode( rEquations, nullptr, nFlags );
601 else if ( mpSecondArg->isConstant() && (*mpSecondArg)() == 1 )
602 aRet = mpFirstArg->fillNode( rEquations, nullptr, nFlags );
603 else if ( ( mpFirstArg->getType() == ExpressionFunct::BinaryDiv ) // don't care of (pi/180)
604 && ( static_cast<BinaryFunctionExpression*>(mpFirstArg.get())->mpFirstArg->getType() == ExpressionFunct::EnumPi )
605 && ( static_cast<BinaryFunctionExpression*>(mpFirstArg.get())->mpSecondArg->getType() == ExpressionFunct::Const ) )
607 aRet = mpSecondArg->fillNode( rEquations, nullptr, nFlags );
609 else if ( ( mpSecondArg->getType() == ExpressionFunct::BinaryDiv ) // don't care of (pi/180)
610 && ( static_cast<BinaryFunctionExpression*>(mpSecondArg.get())->mpFirstArg->getType() == ExpressionFunct::EnumPi )
611 && ( static_cast<BinaryFunctionExpression*>(mpSecondArg.get())->mpSecondArg->getType() == ExpressionFunct::Const ) )
613 aRet = mpFirstArg->fillNode( rEquations, nullptr, nFlags );
615 else
617 EnhancedCustomShapeEquation aEquation;
618 aEquation.nOperation |= 1;
619 FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
620 FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
621 aEquation.nPara[ 2 ] = 1;
622 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
623 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
624 rEquations.push_back( aEquation );
628 break;
629 case ExpressionFunct::BinaryDiv :
631 EnhancedCustomShapeEquation aEquation;
632 aEquation.nOperation |= 1;
633 FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
634 aEquation.nPara[ 1 ] = 1;
635 FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 2, aEquation );
636 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
637 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
638 rEquations.push_back( aEquation );
640 break;
641 case ExpressionFunct::BinaryMin :
643 EnhancedCustomShapeEquation aEquation;
644 aEquation.nOperation |= 4;
645 FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
646 FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
647 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
648 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
649 rEquations.push_back( aEquation );
651 break;
652 case ExpressionFunct::BinaryMax :
654 EnhancedCustomShapeEquation aEquation;
655 aEquation.nOperation |= 5;
656 FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
657 FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
658 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
659 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
660 rEquations.push_back( aEquation );
662 break;
663 case ExpressionFunct::BinaryAtan2:
665 EnhancedCustomShapeEquation aEquation;
666 aEquation.nOperation |= 8;
667 FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
668 FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
669 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
670 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
671 rEquations.push_back( aEquation );
673 break;
674 default:
675 break;
677 return aRet;
681 class IfExpression : public ExpressionNode
683 std::shared_ptr<ExpressionNode> mpFirstArg;
684 std::shared_ptr<ExpressionNode> mpSecondArg;
685 std::shared_ptr<ExpressionNode> mpThirdArg;
687 public:
689 IfExpression( const std::shared_ptr<ExpressionNode>& rFirstArg,
690 const std::shared_ptr<ExpressionNode>& rSecondArg,
691 const std::shared_ptr<ExpressionNode>& rThirdArg ) :
692 mpFirstArg( rFirstArg ),
693 mpSecondArg( rSecondArg ),
694 mpThirdArg( rThirdArg )
697 virtual bool isConstant() const override
699 return
700 mpFirstArg->isConstant() &&
701 mpSecondArg->isConstant() &&
702 mpThirdArg->isConstant();
704 virtual double operator()() const override
706 return (*mpFirstArg)() > 0 ? (*mpSecondArg)() : (*mpThirdArg)();
708 virtual ExpressionFunct getType() const override
710 return ExpressionFunct::TernaryIf;
712 virtual EnhancedCustomShapeParameter fillNode( std::vector< EnhancedCustomShapeEquation >& rEquations, ExpressionNode* /*pOptionalArg*/, sal_uInt32 nFlags ) override
714 EnhancedCustomShapeParameter aRet;
715 aRet.Type = EnhancedCustomShapeParameterType::EQUATION;
716 aRet.Value <<= static_cast<sal_Int32>(rEquations.size());
718 EnhancedCustomShapeEquation aEquation;
719 aEquation.nOperation |= 6;
720 FillEquationParameter( mpFirstArg->fillNode( rEquations, nullptr, nFlags ), 0, aEquation );
721 FillEquationParameter( mpSecondArg->fillNode( rEquations, nullptr, nFlags ), 1, aEquation );
722 FillEquationParameter( mpThirdArg->fillNode( rEquations, nullptr, nFlags ), 2, aEquation );
723 rEquations.push_back( aEquation );
725 return aRet;
730 // FUNCTION PARSER
733 typedef const char* StringIteratorT;
735 struct ParserContext
737 typedef ::std::stack< std::shared_ptr<ExpressionNode> > OperandStack;
739 // stores a stack of not-yet-evaluated operands. This is used
740 // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
741 // arguments from. If all arguments to an operator are constant,
742 // the operator pushes a precalculated result on the stack, and
743 // a composite ExpressionNode otherwise.
744 OperandStack maOperandStack;
746 const EnhancedCustomShape2d* mpCustoShape;
750 typedef std::shared_ptr< ParserContext > ParserContextSharedPtr;
752 /** Generate parse-dependent-but-then-constant value
754 class DoubleConstantFunctor
756 ParserContextSharedPtr mxContext;
758 public:
759 explicit DoubleConstantFunctor( const ParserContextSharedPtr& rContext ) :
760 mxContext( rContext )
763 void operator()( double n ) const
765 mxContext->maOperandStack.push( std::make_shared<ConstantValueExpression>( n ) );
769 class EnumFunctor
771 const ExpressionFunct meFunct;
772 ParserContextSharedPtr mxContext;
774 public:
776 EnumFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext )
777 : meFunct( eFunct )
778 , mxContext( rContext )
781 void operator()( StringIteratorT rFirst, StringIteratorT rSecond ) const
783 /*double nVal = mnValue;*/
784 switch( meFunct )
786 case ExpressionFunct::EnumAdjustment :
788 OUString aVal( rFirst + 1, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
789 mxContext->maOperandStack.push( std::make_shared<AdjustmentExpression>( *mxContext->mpCustoShape, aVal.toInt32() ) );
791 break;
792 case ExpressionFunct::EnumEquation :
794 OUString aVal( rFirst + 1, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
795 mxContext->maOperandStack.push( std::make_shared<EquationExpression>( *mxContext->mpCustoShape, aVal.toInt32() ) );
797 break;
798 default:
799 mxContext->maOperandStack.push( std::make_shared<EnumValueExpression>( *mxContext->mpCustoShape, meFunct ) );
804 class UnaryFunctionFunctor
806 const ExpressionFunct meFunct;
807 ParserContextSharedPtr mxContext;
809 public:
811 UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
812 meFunct( eFunct ),
813 mxContext( rContext )
816 void operator()( StringIteratorT, StringIteratorT ) const
818 ParserContext::OperandStack& rNodeStack( mxContext->maOperandStack );
820 if( rNodeStack.empty() )
821 throw ParseError( "Not enough arguments for unary operator" );
823 // retrieve arguments
824 std::shared_ptr<ExpressionNode> pArg( std::move(rNodeStack.top()) );
825 rNodeStack.pop();
827 if( pArg->isConstant() ) // check for constness
828 rNodeStack.push( std::make_shared<ConstantValueExpression>( UnaryFunctionExpression::getValue( meFunct, pArg ) ) );
829 else // push complex node, that calcs the value on demand
830 rNodeStack.push( std::make_shared<UnaryFunctionExpression>( meFunct, pArg ) );
834 /** Implements a binary function over two ExpressionNodes
836 @tpl Generator
837 Generator functor, to generate an ExpressionNode of
838 appropriate type
841 class BinaryFunctionFunctor
843 const ExpressionFunct meFunct;
844 ParserContextSharedPtr mxContext;
846 public:
848 BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
849 meFunct( eFunct ),
850 mxContext( rContext )
854 void operator()( StringIteratorT, StringIteratorT ) const
856 ParserContext::OperandStack& rNodeStack( mxContext->maOperandStack );
858 if( rNodeStack.size() < 2 )
859 throw ParseError( "Not enough arguments for binary operator" );
861 // retrieve arguments
862 std::shared_ptr<ExpressionNode> pSecondArg( std::move(rNodeStack.top()) );
863 rNodeStack.pop();
864 std::shared_ptr<ExpressionNode> pFirstArg( std::move(rNodeStack.top()) );
865 rNodeStack.pop();
867 // create combined ExpressionNode
868 auto pNode = std::make_shared<BinaryFunctionExpression>( meFunct, pFirstArg, pSecondArg );
869 // check for constness
870 if( pFirstArg->isConstant() && pSecondArg->isConstant() ) // call the operator() at pNode, store result in constant value ExpressionNode.
871 rNodeStack.push( std::make_shared<ConstantValueExpression>( (*pNode)() ) );
872 else // push complex node, that calcs the value on demand
873 rNodeStack.push( pNode );
877 class IfFunctor
879 ParserContextSharedPtr mxContext;
881 public:
883 explicit IfFunctor( const ParserContextSharedPtr& rContext ) :
884 mxContext( rContext )
887 void operator()( StringIteratorT, StringIteratorT ) const
889 ParserContext::OperandStack& rNodeStack( mxContext->maOperandStack );
891 if( rNodeStack.size() < 3 )
892 throw ParseError( "Not enough arguments for ternary operator" );
894 // retrieve arguments
895 std::shared_ptr<ExpressionNode> pThirdArg( std::move(rNodeStack.top()) );
896 rNodeStack.pop();
897 std::shared_ptr<ExpressionNode> pSecondArg( std::move(rNodeStack.top()) );
898 rNodeStack.pop();
899 std::shared_ptr<ExpressionNode> pFirstArg( std::move(rNodeStack.top()) );
900 rNodeStack.pop();
902 // create combined ExpressionNode
903 auto pNode = std::make_shared<IfExpression>( pFirstArg, pSecondArg, pThirdArg );
904 // check for constness
905 if( pFirstArg->isConstant() && pSecondArg->isConstant() && pThirdArg->isConstant() )
906 rNodeStack.push( std::make_shared<ConstantValueExpression>( (*pNode)() ) ); // call the operator() at pNode, store result in constant value ExpressionNode.
907 else
908 rNodeStack.push( pNode ); // push complex node, that calcs the value on demand
912 // Workaround for MSVC compiler anomaly (stack trashing)
914 // The default ureal_parser_policies implementation of parse_exp
915 // triggers a really weird error in MSVC7 (Version 13.00.9466), in
916 // that the real_parser_impl::parse_main() call of parse_exp()
917 // overwrites the frame pointer _on the stack_ (EBP of the calling
918 // function gets overwritten while lying on the stack).
920 // For the time being, our parser thus can only read the 1.0E10
921 // notation, not the 1.0e10 one.
923 // TODO(F1): Also handle the 1.0e10 case here.
924 template< typename T > struct custom_real_parser_policies : public ::boost::spirit::classic::ureal_parser_policies<T>
926 template< typename ScannerT >
927 static typename ::boost::spirit::classic::parser_result< ::boost::spirit::classic::chlit<>, ScannerT >::type
928 parse_exp(ScannerT& scan)
930 // as_lower_d somehow breaks MSVC7
931 return ::boost::spirit::classic::ch_p('E').parse(scan);
935 /* This class implements the following grammar (more or
936 less literally written down below, only slightly
937 obfuscated by the parser actions):
939 identifier = '$'|'pi'|'e'|'X'|'Y'|'Width'|'Height'
941 function = 'abs'|'sqrt'|'sin'|'cos'|'tan'|'atan'|'acos'|'asin'|'exp'|'log'
943 basic_expression =
944 number |
945 identifier |
946 function '(' additive_expression ')' |
947 '(' additive_expression ')'
949 unary_expression =
950 '-' basic_expression |
951 basic_expression
953 multiplicative_expression =
954 unary_expression ( ( '*' unary_expression )* |
955 ( '/' unary_expression )* )
957 additive_expression =
958 multiplicative_expression ( ( '+' multiplicative_expression )* |
959 ( '-' multiplicative_expression )* )
963 class ExpressionGrammar : public ::boost::spirit::classic::grammar< ExpressionGrammar >
965 public:
966 /** Create an arithmetic expression grammar
968 @param rParserContext
969 Contains context info for the parser
971 explicit ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
972 mpParserContext( rParserContext )
976 template< typename ScannerT > class definition
978 public:
979 // grammar definition
980 explicit definition( const ExpressionGrammar& self )
982 using ::boost::spirit::classic::str_p;
983 using ::boost::spirit::classic::range_p;
984 using ::boost::spirit::classic::lexeme_d;
985 using ::boost::spirit::classic::real_parser;
987 identifier =
988 str_p( "pi" )[ EnumFunctor(ExpressionFunct::EnumPi, self.getContext() ) ]
989 | str_p( "left" )[ EnumFunctor(ExpressionFunct::EnumLeft, self.getContext() ) ]
990 | str_p( "top" )[ EnumFunctor(ExpressionFunct::EnumTop, self.getContext() ) ]
991 | str_p( "right" )[ EnumFunctor(ExpressionFunct::EnumRight, self.getContext() ) ]
992 | str_p( "bottom" )[ EnumFunctor(ExpressionFunct::EnumBottom, self.getContext() ) ]
993 | str_p( "xstretch" )[ EnumFunctor(ExpressionFunct::EnumXStretch, self.getContext() ) ]
994 | str_p( "ystretch" )[ EnumFunctor(ExpressionFunct::EnumYStretch, self.getContext() ) ]
995 | str_p( "hasstroke" )[ EnumFunctor(ExpressionFunct::EnumHasStroke, self.getContext() ) ]
996 | str_p( "hasfill" )[ EnumFunctor(ExpressionFunct::EnumHasFill, self.getContext() ) ]
997 | str_p( "width" )[ EnumFunctor(ExpressionFunct::EnumWidth, self.getContext() ) ]
998 | str_p( "height" )[ EnumFunctor(ExpressionFunct::EnumHeight, self.getContext() ) ]
999 | str_p( "logwidth" )[ EnumFunctor(ExpressionFunct::EnumLogWidth, self.getContext() ) ]
1000 | str_p( "logheight" )[ EnumFunctor(ExpressionFunct::EnumLogHeight, self.getContext() ) ]
1003 unaryFunction =
1004 (str_p( "abs" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnaryAbs, self.getContext()) ]
1005 | (str_p( "sqrt" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnarySqrt, self.getContext()) ]
1006 | (str_p( "sin" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnarySin, self.getContext()) ]
1007 | (str_p( "cos" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnaryCos, self.getContext()) ]
1008 | (str_p( "tan" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnaryTan, self.getContext()) ]
1009 | (str_p( "atan" ) >> '(' >> additiveExpression >> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnaryAtan, self.getContext()) ]
1012 binaryFunction =
1013 (str_p( "min" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( ExpressionFunct::BinaryMin, self.getContext()) ]
1014 | (str_p( "max" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( ExpressionFunct::BinaryMax, self.getContext()) ]
1015 | (str_p( "atan2") >> '(' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ BinaryFunctionFunctor( ExpressionFunct::BinaryAtan2,self.getContext()) ]
1018 ternaryFunction =
1019 (str_p( "if" ) >> '(' >> additiveExpression >> ',' >> additiveExpression >> ',' >> additiveExpression >> ')' )[ IfFunctor( self.getContext() ) ]
1022 funcRef_decl =
1023 lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ];
1025 functionReference =
1026 (str_p( "?" ) >> funcRef_decl )[ EnumFunctor( ExpressionFunct::EnumEquation, self.getContext() ) ];
1028 modRef_decl =
1029 lexeme_d[ +( range_p('0','9') ) ];
1031 modifierReference =
1032 (str_p( "$" ) >> modRef_decl )[ EnumFunctor( ExpressionFunct::EnumAdjustment, self.getContext() ) ];
1034 basicExpression =
1035 real_parser<double, custom_real_parser_policies<double> >()[ DoubleConstantFunctor(self.getContext()) ]
1036 | identifier
1037 | functionReference
1038 | modifierReference
1039 | unaryFunction
1040 | binaryFunction
1041 | ternaryFunction
1042 | '(' >> additiveExpression >> ')'
1045 unaryExpression =
1046 ('-' >> basicExpression)[ UnaryFunctionFunctor( ExpressionFunct::UnaryNeg, self.getContext()) ]
1047 | basicExpression
1050 multiplicativeExpression =
1051 unaryExpression
1052 >> *( ('*' >> unaryExpression)[ BinaryFunctionFunctor( ExpressionFunct::BinaryMul, self.getContext()) ]
1053 | ('/' >> unaryExpression)[ BinaryFunctionFunctor( ExpressionFunct::BinaryDiv, self.getContext()) ]
1057 additiveExpression =
1058 multiplicativeExpression
1059 >> *( ('+' >> multiplicativeExpression)[ BinaryFunctionFunctor( ExpressionFunct::BinaryPlus, self.getContext()) ]
1060 | ('-' >> multiplicativeExpression)[ BinaryFunctionFunctor( ExpressionFunct::BinaryMinus, self.getContext()) ]
1064 BOOST_SPIRIT_DEBUG_RULE(additiveExpression);
1065 BOOST_SPIRIT_DEBUG_RULE(multiplicativeExpression);
1066 BOOST_SPIRIT_DEBUG_RULE(unaryExpression);
1067 BOOST_SPIRIT_DEBUG_RULE(basicExpression);
1068 BOOST_SPIRIT_DEBUG_RULE(unaryFunction);
1069 BOOST_SPIRIT_DEBUG_RULE(binaryFunction);
1070 BOOST_SPIRIT_DEBUG_RULE(ternaryFunction);
1071 BOOST_SPIRIT_DEBUG_RULE(identifier);
1074 const ::boost::spirit::classic::rule< ScannerT >& start() const
1076 return additiveExpression;
1079 private:
1080 // the constituents of the Spirit arithmetic expression grammar.
1081 // For the sake of readability, without 'ma' prefix.
1082 ::boost::spirit::classic::rule< ScannerT > additiveExpression;
1083 ::boost::spirit::classic::rule< ScannerT > multiplicativeExpression;
1084 ::boost::spirit::classic::rule< ScannerT > unaryExpression;
1085 ::boost::spirit::classic::rule< ScannerT > basicExpression;
1086 ::boost::spirit::classic::rule< ScannerT > unaryFunction;
1087 ::boost::spirit::classic::rule< ScannerT > binaryFunction;
1088 ::boost::spirit::classic::rule< ScannerT > ternaryFunction;
1089 ::boost::spirit::classic::rule< ScannerT > funcRef_decl;
1090 ::boost::spirit::classic::rule< ScannerT > functionReference;
1091 ::boost::spirit::classic::rule< ScannerT > modRef_decl;
1092 ::boost::spirit::classic::rule< ScannerT > modifierReference;
1093 ::boost::spirit::classic::rule< ScannerT > identifier;
1096 const ParserContextSharedPtr& getContext() const
1098 return mpParserContext;
1101 private:
1102 ParserContextSharedPtr mpParserContext; // might get modified during parsing
1105 const ParserContextSharedPtr& getParserContext()
1107 static ParserContextSharedPtr lcl_parserContext = std::make_shared<ParserContext>();
1109 // clear node stack (since we reuse the static object, that's
1110 // the whole point here)
1111 while( !lcl_parserContext->maOperandStack.empty() )
1112 lcl_parserContext->maOperandStack.pop();
1114 return lcl_parserContext;
1119 namespace EnhancedCustomShape {
1122 std::shared_ptr<ExpressionNode> const & FunctionParser::parseFunction( const OUString& rFunction, const EnhancedCustomShape2d& rCustoShape )
1124 // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
1125 // gives better conversion robustness here (we might want to map space
1126 // etc. to ASCII space here)
1127 const OString& rAsciiFunction(
1128 OUStringToOString( rFunction, RTL_TEXTENCODING_ASCII_US ) );
1130 StringIteratorT aStart( rAsciiFunction.getStr() );
1131 StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
1133 // static parser context, because the actual
1134 // Spirit parser is also a static object
1135 ParserContextSharedPtr pContext = getParserContext();
1136 pContext->mpCustoShape = &rCustoShape;
1138 ExpressionGrammar aExpressionGrammer( pContext );
1139 const ::boost::spirit::classic::parse_info<StringIteratorT> aParseInfo(
1140 ::boost::spirit::classic::parse( aStart,
1141 aEnd,
1142 aExpressionGrammer >> ::boost::spirit::classic::end_p,
1143 ::boost::spirit::classic::space_p ) );
1145 // input fully congested by the parser?
1146 if( !aParseInfo.full )
1147 throw ParseError( "EnhancedCustomShapeFunctionParser::parseFunction(): string not fully parseable" );
1149 // parser's state stack now must contain exactly _one_ ExpressionNode,
1150 // which represents our formula.
1151 if( pContext->maOperandStack.size() != 1 )
1152 throw ParseError( "EnhancedCustomShapeFunctionParser::parseFunction(): incomplete or empty expression" );
1155 return pContext->maOperandStack.top();
1160 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */