AST и приоритет оператора в определении правила

Привет[¹]

У меня есть простой парсер (см. Ниже).

Он намеревается анализировать условные выражения (реляционные арифметические операции и их логические комбинации).

В приведенном там примере он успешно анализирует A> 5, но затем останавливается и игнорирует остальную часть ввода, и это согласуется с моим impl.

Как я могу изменитьexpr_ правило, чтобы он анализировал весь ввод?

#include <cstdint>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/variant/recursive_wrapper.hpp>

namespace qi    = boost::spirit::qi;
namespace phx   = boost::phoenix;

/// Terminals
enum metric_t : std::uint8_t { A=0u, B };
const std::string metric_names[] = { "A", "B" };
struct metrics_parser : boost::spirit::qi::symbols<char, metric_t>
{
metrics_parser()
{
    this->add
    ( metric_names[A], A )
    ( metric_names[B], B )
    ;
}
};


/// Operators
struct op_or  {};
struct op_and {};
struct op_xor {};
struct op_not {};

struct op_eq {};
struct op_lt {};
struct op_let {};
struct op_gt {};
struct op_get {};

template <typename tag> struct unop;
template <typename tag> struct binop;

/// Expression
typedef boost::variant<
int,
double,
metric_t,
boost::recursive_wrapper< unop<op_not> >,
boost::recursive_wrapper< binop<op_and> >,
boost::recursive_wrapper< binop<op_or> >,
boost::recursive_wrapper< binop<op_xor> >,
boost::recursive_wrapper< binop<op_eq> >,
boost::recursive_wrapper< binop<op_lt> >,
boost::recursive_wrapper< binop<op_gt> >
> expr;

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

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

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

    void operator()(const binop<op_and>& b) const { print(" and ", b.oper1, b.oper2); }
    void operator()(const binop<op_or >& b) const { print(" or ",  b.oper1, b.oper2);  }
    void operator()(const binop<op_xor>& b) const { print(" xor ", b.oper1, b.oper2); }
    void operator()(const binop<op_eq>& b) const  { print(" = ",   b.oper1, b.oper2);   }
    void operator()(const binop<op_lt>& b) const  { print(" < ",   b.oper1, b.oper2);   }
    void operator()(const binop<op_gt>& b) const  { print(" > ",   b.oper1, b.oper2);   }

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

    void operator()(const unop<op_not>& u) const
    {
        _os << "(";
            _os << "!";
            boost::apply_visitor(*this, u.oper1);
        _os << ")";
    }
    void operator()(metric_t m) const
    {
    _os << metric_names[m];
    }

    template <typename other_t>
    void operator()(other_t i) const
    {
    _os << i;
    }
};

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

std::ostream& operator<<(std::ostream& os, metric_t m)
{ os<< metric_names[m]; return os; }

