1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_connectivity.hxx" 30 31 // Makes parser a static resource, 32 // we're synchronized externally. 33 // But watch out, the parser might have 34 // state not visible to this code! 35 #define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE 36 #if defined(VERBOSE) && defined(DBG_UTIL) 37 #include <typeinfo> 38 #define BOOST_SPIRIT_DEBUG 39 #endif 40 #include <boost/spirit/include/classic_core.hpp> 41 #include "RowFunctionParser.hxx" 42 #include <rtl/ustring.hxx> 43 #include <tools/fract.hxx> 44 45 46 47 #if (OSL_DEBUG_LEVEL > 0) 48 #include <iostream> 49 #endif 50 #include <functional> 51 #include <algorithm> 52 #include <stack> 53 54 namespace connectivity 55 { 56 using namespace com::sun::star; 57 58 namespace 59 { 60 ////////////////////// 61 ////////////////////// 62 // EXPRESSION NODES 63 ////////////////////// 64 ////////////////////// 65 class ConstantValueExpression : public ExpressionNode 66 { 67 ORowSetValueDecoratorRef maValue; 68 69 public: 70 71 ConstantValueExpression( ORowSetValueDecoratorRef rValue ) : 72 maValue( rValue ) 73 { 74 } 75 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const 76 { 77 return maValue; 78 } 79 virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const 80 { 81 } 82 virtual ExpressionFunct getType() const 83 { 84 return FUNC_CONST; 85 } 86 virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ ) 87 { 88 ODatabaseMetaDataResultSet::ORow aRet; 89 return aRet; 90 } 91 }; 92 93 94 /** ExpressionNode implementation for unary 95 function over two ExpressionNodes 96 */ 97 class BinaryFunctionExpression : public ExpressionNode 98 { 99 const ExpressionFunct meFunct; 100 ExpressionNodeSharedPtr mpFirstArg; 101 ExpressionNodeSharedPtr mpSecondArg; 102 103 public: 104 105 BinaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rFirstArg, const ExpressionNodeSharedPtr& rSecondArg ) : 106 meFunct( eFunct ), 107 mpFirstArg( rFirstArg ), 108 mpSecondArg( rSecondArg ) 109 { 110 } 111 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const 112 { 113 ORowSetValueDecoratorRef aRet; 114 switch(meFunct) 115 { 116 case ENUM_FUNC_EQUATION: 117 aRet = new ORowSetValueDecorator(sal_Bool(mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue()) ); 118 break; 119 case ENUM_FUNC_AND: 120 aRet = new ORowSetValueDecorator( sal_Bool(mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool()) ); 121 break; 122 case ENUM_FUNC_OR: 123 aRet = new ORowSetValueDecorator( sal_Bool(mpFirstArg->evaluate(_aRow )->getValue().getBool() || mpSecondArg->evaluate(_aRow )->getValue().getBool()) ); 124 break; 125 default: 126 break; 127 } 128 return aRet; 129 } 130 virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const 131 { 132 switch(meFunct) 133 { 134 case ENUM_FUNC_EQUATION: 135 (*mpFirstArg->evaluate(_aRow )) = mpSecondArg->evaluate(_aRow )->getValue(); 136 break; 137 default: 138 break; 139 } 140 } 141 virtual ExpressionFunct getType() const 142 { 143 return meFunct; 144 } 145 virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ ) 146 { 147 ODatabaseMetaDataResultSet::ORow aRet; 148 return aRet; 149 } 150 }; 151 152 153 //////////////////////// 154 //////////////////////// 155 // FUNCTION PARSER 156 //////////////////////// 157 //////////////////////// 158 159 typedef const sal_Char* StringIteratorT; 160 161 struct ParserContext 162 { 163 typedef ::std::stack< ExpressionNodeSharedPtr > OperandStack; 164 165 // stores a stack of not-yet-evaluated operands. This is used 166 // by the operators (i.e. '+', '*', 'sin' etc.) to pop their 167 // arguments from. If all arguments to an operator are constant, 168 // the operator pushes a precalculated result on the stack, and 169 // a composite ExpressionNode otherwise. 170 OperandStack maOperandStack; 171 }; 172 173 typedef ::boost::shared_ptr< ParserContext > ParserContextSharedPtr; 174 175 /** Generate apriori constant value 176 */ 177 178 class ConstantFunctor 179 { 180 ParserContextSharedPtr mpContext; 181 182 public: 183 184 ConstantFunctor( const ParserContextSharedPtr& rContext ) : 185 mpContext( rContext ) 186 { 187 } 188 void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const 189 { 190 rtl::OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 ); 191 mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( sVal ) ) ) ); 192 } 193 }; 194 195 /** Generate parse-dependent-but-then-constant value 196 */ 197 class IntConstantFunctor 198 { 199 ParserContextSharedPtr mpContext; 200 201 public: 202 IntConstantFunctor( const ParserContextSharedPtr& rContext ) : 203 mpContext( rContext ) 204 { 205 } 206 void operator()( sal_Int32 n ) const 207 { 208 mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( n ) ) ) ); 209 } 210 void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const 211 { 212 rtl::OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 ); 213 (void)sVal; 214 } 215 }; 216 217 /** Implements a binary function over two ExpressionNodes 218 219 @tpl Generator 220 Generator functor, to generate an ExpressionNode of 221 appropriate type 222 223 */ 224 class BinaryFunctionFunctor 225 { 226 const ExpressionFunct meFunct; 227 ParserContextSharedPtr mpContext; 228 229 public: 230 231 BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) : 232 meFunct( eFunct ), 233 mpContext( rContext ) 234 { 235 } 236 237 void operator()( StringIteratorT, StringIteratorT ) const 238 { 239 ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); 240 241 if( rNodeStack.size() < 2 ) 242 throw ParseError( "Not enough arguments for binary operator" ); 243 244 // retrieve arguments 245 ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() ); 246 rNodeStack.pop(); 247 ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() ); 248 rNodeStack.pop(); 249 250 // create combined ExpressionNode 251 ExpressionNodeSharedPtr pNode = ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct, pFirstArg, pSecondArg ) ); 252 // check for constness 253 rNodeStack.push( pNode ); 254 } 255 }; 256 /** ExpressionNode implementation for unary 257 function over one ExpressionNode 258 */ 259 class UnaryFunctionExpression : public ExpressionNode 260 { 261 const ExpressionFunct meFunct; 262 ExpressionNodeSharedPtr mpArg; 263 264 public: 265 UnaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) : 266 meFunct( eFunct ), 267 mpArg( rArg ) 268 { 269 } 270 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const 271 { 272 return _aRow[mpArg->evaluate(_aRow )->getValue().getInt32()]; 273 } 274 virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const 275 { 276 } 277 virtual ExpressionFunct getType() const 278 { 279 return meFunct; 280 } 281 virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ ) 282 { 283 ODatabaseMetaDataResultSet::ORow aRet; 284 return aRet; 285 } 286 }; 287 288 class UnaryFunctionFunctor 289 { 290 const ExpressionFunct meFunct; 291 ParserContextSharedPtr mpContext; 292 293 public : 294 295 UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) : 296 meFunct( eFunct ), 297 mpContext( rContext ) 298 { 299 } 300 void operator()( StringIteratorT, StringIteratorT ) const 301 { 302 303 ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); 304 305 if( rNodeStack.size() < 1 ) 306 throw ParseError( "Not enough arguments for unary operator" ); 307 308 // retrieve arguments 309 ExpressionNodeSharedPtr pArg( rNodeStack.top() ); 310 rNodeStack.pop(); 311 312 rNodeStack.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct, pArg ) ) ); 313 } 314 }; 315 316 /* This class implements the following grammar (more or 317 less literally written down below, only slightly 318 obfuscated by the parser actions): 319 320 basic_expression = 321 number | 322 '(' additive_expression ')' 323 324 unary_expression = 325 basic_expression 326 327 multiplicative_expression = 328 unary_expression ( ( '*' unary_expression )* | 329 ( '/' unary_expression )* ) 330 331 additive_expression = 332 multiplicative_expression ( ( '+' multiplicative_expression )* | 333 ( '-' multiplicative_expression )* ) 334 335 */ 336 class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar > 337 { 338 public: 339 /** Create an arithmetic expression grammar 340 341 @param rParserContext 342 Contains context info for the parser 343 */ 344 ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) : 345 mpParserContext( rParserContext ) 346 { 347 } 348 349 template< typename ScannerT > class definition 350 { 351 public: 352 // grammar definition 353 definition( const ExpressionGrammar& self ) 354 { 355 using ::boost::spirit::str_p; 356 using ::boost::spirit::space_p; 357 using ::boost::spirit::range_p; 358 using ::boost::spirit::lexeme_d; 359 using ::boost::spirit::real_parser; 360 using ::boost::spirit::chseq_p; 361 using ::boost::spirit::ch_p; 362 using ::boost::spirit::int_p; 363 using ::boost::spirit::as_lower_d; 364 using ::boost::spirit::strlit; 365 using ::boost::spirit::inhibit_case; 366 367 368 typedef inhibit_case<strlit<> > token_t; 369 token_t COLUMN = as_lower_d[ "column" ]; 370 token_t OR_ = as_lower_d[ "or" ]; 371 token_t AND_ = as_lower_d[ "and" ]; 372 373 integer = 374 int_p 375 [IntConstantFunctor(self.getContext())]; 376 377 argument = 378 integer 379 | lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ] 380 [ ConstantFunctor(self.getContext()) ] 381 ; 382 383 unaryFunction = 384 (COLUMN >> '(' >> integer >> ')' ) 385 [ UnaryFunctionFunctor( UNARY_FUNC_COLUMN, self.getContext()) ] 386 ; 387 388 assignment = 389 unaryFunction >> ch_p('=') >> argument 390 [ BinaryFunctionFunctor( ENUM_FUNC_EQUATION, self.getContext()) ] 391 ; 392 393 andExpression = 394 assignment 395 | ( '(' >> orExpression >> ')' ) 396 | ( assignment >> AND_ >> assignment ) [ BinaryFunctionFunctor( ENUM_FUNC_AND, self.getContext()) ] 397 ; 398 399 orExpression = 400 andExpression 401 | ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ENUM_FUNC_OR, self.getContext()) ] 402 ; 403 404 basicExpression = 405 orExpression 406 ; 407 408 BOOST_SPIRIT_DEBUG_RULE(basicExpression); 409 BOOST_SPIRIT_DEBUG_RULE(unaryFunction); 410 BOOST_SPIRIT_DEBUG_RULE(assignment); 411 BOOST_SPIRIT_DEBUG_RULE(argument); 412 BOOST_SPIRIT_DEBUG_RULE(integer); 413 BOOST_SPIRIT_DEBUG_RULE(orExpression); 414 BOOST_SPIRIT_DEBUG_RULE(andExpression); 415 } 416 417 const ::boost::spirit::rule< ScannerT >& start() const 418 { 419 return basicExpression; 420 } 421 422 private: 423 // the constituents of the Spirit arithmetic expression grammar. 424 // For the sake of readability, without 'ma' prefix. 425 ::boost::spirit::rule< ScannerT > basicExpression; 426 ::boost::spirit::rule< ScannerT > unaryFunction; 427 ::boost::spirit::rule< ScannerT > assignment; 428 ::boost::spirit::rule< ScannerT > integer,argument; 429 ::boost::spirit::rule< ScannerT > orExpression,andExpression; 430 }; 431 432 const ParserContextSharedPtr& getContext() const 433 { 434 return mpParserContext; 435 } 436 437 private: 438 ParserContextSharedPtr mpParserContext; // might get modified during parsing 439 }; 440 441 #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE 442 const ParserContextSharedPtr& getParserContext() 443 { 444 static ParserContextSharedPtr lcl_parserContext( new ParserContext() ); 445 446 // clear node stack (since we reuse the static object, that's 447 // the whole point here) 448 while( !lcl_parserContext->maOperandStack.empty() ) 449 lcl_parserContext->maOperandStack.pop(); 450 451 return lcl_parserContext; 452 } 453 #endif 454 } 455 456 ExpressionNodeSharedPtr FunctionParser::parseFunction( const ::rtl::OUString& _sFunction) 457 { 458 // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_* 459 // gives better conversion robustness here (we might want to map space 460 // etc. to ASCII space here) 461 const ::rtl::OString& rAsciiFunction( 462 rtl::OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) ); 463 464 StringIteratorT aStart( rAsciiFunction.getStr() ); 465 StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() ); 466 467 ParserContextSharedPtr pContext; 468 469 #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE 470 // static parser context, because the actual 471 // Spirit parser is also a static object 472 pContext = getParserContext(); 473 #else 474 pContext.reset( new ParserContext() ); 475 #endif 476 477 ExpressionGrammar aExpressionGrammer( pContext ); 478 479 const ::boost::spirit::parse_info<StringIteratorT> aParseInfo( 480 ::boost::spirit::parse( aStart, 481 aEnd, 482 aExpressionGrammer, 483 ::boost::spirit::space_p ) ); 484 485 OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync 486 487 // input fully congested by the parser? 488 if( !aParseInfo.full ) 489 throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" ); 490 491 // parser's state stack now must contain exactly _one_ ExpressionNode, 492 // which represents our formula. 493 if( pContext->maOperandStack.size() != 1 ) 494 throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" ); 495 496 return pContext->maOperandStack.top(); 497 } 498 } 499 500