Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
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)
27 : #include <typeinfo>
28 : #define BOOST_SPIRIT_DEBUG
29 : #endif
30 : #include <boost/spirit/include/classic_core.hpp>
31 : #include "RowFunctionParser.hxx"
32 : #include <rtl/ustring.hxx>
33 : #include <tools/fract.hxx>
34 :
35 :
36 :
37 : #if (OSL_DEBUG_LEVEL > 0)
38 : #include <iostream>
39 : #endif
40 : #include <functional>
41 : #include <algorithm>
42 : #include <stack>
43 :
44 : namespace connectivity
45 : {
46 : using namespace com::sun::star;
47 :
48 : namespace
49 : {
50 : //////////////////////
51 : //////////////////////
52 : // EXPRESSION NODES
53 : //////////////////////
54 : //////////////////////
55 0 : class ConstantValueExpression : public ExpressionNode
56 : {
57 : ORowSetValueDecoratorRef maValue;
58 :
59 : public:
60 :
61 0 : ConstantValueExpression( ORowSetValueDecoratorRef rValue ) :
62 0 : maValue( rValue )
63 : {
64 0 : }
65 0 : virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const
66 : {
67 0 : return maValue;
68 : }
69 0 : virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const
70 : {
71 0 : }
72 0 : virtual ExpressionFunct getType() const
73 : {
74 0 : return FUNC_CONST;
75 : }
76 0 : virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ )
77 : {
78 0 : ODatabaseMetaDataResultSet::ORow aRet;
79 0 : return aRet;
80 : }
81 : };
82 :
83 :
84 : /** ExpressionNode implementation for unary
85 : function over two ExpressionNodes
86 : */
87 0 : class BinaryFunctionExpression : public ExpressionNode
88 : {
89 : const ExpressionFunct meFunct;
90 : ExpressionNodeSharedPtr mpFirstArg;
91 : ExpressionNodeSharedPtr mpSecondArg;
92 :
93 : public:
94 :
95 0 : BinaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rFirstArg, const ExpressionNodeSharedPtr& rSecondArg ) :
96 : meFunct( eFunct ),
97 : mpFirstArg( rFirstArg ),
98 0 : mpSecondArg( rSecondArg )
99 : {
100 0 : }
101 0 : virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const
102 : {
103 0 : ORowSetValueDecoratorRef aRet;
104 0 : switch(meFunct)
105 : {
106 : case ENUM_FUNC_EQUATION:
107 0 : aRet = new ORowSetValueDecorator(sal_Bool(mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue()) );
108 0 : break;
109 : case ENUM_FUNC_AND:
110 0 : aRet = new ORowSetValueDecorator( sal_Bool(mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool()) );
111 0 : break;
112 : case ENUM_FUNC_OR:
113 0 : aRet = new ORowSetValueDecorator( sal_Bool(mpFirstArg->evaluate(_aRow )->getValue().getBool() || mpSecondArg->evaluate(_aRow )->getValue().getBool()) );
114 0 : break;
115 : default:
116 0 : break;
117 : }
118 0 : return aRet;
119 : }
120 0 : virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const
121 : {
122 0 : switch(meFunct)
123 : {
124 : case ENUM_FUNC_EQUATION:
125 0 : (*mpFirstArg->evaluate(_aRow )) = mpSecondArg->evaluate(_aRow )->getValue();
126 0 : break;
127 : default:
128 0 : break;
129 : }
130 0 : }
131 0 : virtual ExpressionFunct getType() const
132 : {
133 0 : return meFunct;
134 : }
135 0 : virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ )
136 : {
137 0 : ODatabaseMetaDataResultSet::ORow aRet;
138 0 : return aRet;
139 : }
140 : };
141 :
142 :
143 : ////////////////////////
144 : ////////////////////////
145 : // FUNCTION PARSER
146 : ////////////////////////
147 : ////////////////////////
148 :
149 : typedef const sal_Char* StringIteratorT;
150 :
151 0 : struct ParserContext
152 : {
153 : typedef ::std::stack< ExpressionNodeSharedPtr > OperandStack;
154 :
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;
161 : };
162 :
163 : typedef ::boost::shared_ptr< ParserContext > ParserContextSharedPtr;
164 :
165 : /** Generate apriori constant value
166 : */
167 :
168 0 : class ConstantFunctor
169 : {
170 : ParserContextSharedPtr mpContext;
171 :
172 : public:
173 :
174 0 : ConstantFunctor( const ParserContextSharedPtr& rContext ) :
175 0 : mpContext( rContext )
176 : {
177 0 : }
178 0 : void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
179 : {
180 0 : rtl::OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
181 0 : mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( sVal ) ) ) );
182 0 : }
183 : };
184 :
185 : /** Generate parse-dependent-but-then-constant value
186 : */
187 0 : class IntConstantFunctor
188 : {
189 : ParserContextSharedPtr mpContext;
190 :
191 : public:
192 0 : IntConstantFunctor( const ParserContextSharedPtr& rContext ) :
193 0 : mpContext( rContext )
194 : {
195 0 : }
196 0 : void operator()( sal_Int32 n ) const
197 : {
198 0 : mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( n ) ) ) );
199 0 : }
200 : void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
201 : {
202 : rtl::OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
203 : (void)sVal;
204 : }
205 : };
206 :
207 : /** Implements a binary function over two ExpressionNodes
208 :
209 : @tpl Generator
210 : Generator functor, to generate an ExpressionNode of
211 : appropriate type
212 :
213 : */
214 0 : class BinaryFunctionFunctor
215 : {
216 : const ExpressionFunct meFunct;
217 : ParserContextSharedPtr mpContext;
218 :
219 : public:
220 :
221 0 : BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
222 : meFunct( eFunct ),
223 0 : mpContext( rContext )
224 : {
225 0 : }
226 :
227 0 : void operator()( StringIteratorT, StringIteratorT ) const
228 : {
229 0 : ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
230 :
231 0 : if( rNodeStack.size() < 2 )
232 0 : throw ParseError( "Not enough arguments for binary operator" );
233 :
234 : // retrieve arguments
235 0 : ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() );
236 0 : rNodeStack.pop();
237 0 : ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() );
238 0 : rNodeStack.pop();
239 :
240 : // create combined ExpressionNode
241 0 : ExpressionNodeSharedPtr pNode = ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct, pFirstArg, pSecondArg ) );
242 : // check for constness
243 0 : rNodeStack.push( pNode );
244 0 : }
245 : };
246 : /** ExpressionNode implementation for unary
247 : function over one ExpressionNode
248 : */
249 0 : class UnaryFunctionExpression : public ExpressionNode
250 : {
251 : const ExpressionFunct meFunct;
252 : ExpressionNodeSharedPtr mpArg;
253 :
254 : public:
255 0 : UnaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) :
256 : meFunct( eFunct ),
257 0 : mpArg( rArg )
258 : {
259 0 : }
260 0 : virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const
261 : {
262 0 : return _aRow[mpArg->evaluate(_aRow )->getValue().getInt32()];
263 : }
264 0 : virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const
265 : {
266 0 : }
267 0 : virtual ExpressionFunct getType() const
268 : {
269 0 : return meFunct;
270 : }
271 0 : virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ )
272 : {
273 0 : ODatabaseMetaDataResultSet::ORow aRet;
274 0 : return aRet;
275 : }
276 : };
277 :
278 0 : class UnaryFunctionFunctor
279 : {
280 : const ExpressionFunct meFunct;
281 : ParserContextSharedPtr mpContext;
282 :
283 : public :
284 :
285 0 : UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
286 : meFunct( eFunct ),
287 0 : mpContext( rContext )
288 : {
289 0 : }
290 0 : void operator()( StringIteratorT, StringIteratorT ) const
291 : {
292 :
293 0 : ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
294 :
295 0 : if( rNodeStack.size() < 1 )
296 0 : throw ParseError( "Not enough arguments for unary operator" );
297 :
298 : // retrieve arguments
299 0 : ExpressionNodeSharedPtr pArg( rNodeStack.top() );
300 0 : rNodeStack.pop();
301 :
302 0 : rNodeStack.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct, pArg ) ) );
303 0 : }
304 : };
305 :
306 : /* This class implements the following grammar (more or
307 : less literally written down below, only slightly
308 : obfuscated by the parser actions):
309 :
310 : basic_expression =
311 : number |
312 : '(' additive_expression ')'
313 :
314 : unary_expression =
315 : basic_expression
316 :
317 : multiplicative_expression =
318 : unary_expression ( ( '*' unary_expression )* |
319 : ( '/' unary_expression )* )
320 :
321 : additive_expression =
322 : multiplicative_expression ( ( '+' multiplicative_expression )* |
323 : ( '-' multiplicative_expression )* )
324 :
325 : */
326 0 : class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar >
327 : {
328 : public:
329 : /** Create an arithmetic expression grammar
330 :
331 : @param rParserContext
332 : Contains context info for the parser
333 : */
334 0 : ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
335 0 : mpParserContext( rParserContext )
336 : {
337 0 : }
338 :
339 0 : template< typename ScannerT > class definition
340 : {
341 : public:
342 : // grammar definition
343 0 : definition( const ExpressionGrammar& self )
344 0 : {
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;
356 :
357 :
358 : typedef inhibit_case<strlit<> > token_t;
359 0 : token_t COLUMN = as_lower_d[ "column" ];
360 0 : token_t OR_ = as_lower_d[ "or" ];
361 0 : token_t AND_ = as_lower_d[ "and" ];
362 :
363 0 : integer =
364 : int_p
365 : [IntConstantFunctor(self.getContext())];
366 :
367 0 : argument =
368 : integer
369 : | lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
370 : [ ConstantFunctor(self.getContext()) ]
371 : ;
372 :
373 0 : unaryFunction =
374 : (COLUMN >> '(' >> integer >> ')' )
375 : [ UnaryFunctionFunctor( UNARY_FUNC_COLUMN, self.getContext()) ]
376 : ;
377 :
378 0 : assignment =
379 : unaryFunction >> ch_p('=') >> argument
380 : [ BinaryFunctionFunctor( ENUM_FUNC_EQUATION, self.getContext()) ]
381 : ;
382 :
383 0 : andExpression =
384 : assignment
385 : | ( '(' >> orExpression >> ')' )
386 : | ( assignment >> AND_ >> assignment ) [ BinaryFunctionFunctor( ENUM_FUNC_AND, self.getContext()) ]
387 : ;
388 :
389 0 : orExpression =
390 : andExpression
391 : | ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ENUM_FUNC_OR, self.getContext()) ]
392 : ;
393 :
394 0 : basicExpression =
395 : orExpression
396 : ;
397 :
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);
405 0 : }
406 :
407 0 : const ::boost::spirit::rule< ScannerT >& start() const
408 : {
409 0 : return basicExpression;
410 : }
411 :
412 : private:
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;
420 : };
421 :
422 0 : const ParserContextSharedPtr& getContext() const
423 : {
424 0 : return mpParserContext;
425 : }
426 :
427 : private:
428 : ParserContextSharedPtr mpParserContext; // might get modified during parsing
429 : };
430 :
431 : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
432 0 : const ParserContextSharedPtr& getParserContext()
433 : {
434 0 : static ParserContextSharedPtr lcl_parserContext( new ParserContext() );
435 :
436 : // clear node stack (since we reuse the static object, that's
437 : // the whole point here)
438 0 : while( !lcl_parserContext->maOperandStack.empty() )
439 0 : lcl_parserContext->maOperandStack.pop();
440 :
441 0 : return lcl_parserContext;
442 : }
443 : #endif
444 : }
445 :
446 0 : ExpressionNodeSharedPtr FunctionParser::parseFunction( const ::rtl::OUString& _sFunction)
447 : {
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 ::rtl::OString& rAsciiFunction(
452 0 : rtl::OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) );
453 :
454 0 : StringIteratorT aStart( rAsciiFunction.getStr() );
455 0 : StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
456 :
457 0 : ParserContextSharedPtr pContext;
458 :
459 : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
460 : // static parser context, because the actual
461 : // Spirit parser is also a static object
462 0 : pContext = getParserContext();
463 : #else
464 : pContext.reset( new ParserContext() );
465 : #endif
466 :
467 0 : ExpressionGrammar aExpressionGrammer( pContext );
468 :
469 : const ::boost::spirit::parse_info<StringIteratorT> aParseInfo(
470 : ::boost::spirit::parse( aStart,
471 : aEnd,
472 : aExpressionGrammer,
473 0 : ::boost::spirit::space_p ) );
474 :
475 : OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync
476 :
477 : // input fully congested by the parser?
478 0 : if( !aParseInfo.full )
479 0 : throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
480 :
481 : // parser's state stack now must contain exactly _one_ ExpressionNode,
482 : // which represents our formula.
483 0 : if( pContext->maOperandStack.size() != 1 )
484 0 : throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
485 :
486 0 : return pContext->maOperandStack.top();
487 : }
488 18 : }
489 :
490 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|