CppEval - 一个 C++ 的表达式分析库

平时编写程序的时候,会在不少地方用到表达式分析,譬如说:用户界面,系统配置之类的。虽然对大多数程序员来说,这都不是一件难事,但是,要保证每次写出的表达式分析完整无错并且功能强大,不是一件易事。
你想在你的程序中可以处理类似于“+ aa * aa / b - b / -2 /2/2 -- 5 ** 2 + -100 + ( aa * aa / b - b / -2 /2/2 -- 5 ** 2 + -100 ) + return1() + negative( 1 ) + sum( 1, 2, 3, sum( 1 + 2 *5-7, 555, 111 ) )这样的变态的表达式吗?(上面这个表达式中,不仅有常数,变量,函数,而且某些函数的参数数目还是可变的)
使用 CppEval,你只需要 include 一个头文件就可以做到这点!

接口

template< typename number >
number eval( const char* expression );
这个直接计算一个表达式,支持+-*/()以及一元+-,并且支持**作为乘方

template< typename number >
number eval( const char* expression, const ::std::map< ::std::string, number >& variables );
这个除了支持上面的功能以外,还支持变量。你提供的 variables 里面就是变量到数的映射。

template< typename number, typename functions >
number eval( const char* expression, const ::std::map< ::std::string, number >& variables, functions& funcs );
这个除了支持上面的功能以外,还支持函数。函数具体的定义方法请参见示例

CppEval.h

#ifndef CPP_EVAL_H_DFF520DB406EDCF31AB9A538F7E1C3BD_20040721__
#define CPP_EVAL_H_DFF520DB406EDCF31AB9A538F7E1C3BD_20040721__

#include <cmath>
#include <map>
#include <vector>
#include <sstream>
#include <stdexcept>
#include <cstdlib>


namespace cpp_eval
{

template< typename number >
number eval( const char* expression );

template< typename number >
number eval( const char* expression, const ::std::map< ::std::string, number >& variables );

template< typename number, typename functions >
number eval( const char* expression, const ::std::map< ::std::string, number >& variables, functions& funcs );

class eval_exception: public ::std::logic_error
{
public:
    eval_exception( const char* desc ): logic_error(desc)
    {}
};

template< typename number >
class dummy_functions
{
public:
    number operator()( const char*, const ::std::vector< number >& params )
    {
        throw eval_exception( "unexisting function called" );
//        return number();
    }
};

template< typename number >
number eval( const char* expression )
{
    ::std::map< ::std::string, number > variables;
    dummy_functions<number> funcs;
    return eval( expression, variables, funcs );
}

template< typename number >
number eval( const char* expression, const ::std::map< ::std::string, number >& variables )
{
    dummy_functions<number> funcs;
    return eval( expression, variables, funcs );
}

template< typename number, typename functions >
class evaler
{
    const ::std::map< ::std::string, number >& mVariables;
    functions& mFuncs;
    const char* mCurrent;
    enum Type
    {
        ADD_OR_POSITIVE = '+',
        SUBTRACT_OR_NEGATIVE = '-',
        MULTIPLY = '*',
        DIVIDE = '/',
        POWER = '~',
        LEFT_BRACKET = '(',
        RIGHT_BRACKET = ')',
        PARAMETER_SEPERATOR = ',',
        IDENTIFIER = 257,
        NUMBER = 258,
        FINISHED = 259
    };
    Type mType;
    std::string mIdentifier;
    number mValue;
    void look_ahead()
    {
        for(;;)
        {
            if( isspace( *mCurrent ) )
            {
                ++mCurrent;
                continue;
            }
            else if( *mCurrent == '*' && *( mCurrent + 1 ) == '*' )
                mType = POWER, mCurrent += 2;
            else if( *mCurrent == ADD_OR_POSITIVE || *mCurrent == SUBTRACT_OR_NEGATIVE ||
                *mCurrent == MULTIPLY || *mCurrent == DIVIDE ||
                *mCurrent == LEFT_BRACKET || *mCurrent == RIGHT_BRACKET ||
                *mCurrent == PARAMETER_SEPERATOR )
                mType = ( Type )*mCurrent, ++mCurrent;
            else if( isalpha( *mCurrent ) )
            {
                mType = IDENTIFIER;
                mIdentifier.clear();
                mIdentifier += *mCurrent;
                ++mCurrent;
                while( isalpha( *mCurrent ) || isdigit( *mCurrent ) )
                    mIdentifier += *mCurrent, ++mCurrent;
            }
            else if( *mCurrent == 0)
                mType = FINISHED;
            else
            {
                mType = NUMBER;
                istringstream iss( mCurrent );
                iss >> mValue;
                if( ! iss )
                    throw eval_exception( "error in number format" );
                mCurrent += iss.rdbuf()->pubseekoff( 0, ios::cur, ios::in );
            }
            break;
        }
    }
    void match( Type type )
    {
        if( mType == type )
            look_ahead();
        else
            throw eval_exception( "unmatched token" );
    }
    number expression()
    {//expression        ->    higher_expression expression_R
        number result = expression_R( higher_expression() );
        return result;
    }
    number expression_R( const number& left )
    {//expression_R        ->    + higher_expression expression_R | - higher_expression expression_R | /e/
        number result = left;
        if( mType == ADD_OR_POSITIVE )
            match( ADD_OR_POSITIVE ), result = expression_R( left + higher_expression() );
        else if( mType == SUBTRACT_OR_NEGATIVE )
            match( SUBTRACT_OR_NEGATIVE ), result = expression_R( left - higher_expression() );
        return result;
    }
    number higher_expression()
    {//higher_expression    ->    sign_expression higher_expression_R
        return higher_expression_R( sign_expression() );
    }
    number higher_expression_R( const number& left )
    {//higher_expression_R    ->    * sign_expression higher_expression_R | / sign_expression higher_expression_R | /e/
        number result = left;
        if( mType == MULTIPLY )
            match( MULTIPLY ), result = higher_expression_R( left * sign_expression() );
        else if( mType == DIVIDE )
            match( DIVIDE ), result = higher_expression_R( left / sign_expression() );
        return result;
    }
    number sign_expression()
    {//sign_expression        ->    + sign_expression | - sign_expression | power_expression
        number result;
        if( mType == ADD_OR_POSITIVE )
            match( ADD_OR_POSITIVE ), result = sign_expression();
        else if( mType == SUBTRACT_OR_NEGATIVE )
            match( SUBTRACT_OR_NEGATIVE ), result = - sign_expression();
        else
            result = power_expression();
        return result;
    }
    number power_expression()
    {//power_expression    ->    factor ** power_expression | factor
        number result = factor();
        if( mType == POWER )
            match( POWER ), result = std::pow( result, static_cast<int>( power_expression() ) );
        return result;
    }
    number factor()
    {//factor            ->    number | ( expression ) | lang_structure
        number result;
        if( mType == NUMBER )
            result = mValue, match( NUMBER );
        else if( mType == LEFT_BRACKET )
            match( LEFT_BRACKET ), result = expression(), match( RIGHT_BRACKET );
        else
            result = lang_structure();
        return result;
    }
    number lang_structure()
    {//lang_structure        ->    identifier lang_tail
        std::string id = mIdentifier;
        match( IDENTIFIER );
        return lang_tail( id );
    }
    number lang_tail( const std::string& id )
    {//lang_tail        ->    ( parameter_list | /e/
        number result;
        if( mType == LEFT_BRACKET )
        {
            match( LEFT_BRACKET );
            std::vector<number> param = parameter_list();
            result = mFuncs( id.c_str(), param );
        }
        else
        {
            if( mVariables.find( id ) == mVariables.end() )
                throw eval_exception( "cannot find variable" );
            result = mVariables.find( id )->second;
        }
        return result;
    }
    std::vector<number> parameter_list()
    {//parameter_list        ->    ) | expression parameter_tail
        std::vector<number> result;
        for(;;)
        {
            if( mType == RIGHT_BRACKET )
            {
                match( RIGHT_BRACKET );
                break;
            }
            result.push_back( expression() );
            parameter_tail( result );
        }
        return result;
    }
    void parameter_tail( std::vector<number>& param )
    {//parameter_tail        ->    , expression parameter_tail | /e/
        if( mType == PARAMETER_SEPERATOR )
            match( PARAMETER_SEPERATOR ), param.push_back( expression() ), parameter_tail( param );
    }
public:
    evaler( const ::std::map< ::std::string, number >& variables, functions& funcs )
        : mVariables( variables ), mFuncs( funcs )
    {}
    number operator()( const char* expr )
    {
        mCurrent = expr;
        look_ahead();
        number result = expression();
        if( mType != FINISHED )
            throw eval_exception( "unexpect expression format" );
        return result;
    }
};

template< typename number, typename functions >
number eval( const char* expression, const ::std::map< ::std::string, number >& variables, functions& funcs )
{
    return evaler<number, functions>( variables, funcs )( expression );
}

};

#endif//CPP_EVAL_H_DFF520DB406EDCF31AB9A538F7E1C3BD_20040721__

用于测试的 C++ 程序:

#include "CppEval.h"
#include <iostream>
#include <numeric>

using namespace std;

class functions
{
public:
    int operator()( const char* name, const ::std::vector< int >& params )
    {
        if( stricmp( name, "return1" ) == 0 )
        {
            if( params.size() != 0 )
                throw 1;
            return 1;
        }
        else if( stricmp( name, "negative" ) == 0 )
        {
            if( params.size() != 1 )
                throw 1;
            return - params[ 0 ];
        }
        else if( stricmp( name, "sum" ) == 0 )
        {
            return accumulate( params.begin(), params.end(), 0 );
        }
    }
};

int main()
{
    map< string, int > variables;
    variables[ "aa" ] = 100;
    variables[ "b" ] = 200;
    functions f;
    cout<<cpp_eval::eval< int >( " + aa * aa / b - b / -2 /2/2 -- 5 ** 2 + -100 "
        " + ( aa * aa / b - b / -2 /2/2 -- 5 ** 2 + -100 )"
        " + return1() + negative( 1 ) + sum( 1, 2, 3, sum( 1 + 2 *5-7, 555, 111 ) )", variables, f )<<endl;
    return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用boost::sprirt编写的表达式解析器,代码很容易扩展,功能很强大,适合做功能强大的客户化定义程序。 -----------表达式解析--------- 已定义的函数有:PI,SIN,COS,TAN,,ABS,EXP,LOGN,POW,SQRT,FORMAT,LENGTH,SUBSTR 强制类型转换请使用:(数据类型)数据 例如:(int) "100" 的值为int型100 已定义的变量有:var1=123,var2=this is a string 请输入您的表达式>>1+2 计算结果:3 XML格式显示计算过程: <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE parsetree SYSTEM "parsetree.dtd"> <!-- 1+2 --> <parsetree version="1.0"> <parsenode rule="add_expr"> <value>+</value> <parsenode rule="integer_const"> <value>1</value> </parsenode> <parsenode rule="integer_const"> <value>2</value> </parsenode> </parsenode> </parsetree> 计算结果数据类型:integer 计算结果:3 请输入您的表达式>>"ab"+"cd" 计算结果:"abcd" XML格式显示计算过程: <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE parsetree SYSTEM "parsetree.dtd"> <!-- "ab"+"cd" --> <parsetree version="1.0"> <parsenode rule="add_expr"> <value>+</value> <parsenode rule="string_const"> <value>"ab"</value> </parsenode> <parsenode rule="string_const"> <value>"cd"</value> </parsenode> </parsenode> </parsetree> 计算结果数据类型:string 计算结果:abcd 请输入您的表达式>>format("1+2=%d",1+2) 计算结果:format("1+2=%d",3) XML格式显示计算过程: <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE parsetree SYSTEM "parsetree.dtd"> <!-- format("1+2=%d",1+2) --> <parsetree version="1.0"> <parsenode rule="function_identifier"> <value>format</value> <parsenode rule="exprlist"> <parsenode rule="string_const"> <value>"1+2=%d"</value> </parsenode> <parsenode rule="add_expr"> <value>+</value> <parsenode rule="integer_const"> <value>1</value> </parsenode> <parsenode rule="integer_const"> <value>2</value> </parsenode> </parsenode> </parsenode> </parsenode> </parsetree> 计算结果数据类型:string 计算结果:1+2=3 请输入您的表达式>>PI() 计算结果:PI() XML格式显示计算过程: <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE parsetree SYSTEM "parsetree.dtd"> <!-- PI() --> <parsetree version="1.0"> <parsenode rule="function_identifier"> <value>PI</value> </parsenode> </parsetree> 计算结果数据类型:double 计算结果:3.1415926535897931 请输入您的表达式>>cos(1.5) 计算结果:cos(1.5) XML格式显示计算过程: <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE parsetree SYSTEM "parsetree.dtd"> <!-- cos(1.5) --> <parsetree version="1.0"> <parsenode rule="function_identifier"> <value>cos</value> <parsenode rule="double_const"> <value>1.5</value> </parsenode> </parsenode> </parsetree> 计算结果数据类型:double 计算结果:0.070737201667702906 请输入您的表达式>>q
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值