// Makes parser a static resource, // we're synchronized externally. // But watch out, the parser might have // state not visible to this code! #define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
// stores a stack of not-yet-evaluated operands. This is used // by the operators (i.e. '+', '*', 'sin' etc.) to pop their // arguments from. If all arguments to an operator are constant, // the operator pushes a precalculated result on the stack, and // a composite ExpressionNode otherwise.
OperandStack maOperandStack;
// bounds of the shape this expression is associated with
::basegfx::B2DRectangle maShapeBounds;
// when true, enable usage of time-dependent variable '$' // in expressions bool mbParseAnimationFunction;
};
voidoperator()( double n ) const
{ // push constant value expression to the stack
mpContext->maOperandStack.push(
ExpressionNodeFactory::createConstantValueExpression( n ) );
}
private:
ParserContextSharedPtr mpContext;
};
/** Generate special t value expression node
*/ class ValueTFunctor
{ public: explicit ValueTFunctor( ParserContextSharedPtr xContext ) :
mpContext(std::move( xContext ))
{
ENSURE_OR_THROW( mpContext, "ValueTFunctor::ValueTFunctor(): Invalid context" );
}
voidoperator()( StringIteratorT, StringIteratorT ) const
{ if( !mpContext->mbParseAnimationFunction )
{
SAL_WARN("slideshow", "ValueTFunctor::operator(): variable encountered, but we're not parsing a function here" ); throw ParseError();
}
// push special t value expression to the stack
mpContext->maOperandStack.push(
ExpressionNodeFactory::createValueTExpression() );
}
private:
ParserContextSharedPtr mpContext;
};
template< typename Functor > class UnaryFunctionFunctor
{ private: /** ExpressionNode implementation for unary functionoveroneExpressionNode
*/ class UnaryFunctionExpression : public ExpressionNode
{ public:
UnaryFunctionExpression( const Functor& rFunctor,
std::shared_ptr<ExpressionNode> xArg ) :
maFunctor( rFunctor ),
mpArg(std::move( xArg ))
{
}
// TODO(Q2): Refactor makeUnaryFunctionFunctor, // makeBinaryFunctionFunctor and the whole // ExpressionNodeFactory, to use a generic // makeFunctionFunctor template, which is overloaded for // unary, binary, ternary, etc. function pointers. template< typename Functor > UnaryFunctionFunctor<Functor>
makeUnaryFunctionFunctor( const Functor& rFunctor, const ParserContextSharedPtr& rContext )
{ return UnaryFunctionFunctor<Functor>( rFunctor, rContext );
}
// MSVC has problems instantiating above template function with plain function // pointers (doesn't like the const reference there). Thus, provide it with // a dedicated overload here.
UnaryFunctionFunctor< double (*)(double) >
makeUnaryFunctionFunctor( double (*pFunc)(double), const ParserContextSharedPtr& rContext )
{ return UnaryFunctionFunctor< double (*)(double) >( pFunc, rContext );
}
/** Implements a binary function over two ExpressionNodes
// check for constness if (pFirstArg->isConstant() && pSecondArg->isConstant())
{ // call the operator() at pNode, store result // in constant value ExpressionNode.
rNodeStack.push(
ExpressionNodeFactory::createConstantValueExpression(
(*pNode)( 0.0 ) ) );
} else
{ // push complex node, that calcs the value on demand
rNodeStack.push( pNode );
}
}
// Workaround for MSVC compiler anomaly (stack trashing)
// The default ureal_parser_policies implementation of parse_exp // triggers a really weird error in MSVC7 (Version 13.00.9466), in // that the real_parser_impl::parse_main() call of parse_exp() // overwrites the frame pointer _on the stack_ (EBP of the calling // function gets overwritten while lying on the stack).
// For the time being, our parser thus can only read the 1.0E10 // notation, not the 1.0e10 one.
// TODO(F1): Also handle the 1.0e10 case here. template< typename T > struct custom_real_parser_policies : public ::boost::spirit::classic::ureal_parser_policies<T>
{ template< typename ScannerT > statictypename ::boost::spirit::classic::parser_result< ::boost::spirit::classic::chlit<>, ScannerT >::type
parse_exp(ScannerT& scan)
{ // as_lower_d somehow breaks MSVC7 return ::boost::spirit::classic::ch_p('E').parse(scan);
}
};
/* This class implements the following grammar (more or lessliterallywrittendownbelow,onlyslightly obfuscatedbytheparseractions):
// clear node stack (since we reuse the static object, that's // the whole point here) while( !lcl_parserContext->maOperandStack.empty() )
lcl_parserContext->maOperandStack.pop();
return lcl_parserContext;
}
}
std::shared_ptr<ExpressionNode> const & SmilFunctionParser::parseSmilValue( const OUString& rSmilValue, const ::basegfx::B2DRectangle& rRelativeShapeBounds )
{ // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_* // gives better conversion robustness here (we might want to map space // etc. to ASCII space here) const OString aAsciiSmilValue(
OUStringToOString( rSmilValue, RTL_TEXTENCODING_ASCII_US ) );
#if OSL_DEBUG_LEVEL > 0
::std::cout.flush(); // needed to keep stdout and cout in sync #endif
// input fully congested by the parser? if( !aParseInfo.full ) throw ParseError( "SmilFunctionParser::parseSmilValue(): string not fully parseable" );
// parser's state stack now must contain exactly _one_ ExpressionNode, // which represents our formula. if( pContext->maOperandStack.size() != 1 ) throw ParseError( "SmilFunctionParser::parseSmilValue(): incomplete or empty expression" );
return pContext->maOperandStack.top();
}
std::shared_ptr<ExpressionNode> const & SmilFunctionParser::parseSmilFunction( const OUString& rSmilFunction, const ::basegfx::B2DRectangle& rRelativeShapeBounds )
{ // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_* // gives better conversion robustness here (we might want to map space // etc. to ASCII space here) const OString aAsciiSmilFunction(
OUStringToOString( rSmilFunction, RTL_TEXTENCODING_ASCII_US ) );
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.