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 SAL_OVERRIDE
66 : {
67 0 : return maValue;
68 : }
69 0 : virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const SAL_OVERRIDE
70 : {
71 0 : }
72 0 : virtual ExpressionFunct getType() const SAL_OVERRIDE
73 : {
74 0 : return FUNC_CONST;
75 : }
76 0 : virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ ) SAL_OVERRIDE
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 SAL_OVERRIDE
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 SAL_OVERRIDE
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 SAL_OVERRIDE
132 : {
133 0 : return meFunct;
134 : }
135 0 : virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ ) SAL_OVERRIDE
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 : 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 : };
201 :
202 : /** Implements a binary function over two ExpressionNodes
203 :
204 : @tpl Generator
205 : Generator functor, to generate an ExpressionNode of
206 : appropriate type
207 :
208 : */
209 0 : class BinaryFunctionFunctor
210 : {
211 : const ExpressionFunct meFunct;
212 : ParserContextSharedPtr mpContext;
213 :
214 : public:
215 :
216 0 : BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
217 : meFunct( eFunct ),
218 0 : mpContext( rContext )
219 : {
220 0 : }
221 :
222 0 : void operator()( StringIteratorT, StringIteratorT ) const
223 : {
224 0 : ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
225 :
226 0 : if( rNodeStack.size() < 2 )
227 0 : throw ParseError( "Not enough arguments for binary operator" );
228 :
229 : // retrieve arguments
230 0 : ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() );
231 0 : rNodeStack.pop();
232 0 : ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() );
233 0 : rNodeStack.pop();
234 :
235 : // create combined ExpressionNode
236 0 : ExpressionNodeSharedPtr pNode = ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct, pFirstArg, pSecondArg ) );
237 : // check for constness
238 0 : rNodeStack.push( pNode );
239 0 : }
240 : };
241 : /** ExpressionNode implementation for unary
242 : function over one ExpressionNode
243 : */
244 0 : class UnaryFunctionExpression : public ExpressionNode
245 : {
246 : const ExpressionFunct meFunct;
247 : ExpressionNodeSharedPtr mpArg;
248 :
249 : public:
250 0 : UnaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) :
251 : meFunct( eFunct ),
252 0 : mpArg( rArg )
253 : {
254 0 : }
255 0 : virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const SAL_OVERRIDE
256 : {
257 0 : return _aRow[mpArg->evaluate(_aRow )->getValue().getInt32()];
258 : }
259 0 : virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const SAL_OVERRIDE
260 : {
261 0 : }
262 0 : virtual ExpressionFunct getType() const SAL_OVERRIDE
263 : {
264 0 : return meFunct;
265 : }
266 0 : virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ ) SAL_OVERRIDE
267 : {
268 0 : ODatabaseMetaDataResultSet::ORow aRet;
269 0 : return aRet;
270 : }
271 : };
272 :
273 0 : class UnaryFunctionFunctor
274 : {
275 : const ExpressionFunct meFunct;
276 : ParserContextSharedPtr mpContext;
277 :
278 : public :
279 :
280 0 : UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
281 : meFunct( eFunct ),
282 0 : mpContext( rContext )
283 : {
284 0 : }
285 0 : void operator()( StringIteratorT, StringIteratorT ) const
286 : {
287 :
288 0 : ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
289 :
290 0 : if( rNodeStack.size() < 1 )
291 0 : throw ParseError( "Not enough arguments for unary operator" );
292 :
293 : // retrieve arguments
294 0 : ExpressionNodeSharedPtr pArg( rNodeStack.top() );
295 0 : rNodeStack.pop();
296 :
297 0 : rNodeStack.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct, pArg ) ) );
298 0 : }
299 : };
300 :
301 : /* This class implements the following grammar (more or
302 : less literally written down below, only slightly
303 : obfuscated by the parser actions):
304 :
305 : basic_expression =
306 : number |
307 : '(' additive_expression ')'
308 :
309 : unary_expression =
310 : basic_expression
311 :
312 : multiplicative_expression =
313 : unary_expression ( ( '*' unary_expression )* |
314 : ( '/' unary_expression )* )
315 :
316 : additive_expression =
317 : multiplicative_expression ( ( '+' multiplicative_expression )* |
318 : ( '-' multiplicative_expression )* )
319 :
320 : */
321 0 : class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar >
322 : {
323 : public:
324 : /** Create an arithmetic expression grammar
325 :
326 : @param rParserContext
327 : Contains context info for the parser
328 : */
329 0 : ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
330 0 : mpParserContext( rParserContext )
331 : {
332 0 : }
333 :
334 0 : template< typename ScannerT > class definition
335 : {
336 : public:
337 : // grammar definition
338 0 : definition( const ExpressionGrammar& self )
339 0 : {
340 : using ::boost::spirit::str_p;
341 : using ::boost::spirit::space_p;
342 : using ::boost::spirit::range_p;
343 : using ::boost::spirit::lexeme_d;
344 : using ::boost::spirit::real_parser;
345 : using ::boost::spirit::chseq_p;
346 : using ::boost::spirit::ch_p;
347 : using ::boost::spirit::int_p;
348 : using ::boost::spirit::as_lower_d;
349 : using ::boost::spirit::strlit;
350 : using ::boost::spirit::inhibit_case;
351 :
352 :
353 : typedef inhibit_case<strlit<> > token_t;
354 0 : token_t COLUMN = as_lower_d[ "column" ];
355 0 : token_t OR_ = as_lower_d[ "or" ];
356 0 : token_t AND_ = as_lower_d[ "and" ];
357 :
358 0 : integer =
359 : int_p
360 0 : [IntConstantFunctor(self.getContext())];
361 :
362 0 : argument =
363 : integer
364 0 : | lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
365 0 : [ ConstantFunctor(self.getContext()) ]
366 : ;
367 :
368 0 : unaryFunction =
369 0 : (COLUMN >> '(' >> integer >> ')' )
370 0 : [ UnaryFunctionFunctor( UNARY_FUNC_COLUMN, self.getContext()) ]
371 : ;
372 :
373 0 : assignment =
374 0 : unaryFunction >> ch_p('=') >> argument
375 0 : [ BinaryFunctionFunctor( ENUM_FUNC_EQUATION, self.getContext()) ]
376 : ;
377 :
378 0 : andExpression =
379 : assignment
380 0 : | ( '(' >> orExpression >> ')' )
381 0 : | ( assignment >> AND_ >> assignment ) [ BinaryFunctionFunctor( ENUM_FUNC_AND, self.getContext()) ]
382 : ;
383 :
384 0 : orExpression =
385 : andExpression
386 0 : | ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ENUM_FUNC_OR, self.getContext()) ]
387 : ;
388 :
389 0 : basicExpression =
390 : orExpression
391 : ;
392 :
393 : BOOST_SPIRIT_DEBUG_RULE(basicExpression);
394 : BOOST_SPIRIT_DEBUG_RULE(unaryFunction);
395 : BOOST_SPIRIT_DEBUG_RULE(assignment);
396 : BOOST_SPIRIT_DEBUG_RULE(argument);
397 : BOOST_SPIRIT_DEBUG_RULE(integer);
398 : BOOST_SPIRIT_DEBUG_RULE(orExpression);
399 : BOOST_SPIRIT_DEBUG_RULE(andExpression);
400 0 : }
401 :
402 0 : const ::boost::spirit::rule< ScannerT >& start() const
403 : {
404 0 : return basicExpression;
405 : }
406 :
407 : private:
408 : // the constituents of the Spirit arithmetic expression grammar.
409 : // For the sake of readability, without 'ma' prefix.
410 : ::boost::spirit::rule< ScannerT > basicExpression;
411 : ::boost::spirit::rule< ScannerT > unaryFunction;
412 : ::boost::spirit::rule< ScannerT > assignment;
413 : ::boost::spirit::rule< ScannerT > integer,argument;
414 : ::boost::spirit::rule< ScannerT > orExpression,andExpression;
415 : };
416 :
417 0 : const ParserContextSharedPtr& getContext() const
418 : {
419 0 : return mpParserContext;
420 : }
421 :
422 : private:
423 : ParserContextSharedPtr mpParserContext; // might get modified during parsing
424 : };
425 :
426 : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
427 0 : const ParserContextSharedPtr& getParserContext()
428 : {
429 0 : static ParserContextSharedPtr lcl_parserContext( new ParserContext() );
430 :
431 : // clear node stack (since we reuse the static object, that's
432 : // the whole point here)
433 0 : while( !lcl_parserContext->maOperandStack.empty() )
434 0 : lcl_parserContext->maOperandStack.pop();
435 :
436 0 : return lcl_parserContext;
437 : }
438 : #endif
439 : }
440 :
441 0 : ExpressionNodeSharedPtr FunctionParser::parseFunction( const OUString& _sFunction)
442 : {
443 : // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
444 : // gives better conversion robustness here (we might want to map space
445 : // etc. to ASCII space here)
446 : const OString& rAsciiFunction(
447 0 : OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) );
448 :
449 0 : StringIteratorT aStart( rAsciiFunction.getStr() );
450 0 : StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
451 :
452 0 : ParserContextSharedPtr pContext;
453 :
454 : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
455 : // static parser context, because the actual
456 : // Spirit parser is also a static object
457 0 : pContext = getParserContext();
458 : #else
459 : pContext.reset( new ParserContext() );
460 : #endif
461 :
462 0 : ExpressionGrammar aExpressionGrammer( pContext );
463 :
464 : const ::boost::spirit::parse_info<StringIteratorT> aParseInfo(
465 : ::boost::spirit::parse( aStart,
466 : aEnd,
467 : aExpressionGrammer,
468 0 : ::boost::spirit::space_p ) );
469 :
470 : #if (OSL_DEBUG_LEVEL > 0)
471 : ::std::cout.flush(); // needed to keep stdout and cout in sync
472 : #endif
473 :
474 : // input fully congested by the parser?
475 0 : if( !aParseInfo.full )
476 0 : throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
477 :
478 : // parser's state stack now must contain exactly _one_ ExpressionNode,
479 : // which represents our formula.
480 0 : if( pContext->maOperandStack.size() != 1 )
481 0 : throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
482 :
483 0 : return pContext->maOperandStack.top();
484 : }
485 0 : }
486 :
487 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|