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 .
21 // Makes parser a static resource,
22 // we're synchronized externally.
23 // But watch out, the parser might have
24 // state not visible to this code!
25 #define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
26 #if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
28 #define BOOST_SPIRIT_DEBUG
30 #include <boost/spirit/include/classic_core.hpp>
31 #include "RowFunctionParser.hxx"
32 #include <rtl/ustring.hxx>
33 #include <tools/fract.hxx>
37 #if (OSL_DEBUG_LEVEL > 0)
44 namespace connectivity
46 using namespace com::sun::star
;
50 //////////////////////
51 //////////////////////
53 //////////////////////
54 //////////////////////
55 class ConstantValueExpression
: public ExpressionNode
57 ORowSetValueDecoratorRef maValue
;
61 ConstantValueExpression( ORowSetValueDecoratorRef rValue
) :
65 virtual ORowSetValueDecoratorRef
evaluate(const ODatabaseMetaDataResultSet::ORow
& /*_aRow*/ ) const
69 virtual void fill(const ODatabaseMetaDataResultSet::ORow
& /*_aRow*/ ) const
72 virtual ExpressionFunct
getType() const
76 virtual ODatabaseMetaDataResultSet::ORow
fillNode( std::vector
< RowEquation
>& /*rEquations*/, ExpressionNode
* /* pOptionalArg */, sal_uInt32
/* nFlags */ )
78 ODatabaseMetaDataResultSet::ORow aRet
;
84 /** ExpressionNode implementation for unary
85 function over two ExpressionNodes
87 class BinaryFunctionExpression
: public ExpressionNode
89 const ExpressionFunct meFunct
;
90 ExpressionNodeSharedPtr mpFirstArg
;
91 ExpressionNodeSharedPtr mpSecondArg
;
95 BinaryFunctionExpression( const ExpressionFunct eFunct
, const ExpressionNodeSharedPtr
& rFirstArg
, const ExpressionNodeSharedPtr
& rSecondArg
) :
97 mpFirstArg( rFirstArg
),
98 mpSecondArg( rSecondArg
)
101 virtual ORowSetValueDecoratorRef
evaluate(const ODatabaseMetaDataResultSet::ORow
& _aRow
) const
103 ORowSetValueDecoratorRef aRet
;
106 case ENUM_FUNC_EQUATION
:
107 aRet
= new ORowSetValueDecorator(sal_Bool(mpFirstArg
->evaluate(_aRow
)->getValue() == mpSecondArg
->evaluate(_aRow
)->getValue()) );
110 aRet
= new ORowSetValueDecorator( sal_Bool(mpFirstArg
->evaluate(_aRow
)->getValue().getBool() && mpSecondArg
->evaluate(_aRow
)->getValue().getBool()) );
113 aRet
= new ORowSetValueDecorator( sal_Bool(mpFirstArg
->evaluate(_aRow
)->getValue().getBool() || mpSecondArg
->evaluate(_aRow
)->getValue().getBool()) );
120 virtual void fill(const ODatabaseMetaDataResultSet::ORow
& _aRow
) const
124 case ENUM_FUNC_EQUATION
:
125 (*mpFirstArg
->evaluate(_aRow
)) = mpSecondArg
->evaluate(_aRow
)->getValue();
131 virtual ExpressionFunct
getType() const
135 virtual ODatabaseMetaDataResultSet::ORow
fillNode( std::vector
< RowEquation
>& /*rEquations*/, ExpressionNode
* /*pOptionalArg*/, sal_uInt32
/*nFlags*/ )
137 ODatabaseMetaDataResultSet::ORow aRet
;
143 ////////////////////////
144 ////////////////////////
146 ////////////////////////
147 ////////////////////////
149 typedef const sal_Char
* StringIteratorT
;
153 typedef ::std::stack
< ExpressionNodeSharedPtr
> OperandStack
;
155 // stores a stack of not-yet-evaluated operands. This is used
156 // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
157 // arguments from. If all arguments to an operator are constant,
158 // the operator pushes a precalculated result on the stack, and
159 // a composite ExpressionNode otherwise.
160 OperandStack maOperandStack
;
163 typedef ::boost::shared_ptr
< ParserContext
> ParserContextSharedPtr
;
165 /** Generate apriori constant value
168 class ConstantFunctor
170 ParserContextSharedPtr mpContext
;
174 ConstantFunctor( const ParserContextSharedPtr
& rContext
) :
175 mpContext( rContext
)
178 void operator()( StringIteratorT rFirst
,StringIteratorT rSecond
) const
180 OUString
sVal( rFirst
, rSecond
- rFirst
, RTL_TEXTENCODING_UTF8
);
181 mpContext
->maOperandStack
.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( sVal
) ) ) );
185 /** Generate parse-dependent-but-then-constant value
187 class IntConstantFunctor
189 ParserContextSharedPtr mpContext
;
192 IntConstantFunctor( const ParserContextSharedPtr
& rContext
) :
193 mpContext( rContext
)
196 void operator()( sal_Int32 n
) const
198 mpContext
->maOperandStack
.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( n
) ) ) );
200 void operator()( StringIteratorT rFirst
,StringIteratorT rSecond
) const
202 OUString
sVal( rFirst
, rSecond
- rFirst
, RTL_TEXTENCODING_UTF8
);
207 /** Implements a binary function over two ExpressionNodes
210 Generator functor, to generate an ExpressionNode of
214 class BinaryFunctionFunctor
216 const ExpressionFunct meFunct
;
217 ParserContextSharedPtr mpContext
;
221 BinaryFunctionFunctor( const ExpressionFunct eFunct
, const ParserContextSharedPtr
& rContext
) :
223 mpContext( rContext
)
227 void operator()( StringIteratorT
, StringIteratorT
) const
229 ParserContext::OperandStack
& rNodeStack( mpContext
->maOperandStack
);
231 if( rNodeStack
.size() < 2 )
232 throw ParseError( "Not enough arguments for binary operator" );
234 // retrieve arguments
235 ExpressionNodeSharedPtr
pSecondArg( rNodeStack
.top() );
237 ExpressionNodeSharedPtr
pFirstArg( rNodeStack
.top() );
240 // create combined ExpressionNode
241 ExpressionNodeSharedPtr pNode
= ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct
, pFirstArg
, pSecondArg
) );
242 // check for constness
243 rNodeStack
.push( pNode
);
246 /** ExpressionNode implementation for unary
247 function over one ExpressionNode
249 class UnaryFunctionExpression
: public ExpressionNode
251 const ExpressionFunct meFunct
;
252 ExpressionNodeSharedPtr mpArg
;
255 UnaryFunctionExpression( const ExpressionFunct eFunct
, const ExpressionNodeSharedPtr
& rArg
) :
260 virtual ORowSetValueDecoratorRef
evaluate(const ODatabaseMetaDataResultSet::ORow
& _aRow
) const
262 return _aRow
[mpArg
->evaluate(_aRow
)->getValue().getInt32()];
264 virtual void fill(const ODatabaseMetaDataResultSet::ORow
& /*_aRow*/ ) const
267 virtual ExpressionFunct
getType() const
271 virtual ODatabaseMetaDataResultSet::ORow
fillNode( std::vector
< RowEquation
>& /*rEquations*/, ExpressionNode
* /* pOptionalArg */, sal_uInt32
/* nFlags */ )
273 ODatabaseMetaDataResultSet::ORow aRet
;
278 class UnaryFunctionFunctor
280 const ExpressionFunct meFunct
;
281 ParserContextSharedPtr mpContext
;
285 UnaryFunctionFunctor( const ExpressionFunct eFunct
, const ParserContextSharedPtr
& rContext
) :
287 mpContext( rContext
)
290 void operator()( StringIteratorT
, StringIteratorT
) const
293 ParserContext::OperandStack
& rNodeStack( mpContext
->maOperandStack
);
295 if( rNodeStack
.size() < 1 )
296 throw ParseError( "Not enough arguments for unary operator" );
298 // retrieve arguments
299 ExpressionNodeSharedPtr
pArg( rNodeStack
.top() );
302 rNodeStack
.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct
, pArg
) ) );
306 /* This class implements the following grammar (more or
307 less literally written down below, only slightly
308 obfuscated by the parser actions):
312 '(' additive_expression ')'
317 multiplicative_expression =
318 unary_expression ( ( '*' unary_expression )* |
319 ( '/' unary_expression )* )
321 additive_expression =
322 multiplicative_expression ( ( '+' multiplicative_expression )* |
323 ( '-' multiplicative_expression )* )
326 class ExpressionGrammar
: public ::boost::spirit::grammar
< ExpressionGrammar
>
329 /** Create an arithmetic expression grammar
331 @param rParserContext
332 Contains context info for the parser
334 ExpressionGrammar( const ParserContextSharedPtr
& rParserContext
) :
335 mpParserContext( rParserContext
)
339 template< typename ScannerT
> class definition
342 // grammar definition
343 definition( const ExpressionGrammar
& self
)
345 using ::boost::spirit::str_p
;
346 using ::boost::spirit::space_p
;
347 using ::boost::spirit::range_p
;
348 using ::boost::spirit::lexeme_d
;
349 using ::boost::spirit::real_parser
;
350 using ::boost::spirit::chseq_p
;
351 using ::boost::spirit::ch_p
;
352 using ::boost::spirit::int_p
;
353 using ::boost::spirit::as_lower_d
;
354 using ::boost::spirit::strlit
;
355 using ::boost::spirit::inhibit_case
;
358 typedef inhibit_case
<strlit
<> > token_t
;
359 token_t COLUMN
= as_lower_d
[ "column" ];
360 token_t OR_
= as_lower_d
[ "or" ];
361 token_t AND_
= as_lower_d
[ "and" ];
365 [IntConstantFunctor(self
.getContext())];
369 | lexeme_d
[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
370 [ ConstantFunctor(self
.getContext()) ]
374 (COLUMN
>> '(' >> integer
>> ')' )
375 [ UnaryFunctionFunctor( UNARY_FUNC_COLUMN
, self
.getContext()) ]
379 unaryFunction
>> ch_p('=') >> argument
380 [ BinaryFunctionFunctor( ENUM_FUNC_EQUATION
, self
.getContext()) ]
385 | ( '(' >> orExpression
>> ')' )
386 | ( assignment
>> AND_
>> assignment
) [ BinaryFunctionFunctor( ENUM_FUNC_AND
, self
.getContext()) ]
391 | ( orExpression
>> OR_
>> andExpression
) [ BinaryFunctionFunctor( ENUM_FUNC_OR
, self
.getContext()) ]
398 BOOST_SPIRIT_DEBUG_RULE(basicExpression
);
399 BOOST_SPIRIT_DEBUG_RULE(unaryFunction
);
400 BOOST_SPIRIT_DEBUG_RULE(assignment
);
401 BOOST_SPIRIT_DEBUG_RULE(argument
);
402 BOOST_SPIRIT_DEBUG_RULE(integer
);
403 BOOST_SPIRIT_DEBUG_RULE(orExpression
);
404 BOOST_SPIRIT_DEBUG_RULE(andExpression
);
407 const ::boost::spirit::rule
< ScannerT
>& start() const
409 return basicExpression
;
413 // the constituents of the Spirit arithmetic expression grammar.
414 // For the sake of readability, without 'ma' prefix.
415 ::boost::spirit::rule
< ScannerT
> basicExpression
;
416 ::boost::spirit::rule
< ScannerT
> unaryFunction
;
417 ::boost::spirit::rule
< ScannerT
> assignment
;
418 ::boost::spirit::rule
< ScannerT
> integer
,argument
;
419 ::boost::spirit::rule
< ScannerT
> orExpression
,andExpression
;
422 const ParserContextSharedPtr
& getContext() const
424 return mpParserContext
;
428 ParserContextSharedPtr mpParserContext
; // might get modified during parsing
431 #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
432 const ParserContextSharedPtr
& getParserContext()
434 static ParserContextSharedPtr
lcl_parserContext( new ParserContext() );
436 // clear node stack (since we reuse the static object, that's
437 // the whole point here)
438 while( !lcl_parserContext
->maOperandStack
.empty() )
439 lcl_parserContext
->maOperandStack
.pop();
441 return lcl_parserContext
;
446 ExpressionNodeSharedPtr
FunctionParser::parseFunction( const OUString
& _sFunction
)
448 // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
449 // gives better conversion robustness here (we might want to map space
450 // etc. to ASCII space here)
451 const OString
& rAsciiFunction(
452 OUStringToOString( _sFunction
, RTL_TEXTENCODING_ASCII_US
) );
454 StringIteratorT
aStart( rAsciiFunction
.getStr() );
455 StringIteratorT
aEnd( rAsciiFunction
.getStr()+rAsciiFunction
.getLength() );
457 ParserContextSharedPtr pContext
;
459 #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
460 // static parser context, because the actual
461 // Spirit parser is also a static object
462 pContext
= getParserContext();
464 pContext
.reset( new ParserContext() );
467 ExpressionGrammar
aExpressionGrammer( pContext
);
469 const ::boost::spirit::parse_info
<StringIteratorT
> aParseInfo(
470 ::boost::spirit::parse( aStart
,
473 ::boost::spirit::space_p
) );
475 OSL_DEBUG_ONLY(::std::cout
.flush()); // needed to keep stdout and cout in sync
477 // input fully congested by the parser?
478 if( !aParseInfo
.full
)
479 throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
481 // parser's state stack now must contain exactly _one_ ExpressionNode,
482 // which represents our formula.
483 if( pContext
->maOperandStack
.size() != 1 )
484 throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
486 return pContext
->maOperandStack
.top();
490 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */