1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
39 #include <boost/spirit/include/classic_core.hpp>
47 using namespace EnhancedCustomShape
;
48 using namespace com::sun::star
;
49 using namespace com::sun::star::drawing
;
51 void EnhancedCustomShape::FillEquationParameter( const EnhancedCustomShapeParameter
& rSource
, const sal_Int32 nDestPara
, EnhancedCustomShapeEquation
& rDest
)
54 if ( rSource
.Value
.getValueTypeClass() == uno::TypeClass_DOUBLE
)
57 if ( rSource
.Value
>>= fValue
)
58 nValue
= static_cast<sal_Int32
>(fValue
);
61 rSource
.Value
>>= nValue
;
63 switch( rSource
.Type
)
65 case css::drawing::EnhancedCustomShapeParameterType::EQUATION
:
67 if ( nValue
& 0x40000000 )
70 rDest
.nOperation
|= 0x20000000 << nDestPara
; // the bit is indicating that this value has to be adjusted later
75 case css::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT
: nValue
+= DFF_Prop_adjustValue
; break;
76 case css::drawing::EnhancedCustomShapeParameterType::BOTTOM
: nValue
= DFF_Prop_geoBottom
; break;
77 case css::drawing::EnhancedCustomShapeParameterType::RIGHT
: nValue
= DFF_Prop_geoRight
; break;
78 case css::drawing::EnhancedCustomShapeParameterType::TOP
: nValue
= DFF_Prop_geoTop
; break;
79 case css::drawing::EnhancedCustomShapeParameterType::LEFT
: nValue
= DFF_Prop_geoLeft
; break;
81 if ( rSource
.Type
!= css::drawing::EnhancedCustomShapeParameterType::NORMAL
)
82 rDest
.nOperation
|= ( 0x2000 << nDestPara
);
83 rDest
.nPara
[ nDestPara
] = nValue
;
86 ExpressionNode::~ExpressionNode()
96 class ConstantValueExpression
: public ExpressionNode
102 explicit ConstantValueExpression( double rValue
) :
106 virtual double operator()() const override
110 virtual bool isConstant() const override
114 virtual ExpressionFunct
getType() const override
116 return ExpressionFunct::Const
;
118 virtual EnhancedCustomShapeParameter
fillNode( std::vector
< EnhancedCustomShapeEquation
>& rEquations
, ExpressionNode
* /* pOptionalArg */, sal_uInt32
/* nFlags */ ) override
120 EnhancedCustomShapeParameter aRet
;
121 Fraction
aFract( maValue
);
122 if ( aFract
.GetDenominator() == 1 )
124 aRet
.Type
= EnhancedCustomShapeParameterType::NORMAL
;
125 aRet
.Value
<<= aFract
.GetNumerator();
129 EnhancedCustomShapeEquation aEquation
;
130 aEquation
.nOperation
= 1;
131 aEquation
.nPara
[ 0 ] = 1;
132 aEquation
.nPara
[ 1 ] = static_cast<sal_Int16
>(aFract
.GetNumerator());
133 aEquation
.nPara
[ 2 ] = static_cast<sal_Int16
>(aFract
.GetDenominator());
134 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
135 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
136 rEquations
.push_back( aEquation
);
142 class AdjustmentExpression
: public ExpressionNode
145 const EnhancedCustomShape2d
& mrCustoShape
;
149 AdjustmentExpression( const EnhancedCustomShape2d
& rCustoShape
, sal_Int32 nIndex
)
151 , mrCustoShape( rCustoShape
)
155 virtual double operator()() const override
159 "$" << mnIndex
<< " --> "
160 << mrCustoShape
.GetAdjustValueAsDouble(mnIndex
) << " (angle: "
161 << 180.0*mrCustoShape
.GetAdjustValueAsDouble(mnIndex
)/10800000.0
163 return mrCustoShape
.GetAdjustValueAsDouble( mnIndex
);
165 virtual bool isConstant() const override
169 virtual ExpressionFunct
getType() const override
171 return ExpressionFunct::EnumAdjustment
;
173 virtual EnhancedCustomShapeParameter
fillNode( std::vector
< EnhancedCustomShapeEquation
>& /*rEquations*/, ExpressionNode
* /*pOptionalArg*/, sal_uInt32
/*nFlags*/ ) override
175 EnhancedCustomShapeParameter aRet
;
176 aRet
.Type
= EnhancedCustomShapeParameterType::ADJUSTMENT
;
177 aRet
.Value
<<= mnIndex
;
182 class EquationExpression
: public ExpressionNode
184 const sal_Int32 mnIndex
;
185 const EnhancedCustomShape2d
& mrCustoShape
;
186 mutable bool mbGettingValueGuard
;
190 EquationExpression( const EnhancedCustomShape2d
& rCustoShape
, sal_Int32 nIndex
)
192 , mrCustoShape( rCustoShape
)
193 , mbGettingValueGuard(false)
196 virtual double operator()() const override
198 if (mbGettingValueGuard
)
199 throw ParseError("Loop in Expression");
200 mbGettingValueGuard
= true;
201 double fRet
= mrCustoShape
.GetEquationValueAsDouble(mnIndex
);
202 mbGettingValueGuard
= false;
205 virtual bool isConstant() const override
209 virtual ExpressionFunct
getType() const override
211 return ExpressionFunct::EnumEquation
;
213 virtual EnhancedCustomShapeParameter
fillNode( std::vector
< EnhancedCustomShapeEquation
>& /*rEquations*/, ExpressionNode
* /*pOptionalArg*/, sal_uInt32
/*nFlags*/ ) override
215 EnhancedCustomShapeParameter aRet
;
216 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
217 aRet
.Value
<<= mnIndex
| 0x40000000; // the bit is indicating that this equation needs to be adjusted later
222 class EnumValueExpression
: public ExpressionNode
224 const ExpressionFunct meFunct
;
225 const EnhancedCustomShape2d
& mrCustoShape
;
229 EnumValueExpression( const EnhancedCustomShape2d
& rCustoShape
, const ExpressionFunct eFunct
)
231 , mrCustoShape ( rCustoShape
)
234 virtual double operator()() const override
236 SAL_INFO("svx", meFunct
<< " --> " << mrCustoShape
.GetEnumFunc(meFunct
) << "(angle: " <<
237 180.0 * mrCustoShape
.GetEnumFunc(meFunct
) / 10800000.0 << ")");
239 return mrCustoShape
.GetEnumFunc( meFunct
);
241 virtual bool isConstant() const override
245 virtual ExpressionFunct
getType() const override
249 virtual EnhancedCustomShapeParameter
fillNode( std::vector
< EnhancedCustomShapeEquation
>& rEquations
, ExpressionNode
* /*pOptionalArg*/, sal_uInt32 nFlags
) override
251 EnhancedCustomShapeParameter aRet
;
253 aRet
.Value
<<= sal_Int32(1);
257 case ExpressionFunct::EnumWidth
: // TODO: do not use this as constant value
258 case ExpressionFunct::EnumHeight
:
259 case ExpressionFunct::EnumLogWidth
:
260 case ExpressionFunct::EnumLogHeight
:
261 case ExpressionFunct::EnumPi
:
263 ConstantValueExpression
aConstantValue( mrCustoShape
.GetEnumFunc( meFunct
) );
264 aRet
= aConstantValue
.fillNode( rEquations
, nullptr, nFlags
);
267 case ExpressionFunct::EnumLeft
: aRet
.Type
= EnhancedCustomShapeParameterType::LEFT
; break;
268 case ExpressionFunct::EnumTop
: aRet
.Type
= EnhancedCustomShapeParameterType::TOP
; break;
269 case ExpressionFunct::EnumRight
: aRet
.Type
= EnhancedCustomShapeParameterType::RIGHT
; break;
270 case ExpressionFunct::EnumBottom
: aRet
.Type
= EnhancedCustomShapeParameterType::BOTTOM
; break;
272 // not implemented so far
273 case ExpressionFunct::EnumXStretch
:
274 case ExpressionFunct::EnumYStretch
:
275 case ExpressionFunct::EnumHasStroke
:
276 case ExpressionFunct::EnumHasFill
: aRet
.Type
= EnhancedCustomShapeParameterType::NORMAL
; break;
285 /** ExpressionNode implementation for unary
286 function over one ExpressionNode
288 class UnaryFunctionExpression
: public ExpressionNode
290 const ExpressionFunct meFunct
;
291 std::shared_ptr
<ExpressionNode
> mpArg
;
294 UnaryFunctionExpression( const ExpressionFunct eFunct
, std::shared_ptr
<ExpressionNode
> aArg
) :
296 mpArg(std::move( aArg
))
299 static double getValue( const ExpressionFunct eFunct
, const std::shared_ptr
<ExpressionNode
>& rArg
)
304 case ExpressionFunct::UnaryAbs
: fRet
= fabs( (*rArg
)() ); break;
305 case ExpressionFunct::UnarySqrt
: fRet
= sqrt( (*rArg
)() ); break;
306 case ExpressionFunct::UnarySin
: fRet
= sin( (*rArg
)() ); break;
307 case ExpressionFunct::UnaryCos
: fRet
= cos( (*rArg
)() ); break;
308 case ExpressionFunct::UnaryTan
: fRet
= tan( (*rArg
)() ); break;
309 case ExpressionFunct::UnaryAtan
: fRet
= atan( (*rArg
)() ); break;
310 case ExpressionFunct::UnaryNeg
: fRet
= ::std::negate
<double>()( (*rArg
)() ); break;
316 virtual double operator()() const override
318 return getValue( meFunct
, mpArg
);
320 virtual bool isConstant() const override
322 return mpArg
->isConstant();
324 virtual ExpressionFunct
getType() const override
328 virtual EnhancedCustomShapeParameter
fillNode( std::vector
< EnhancedCustomShapeEquation
>& rEquations
, ExpressionNode
* pOptionalArg
, sal_uInt32 nFlags
) override
330 EnhancedCustomShapeParameter aRet
;
333 case ExpressionFunct::UnaryAbs
:
335 EnhancedCustomShapeEquation aEquation
;
336 aEquation
.nOperation
|= 3;
337 FillEquationParameter( mpArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
338 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
339 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
340 rEquations
.push_back( aEquation
);
343 case ExpressionFunct::UnarySqrt
:
345 EnhancedCustomShapeEquation aEquation
;
346 aEquation
.nOperation
|= 13;
347 FillEquationParameter( mpArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
348 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
349 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
350 rEquations
.push_back( aEquation
);
353 case ExpressionFunct::UnarySin
:
355 EnhancedCustomShapeEquation aEquation
;
356 aEquation
.nOperation
|= 9;
358 FillEquationParameter( pOptionalArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
360 aEquation
.nPara
[ 0 ] = 1;
362 EnhancedCustomShapeParameter
aSource( mpArg
->fillNode( rEquations
, nullptr, nFlags
| EXPRESSION_FLAG_SUMANGLE_MODE
) );
363 if ( aSource
.Type
== EnhancedCustomShapeParameterType::NORMAL
)
364 { // sumangle needed :-(
365 EnhancedCustomShapeEquation _aEquation
;
366 _aEquation
.nOperation
|= 0xe; // sumangle
367 FillEquationParameter( aSource
, 1, _aEquation
);
368 aSource
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
369 aSource
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
370 rEquations
.push_back( _aEquation
);
372 FillEquationParameter( aSource
, 1, aEquation
);
373 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
374 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
375 rEquations
.push_back( aEquation
);
378 case ExpressionFunct::UnaryCos
:
380 EnhancedCustomShapeEquation aEquation
;
381 aEquation
.nOperation
|= 10;
383 FillEquationParameter( pOptionalArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
385 aEquation
.nPara
[ 0 ] = 1;
387 EnhancedCustomShapeParameter
aSource( mpArg
->fillNode( rEquations
, nullptr, nFlags
| EXPRESSION_FLAG_SUMANGLE_MODE
) );
388 if ( aSource
.Type
== EnhancedCustomShapeParameterType::NORMAL
)
389 { // sumangle needed :-(
390 EnhancedCustomShapeEquation aTmpEquation
;
391 aTmpEquation
.nOperation
|= 0xe; // sumangle
392 FillEquationParameter( aSource
, 1, aTmpEquation
);
393 aSource
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
394 aSource
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
395 rEquations
.push_back( aTmpEquation
);
397 FillEquationParameter( aSource
, 1, aEquation
);
398 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
399 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
400 rEquations
.push_back( aEquation
);
403 case ExpressionFunct::UnaryTan
:
405 EnhancedCustomShapeEquation aEquation
;
406 aEquation
.nOperation
|= 16;
408 FillEquationParameter( pOptionalArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
410 aEquation
.nPara
[ 0 ] = 1;
412 EnhancedCustomShapeParameter
aSource( mpArg
->fillNode( rEquations
, nullptr, nFlags
| EXPRESSION_FLAG_SUMANGLE_MODE
) );
413 if ( aSource
.Type
== EnhancedCustomShapeParameterType::NORMAL
)
414 { // sumangle needed :-(
415 EnhancedCustomShapeEquation aTmpEquation
;
416 aTmpEquation
.nOperation
|= 0xe; // sumangle
417 FillEquationParameter( aSource
, 1, aTmpEquation
);
418 aSource
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
419 aSource
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
420 rEquations
.push_back( aTmpEquation
);
422 FillEquationParameter( aSource
, 1, aEquation
);
423 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
424 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
425 rEquations
.push_back( aEquation
);
428 case ExpressionFunct::UnaryAtan
:
431 aRet
.Type
= EnhancedCustomShapeParameterType::NORMAL
;
434 case ExpressionFunct::UnaryNeg
:
436 EnhancedCustomShapeEquation aEquation
;
437 aEquation
.nOperation
|= 1;
438 aEquation
.nPara
[ 1 ] = -1;
439 aEquation
.nPara
[ 2 ] = 1;
440 FillEquationParameter( mpArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
441 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
442 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
443 rEquations
.push_back( aEquation
);
453 /** ExpressionNode implementation for unary
454 function over two ExpressionNodes
456 class BinaryFunctionExpression
: public ExpressionNode
458 const ExpressionFunct meFunct
;
459 std::shared_ptr
<ExpressionNode
> mpFirstArg
;
460 std::shared_ptr
<ExpressionNode
> mpSecondArg
;
464 BinaryFunctionExpression( const ExpressionFunct eFunct
, std::shared_ptr
<ExpressionNode
> xFirstArg
, std::shared_ptr
<ExpressionNode
> xSecondArg
) :
466 mpFirstArg(std::move( xFirstArg
)),
467 mpSecondArg(std::move( xSecondArg
))
470 #if defined(__clang__) || defined (__GNUC__)
471 //GetEquationValueAsDouble calls isFinite on the result
472 __attribute__((no_sanitize("float-divide-by-zero")))
474 static double getValue( const ExpressionFunct eFunct
, const std::shared_ptr
<ExpressionNode
>& rFirstArg
, const std::shared_ptr
<ExpressionNode
>& rSecondArg
)
479 case ExpressionFunct::BinaryPlus
: fRet
= (*rFirstArg
)() + (*rSecondArg
)(); break;
480 case ExpressionFunct::BinaryMinus
: fRet
= (*rFirstArg
)() - (*rSecondArg
)(); break;
481 case ExpressionFunct::BinaryMul
: fRet
= (*rFirstArg
)() * (*rSecondArg
)(); break;
482 case ExpressionFunct::BinaryDiv
: fRet
= (*rFirstArg
)() / (*rSecondArg
)(); break;
483 case ExpressionFunct::BinaryMin
: fRet
= ::std::min( (*rFirstArg
)(), (*rSecondArg
)() ); break;
484 case ExpressionFunct::BinaryMax
: fRet
= ::std::max( (*rFirstArg
)(), (*rSecondArg
)() ); break;
485 case ExpressionFunct::BinaryAtan2
: fRet
= atan2( (*rFirstArg
)(), (*rSecondArg
)() ); break;
491 virtual double operator()() const override
493 return getValue( meFunct
, mpFirstArg
, mpSecondArg
);
495 virtual bool isConstant() const override
497 return mpFirstArg
->isConstant() && mpSecondArg
->isConstant();
499 virtual ExpressionFunct
getType() const override
503 virtual EnhancedCustomShapeParameter
fillNode( std::vector
< EnhancedCustomShapeEquation
>& rEquations
, ExpressionNode
* /*pOptionalArg*/, sal_uInt32 nFlags
) override
505 EnhancedCustomShapeParameter aRet
;
508 case ExpressionFunct::BinaryPlus
:
510 if ( nFlags
& EXPRESSION_FLAG_SUMANGLE_MODE
)
512 if ( mpFirstArg
->getType() == ExpressionFunct::EnumAdjustment
)
514 EnhancedCustomShapeEquation aEquation
;
515 aEquation
.nOperation
|= 0xe; // sumangle
516 FillEquationParameter( mpFirstArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
517 FillEquationParameter( mpSecondArg
->fillNode( rEquations
, nullptr, nFlags
), 1, aEquation
);
518 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
519 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
520 rEquations
.push_back( aEquation
);
522 else if ( mpSecondArg
->getType() == ExpressionFunct::EnumAdjustment
)
524 EnhancedCustomShapeEquation aEquation
;
525 aEquation
.nOperation
|= 0xe; // sumangle
526 FillEquationParameter( mpSecondArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
527 FillEquationParameter( mpFirstArg
->fillNode( rEquations
, nullptr, nFlags
), 1, aEquation
);
528 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
529 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
530 rEquations
.push_back( aEquation
);
534 EnhancedCustomShapeEquation aSumangle1
;
535 aSumangle1
.nOperation
|= 0xe; // sumangle
536 FillEquationParameter( mpFirstArg
->fillNode( rEquations
, nullptr, nFlags
&~EXPRESSION_FLAG_SUMANGLE_MODE
), 1, aSumangle1
);
537 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
538 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
539 rEquations
.push_back( aSumangle1
);
541 EnhancedCustomShapeEquation aSumangle2
;
542 aSumangle2
.nOperation
|= 0xe; // sumangle
543 FillEquationParameter( mpSecondArg
->fillNode( rEquations
, nullptr, nFlags
&~EXPRESSION_FLAG_SUMANGLE_MODE
), 1, aSumangle2
);
544 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
545 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
546 rEquations
.push_back( aSumangle2
);
548 EnhancedCustomShapeEquation aEquation
;
549 aEquation
.nOperation
|= 0;
550 aEquation
.nPara
[ 0 ] = ( rEquations
.size() - 2 ) | 0x400;
551 aEquation
.nPara
[ 1 ] = ( rEquations
.size() - 1 ) | 0x400;
552 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
553 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
554 rEquations
.push_back( aEquation
);
559 bool bFirstIsEmpty
= mpFirstArg
->isConstant() && ( (*mpFirstArg
)() == 0 );
560 bool bSecondIsEmpty
= mpSecondArg
->isConstant() && ( (*mpSecondArg
)() == 0 );
563 aRet
= mpSecondArg
->fillNode( rEquations
, nullptr, nFlags
);
564 else if ( bSecondIsEmpty
)
565 aRet
= mpFirstArg
->fillNode( rEquations
, nullptr, nFlags
);
568 EnhancedCustomShapeEquation aEquation
;
569 aEquation
.nOperation
|= 0;
570 FillEquationParameter( mpFirstArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
571 FillEquationParameter( mpSecondArg
->fillNode( rEquations
, nullptr, nFlags
), 1, aEquation
);
572 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
573 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
574 rEquations
.push_back( aEquation
);
579 case ExpressionFunct::BinaryMinus
:
581 EnhancedCustomShapeEquation aEquation
;
582 aEquation
.nOperation
|= 0;
583 FillEquationParameter( mpFirstArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
584 FillEquationParameter( mpSecondArg
->fillNode( rEquations
, nullptr, nFlags
), 2, aEquation
);
585 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
586 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
587 rEquations
.push_back( aEquation
);
590 case ExpressionFunct::BinaryMul
:
592 // in the dest. format the cos function is using integer as result :-(
593 // so we can't use the generic algorithm
594 if ( ( mpFirstArg
->getType() == ExpressionFunct::UnarySin
) || ( mpFirstArg
->getType() == ExpressionFunct::UnaryCos
) || ( mpFirstArg
->getType() == ExpressionFunct::UnaryTan
) )
595 aRet
= mpFirstArg
->fillNode( rEquations
, mpSecondArg
.get(), nFlags
);
596 else if ( ( mpSecondArg
->getType() == ExpressionFunct::UnarySin
) || ( mpSecondArg
->getType() == ExpressionFunct::UnaryCos
) || ( mpSecondArg
->getType() == ExpressionFunct::UnaryTan
) )
597 aRet
= mpSecondArg
->fillNode( rEquations
, mpFirstArg
.get(), nFlags
);
600 if ( mpFirstArg
->isConstant() && (*mpFirstArg
)() == 1 )
601 aRet
= mpSecondArg
->fillNode( rEquations
, nullptr, nFlags
);
602 else if ( mpSecondArg
->isConstant() && (*mpSecondArg
)() == 1 )
603 aRet
= mpFirstArg
->fillNode( rEquations
, nullptr, nFlags
);
604 else if ( ( mpFirstArg
->getType() == ExpressionFunct::BinaryDiv
) // don't care of (pi/180)
605 && ( static_cast<BinaryFunctionExpression
*>(mpFirstArg
.get())->mpFirstArg
->getType() == ExpressionFunct::EnumPi
)
606 && ( static_cast<BinaryFunctionExpression
*>(mpFirstArg
.get())->mpSecondArg
->getType() == ExpressionFunct::Const
) )
608 aRet
= mpSecondArg
->fillNode( rEquations
, nullptr, nFlags
);
610 else if ( ( mpSecondArg
->getType() == ExpressionFunct::BinaryDiv
) // don't care of (pi/180)
611 && ( static_cast<BinaryFunctionExpression
*>(mpSecondArg
.get())->mpFirstArg
->getType() == ExpressionFunct::EnumPi
)
612 && ( static_cast<BinaryFunctionExpression
*>(mpSecondArg
.get())->mpSecondArg
->getType() == ExpressionFunct::Const
) )
614 aRet
= mpFirstArg
->fillNode( rEquations
, nullptr, nFlags
);
618 EnhancedCustomShapeEquation aEquation
;
619 aEquation
.nOperation
|= 1;
620 FillEquationParameter( mpFirstArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
621 FillEquationParameter( mpSecondArg
->fillNode( rEquations
, nullptr, nFlags
), 1, aEquation
);
622 aEquation
.nPara
[ 2 ] = 1;
623 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
624 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
625 rEquations
.push_back( aEquation
);
630 case ExpressionFunct::BinaryDiv
:
632 EnhancedCustomShapeEquation aEquation
;
633 aEquation
.nOperation
|= 1;
634 FillEquationParameter( mpFirstArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
635 aEquation
.nPara
[ 1 ] = 1;
636 FillEquationParameter( mpSecondArg
->fillNode( rEquations
, nullptr, nFlags
), 2, aEquation
);
637 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
638 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
639 rEquations
.push_back( aEquation
);
642 case ExpressionFunct::BinaryMin
:
644 EnhancedCustomShapeEquation aEquation
;
645 aEquation
.nOperation
|= 4;
646 FillEquationParameter( mpFirstArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
647 FillEquationParameter( mpSecondArg
->fillNode( rEquations
, nullptr, nFlags
), 1, aEquation
);
648 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
649 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
650 rEquations
.push_back( aEquation
);
653 case ExpressionFunct::BinaryMax
:
655 EnhancedCustomShapeEquation aEquation
;
656 aEquation
.nOperation
|= 5;
657 FillEquationParameter( mpFirstArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
658 FillEquationParameter( mpSecondArg
->fillNode( rEquations
, nullptr, nFlags
), 1, aEquation
);
659 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
660 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
661 rEquations
.push_back( aEquation
);
664 case ExpressionFunct::BinaryAtan2
:
666 EnhancedCustomShapeEquation aEquation
;
667 aEquation
.nOperation
|= 8;
668 FillEquationParameter( mpSecondArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
669 FillEquationParameter( mpFirstArg
->fillNode( rEquations
, nullptr, nFlags
), 1, aEquation
);
670 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
671 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
672 rEquations
.push_back( aEquation
);
682 class IfExpression
: public ExpressionNode
684 std::shared_ptr
<ExpressionNode
> mpFirstArg
;
685 std::shared_ptr
<ExpressionNode
> mpSecondArg
;
686 std::shared_ptr
<ExpressionNode
> mpThirdArg
;
690 IfExpression( std::shared_ptr
<ExpressionNode
> xFirstArg
,
691 std::shared_ptr
<ExpressionNode
> xSecondArg
,
692 std::shared_ptr
<ExpressionNode
> xThirdArg
) :
693 mpFirstArg(std::move( xFirstArg
)),
694 mpSecondArg(std::move(xSecondArg
)),
695 mpThirdArg(std::move( xThirdArg
))
698 virtual bool isConstant() const override
701 mpFirstArg
->isConstant() &&
702 mpSecondArg
->isConstant() &&
703 mpThirdArg
->isConstant();
705 virtual double operator()() const override
707 return (*mpFirstArg
)() > 0 ? (*mpSecondArg
)() : (*mpThirdArg
)();
709 virtual ExpressionFunct
getType() const override
711 return ExpressionFunct::TernaryIf
;
713 virtual EnhancedCustomShapeParameter
fillNode( std::vector
< EnhancedCustomShapeEquation
>& rEquations
, ExpressionNode
* /*pOptionalArg*/, sal_uInt32 nFlags
) override
715 EnhancedCustomShapeParameter aRet
;
716 aRet
.Type
= EnhancedCustomShapeParameterType::EQUATION
;
717 aRet
.Value
<<= static_cast<sal_Int32
>(rEquations
.size());
719 EnhancedCustomShapeEquation aEquation
;
720 aEquation
.nOperation
|= 6;
721 FillEquationParameter( mpFirstArg
->fillNode( rEquations
, nullptr, nFlags
), 0, aEquation
);
722 FillEquationParameter( mpSecondArg
->fillNode( rEquations
, nullptr, nFlags
), 1, aEquation
);
723 FillEquationParameter( mpThirdArg
->fillNode( rEquations
, nullptr, nFlags
), 2, aEquation
);
724 rEquations
.push_back( aEquation
);
734 typedef const char* StringIteratorT
;
738 typedef ::std::stack
< std::shared_ptr
<ExpressionNode
> > OperandStack
;
740 // stores a stack of not-yet-evaluated operands. This is used
741 // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
742 // arguments from. If all arguments to an operator are constant,
743 // the operator pushes a precalculated result on the stack, and
744 // a composite ExpressionNode otherwise.
745 OperandStack maOperandStack
;
747 const EnhancedCustomShape2d
* mpCustoShape
;
751 typedef std::shared_ptr
< ParserContext
> ParserContextSharedPtr
;
753 /** Generate parse-dependent-but-then-constant value
755 class DoubleConstantFunctor
757 ParserContextSharedPtr mxContext
;
760 explicit DoubleConstantFunctor( ParserContextSharedPtr xContext
) :
761 mxContext(std::move( xContext
))
764 void operator()( double n
) const
766 mxContext
->maOperandStack
.push( std::make_shared
<ConstantValueExpression
>( n
) );
772 const ExpressionFunct meFunct
;
773 ParserContextSharedPtr mxContext
;
777 EnumFunctor( const ExpressionFunct eFunct
, ParserContextSharedPtr xContext
)
779 , mxContext(std::move( xContext
))
782 void operator()( StringIteratorT rFirst
, StringIteratorT rSecond
) const
784 /*double nVal = mnValue;*/
787 case ExpressionFunct::EnumAdjustment
:
789 OUString
aVal( rFirst
+ 1, rSecond
- rFirst
, RTL_TEXTENCODING_UTF8
);
790 mxContext
->maOperandStack
.push( std::make_shared
<AdjustmentExpression
>( *mxContext
->mpCustoShape
, aVal
.toInt32() ) );
793 case ExpressionFunct::EnumEquation
:
795 OUString
aVal( rFirst
+ 1, rSecond
- rFirst
, RTL_TEXTENCODING_UTF8
);
796 mxContext
->maOperandStack
.push( std::make_shared
<EquationExpression
>( *mxContext
->mpCustoShape
, aVal
.toInt32() ) );
800 mxContext
->maOperandStack
.push( std::make_shared
<EnumValueExpression
>( *mxContext
->mpCustoShape
, meFunct
) );
805 class UnaryFunctionFunctor
807 const ExpressionFunct meFunct
;
808 ParserContextSharedPtr mxContext
;
812 UnaryFunctionFunctor( const ExpressionFunct eFunct
, ParserContextSharedPtr xContext
) :
814 mxContext(std::move( xContext
))
817 void operator()( StringIteratorT
, StringIteratorT
) const
819 ParserContext::OperandStack
& rNodeStack( mxContext
->maOperandStack
);
821 if( rNodeStack
.empty() )
822 throw ParseError( "Not enough arguments for unary operator" );
824 // retrieve arguments
825 std::shared_ptr
<ExpressionNode
> pArg( std::move(rNodeStack
.top()) );
828 if( pArg
->isConstant() ) // check for constness
829 rNodeStack
.push( std::make_shared
<ConstantValueExpression
>( UnaryFunctionExpression::getValue( meFunct
, pArg
) ) );
830 else // push complex node, that calcs the value on demand
831 rNodeStack
.push( std::make_shared
<UnaryFunctionExpression
>( meFunct
, pArg
) );
835 /** Implements a binary function over two ExpressionNodes
838 Generator functor, to generate an ExpressionNode of
842 class BinaryFunctionFunctor
844 const ExpressionFunct meFunct
;
845 ParserContextSharedPtr mxContext
;
849 BinaryFunctionFunctor( const ExpressionFunct eFunct
, ParserContextSharedPtr xContext
) :
851 mxContext(std::move( xContext
))
855 void operator()( StringIteratorT
, StringIteratorT
) const
857 ParserContext::OperandStack
& rNodeStack( mxContext
->maOperandStack
);
859 if( rNodeStack
.size() < 2 )
860 throw ParseError( "Not enough arguments for binary operator" );
862 // retrieve arguments
863 std::shared_ptr
<ExpressionNode
> pSecondArg( std::move(rNodeStack
.top()) );
865 std::shared_ptr
<ExpressionNode
> pFirstArg( std::move(rNodeStack
.top()) );
868 assert(pSecondArg
&& pFirstArg
&& "count of arg checked before we get here");
870 // create combined ExpressionNode
871 auto pNode
= std::make_shared
<BinaryFunctionExpression
>( meFunct
, pFirstArg
, pSecondArg
);
872 // check for constness
873 if( pFirstArg
->isConstant() && pSecondArg
->isConstant() ) // call the operator() at pNode, store result in constant value ExpressionNode.
874 rNodeStack
.push( std::make_shared
<ConstantValueExpression
>( (*pNode
)() ) );
875 else // push complex node, that calcs the value on demand
876 rNodeStack
.push( pNode
);
882 ParserContextSharedPtr mxContext
;
886 explicit IfFunctor( ParserContextSharedPtr xContext
) :
887 mxContext(std::move( xContext
))
890 void operator()( StringIteratorT
, StringIteratorT
) const
892 ParserContext::OperandStack
& rNodeStack( mxContext
->maOperandStack
);
894 if( rNodeStack
.size() < 3 )
895 throw ParseError( "Not enough arguments for ternary operator" );
897 // retrieve arguments
898 std::shared_ptr
<ExpressionNode
> pThirdArg( std::move(rNodeStack
.top()) );
900 std::shared_ptr
<ExpressionNode
> pSecondArg( std::move(rNodeStack
.top()) );
902 std::shared_ptr
<ExpressionNode
> pFirstArg( std::move(rNodeStack
.top()) );
905 assert(pThirdArg
&& pSecondArg
&& pFirstArg
);
907 // create combined ExpressionNode
908 auto pNode
= std::make_shared
<IfExpression
>( pFirstArg
, pSecondArg
, pThirdArg
);
909 // check for constness
910 if( pFirstArg
->isConstant() && pSecondArg
->isConstant() && pThirdArg
->isConstant() )
911 rNodeStack
.push( std::make_shared
<ConstantValueExpression
>( (*pNode
)() ) ); // call the operator() at pNode, store result in constant value ExpressionNode.
913 rNodeStack
.push( pNode
); // push complex node, that calcs the value on demand
917 // Workaround for MSVC compiler anomaly (stack trashing)
919 // The default ureal_parser_policies implementation of parse_exp
920 // triggers a really weird error in MSVC7 (Version 13.00.9466), in
921 // that the real_parser_impl::parse_main() call of parse_exp()
922 // overwrites the frame pointer _on the stack_ (EBP of the calling
923 // function gets overwritten while lying on the stack).
925 // For the time being, our parser thus can only read the 1.0E10
926 // notation, not the 1.0e10 one.
928 // TODO(F1): Also handle the 1.0e10 case here.
929 template< typename T
> struct custom_real_parser_policies
: public ::boost::spirit::classic::ureal_parser_policies
<T
>
931 template< typename ScannerT
>
932 static typename ::boost::spirit::classic::parser_result
< ::boost::spirit::classic::chlit
<>, ScannerT
>::type
933 parse_exp(ScannerT
& scan
)
935 // as_lower_d somehow breaks MSVC7
936 return ::boost::spirit::classic::ch_p('E').parse(scan
);
940 /* This class implements the following grammar (more or
941 less literally written down below, only slightly
942 obfuscated by the parser actions):
944 identifier = '$'|'pi'|'e'|'X'|'Y'|'Width'|'Height'
946 function = 'abs'|'sqrt'|'sin'|'cos'|'tan'|'atan'|'acos'|'asin'|'exp'|'log'
951 function '(' additive_expression ')' |
952 '(' additive_expression ')'
955 '-' basic_expression |
958 multiplicative_expression =
959 unary_expression ( ( '*' unary_expression )* |
960 ( '/' unary_expression )* )
962 additive_expression =
963 multiplicative_expression ( ( '+' multiplicative_expression )* |
964 ( '-' multiplicative_expression )* )
968 class ExpressionGrammar
: public ::boost::spirit::classic::grammar
< ExpressionGrammar
>
971 /** Create an arithmetic expression grammar
973 @param rParserContext
974 Contains context info for the parser
976 explicit ExpressionGrammar( ParserContextSharedPtr xParserContext
) :
977 mpParserContext(std::move( xParserContext
))
981 template< typename ScannerT
> class definition
984 // grammar definition
985 explicit definition( const ExpressionGrammar
& self
)
987 using ::boost::spirit::classic::str_p
;
988 using ::boost::spirit::classic::range_p
;
989 using ::boost::spirit::classic::lexeme_d
;
990 using ::boost::spirit::classic::real_parser
;
993 str_p( "pi" )[ EnumFunctor(ExpressionFunct::EnumPi
, self
.getContext() ) ]
994 | str_p( "left" )[ EnumFunctor(ExpressionFunct::EnumLeft
, self
.getContext() ) ]
995 | str_p( "top" )[ EnumFunctor(ExpressionFunct::EnumTop
, self
.getContext() ) ]
996 | str_p( "right" )[ EnumFunctor(ExpressionFunct::EnumRight
, self
.getContext() ) ]
997 | str_p( "bottom" )[ EnumFunctor(ExpressionFunct::EnumBottom
, self
.getContext() ) ]
998 | str_p( "xstretch" )[ EnumFunctor(ExpressionFunct::EnumXStretch
, self
.getContext() ) ]
999 | str_p( "ystretch" )[ EnumFunctor(ExpressionFunct::EnumYStretch
, self
.getContext() ) ]
1000 | str_p( "hasstroke" )[ EnumFunctor(ExpressionFunct::EnumHasStroke
, self
.getContext() ) ]
1001 | str_p( "hasfill" )[ EnumFunctor(ExpressionFunct::EnumHasFill
, self
.getContext() ) ]
1002 | str_p( "width" )[ EnumFunctor(ExpressionFunct::EnumWidth
, self
.getContext() ) ]
1003 | str_p( "height" )[ EnumFunctor(ExpressionFunct::EnumHeight
, self
.getContext() ) ]
1004 | str_p( "logwidth" )[ EnumFunctor(ExpressionFunct::EnumLogWidth
, self
.getContext() ) ]
1005 | str_p( "logheight" )[ EnumFunctor(ExpressionFunct::EnumLogHeight
, self
.getContext() ) ]
1009 (str_p( "abs" ) >> '(' >> additiveExpression
>> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnaryAbs
, self
.getContext()) ]
1010 | (str_p( "sqrt" ) >> '(' >> additiveExpression
>> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnarySqrt
, self
.getContext()) ]
1011 | (str_p( "sin" ) >> '(' >> additiveExpression
>> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnarySin
, self
.getContext()) ]
1012 | (str_p( "cos" ) >> '(' >> additiveExpression
>> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnaryCos
, self
.getContext()) ]
1013 | (str_p( "tan" ) >> '(' >> additiveExpression
>> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnaryTan
, self
.getContext()) ]
1014 | (str_p( "atan" ) >> '(' >> additiveExpression
>> ')' )[ UnaryFunctionFunctor( ExpressionFunct::UnaryAtan
, self
.getContext()) ]
1018 (str_p( "min" ) >> '(' >> additiveExpression
>> ',' >> additiveExpression
>> ')' )[ BinaryFunctionFunctor( ExpressionFunct::BinaryMin
, self
.getContext()) ]
1019 | (str_p( "max" ) >> '(' >> additiveExpression
>> ',' >> additiveExpression
>> ')' )[ BinaryFunctionFunctor( ExpressionFunct::BinaryMax
, self
.getContext()) ]
1020 | (str_p( "atan2") >> '(' >> additiveExpression
>> ',' >> additiveExpression
>> ')' )[ BinaryFunctionFunctor( ExpressionFunct::BinaryAtan2
,self
.getContext()) ]
1024 (str_p( "if" ) >> '(' >> additiveExpression
>> ',' >> additiveExpression
>> ',' >> additiveExpression
>> ')' )[ IfFunctor( self
.getContext() ) ]
1028 lexeme_d
[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ];
1031 (str_p( "?" ) >> funcRef_decl
)[ EnumFunctor( ExpressionFunct::EnumEquation
, self
.getContext() ) ];
1034 lexeme_d
[ +( range_p('0','9') ) ];
1037 (str_p( "$" ) >> modRef_decl
)[ EnumFunctor( ExpressionFunct::EnumAdjustment
, self
.getContext() ) ];
1040 real_parser
<double, custom_real_parser_policies
<double> >()[ DoubleConstantFunctor(self
.getContext()) ]
1047 | '(' >> additiveExpression
>> ')'
1051 ('-' >> basicExpression
)[ UnaryFunctionFunctor( ExpressionFunct::UnaryNeg
, self
.getContext()) ]
1055 multiplicativeExpression
=
1057 >> *( ('*' >> unaryExpression
)[ BinaryFunctionFunctor( ExpressionFunct::BinaryMul
, self
.getContext()) ]
1058 | ('/' >> unaryExpression
)[ BinaryFunctionFunctor( ExpressionFunct::BinaryDiv
, self
.getContext()) ]
1062 additiveExpression
=
1063 multiplicativeExpression
1064 >> *( ('+' >> multiplicativeExpression
)[ BinaryFunctionFunctor( ExpressionFunct::BinaryPlus
, self
.getContext()) ]
1065 | ('-' >> multiplicativeExpression
)[ BinaryFunctionFunctor( ExpressionFunct::BinaryMinus
, self
.getContext()) ]
1069 BOOST_SPIRIT_DEBUG_RULE(additiveExpression
);
1070 BOOST_SPIRIT_DEBUG_RULE(multiplicativeExpression
);
1071 BOOST_SPIRIT_DEBUG_RULE(unaryExpression
);
1072 BOOST_SPIRIT_DEBUG_RULE(basicExpression
);
1073 BOOST_SPIRIT_DEBUG_RULE(unaryFunction
);
1074 BOOST_SPIRIT_DEBUG_RULE(binaryFunction
);
1075 BOOST_SPIRIT_DEBUG_RULE(ternaryFunction
);
1076 BOOST_SPIRIT_DEBUG_RULE(identifier
);
1079 const ::boost::spirit::classic::rule
< ScannerT
>& start() const
1081 return additiveExpression
;
1085 // the constituents of the Spirit arithmetic expression grammar.
1086 // For the sake of readability, without 'ma' prefix.
1087 ::boost::spirit::classic::rule
< ScannerT
> additiveExpression
;
1088 ::boost::spirit::classic::rule
< ScannerT
> multiplicativeExpression
;
1089 ::boost::spirit::classic::rule
< ScannerT
> unaryExpression
;
1090 ::boost::spirit::classic::rule
< ScannerT
> basicExpression
;
1091 ::boost::spirit::classic::rule
< ScannerT
> unaryFunction
;
1092 ::boost::spirit::classic::rule
< ScannerT
> binaryFunction
;
1093 ::boost::spirit::classic::rule
< ScannerT
> ternaryFunction
;
1094 ::boost::spirit::classic::rule
< ScannerT
> funcRef_decl
;
1095 ::boost::spirit::classic::rule
< ScannerT
> functionReference
;
1096 ::boost::spirit::classic::rule
< ScannerT
> modRef_decl
;
1097 ::boost::spirit::classic::rule
< ScannerT
> modifierReference
;
1098 ::boost::spirit::classic::rule
< ScannerT
> identifier
;
1101 const ParserContextSharedPtr
& getContext() const
1103 return mpParserContext
;
1107 ParserContextSharedPtr mpParserContext
; // might get modified during parsing
1110 const ParserContextSharedPtr
& getParserContext()
1112 static ParserContextSharedPtr lcl_parserContext
= std::make_shared
<ParserContext
>();
1114 // clear node stack (since we reuse the static object, that's
1115 // the whole point here)
1116 while( !lcl_parserContext
->maOperandStack
.empty() )
1117 lcl_parserContext
->maOperandStack
.pop();
1119 return lcl_parserContext
;
1124 namespace EnhancedCustomShape
{
1127 std::shared_ptr
<ExpressionNode
> const & FunctionParser::parseFunction( std::u16string_view rFunction
, const EnhancedCustomShape2d
& rCustoShape
)
1129 // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
1130 // gives better conversion robustness here (we might want to map space
1131 // etc. to ASCII space here)
1132 const OString
aAsciiFunction(
1133 OUStringToOString( rFunction
, RTL_TEXTENCODING_ASCII_US
) );
1135 StringIteratorT
aStart( aAsciiFunction
.getStr() );
1136 StringIteratorT
aEnd( aAsciiFunction
.getStr()+aAsciiFunction
.getLength() );
1138 // static parser context, because the actual
1139 // Spirit parser is also a static object
1140 const ParserContextSharedPtr
& pContext
= getParserContext();
1141 pContext
->mpCustoShape
= &rCustoShape
;
1143 ExpressionGrammar
aExpressionGrammer( pContext
);
1144 const ::boost::spirit::classic::parse_info
<StringIteratorT
> aParseInfo(
1145 ::boost::spirit::classic::parse( aStart
,
1147 aExpressionGrammer
>> ::boost::spirit::classic::end_p
,
1148 ::boost::spirit::classic::space_p
) );
1150 // input fully congested by the parser?
1151 if( !aParseInfo
.full
)
1152 throw ParseError( "EnhancedCustomShapeFunctionParser::parseFunction(): string not fully parseable" );
1154 // parser's state stack now must contain exactly _one_ ExpressionNode,
1155 // which represents our formula.
1156 if( pContext
->maOperandStack
.size() != 1 )
1157 throw ParseError( "EnhancedCustomShapeFunctionParser::parseFunction(): incomplete or empty expression" );
1160 return pContext
->maOperandStack
.top();
1165 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */