office-gobmx/connectivity/source/commontools/RowFunctionParser.cxx
Ivo Hinkelmann 4e5d76b3ce CWS-TOOLING: integrate CWS boost134
2009-09-09 10:30:24 +0200 fs  r275970 : #i100127# provided by rene: check whether system-boost's function.hpp compiles without exception support
2009-09-04 21:58:00 +0200 fs  r275832 : indention
2009-09-04 21:57:10 +0200 fs  r275831 : #i10000# type in boost/spirit check. Thanks to thb
2009-09-04 10:58:54 +0200 fs  r275787 : #i100127# provided by tono@openoffice.org: mingw needs using directives for std::min/max
2009-09-04 10:31:54 +0200 fs  r275782 : #i100127# (approved by hjs) on Solaris, set GNUTAR to /usr/sfw/bin/gtar, this is available on baseline machines (Solaris 10.x), but not necessarily available in LD_LIBRARY_PATH
2009-08-19 21:47:55 +0200 rene  r275161 : #i10000# check for the header actually used now
2009-08-17 21:55:31 +0200 fs  r275073 : CWS-TOOLING: rebase CWS boost134 to trunk@275001 (milestone: DEV300:m55)
2009-07-16 09:39:25 +0200 fs  r274031 : #i100127# extract download/% with GNUTAR instead of TAR
2009-07-14 09:18:15 +0200 fs  r273960 : CWS-TOOLING: rebase CWS boost134 to trunk@273858 (milestone: DEV300:m52)
2009-07-13 09:55:14 +0200 fs  r273919 : #i100127# use boost 1.39, not 1.34
2009-07-13 09:45:57 +0200 fs  r273918 : use GNUTAR when extracting download/%.tar.gz, not TAR (necessary with boost 1.39 tarball)
2009-07-10 21:10:52 +0200 fs  r273905 : #i100127# spirit now part of boost
2009-07-06 12:12:13 +0200 fs  r273732 : #i10000# lngconvex, used in src/wizards, is built in shell => added missing module dependency
2009-07-02 15:34:51 +0200 fs  r273660 : #i100127#
2009-07-02 13:35:24 +0200 fs  r273645 : #i100127# MSVC needs some hinting when using boost::bind on (some) member functions
2009-07-02 10:33:59 +0200 fs  r273625 : removed unused include (lead to an internal compiler error with MSVC and boost 1.34+)
2009-07-02 09:44:35 +0200 fs  r273619 : change some include orders, prevents 'internal compiler errors' with MSVC
2009-07-01 09:19:25 +0200 fs  r273547 : #i100127# who the heck is defining max as something unusable?
2009-07-01 09:17:28 +0200 fs  r273546 : #i100127# defining min/max is causing trouble now
2009-07-01 09:15:40 +0200 fs  r273545 : #i100127# reverted previous patch, and properly fixed the problem by defining BOOST_MEM_FN_ENABLE_CDECL, and disabling warning 4180
2009-07-01 09:14:23 +0200 fs  r273544 : #i100127# re-disable warning 4180, still needed for some files
2009-07-01 09:07:33 +0200 fs  r273543 : #i100127# reverted previous patch, and properly fixed the problem by defining BOOST_MEM_FN_ENABLE_CDECL
2009-06-24 11:00:32 +0200 fs  r273319 : oops, re-introduced some inc locations
2009-06-23 22:10:02 +0200 fs  r273304 : #i100127# disable warning C4180
2009-06-23 22:08:36 +0200 fs  r273303 : #i100127# disable warning C4180
2009-06-16 12:26:49 +0200 fs  r273015 : #i10000# (provided by mst@openoffice.org)
2009-06-15 09:10:27 +0200 fs  r272962 : #i10000# use -r instead of -a when copying the include files, this prevents the spurious 'failed to preserve ownership' errors
2009-06-11 23:55:06 +0200 fs  r272902 : #i100127#
2009-06-11 23:54:47 +0200 fs  r272901 : #i100127#
2009-06-11 23:54:05 +0200 fs  r272900 : make compile on unxsol[i|s]4
2009-06-10 10:12:22 +0200 fs  r272798 : #i100127# don't deliver from within unxlngi6/misc/build/boost, but from a 'normalized' location unxlngi6/inc
2009-06-10 09:48:00 +0200 fs  r272795 : #i100127# use 1.34.1 unconditionally on all platforms
2009-09-17 10:11:42 +00:00

502 lines
16 KiB
C++

/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: RowFunctionParser.cxx,v $
* $Revision: 1.3 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 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();
}
}