我正在尝试解析一些表达式。我从llonesmizSehe令人印象深刻的答案开始

我想添加一些:

(1)定义参数。这些婴儿车由另一个类(class)作为 map 提供。他们可能没有一个或两个参数(整数):


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

  • 我正在准备首先获得参数名称“imf”,然后如果存在它们的参数(1),(2,2)...

    (2)另一个类作为 map 给出的定义函数。他们可能有一个,两个或三个参数:


  • 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)");
    }
    

    成功。
    imf => imf多数民众赞成在工作

    成功。
    spect => spectro多数民众赞成在工作

    imf(1)=>失败。预期的imf(1)

    spect(1,2)=>失败。预期光谱(1,2)

    最佳答案

    (1)的输出不为空。它是ASCII 0x01:

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

    那是因为
    var_ %= qi::lexeme[+qi::int_];
    

    不会做你想要的。它将1解析为一个整数,然后将其放入char的容器中(std::string是一个容器)。要简单地解析数字,仅解析int_并将其视为字符串,请考虑raw[]:
    var_ = qi::raw[qi::int_];
    

    现在打印:
    Success.
    (1) => 1
    Success.
    1+1 => (1+1)
    

    至于其他方面,我完全不清楚您要如何解析事物。我怀疑自己也不清楚:
  • 一元运算符是一元运算符,不是唯一的
  • 一元运算符是运算符,不是表达式子类型或标识符
  • 如果要让函数接受参数列表,为什么没有规则这么说
  • 如果“definedParams”是参数-该变量和变量之间有什么区别?

  • 为了获得启发,请看一下已经使用参数进行解析器函数调用的以下答案:
  • Spirit qi parsing to an Abstract Syntax Tree for nested functions
  • 比较好:Boost::spirit how to parse and call c++ function-like expressions的此答案可即时解释已解析的表达式(这将在您自己的解析器中模拟[std::cout << "Parse multiplication: " << (qi::_1 * qi::_2)]的方法)
  • 那里的另一个答案(Boost::spirit how to parse and call c++ function-like expressions)使用专用的AST表示形式和单独的解释阶段来实现目标。

  • 更高级/相关的:
  • 定义函数以及detecting function call with regex
  • Implementing operator precedence with boost spirit
  • 高度高级:How to provider user with autocomplete suggestions for given boost::spirit grammar?
  • 关于c++ - 具有定义函数的Boost::Spirit表达式解析器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55419148/

    10-11 15:59