template <typename It, typename Skipper = qi::space_type>
struct parser : qi::grammar<It, expr(), Skipper>
{
    parser() : parser::base_type(expr_)
    {
        using namespace qi;
        using namespace phx;
        using local_names::_a;

        number_r_ %= int_ | double_;

        metric_r_ %= metric_p_;

        eq_r_ =
        (metric_r_ >> "=" >> number_r_)  
            [ _val = phx::construct< binop<op_eq> >(_1,_2) ] |
        (metric_r_ >> "!=" >> number_r_) 
            [ _val = phx::construct< unop<op_not> >( phx::construct< binop<op_eq> >(_1,_2) ) ]
        ;

        ineq_r_ =
        (metric_r_ >> ">" >> number_r_)  
            [ _val = phx::construct< binop<op_gt> >(_1,_2) ] |
        (metric_r_ >> "<" >> number_r_)  
            [ _val = phx::construct< binop<op_lt> >(_1,_2) ] |
        (metric_r_ >> ">=" >> number_r_) 
            [ _val = phx::construct< binop<op_or> >( 
            phx::construct< binop<op_gt> >(_1,_2),
            phx::construct< binop<op_eq> >(_1,_2) ) 
            ] |
        (metric_r_ >> "<=" >> number_r_) 
            [ _val = phx::construct< binop<op_or> >( 
            phx::construct< binop<op_lt> >(_1,_2), 
            phx::construct< binop<op_eq> >(_1,_2) )
            ]
        ;

        ineq_2_r_ = 
        (number_r_ >> "<" >> metric_r_ >> "<" >> number_r_)
            [ _val = phx::construct< binop<op_and> >(
            phx::construct< binop<op_gt> >(_2,_1), 
            phx::construct< binop<op_lt> >(_2,_3) ) 
            ] |
        (number_r_ >> "<=" >> metric_r_ >> "<" >> number_r_)
            [ _val = phx::construct< binop<op_and> >(
            phx::construct< binop<op_or> >(
                phx::construct< binop<op_gt> >(_2,_1),
                phx::construct< binop<op_eq> >(_2,_1)
            ),
            phx::construct< binop<op_lt> >(_2,_3) )
            ] |
        (number_r_ >> "<" >> metric_r_ >> "<=" >> number_r_)
            [ _val = phx::construct< binop<op_and> >(
            phx::construct< binop<op_gt> >(_2,_1),
            phx::construct< binop<op_or> >(                
                phx::construct< binop<op_eq> >(_2,_3),
                phx::construct< binop<op_lt> >(_2,_3) )
            )
            ] |
        (number_r_ >> "<=" >> metric_r_ >> "<=" >> number_r_)
            [ _val = phx::construct< binop<op_and> >(
            phx::construct< binop<op_or> >(
                phx::construct< binop<op_eq> >(_2,_1),
                phx::construct< binop<op_gt> >(_2,_1) 
            ),
            phx::construct< binop<op_or> >(                
                phx::construct< binop<op_eq> >(_2,_3),
                phx::construct< binop<op_lt> >(_2,_3)
            )
            )
            ]
        ;

        expr_  = 
        eq_r_                     [ _val = _1 ]                                     |
        ineq_r_                   [ _val = _1 ]                                     |
        ineq_2_r_                 [ _val = _1 ]                                     |
        ("not" >> expr_)          [ _val = phx::construct< unop<op_not> >(_1) ]     |
        (expr_ >> "and" >> expr_) [ _val = phx::construct< binop<op_and> >(_1,_2) ] |
        (expr_ >> "or" >> expr_)  [ _val = phx::construct< binop<op_or>  >(_1,_2) ] |
        (expr_ >> "xor" >> expr_) [ _val = phx::construct< binop<op_xor> >(_1,_2) ];

        metric_r_.name("metric r");
        eq_r_.name("eq_r_");
        ineq_r_.name("ineq_r_");
        ineq_2_r_.name("ineq_2_r_");
        expr_.name("expr_");
        debug(metric_r_);
        debug(eq_r_);
        debug(ineq_r_);
        debug(ineq_2_r_);
        debug(expr_);
    }

private:
    metrics_parser                metric_p_;
    qi::rule<It, expr(), Skipper> number_r_;
    qi::rule<It, expr(), Skipper> metric_r_;
    qi::rule<It, expr(), Skipper> eq_r_;
    qi::rule<It, expr(), Skipper> ineq_r_;
    qi::rule<It, expr(), Skipper> ineq_2_r_;
    qi::rule<It, expr(), Skipper> expr_;
};



int main()
{
    std::list<std::string> lstr;
    lstr.emplace_back("A>5 and B<4 xor A>3.4 or 2<A<3");

    for (auto i=std::begin(lstr); i!=std::end(lstr); ++i)
    {
        auto& input = *i;

        auto f(std::begin(input)), l(std::end(input));
        parser<decltype(f)> p;

        try
        {
            expr result;
            bool ok = qi::phrase_parse(f,l,p,qi::space,result);

            if (!ok)
                std::cerr << "invalid input\n";
            else
                std::cout << "result: " << result << "\n";

        } catch (const qi::expectation_failure<decltype(f)>& e)
        {
            std::cerr << "expectation_failure at '" << std::string(e.first, e.last) << "'\n";
        }

        if (f!=l) std::cerr << "unparsed: '" << std::string(f,l) << "'\n";
    }

    return 0;
}

Спасибо мм

[¹] Вопрос телепортировался из[spirit-general] список пользователей

Ответы на вопрос(2)

Ваш ответ на вопрос