| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_connectivity.hxx" |
| |
| // Makes parser a static resource, |
| // we're synchronized externally. |
| // But watch out, the parser might have |
| // state not visible to this code! |
| #define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE |
| #if defined(VERBOSE) && defined(DBG_UTIL) |
| #include <typeinfo> |
| #define BOOST_SPIRIT_DEBUG |
| #endif |
| #include <boost/spirit/include/classic_core.hpp> |
| #include "RowFunctionParser.hxx" |
| #include <rtl/ustring.hxx> |
| #include <tools/fract.hxx> |
| |
| |
| |
| #if (OSL_DEBUG_LEVEL > 0) |
| #include <iostream> |
| #endif |
| #include <functional> |
| #include <algorithm> |
| #include <stack> |
| |
| namespace connectivity |
| { |
| using namespace com::sun::star; |
| |
| namespace |
| { |
| ////////////////////// |
| ////////////////////// |
| // EXPRESSION NODES |
| ////////////////////// |
| ////////////////////// |
| class ConstantValueExpression : public ExpressionNode |
| { |
| ORowSetValueDecoratorRef maValue; |
| |
| public: |
| |
| ConstantValueExpression( ORowSetValueDecoratorRef rValue ) : |
| maValue( rValue ) |
| { |
| } |
| virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const |
| { |
| return maValue; |
| } |
| virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const |
| { |
| } |
| virtual ExpressionFunct getType() const |
| { |
| return FUNC_CONST; |
| } |
| virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ ) |
| { |
| ODatabaseMetaDataResultSet::ORow aRet; |
| return aRet; |
| } |
| }; |
| |
| |
| /** ExpressionNode implementation for unary |
| function over two ExpressionNodes |
| */ |
| class BinaryFunctionExpression : public ExpressionNode |
| { |
| const ExpressionFunct meFunct; |
| ExpressionNodeSharedPtr mpFirstArg; |
| ExpressionNodeSharedPtr mpSecondArg; |
| |
| public: |
| |
| BinaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rFirstArg, const ExpressionNodeSharedPtr& rSecondArg ) : |
| meFunct( eFunct ), |
| mpFirstArg( rFirstArg ), |
| mpSecondArg( rSecondArg ) |
| { |
| } |
| virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const |
| { |
| ORowSetValueDecoratorRef aRet; |
| switch(meFunct) |
| { |
| case ENUM_FUNC_EQUATION: |
| aRet = new ORowSetValueDecorator(sal_Bool(mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue()) ); |
| break; |
| case ENUM_FUNC_AND: |
| aRet = new ORowSetValueDecorator( sal_Bool(mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool()) ); |
| break; |
| case ENUM_FUNC_OR: |
| aRet = new ORowSetValueDecorator( sal_Bool(mpFirstArg->evaluate(_aRow )->getValue().getBool() || mpSecondArg->evaluate(_aRow )->getValue().getBool()) ); |
| break; |
| default: |
| break; |
| } |
| return aRet; |
| } |
| virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const |
| { |
| switch(meFunct) |
| { |
| case ENUM_FUNC_EQUATION: |
| (*mpFirstArg->evaluate(_aRow )) = mpSecondArg->evaluate(_aRow )->getValue(); |
| break; |
| default: |
| break; |
| } |
| } |
| virtual ExpressionFunct getType() const |
| { |
| return meFunct; |
| } |
| virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ ) |
| { |
| ODatabaseMetaDataResultSet::ORow aRet; |
| return aRet; |
| } |
| }; |
| |
| |
| //////////////////////// |
| //////////////////////// |
| // FUNCTION PARSER |
| //////////////////////// |
| //////////////////////// |
| |
| typedef const sal_Char* StringIteratorT; |
| |
| struct ParserContext |
| { |
| typedef ::std::stack< ExpressionNodeSharedPtr > OperandStack; |
| |
| // stores a stack of not-yet-evaluated operands. This is used |
| // by the operators (i.e. '+', '*', 'sin' etc.) to pop their |
| // arguments from. If all arguments to an operator are constant, |
| // the operator pushes a precalculated result on the stack, and |
| // a composite ExpressionNode otherwise. |
| OperandStack maOperandStack; |
| }; |
| |
| typedef ::boost::shared_ptr< ParserContext > ParserContextSharedPtr; |
| |
| /** Generate apriori constant value |
| */ |
| |
| class ConstantFunctor |
| { |
| ParserContextSharedPtr mpContext; |
| |
| public: |
| |
| ConstantFunctor( const ParserContextSharedPtr& rContext ) : |
| mpContext( rContext ) |
| { |
| } |
| void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const |
| { |
| rtl::OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 ); |
| mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( sVal ) ) ) ); |
| } |
| }; |
| |
| /** Generate parse-dependent-but-then-constant value |
| */ |
| class IntConstantFunctor |
| { |
| ParserContextSharedPtr mpContext; |
| |
| public: |
| IntConstantFunctor( const ParserContextSharedPtr& rContext ) : |
| mpContext( rContext ) |
| { |
| } |
| void operator()( sal_Int32 n ) const |
| { |
| mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( n ) ) ) ); |
| } |
| void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const |
| { |
| rtl::OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 ); |
| (void)sVal; |
| } |
| }; |
| |
| /** Implements a binary function over two ExpressionNodes |
| |
| @tpl Generator |
| Generator functor, to generate an ExpressionNode of |
| appropriate type |
| |
| */ |
| class BinaryFunctionFunctor |
| { |
| const ExpressionFunct meFunct; |
| ParserContextSharedPtr mpContext; |
| |
| public: |
| |
| BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) : |
| meFunct( eFunct ), |
| mpContext( rContext ) |
| { |
| } |
| |
| void operator()( StringIteratorT, StringIteratorT ) const |
| { |
| ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); |
| |
| if( rNodeStack.size() < 2 ) |
| throw ParseError( "Not enough arguments for binary operator" ); |
| |
| // retrieve arguments |
| ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() ); |
| rNodeStack.pop(); |
| ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() ); |
| rNodeStack.pop(); |
| |
| // create combined ExpressionNode |
| ExpressionNodeSharedPtr pNode = ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct, pFirstArg, pSecondArg ) ); |
| // check for constness |
| rNodeStack.push( pNode ); |
| } |
| }; |
| /** ExpressionNode implementation for unary |
| function over one ExpressionNode |
| */ |
| class UnaryFunctionExpression : public ExpressionNode |
| { |
| const ExpressionFunct meFunct; |
| ExpressionNodeSharedPtr mpArg; |
| |
| public: |
| UnaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) : |
| meFunct( eFunct ), |
| mpArg( rArg ) |
| { |
| } |
| virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const |
| { |
| return _aRow[mpArg->evaluate(_aRow )->getValue().getInt32()]; |
| } |
| virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const |
| { |
| } |
| virtual ExpressionFunct getType() const |
| { |
| return meFunct; |
| } |
| virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ ) |
| { |
| ODatabaseMetaDataResultSet::ORow aRet; |
| return aRet; |
| } |
| }; |
| |
| class UnaryFunctionFunctor |
| { |
| const ExpressionFunct meFunct; |
| ParserContextSharedPtr mpContext; |
| |
| public : |
| |
| UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) : |
| meFunct( eFunct ), |
| mpContext( rContext ) |
| { |
| } |
| void operator()( StringIteratorT, StringIteratorT ) const |
| { |
| |
| ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); |
| |
| if( rNodeStack.size() < 1 ) |
| throw ParseError( "Not enough arguments for unary operator" ); |
| |
| // retrieve arguments |
| ExpressionNodeSharedPtr pArg( rNodeStack.top() ); |
| rNodeStack.pop(); |
| |
| rNodeStack.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct, pArg ) ) ); |
| } |
| }; |
| |
| /* This class implements the following grammar (more or |
| less literally written down below, only slightly |
| obfuscated by the parser actions): |
| |
| basic_expression = |
| number | |
| '(' additive_expression ')' |
| |
| unary_expression = |
| basic_expression |
| |
| multiplicative_expression = |
| unary_expression ( ( '*' unary_expression )* | |
| ( '/' unary_expression )* ) |
| |
| additive_expression = |
| multiplicative_expression ( ( '+' multiplicative_expression )* | |
| ( '-' multiplicative_expression )* ) |
| |
| */ |
| class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar > |
| { |
| public: |
| /** Create an arithmetic expression grammar |
| |
| @param rParserContext |
| Contains context info for the parser |
| */ |
| ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) : |
| mpParserContext( rParserContext ) |
| { |
| } |
| |
| template< typename ScannerT > class definition |
| { |
| public: |
| // grammar definition |
| definition( const ExpressionGrammar& self ) |
| { |
| using ::boost::spirit::str_p; |
| using ::boost::spirit::space_p; |
| using ::boost::spirit::range_p; |
| using ::boost::spirit::lexeme_d; |
| using ::boost::spirit::real_parser; |
| using ::boost::spirit::chseq_p; |
| using ::boost::spirit::ch_p; |
| using ::boost::spirit::int_p; |
| using ::boost::spirit::as_lower_d; |
| using ::boost::spirit::strlit; |
| using ::boost::spirit::inhibit_case; |
| |
| |
| typedef inhibit_case<strlit<> > token_t; |
| token_t COLUMN = as_lower_d[ "column" ]; |
| token_t OR_ = as_lower_d[ "or" ]; |
| token_t AND_ = as_lower_d[ "and" ]; |
| |
| integer = |
| int_p |
| [IntConstantFunctor(self.getContext())]; |
| |
| argument = |
| integer |
| | lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ] |
| [ ConstantFunctor(self.getContext()) ] |
| ; |
| |
| unaryFunction = |
| (COLUMN >> '(' >> integer >> ')' ) |
| [ UnaryFunctionFunctor( UNARY_FUNC_COLUMN, self.getContext()) ] |
| ; |
| |
| assignment = |
| unaryFunction >> ch_p('=') >> argument |
| [ BinaryFunctionFunctor( ENUM_FUNC_EQUATION, self.getContext()) ] |
| ; |
| |
| andExpression = |
| assignment |
| | ( '(' >> orExpression >> ')' ) |
| | ( assignment >> AND_ >> assignment ) [ BinaryFunctionFunctor( ENUM_FUNC_AND, self.getContext()) ] |
| ; |
| |
| orExpression = |
| andExpression |
| | ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ENUM_FUNC_OR, self.getContext()) ] |
| ; |
| |
| basicExpression = |
| orExpression |
| ; |
| |
| BOOST_SPIRIT_DEBUG_RULE(basicExpression); |
| BOOST_SPIRIT_DEBUG_RULE(unaryFunction); |
| BOOST_SPIRIT_DEBUG_RULE(assignment); |
| BOOST_SPIRIT_DEBUG_RULE(argument); |
| BOOST_SPIRIT_DEBUG_RULE(integer); |
| BOOST_SPIRIT_DEBUG_RULE(orExpression); |
| BOOST_SPIRIT_DEBUG_RULE(andExpression); |
| } |
| |
| const ::boost::spirit::rule< ScannerT >& start() const |
| { |
| return basicExpression; |
| } |
| |
| private: |
| // the constituents of the Spirit arithmetic expression grammar. |
| // For the sake of readability, without 'ma' prefix. |
| ::boost::spirit::rule< ScannerT > basicExpression; |
| ::boost::spirit::rule< ScannerT > unaryFunction; |
| ::boost::spirit::rule< ScannerT > assignment; |
| ::boost::spirit::rule< ScannerT > integer,argument; |
| ::boost::spirit::rule< ScannerT > orExpression,andExpression; |
| }; |
| |
| const ParserContextSharedPtr& getContext() const |
| { |
| return mpParserContext; |
| } |
| |
| private: |
| ParserContextSharedPtr mpParserContext; // might get modified during parsing |
| }; |
| |
| #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE |
| const ParserContextSharedPtr& getParserContext() |
| { |
| static ParserContextSharedPtr lcl_parserContext( new ParserContext() ); |
| |
| // clear node stack (since we reuse the static object, that's |
| // the whole point here) |
| while( !lcl_parserContext->maOperandStack.empty() ) |
| lcl_parserContext->maOperandStack.pop(); |
| |
| return lcl_parserContext; |
| } |
| #endif |
| } |
| |
| ExpressionNodeSharedPtr FunctionParser::parseFunction( const ::rtl::OUString& _sFunction) |
| { |
| // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_* |
| // gives better conversion robustness here (we might want to map space |
| // etc. to ASCII space here) |
| const ::rtl::OString& rAsciiFunction( |
| rtl::OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) ); |
| |
| StringIteratorT aStart( rAsciiFunction.getStr() ); |
| StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() ); |
| |
| ParserContextSharedPtr pContext; |
| |
| #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE |
| // static parser context, because the actual |
| // Spirit parser is also a static object |
| pContext = getParserContext(); |
| #else |
| pContext.reset( new ParserContext() ); |
| #endif |
| |
| ExpressionGrammar aExpressionGrammer( pContext ); |
| |
| const ::boost::spirit::parse_info<StringIteratorT> aParseInfo( |
| ::boost::spirit::parse( aStart, |
| aEnd, |
| aExpressionGrammer, |
| ::boost::spirit::space_p ) ); |
| |
| OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync |
| |
| // input fully congested by the parser? |
| if( !aParseInfo.full ) |
| throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" ); |
| |
| // parser's state stack now must contain exactly _one_ ExpressionNode, |
| // which represents our formula. |
| if( pContext->maOperandStack.size() != 1 ) |
| throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" ); |
| |
| return pContext->maOperandStack.top(); |
| } |
| } |
| |