1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: RowFunctionParser.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_connectivity.hxx"
34 // Makes parser a static resource,
35 // we're synchronized externally.
36 // But watch out, the parser might have
37 // state not visible to this code!
38 #define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
39 #if defined(VERBOSE) && defined(DBG_UTIL)
41 #define BOOST_SPIRIT_DEBUG
43 #include <boost/spirit/include/classic_core.hpp>
44 #include "RowFunctionParser.hxx"
45 #include <rtl/ustring.hxx>
46 #include <tools/fract.hxx>
50 #if (OSL_DEBUG_LEVEL > 0)
57 namespace connectivity
59 using namespace com::sun::star
;
63 //////////////////////
64 //////////////////////
66 //////////////////////
67 //////////////////////
68 class ConstantValueExpression
: public ExpressionNode
70 ORowSetValueDecoratorRef maValue
;
74 ConstantValueExpression( ORowSetValueDecoratorRef rValue
) :
78 virtual ORowSetValueDecoratorRef
evaluate(const ODatabaseMetaDataResultSet::ORow
& /*_aRow*/ ) const
82 virtual void fill(const ODatabaseMetaDataResultSet::ORow
& /*_aRow*/ ) const
85 virtual ExpressionFunct
getType() const
89 virtual ODatabaseMetaDataResultSet::ORow
fillNode( std::vector
< RowEquation
>& /*rEquations*/, ExpressionNode
* /* pOptionalArg */, sal_uInt32
/* nFlags */ )
91 ODatabaseMetaDataResultSet::ORow aRet
;
97 /** ExpressionNode implementation for unary
98 function over two ExpressionNodes
100 class BinaryFunctionExpression
: public ExpressionNode
102 const ExpressionFunct meFunct
;
103 ExpressionNodeSharedPtr mpFirstArg
;
104 ExpressionNodeSharedPtr mpSecondArg
;
108 BinaryFunctionExpression( const ExpressionFunct eFunct
, const ExpressionNodeSharedPtr
& rFirstArg
, const ExpressionNodeSharedPtr
& rSecondArg
) :
110 mpFirstArg( rFirstArg
),
111 mpSecondArg( rSecondArg
)
114 virtual ORowSetValueDecoratorRef
evaluate(const ODatabaseMetaDataResultSet::ORow
& _aRow
) const
116 ORowSetValueDecoratorRef aRet
;
119 case ENUM_FUNC_EQUATION
:
120 aRet
= new ORowSetValueDecorator(sal_Bool(mpFirstArg
->evaluate(_aRow
)->getValue() == mpSecondArg
->evaluate(_aRow
)->getValue()) );
123 aRet
= new ORowSetValueDecorator( sal_Bool(mpFirstArg
->evaluate(_aRow
)->getValue().getBool() && mpSecondArg
->evaluate(_aRow
)->getValue().getBool()) );
126 aRet
= new ORowSetValueDecorator( sal_Bool(mpFirstArg
->evaluate(_aRow
)->getValue().getBool() || mpSecondArg
->evaluate(_aRow
)->getValue().getBool()) );
133 virtual void fill(const ODatabaseMetaDataResultSet::ORow
& _aRow
) const
137 case ENUM_FUNC_EQUATION
:
138 (*mpFirstArg
->evaluate(_aRow
)) = mpSecondArg
->evaluate(_aRow
)->getValue();
144 virtual ExpressionFunct
getType() const
148 virtual ODatabaseMetaDataResultSet::ORow
fillNode( std::vector
< RowEquation
>& /*rEquations*/, ExpressionNode
* /*pOptionalArg*/, sal_uInt32
/*nFlags*/ )
150 ODatabaseMetaDataResultSet::ORow aRet
;
156 ////////////////////////
157 ////////////////////////
159 ////////////////////////
160 ////////////////////////
162 typedef const sal_Char
* StringIteratorT
;
166 typedef ::std::stack
< ExpressionNodeSharedPtr
> OperandStack
;
168 // stores a stack of not-yet-evaluated operands. This is used
169 // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
170 // arguments from. If all arguments to an operator are constant,
171 // the operator pushes a precalculated result on the stack, and
172 // a composite ExpressionNode otherwise.
173 OperandStack maOperandStack
;
176 typedef ::boost::shared_ptr
< ParserContext
> ParserContextSharedPtr
;
178 /** Generate apriori constant value
181 class ConstantFunctor
183 ParserContextSharedPtr mpContext
;
187 ConstantFunctor( const ParserContextSharedPtr
& rContext
) :
188 mpContext( rContext
)
191 void operator()( StringIteratorT rFirst
,StringIteratorT rSecond
) const
193 rtl::OUString
sVal( rFirst
, rSecond
- rFirst
, RTL_TEXTENCODING_UTF8
);
194 mpContext
->maOperandStack
.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( sVal
) ) ) );
198 /** Generate parse-dependent-but-then-constant value
200 class IntConstantFunctor
202 ParserContextSharedPtr mpContext
;
205 IntConstantFunctor( const ParserContextSharedPtr
& rContext
) :
206 mpContext( rContext
)
209 void operator()( sal_Int32 n
) const
211 mpContext
->maOperandStack
.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( n
) ) ) );
213 void operator()( StringIteratorT rFirst
,StringIteratorT rSecond
) const
215 rtl::OUString
sVal( rFirst
, rSecond
- rFirst
, RTL_TEXTENCODING_UTF8
);
220 /** Implements a binary function over two ExpressionNodes
223 Generator functor, to generate an ExpressionNode of
227 class BinaryFunctionFunctor
229 const ExpressionFunct meFunct
;
230 ParserContextSharedPtr mpContext
;
234 BinaryFunctionFunctor( const ExpressionFunct eFunct
, const ParserContextSharedPtr
& rContext
) :
236 mpContext( rContext
)
240 void operator()( StringIteratorT
, StringIteratorT
) const
242 ParserContext::OperandStack
& rNodeStack( mpContext
->maOperandStack
);
244 if( rNodeStack
.size() < 2 )
245 throw ParseError( "Not enough arguments for binary operator" );
247 // retrieve arguments
248 ExpressionNodeSharedPtr
pSecondArg( rNodeStack
.top() );
250 ExpressionNodeSharedPtr
pFirstArg( rNodeStack
.top() );
253 // create combined ExpressionNode
254 ExpressionNodeSharedPtr pNode
= ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct
, pFirstArg
, pSecondArg
) );
255 // check for constness
256 rNodeStack
.push( pNode
);
259 /** ExpressionNode implementation for unary
260 function over one ExpressionNode
262 class UnaryFunctionExpression
: public ExpressionNode
264 const ExpressionFunct meFunct
;
265 ExpressionNodeSharedPtr mpArg
;
268 UnaryFunctionExpression( const ExpressionFunct eFunct
, const ExpressionNodeSharedPtr
& rArg
) :
273 virtual ORowSetValueDecoratorRef
evaluate(const ODatabaseMetaDataResultSet::ORow
& _aRow
) const
275 return _aRow
[mpArg
->evaluate(_aRow
)->getValue().getInt32()];
277 virtual void fill(const ODatabaseMetaDataResultSet::ORow
& /*_aRow*/ ) const
280 virtual ExpressionFunct
getType() const
284 virtual ODatabaseMetaDataResultSet::ORow
fillNode( std::vector
< RowEquation
>& /*rEquations*/, ExpressionNode
* /* pOptionalArg */, sal_uInt32
/* nFlags */ )
286 ODatabaseMetaDataResultSet::ORow aRet
;
291 class UnaryFunctionFunctor
293 const ExpressionFunct meFunct
;
294 ParserContextSharedPtr mpContext
;
298 UnaryFunctionFunctor( const ExpressionFunct eFunct
, const ParserContextSharedPtr
& rContext
) :
300 mpContext( rContext
)
303 void operator()( StringIteratorT
, StringIteratorT
) const
306 ParserContext::OperandStack
& rNodeStack( mpContext
->maOperandStack
);
308 if( rNodeStack
.size() < 1 )
309 throw ParseError( "Not enough arguments for unary operator" );
311 // retrieve arguments
312 ExpressionNodeSharedPtr
pArg( rNodeStack
.top() );
315 rNodeStack
.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct
, pArg
) ) );
319 /* This class implements the following grammar (more or
320 less literally written down below, only slightly
321 obfuscated by the parser actions):
325 '(' additive_expression ')'
330 multiplicative_expression =
331 unary_expression ( ( '*' unary_expression )* |
332 ( '/' unary_expression )* )
334 additive_expression =
335 multiplicative_expression ( ( '+' multiplicative_expression )* |
336 ( '-' multiplicative_expression )* )
339 class ExpressionGrammar
: public ::boost::spirit::grammar
< ExpressionGrammar
>
342 /** Create an arithmetic expression grammar
344 @param rParserContext
345 Contains context info for the parser
347 ExpressionGrammar( const ParserContextSharedPtr
& rParserContext
) :
348 mpParserContext( rParserContext
)
352 template< typename ScannerT
> class definition
355 // grammar definition
356 definition( const ExpressionGrammar
& self
)
358 using ::boost::spirit::str_p
;
359 using ::boost::spirit::space_p
;
360 using ::boost::spirit::range_p
;
361 using ::boost::spirit::lexeme_d
;
362 using ::boost::spirit::real_parser
;
363 using ::boost::spirit::chseq_p
;
364 using ::boost::spirit::ch_p
;
365 using ::boost::spirit::int_p
;
366 using ::boost::spirit::as_lower_d
;
367 using ::boost::spirit::strlit
;
368 using ::boost::spirit::inhibit_case
;
371 typedef inhibit_case
<strlit
<> > token_t
;
372 token_t COLUMN
= as_lower_d
[ "column" ];
373 token_t OR_
= as_lower_d
[ "or" ];
374 token_t AND_
= as_lower_d
[ "and" ];
378 [IntConstantFunctor(self
.getContext())];
382 | lexeme_d
[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
383 [ ConstantFunctor(self
.getContext()) ]
387 (COLUMN
>> '(' >> integer
>> ')' )
388 [ UnaryFunctionFunctor( UNARY_FUNC_COLUMN
, self
.getContext()) ]
392 unaryFunction
>> ch_p('=') >> argument
393 [ BinaryFunctionFunctor( ENUM_FUNC_EQUATION
, self
.getContext()) ]
398 | ( '(' >> orExpression
>> ')' )
399 | ( assignment
>> AND_
>> assignment
) [ BinaryFunctionFunctor( ENUM_FUNC_AND
, self
.getContext()) ]
404 | ( orExpression
>> OR_
>> andExpression
) [ BinaryFunctionFunctor( ENUM_FUNC_OR
, self
.getContext()) ]
411 BOOST_SPIRIT_DEBUG_RULE(basicExpression
);
412 BOOST_SPIRIT_DEBUG_RULE(unaryFunction
);
413 BOOST_SPIRIT_DEBUG_RULE(assignment
);
414 BOOST_SPIRIT_DEBUG_RULE(argument
);
415 BOOST_SPIRIT_DEBUG_RULE(integer
);
416 BOOST_SPIRIT_DEBUG_RULE(orExpression
);
417 BOOST_SPIRIT_DEBUG_RULE(andExpression
);
420 const ::boost::spirit::rule
< ScannerT
>& start() const
422 return basicExpression
;
426 // the constituents of the Spirit arithmetic expression grammar.
427 // For the sake of readability, without 'ma' prefix.
428 ::boost::spirit::rule
< ScannerT
> basicExpression
;
429 ::boost::spirit::rule
< ScannerT
> unaryFunction
;
430 ::boost::spirit::rule
< ScannerT
> assignment
;
431 ::boost::spirit::rule
< ScannerT
> integer
,argument
;
432 ::boost::spirit::rule
< ScannerT
> orExpression
,andExpression
;
435 const ParserContextSharedPtr
& getContext() const
437 return mpParserContext
;
441 ParserContextSharedPtr mpParserContext
; // might get modified during parsing
444 #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
445 const ParserContextSharedPtr
& getParserContext()
447 static ParserContextSharedPtr
lcl_parserContext( new ParserContext() );
449 // clear node stack (since we reuse the static object, that's
450 // the whole point here)
451 while( !lcl_parserContext
->maOperandStack
.empty() )
452 lcl_parserContext
->maOperandStack
.pop();
454 return lcl_parserContext
;
459 ExpressionNodeSharedPtr
FunctionParser::parseFunction( const ::rtl::OUString
& _sFunction
)
461 // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
462 // gives better conversion robustness here (we might want to map space
463 // etc. to ASCII space here)
464 const ::rtl::OString
& rAsciiFunction(
465 rtl::OUStringToOString( _sFunction
, RTL_TEXTENCODING_ASCII_US
) );
467 StringIteratorT
aStart( rAsciiFunction
.getStr() );
468 StringIteratorT
aEnd( rAsciiFunction
.getStr()+rAsciiFunction
.getLength() );
470 ParserContextSharedPtr pContext
;
472 #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
473 // static parser context, because the actual
474 // Spirit parser is also a static object
475 pContext
= getParserContext();
477 pContext
.reset( new ParserContext() );
480 ExpressionGrammar
aExpressionGrammer( pContext
);
482 const ::boost::spirit::parse_info
<StringIteratorT
> aParseInfo(
483 ::boost::spirit::parse( aStart
,
486 ::boost::spirit::space_p
) );
488 OSL_DEBUG_ONLY(::std::cout
.flush()); // needed to keep stdout and cout in sync
490 // input fully congested by the parser?
491 if( !aParseInfo
.full
)
492 throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
494 // parser's state stack now must contain exactly _one_ ExpressionNode,
495 // which represents our formula.
496 if( pContext
->maOperandStack
.size() != 1 )
497 throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
499 return pContext
->maOperandStack
.top();