1

I'm trying to parse some expression. I started from impressive answers of llonesmiz and Sehe

I wanted to add some:

(1) defined parameters. These prams are given as map by another class. They may have no argument (integer) one or two :

  • imf ---> $imf
  • imf(1) ---> $imf(1)
  • imf(1,2) ---> $imf(1,2)

I'm traying to fist get the parameter name "imf" an then its arguments if they exist (1), (2,2) ...

(2) defined function given as a map by another class. They may have one, two or three argument :

  • cos(1) ---> cos(1)
  • cross(imf(1),1) ---> cross($imf(1),1)
  • fun3(1,2,1) ---> fun3(1,2,1)

custom_fold_directive.hpp

namespace custom
    {
        namespace tag
        {
            struct fold { BOOST_SPIRIT_IS_TAG() };
        }

        template <typename Exposed, typename Expr>
        boost::spirit::stateful_tag_type<Expr, tag::fold, Exposed>
        fold(Expr const& expr)
        {
            return boost::spirit::stateful_tag_type<Expr, tag::fold, Exposed>(expr);
        }

    }

    namespace boost { namespace spirit 
    {
        template <typename Expr, typename Exposed>
        struct use_directive<qi::domain
              , tag::stateful_tag<Expr, custom::tag::fold, Exposed> >
          : mpl::true_ {};
    }}

    namespace custom
    {
        template <typename Exposed, typename InitialParser, typename RepeatingParser>
        struct fold_directive
        {
            fold_directive(InitialParser const& initial, RepeatingParser const& repeating):initial(initial),repeating(repeating){}

            template <typename Context, typename Iterator>
            struct attribute
            {
                typedef typename boost::spirit::traits::attribute_of<InitialParser,Context,Iterator>::type type;//This works in this case but is not generic
            };

            template <typename Iterator, typename Context
              , typename Skipper, typename Attribute>
            bool parse(Iterator& first, Iterator const& last
              , Context& context, Skipper const& skipper, Attribute& attr_) const
            {
                Iterator start = first;

                typename boost::spirit::traits::attribute_of<InitialParser,Context,Iterator>::type initial_attr;


                if (!initial.parse(first, last, context, skipper, initial_attr))
                {
                    first=start;
                    return false;
                }

                typename boost::spirit::traits::attribute_of<RepeatingParser,Context,Iterator>::type repeating_attr;

                if(!repeating.parse(first, last, context, skipper, repeating_attr))
                {
                    boost::spirit::traits::assign_to(initial_attr, attr_);
                    return true;
                }
                Exposed current_attr(initial_attr,repeating_attr);

                while(repeating.parse(first, last, context, skipper, repeating_attr))
                {
                    boost::spirit::traits::assign_to(Exposed(current_attr,repeating_attr),current_attr);
                }
                boost::spirit::traits::assign_to(current_attr,attr_);
                return true;
            }

            template <typename Context>
            boost::spirit::info what(Context& context) const
            {
                return boost::spirit::info("fold");
            }

            InitialParser initial;
            RepeatingParser repeating;
        };
    }

    namespace boost { namespace spirit { namespace qi
    {
        template <typename Expr, typename Exposed, typename Subject, typename Modifiers>
        struct make_directive<
            tag::stateful_tag<Expr, custom::tag::fold, Exposed>, Subject, Modifiers>
        {
            typedef custom::fold_directive<Exposed, Expr, Subject> result_type;

            template <typename Terminal>
            result_type operator()(Terminal const& term, Subject const& subject, Modifiers const&) const
            {
                typedef tag::stateful_tag<
                    Expr, custom::tag::fold, Exposed> tag_type;
                using spirit::detail::get_stateful_data;

                return result_type(get_stateful_data<tag_type>::call(term),subject);
            }
        };
    }}}

main.cpp

//#define BOOST_SPIRIT_DEBUG
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include "custom_fold_directive.hpp"

namespace qi = boost::spirit::qi;

// DEFINING TYPES
struct op_not {};
struct op_or {};
struct op_and {};
struct op_equal {};
struct op_unequal {};
struct op_sum {};
struct op_difference {};
struct op_factor {};
struct op_division {};
struct op_component{};

namespace Expression{

typedef  std::string var;
template <typename tag> struct binop;
template <typename tag> struct unop;


/*
 * tree structure definition 
 */
typedef boost::variant<var,
    boost::recursive_wrapper<unop <op_not> >,
    boost::recursive_wrapper<binop<op_equal> >,
    boost::recursive_wrapper<binop<op_unequal> >,
    boost::recursive_wrapper<binop<op_and> >,
    boost::recursive_wrapper<binop<op_or> >,
    boost::recursive_wrapper<binop<op_difference> >,
    boost::recursive_wrapper<binop<op_sum> >,
    boost::recursive_wrapper<binop<op_factor> >,
    boost::recursive_wrapper<binop<op_division> >,
    boost::recursive_wrapper<binop<op_component> >
> expressionContainer;


template <typename tag> struct binop
{
    explicit binop(const expressionContainer& l
        , const expressionContainer& r)
        : oper1(l), oper2(r) { }
    expressionContainer oper1, oper2;
};

template <typename tag> struct comop
{
    explicit comop(const expressionContainer& l
        , const expressionContainer& r)
        : oper1(l), oper2(r) { }
    expressionContainer oper1, oper2;
};

template <typename tag> struct unop
{
    explicit unop(const expressionContainer& o) : oper1(o) { }
    expressionContainer oper1;

};

struct printer : boost::static_visitor<void>
{
    printer(std::ostream& os) : _os(os) {}
    std::ostream& _os;

    //
    void operator()(const var& v) const { _os << v;}

    // Logical
    void operator()(const binop<op_and>& b) const { print(" & ", b.oper1, b.oper2); }
    void operator()(const binop<op_or >& b) const { print(" || ", b.oper1, b.oper2); }
    void operator()(const binop<op_equal>& b) const { print(" == ", b.oper1, b.oper2); }
    void operator()(const binop<op_unequal>& b) const { print(" != ", b.oper1, b.oper2); }


    //Math operators
    void operator()(const binop<op_difference>& b) const { print("-", b.oper1, b.oper2); }
    void operator()(const binop<op_sum>& b) const { print("+", b.oper1, b.oper2); }
    void operator()(const binop<op_factor>& b) const { print("*", b.oper1, b.oper2); }
    void operator()(const binop<op_division>& b) const { print("/", b.oper1, b.oper2); }

    void operator()(const binop<op_component>& b) const { print(",", b.oper1, b.oper2); }

    //unique operators 
     void operator()(const unop<op_not>& u) const{printUnique("!",u.oper1);}



