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