     //Printer 
    void print(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
    {
        _os << "(";
            boost::apply_visitor(*this, l);
            _os << op;
            boost::apply_visitor(*this, r);
        _os << ")";
    }

    void printUnique(const std::string& op, const expressionContainer& l) const
    {
            _os << op;
            boost::apply_visitor(*this, l);
    }
      void printPower(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
    {
            boost::apply_visitor(*this, l);
            _os << op;
            boost::apply_visitor(*this, r);
    }
          void printOutSide(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
    {
        _os << op;
        _os << "(";
            boost::apply_visitor(*this, l);
        _os << ",";
            boost::apply_visitor(*this, r);
        _os << ")";
    }
          /**
           *            void printConst( const expressionContainer& l) const
    { 
            std::map<std::string, std::string> consts;
            consts["@pi"] = "3.14";
            consts["@ro"]="1.5";
            std::string key="@"+l.
            boost::apply_visitor(*this, consts(key));         
    }
           * @param l
           */


};

std::ostream& operator<<(std::ostream& os, const expressionContainer& e)
{ boost::apply_visitor(printer(os), e); return os; }

}

    /*
     * EXPRESSION PARSER DEFINITION 
     */
template <typename It, typename Skipper = boost::spirit::standard_wide::space_type>
struct parserExpression : qi::grammar<It, Expression::expressionContainer(), Skipper>
{
    parserExpression() : parserExpression::base_type(expr_)
    {
        using namespace qi;
        using namespace Expression;
        using custom::fold;

        expr_ = or_.alias();

        // Logical Operators
        or_ = fold<binop<op_or> >(and_.alias())[orOperator_ >> and_];
        and_ = fold<binop<op_and> >(equal_.alias())[andOperator_ >> equal_];
        equal_ = fold<binop<op_equal> >(unequal_.alias())[equalOperator_ >> unequal_]; 
        unequal_ = fold<binop<op_unequal> >(sum_.alias())[unequalOperator_ >>sum_];


        // Numerical Operators
        sum_ = fold<binop<op_sum> >(difference_.alias())[sumOperator_ >> difference_];
        difference_ = fold<binop<op_difference> >(factor_.alias())[differenceOperator_ >> factor_];
        factor_ = fold<binop<op_factor> >(division_.alias())[factorOperator_ >> division_]; 
        division_ = fold<binop<op_division> >(not_.alias())[divisionOperator_ >> not_];


        // UNARY OPERATION
        not_ = (notOperator_ > param_) [_val = boost::phoenix::construct<Expression::unop <op_not>>(_1)] | param_[_val=_1];  
        param_ = (definedParams ) [_val =_1] |  component_[_val = _1];
        component_=definedParams >> '(' >> args_[_val=_1] >>')'| simple[_val = _1];
        simple = (('(' > expr_ > ')') | var_);


        var_ %= qi::raw[+qi::double_];
        args_%=qi::raw[+qi::int_ % ','];
        notOperator_        = qi::char_('!');
        andOperator_        = qi::string("&&");
        orOperator_         = qi::string("||");
        xorOperator_        = qi::char_("^");
        equalOperator_      = qi::string("==");
        unequalOperator_    = qi::string("!=");
        sumOperator_        = qi::char_("+");
        differenceOperator_ = qi::char_("-");
        factorOperator_     = qi::char_("*");
        divisionOperator_   = qi::char_("/");
        greaterOperator_   = qi::char_(">");
        greaterOrEqualOperator_   = qi::string(">=");
        lowerOrEqualOperator_   = qi::string("<=");
        lowerOperator_   = qi::char_("<");
        componentOperator_=qi::char_(",");

        // Defined Function 
        std::map<std::string, std::string> functions;
        functions["fun1"] = "cos";
        functions["fun2"] = "sin";
        for(auto const&x:functions){
        definedFunctions.add (x.first, x.second) ;
        }
        //defined parameters 
        std::map<std::string, std::string> paramsList;
        paramsList["imf"] = "imf";
        paramsList["spect"] = "spectro";
        for(auto const&x:paramsList){
        definedParams.add (x.first, x.second) ;
        }



        BOOST_SPIRIT_DEBUG_NODES((expr_)(or_)(xor_)(and_)(equal_)(unequal_)(greaterOrEqual_)(lowerOrEqual_)(lower_)(sum_)
                (difference_)(factor_)(division_)(simple)(notOperator_)(andOperator_)(orOperator_)(xorOperator_)(equalOperator_)(unequalOperator_)
                (sumOperator_)(differenceOperator_)(factorOperator_)(divisionOperator_)(greater_)(lower_));

    }

private:
    qi::rule<It, Expression::var(), Skipper> var_, args_;
    qi::rule<It, Expression::expressionContainer(), Skipper> not_
        , and_
        , xor_
        , or_
        , equal_
        , unequal_
        , sum_
        , difference_
        , factor_
        , division_
        , simple
        , expr_
        ,plusSign_
        ,minusSign_
       ,greater_
       ,greaterOrEqual_
       ,lowerOrEqual_
       ,lower_
       ,functions_
       ,param_
       ,component_;

    qi::rule<It, Skipper> notOperator_
        , andOperator_
        , orOperator_
        , xorOperator_
        , equalOperator_
        , unequalOperator_
        , sumOperator_
        , differenceOperator_
        , factorOperator_
        , divisionOperator_
        , greaterOperator_ 
        , greaterOrEqualOperator_ 
        ,lowerOrEqualOperator_
        ,lowerOperator_ 
        ,componentOperator_;
        qi::symbols<char, std::string> definedFunctions;
        qi::symbols<char, std::string> definedParams;
};





void parse(const std::string& str)
{
    std::string::const_iterator iter = str.begin(), end = str.end();

    parserExpression<std::string::const_iterator,qi::space_type> parser;
    Expression::expressionContainer expr;

    bool result = qi::phrase_parse(iter,end,parser,qi::space, expr);

    if(result && iter==end)
    {
        std::cout << "Success." << std::endl;
        std::cout << str << " => " << expr << std::endl;
    }
    else
    {
        std::cout << "Failure." << std::endl;
    }
}

int main()
{
    parse("imf");
    parse("spect");
    parse("imf(1)");
    parse("spect(1,2)");
}

Success. imf => imf thats working

Success. spect => spectro thats working

imf(1) => Failure. expected imf(1)

spect(1,2) => Failure. expected spectro(1,2)

hacenesh
  • 75
  • 5

2 Answers2

2

The output for (1) isn't empty. It's ASCII 0x01:

00000000: 2831 2920 3d3e 2001 0a                   (1) => ..

That's because

var_ %= qi::lexeme[+qi::int_];

doesn't do what you want. It parses 1 as an integer and then puts that into the container of char (std::string is a container). To simply parse a number, only parse int_ and to treat is as a string, consider raw[]:

var_ = qi::raw[qi::int_];

Now it prints:

Success.
(1) => 1
Success.
1+1 => (1+1)

With regards to the rest, it's completely unclear to me how you want to parse things. I have a suspicion it's unclear to yourself too:

  • unary operators are unary, not unique
  • unary operators are operators, not expression subtypes or identifiers
  • if you want functions to take argument lists, why is there no rule that says so
  • if the "definedParams" are arguments - what's the difference between that and a variable?

For inspiration look at these answers that already do parser function calls with parameters:

More slightly advanced/related:

sehe
  • 374,641
  • 47
  • 450
  • 633
  • +1 from me, but Is not using `qi::int_` here is an evil? it will fail on numbers that does not fit `int`, and it is somewhat slower because of the overflow/underflow check. – Nikita Kniazev Mar 29 '19 at 23:40
  • @NikitaKniazev Your guess is as good as mine. The grammar is as posed by OP. It seems useless for me to change that. So, it's definitely not "an evil". It seems like a code smell. Like I said, _" I have a suspicion it's unclear to [OP] too"_ :) – sehe Mar 30 '19 at 15:29
0

Following sehe suggestions, I added rules for parameters and functions. For function I build 3 lists “qi::symbols” depending on the number of arguments. The parser works fine.

custom_fold_directive.hpp

namespace custom
{
    namespace tag
    {
        struct fold { BOOST_SPIRIT_IS_TAG() };
    }

    template <typename Exposed, typename Expr>
    boost::spirit::stateful_tag_type<Expr, tag::fold, Exposed>
    fold(Expr const& expr)
    {
        return boost::spirit::stateful_tag_type<Expr, tag::fold, Exposed>(expr);
    }

}

namespace boost { namespace spirit 
{
    template <typename Expr, typename Exposed>
    struct use_directive<qi::domain
          , tag::stateful_tag<Expr, custom::tag::fold, Exposed> >
      : mpl::true_ {};
}}

namespace custom
{
    template <typename Exposed, typename InitialParser, typename RepeatingParser>
    struct fold_directive
    {
        fold_directive(InitialParser const& initial, RepeatingParser const& repeating):initial(initial),repeating(repeating){}

        template <typename Context, typename Iterator>
        struct attribute
        {
            typedef typename boost::spirit::traits::attribute_of<InitialParser,Context,Iterator>::type type;//This works in this case but is not generic
        };

        template <typename Iterator, typename Context
          , typename Skipper, typename Attribute>
        bool parse(Iterator& first, Iterator const& last
          , Context& context, Skipper const& skipper, Attribute& attr_) const
        {
            Iterator start = first;

            typename boost::spirit::traits::attribute_of<InitialParser,Context,Iterator>::type initial_attr;


            if (!initial.parse(first, last, context, skipper, initial_attr))
            {
                first=start;
                return false;
            }

            typename boost::spirit::traits::attribute_of<RepeatingParser,Context,Iterator>::type repeating_attr;

            if(!repeating.parse(first, last, context, skipper, repeating_attr))
            {
                boost::spirit::traits::assign_to(initial_attr, attr_);
                return true;
            }
            Exposed current_attr(initial_attr,repeating_attr);

            while(repeating.parse(first, last, context, skipper, repeating_attr))
            {
                boost::spirit::traits::assign_to(Exposed(current_attr,repeating_attr),current_attr);
            }
            boost::spirit::traits::assign_to(current_attr,attr_);
            return true;
        }

        template <typename Context>
        boost::spirit::info what(Context& context) const
        {
            return boost::spirit::info("fold");
        }

        InitialParser initial;
        RepeatingParser repeating;
    };
}

namespace boost { namespace spirit { namespace qi
{
    template <typename Expr, typename Exposed, typename Subject, typename Modifiers>
    struct make_directive<
        tag::stateful_tag<Expr, custom::tag::fold, Exposed>, Subject, Modifiers>
    {
        typedef custom::fold_directive<Exposed, Expr, Subject> result_type;

        template <typename Terminal>
        result_type operator()(Terminal const& term, Subject const& subject, Modifiers const&) const
        {
            typedef tag::stateful_tag<
                Expr, custom::tag::fold, Exposed> tag_type;
            using spirit::detail::get_stateful_data;

            return result_type(get_stateful_data<tag_type>::call(term),subject);
        }
    };
}}}

main.cpp

#include <boost/mpl/list.hpp>

//#define BOOST_SPIRIT_DEBUG
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include "custom_fold_directive.hpp"

namespace qi = boost::spirit::qi;

// Expression::triop <fun_generic>

// DEFINING TYPES
struct op_not {};
struct op_or {};
struct op_and {};
struct op_xor {};
struct op_equal {};
struct op_unequal {};
struct op_sum {};
struct op_difference {};
struct op_factor {};
struct op_division {};
struct op_power{};
struct op_powerTen{};
struct op_plusSign {};
struct op_minusSign {};
struct op_const {};
struct fun_three{};
struct fun_two{};
struct fun_one{};

namespace Expression{

typedef  std::string var;
template <typename tag> struct binop;
template <typename tag> struct unop;
template <typename tag> struct triop;
template <typename tag> struct forop;



/*
 * tree structure definition 
 */
typedef boost::variant<var,
    boost::recursive_wrapper<unop <op_not> >,
    boost::recursive_wrapper<binop<op_equal> >,
    boost::recursive_wrapper<binop<op_unequal> >,
    boost::recursive_wrapper<binop<op_and> >,
    boost::recursive_wrapper<binop<op_xor> >,
    boost::recursive_wrapper<binop<op_or> >,
    boost::recursive_wrapper<binop<op_difference> >,
    boost::recursive_wrapper<binop<op_sum> >,
    boost::recursive_wrapper<binop<op_factor> >,
    boost::recursive_wrapper<binop<op_division> >,
    boost::recursive_wrapper<binop<op_power> >, 
    boost::recursive_wrapper<binop<op_powerTen> >,
    boost::recursive_wrapper<unop<op_minusSign> >,
    boost::recursive_wrapper<unop<op_plusSign> >,
    boost::recursive_wrapper<unop<op_const> >,
    boost::recursive_wrapper<binop<fun_one> >,
    boost::recursive_wrapper<triop<fun_two> >,
    boost::recursive_wrapper<forop<fun_three> >
> expressionContainer;


template <typename tag> struct binop
{
    explicit binop(const expressionContainer& l
        , const expressionContainer& r)
        : oper1(l), oper2(r) { }
    expressionContainer oper1, oper2;
};

template <typename tag> struct unop
{
    explicit unop(const expressionContainer& o) : oper1(o) { }
    expressionContainer oper1;

};

template <typename tag> struct triop
{
    explicit triop(const expressionContainer& functionId,
            const expressionContainer& l
        , const expressionContainer& r)
        : oper1(functionId), oper2(l), oper3(r) { }
expressionContainer oper1, oper2, oper3;
};

template <typename tag> struct forop
{
    explicit forop(const expressionContainer& functionId,
            const expressionContainer& l,
            const expressionContainer& m,
          const expressionContainer& r)
        : oper1(functionId), oper2(l), oper3(m),oper4(r) { }
expressionContainer oper1, oper2, oper3,oper4;
};



struct printer : boost::static_visitor<void>
{
    printer(std::ostream& os) : _os(os) {}
    std::ostream& _os;

        void operator()(const var& v) const { _os << v; }

    // Logical
    void operator()(const binop<op_and>& b) const { print(" & ", b.oper1, b.oper2); }
    void operator()(const binop<op_or >& b) const { print(" || ", b.oper1, b.oper2); }
    void operator()(const binop<op_xor>& b) const { print(" | ", b.oper1, b.oper2); }
    void operator()(const binop<op_equal>& b) const { print(" == ", b.oper1, b.oper2); }
    void operator()(const binop<op_unequal>& b) const { print(" != ", b.oper1, b.oper2); }

    //Math operators
    void operator()(const binop<op_difference>& b) const { print("-", b.oper1, b.oper2); }
    void operator()(const binop<op_sum>& b) const { print("+", b.oper1, b.oper2); }
    void operator()(const binop<op_factor>& b) const { print("*", b.oper1, b.oper2); }
    void operator()(const binop<op_division>& b) const { print("/", b.oper1, b.oper2); }

    //Power Math operators 
    void operator()(const binop<op_power>& b) const { print("pow", b.oper1, b.oper2); }
    void operator()(const binop<op_powerTen>& b) const { printPower("e", b.oper1, b.oper2); }

    //unique operators 
     void operator()(const unop<op_not>& u) const{printUnique("!",u.oper1);}
     void operator()(const unop<op_plusSign>& u) const{printUnique("",u.oper1);}
     void operator()(const unop<op_minusSign>& u) const{printUnique("-",u.oper1);}
     void operator()(const unop<op_const>& u) const{printUnique("",u.oper1);}

   // print Functions 
    void operator()(const forop<fun_three>& b) const { printFunctionThree(b.oper1, b.oper2, b.oper3,  b.oper4); }
    void operator()(const triop<fun_two>& b) const { printFunctionTwo(b.oper1, b.oper2, b.oper3); }
    void operator()(const binop<fun_one>& b) const { printFunctionOne(b.oper1, b.oper2); }





     //Printer 
    void print(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
    {
        _os << "(";
            boost::apply_visitor(*this, l);
            _os << op;
            boost::apply_visitor(*this, r);
        _os << ")";
    }

    void printUnique(const std::string& op, const expressionContainer& l) const
    {
            _os << op;
            boost::apply_visitor(*this, l);
    }
      void printPower(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
    {
            boost::apply_visitor(*this, l);
            _os << op;
            boost::apply_visitor(*this, r);
    }
          void printOutSide(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
    {
        _os << op;
        _os << "(";
            boost::apply_visitor(*this, l);
        _os << ",";
            boost::apply_visitor(*this, r);
        _os << ")";
    }
  void printFunctionThree(const expressionContainer& functionId, const expressionContainer& l, const expressionContainer& m, const expressionContainer& r) const
    {
        boost::apply_visitor(*this, functionId);
        _os << "(";
            boost::apply_visitor(*this, l);
            _os << ',';
            boost::apply_visitor(*this, m);
            _os << ',';
            boost::apply_visitor(*this, r);
        _os << ")";
    }

    void printFunctionTwo(const expressionContainer& functionId, const expressionContainer& l, const expressionContainer& r) const
    {
        boost::apply_visitor(*this, functionId);
        _os << "(";
            boost::apply_visitor(*this, l);
            _os << ',';
            boost::apply_visitor(*this, r);
        _os << ")";
    }

        void printFunctionOne(const expressionContainer& functionId, const expressionContainer& l) const
    {
        boost::apply_visitor(*this, functionId);
        _os << "(";
            boost::apply_visitor(*this, l);
        _os << ")";
    }

};

std::ostream& operator<<(std::ostream& os, const expressionContainer& e)
{ boost::apply_visitor(printer(os), e); return os; }

}

    /*
     * EXPRESSION PARSER DEFINITION 
     */
template <typename It, typename Skipper = boost::spirit::standard_wide::space_type>
struct parserExpression : qi::grammar<It, Expression::expressionContainer(), Skipper>
{
    parserExpression() : parserExpression::base_type(expr_)
    {
        using namespace qi;
        using namespace Expression;
        using custom::fold;

        expr_ = or_.alias();

        // Logical Operators
        or_ = fold<binop<op_or> >(and_.alias())[orOperator_ >> and_];
        and_ = fold<binop<op_and> >(equal_.alias())[andOperator_ >> equal_];
        equal_ = fold<binop<op_equal> >(unequal_.alias())[equalOperator_ >> unequal_]; 
        unequal_ = fold<binop<op_unequal> >(sum_.alias())[unequalOperator_ >>sum_];


        // Numerical Operators
        sum_ = fold<binop<op_sum> >(difference_.alias())[sumOperator_ >> difference_];
        difference_ = fold<binop<op_difference> >(factor_.alias())[differenceOperator_ >> factor_];
        factor_ = fold<binop<op_factor> >(division_.alias())[factorOperator_ >> division_]; 
        division_ = fold<binop<op_division> >(functions_.alias())[divisionOperator_ >> functions_];
        functions_ = (threeArgsFunction>>"(">>funArgs_>>componentOperator_>>funArgs_>>componentOperator_>>funArgs_>>")")[_val= boost::phoenix::construct<Expression::forop <fun_three>>(_1,_2,_3,_4)] ||
                               (twoArgsFunction>>"(">>funArgs_>>componentOperator_>>funArgs_>>")")[_val= boost::phoenix::construct<Expression::triop <fun_two>>(_1,_2,_3)]||
                               (oneArgsFunction>>"(">>funArgs_>>")")[_val= boost::phoenix::construct<Expression::binop <fun_one>>(_1,_2)]|not_[_val=_1];

        // UNARY OPERATION
        not_ = (notOperator_ > param_) [_val = boost::phoenix::construct<Expression::unop <op_not>>(_1)] | param_[_val=_1]; 
        param_= (definedParams >>('(' >> (spectArgs_|vectorArgs_)>>')'))[_val='$'+_1+"("+qi::_2+")"] ||
                definedParams[_val='$'+_1]| simple[_val = _1];

        funArgs_=((expr_   |var_) |functions_);
        simple = (('(' > expr_ > ')') |  var_);



        var_ = (+qi::char_('0','9') >> -qi::char_('.') >> -(+qi::char_('0','9'))) | ((qi::char_('.') >> +qi::char_('0','9')));
        vectorArgs_%=qi::raw[qi::int_ > -(qi::char_(',')>>qi::int_) ];
        spectArgs_ %=qi::raw[(qi::int_>>qi::char_(',')>>'*')|(qi::char_('*')>>qi::char_(',')>>qi::int_)];
        notOperator_        = qi::char_('!');
        andOperator_        = qi::string("&&");
        orOperator_         = qi::string("||");
        xorOperator_        = qi::char_("^");
        equalOperator_      = qi::string("==");
        unequalOperator_    = qi::string("!=");
        sumOperator_        = qi::char_("+");
        differenceOperator_ = qi::char_("-");
        factorOperator_     = qi::char_("*");
        divisionOperator_   = qi::char_("/");
        greaterOperator_   = qi::char_(">");
        greaterOrEqualOperator_   = qi::string(">=");
        lowerOrEqualOperator_   = qi::string("<=");
        lowerOperator_   = qi::char_("<");
        componentOperator_=qi::char_(",");

        // Defined Function 
        std::map<std::string, std::string> oneFunctions;
        oneFunctions["fun1_1"] = "f11";
        oneFunctions["fun1_2"] = "f12";
        for(auto const&x:oneFunctions){
        oneArgsFunction.add (x.first, x.second) ;
        }

        std::map<std::string, std::string> twoFunctions;
        twoFunctions["fun2_1"] = "f21";
        twoFunctions["fun2_2"] = "f22";
        for(auto const&x:twoFunctions){
        twoArgsFunction.add (x.first, x.second) ;
        }

        std::map<std::string, std::string> threeFunctions;
        threeFunctions["fun3_1"] = "f31";
        threeFunctions["fun3_2"] = "f32";
        for(auto const&x:threeFunctions){
        threeArgsFunction.add (x.first, x.second) ;
        }
        //defined parameters 
        std::map<std::string, std::string> paramsList;
        paramsList["imf"] = "imf";
        paramsList["param"] = "param";
        for(auto const&x:paramsList){
        definedParams.add (x.first, x.second) ;
        }



        BOOST_SPIRIT_DEBUG_NODES((expr_)(or_)(xor_)(and_)(equal_)(unequal_)(sum_)(difference_)(factor_)(division_)
                (simple)(notOperator_)(andOperator_)(orOperator_)(xorOperator_)(equalOperator_)(unequalOperator_)
                (sumOperator_)(differenceOperator_)(factorOperator_)(divisionOperator_)(functions_));

    }

private:
    qi::rule<It, Expression::var(), Skipper> var_,  vectorArgs_, spectArgs_;
    qi::rule<It, Expression::expressionContainer(), Skipper> not_
        , and_
        , xor_
        , or_
        , equal_
        , unequal_
        , sum_
        , difference_
        , factor_
        , division_
        , simple
        , expr_
        ,plusSign_
        ,minusSign_
       ,greater_
       ,greaterOrEqual_
       ,lowerOrEqual_
       ,lower_
       ,functions_
       ,param_
       ,funArgs_;

    qi::rule<It, Skipper> notOperator_
        , andOperator_
        , orOperator_
        , xorOperator_
        , equalOperator_
        , unequalOperator_
        , sumOperator_
        , differenceOperator_
        , factorOperator_
        , divisionOperator_
        , greaterOperator_ 
        , greaterOrEqualOperator_ 
        ,lowerOrEqualOperator_
        ,lowerOperator_ 
        ,componentOperator_;
        qi::symbols<char, std::string> twoArgsFunction;
        qi::symbols<char, std::string> oneArgsFunction;
        qi::symbols<char, std::string> threeArgsFunction;
        qi::symbols<char, std::string> definedParams;
};





void parse(const std::string& str)
{
    std::string::const_iterator iter = str.begin(), end = str.end();

    parserExpression<std::string::const_iterator,qi::space_type> parser;
    Expression::expressionContainer expr;

    bool result = qi::phrase_parse(iter,end,parser,qi::space, expr);

    if(result && iter==end)
    {
        std::cout << "Success." << std::endl;
        std::cout << str << " => " << expr << std::endl;
    }
    else
    {
        std::cout << "Failure." << std::endl;
    }
}

int main()
{
    parse("1");
    parse("1+1");
    parse("(1+1)");
    //
    parse("fun1_1((1))");
    //
    parse("fun2_1(1,2)");
    parse("fun2_1( (fun2_1(1,1)), (2))");
    //
    parse("fun3_1(fun1_1(1),fun2_1(2,3),imf(1,1))");


}

output
Success. 1 => 1
Success. imf => $imf
Success. imf(1) => $imf(1)
Success. (1+1) => (1+1)
Success. fun1_1((1)) => f11(1)
Success. fun2_1(1,2) => f21(1,2)
Success. fun2_1( (fun2_1(1,1)), (2)) => f21(f21(1,1),2)
Success. fun3_1(fun1_1(1),fun2_1(2,3),imf(1,1)) => f31(f11(1),f21(2,3),$imf(1,1))

hacenesh
  • 75
  • 5