C++ 使用Boost.Spirit中的Lex和Qi在语法规则中使用lexer标记属性 让我们考虑下面的代码: #include <boost/phoenix.hpp> #include <boost/spirit/include/lex_lexertl.hpp> #include <boost/spirit/include/qi.hpp> #include <algorithm> #include <iostream> #include <string> #include <utility> #include <vector> namespace lex = boost::spirit::lex; namespace qi = boost::spirit::qi; namespace phoenix = boost::phoenix; struct operation { enum type { add, sub, mul, div }; }; template<typename Lexer> class expression_lexer : public lex::lexer<Lexer> { public: typedef lex::token_def<operation::type> operator_token_type; typedef lex::token_def<double> value_token_type; typedef lex::token_def<std::string> variable_token_type; typedef lex::token_def<lex::omit> parenthesis_token_type; typedef std::pair<parenthesis_token_type, parenthesis_token_type> parenthesis_token_pair_type; typedef lex::token_def<lex::omit> whitespace_token_type; expression_lexer() : operator_add('+'), operator_sub('-'), operator_mul("[x*]"), operator_div("[:/]"), value("\\d+(\\.\\d+)?"), variable("%(\\w+)"), parenthesis({ std::make_pair(parenthesis_token_type('('), parenthesis_token_type(')')), std::make_pair(parenthesis_token_type('['), parenthesis_token_type(']')) }), whitespace("[ \\t]+") { this->self += operator_add [lex::_val = operation::add] | operator_sub [lex::_val = operation::sub] | operator_mul [lex::_val = operation::mul] | operator_div [lex::_val = operation::div] | value | variable [lex::_val = phoenix::construct<std::string>(lex::_start + 1, lex::_end)] | whitespace [lex::_pass = lex::pass_flags::pass_ignore] ; std::for_each(parenthesis.cbegin(), parenthesis.cend(), [&](parenthesis_token_pair_type const& token_pair) { this->self += token_pair.first | token_pair.second; } ); } operator_token_type operator_add; operator_token_type operator_sub; operator_token_type operator_mul; operator_token_type operator_div; value_token_type value; variable_token_type variable; std::vector<parenthesis_token_pair_type> parenthesis; whitespace_token_type whitespace; }; template<typename Iterator> class expression_grammar : public qi::grammar<Iterator> { public: template<typename Tokens> explicit expression_grammar(Tokens const& tokens) : expression_grammar::base_type(start) { start %= expression >> qi::eoi; expression %= sum_operand >> -(sum_operator >> expression); sum_operator %= tokens.operator_add | tokens.operator_sub; sum_operand %= fac_operand >> -(fac_operator >> sum_operand); fac_operator %= tokens.operator_mul | tokens.operator_div; if(!tokens.parenthesis.empty()) fac_operand %= parenthesised | terminal; else fac_operand %= terminal; terminal %= tokens.value | tokens.variable; if(!tokens.parenthesis.empty()) { parenthesised %= tokens.parenthesis.front().first >> expression >> tokens.parenthesis.front().second; std::for_each(tokens.parenthesis.cbegin() + 1, tokens.parenthesis.cend(), [&](typename Tokens::parenthesis_token_pair_type const& token_pair) { parenthesised %= parenthesised.copy() | (token_pair.first >> expression >> token_pair.second); } ); } } private: qi::rule<Iterator> start; qi::rule<Iterator> expression; qi::rule<Iterator> sum_operand; qi::rule<Iterator> sum_operator; qi::rule<Iterator> fac_operand; qi::rule<Iterator> fac_operator; qi::rule<Iterator> terminal; qi::rule<Iterator> parenthesised; }; int main() { typedef lex::lexertl::token<std::string::const_iterator, boost::mpl::vector<operation::type, double, std::string>> token_type; typedef expression_lexer<lex::lexertl::actor_lexer<token_type>> expression_lexer_type; typedef expression_lexer_type::iterator_type expression_lexer_iterator_type; typedef expression_grammar<expression_lexer_iterator_type> expression_grammar_type; expression_lexer_type lexer; expression_grammar_type grammar(lexer); while(std::cin) { std::string line; std::getline(std::cin, line); std::string::const_iterator first = line.begin(); std::string::const_iterator const last = line.end(); bool const result = lex::tokenize_and_parse(first, last, lexer, grammar); if(!result) std::cout << "Parsing failed! Reminder: >" << std::string(first, last) << "<" << std::endl; else { if(first != last) std::cout << "Parsing succeeded! Reminder: >" << std::string(first, last) << "<" << std::endl; else std::cout << "Parsing succeeded!" << std::endl; } } }

C++ 使用Boost.Spirit中的Lex和Qi在语法规则中使用lexer标记属性 让我们考虑下面的代码: #include <boost/phoenix.hpp> #include <boost/spirit/include/lex_lexertl.hpp> #include <boost/spirit/include/qi.hpp> #include <algorithm> #include <iostream> #include <string> #include <utility> #include <vector> namespace lex = boost::spirit::lex; namespace qi = boost::spirit::qi; namespace phoenix = boost::phoenix; struct operation { enum type { add, sub, mul, div }; }; template<typename Lexer> class expression_lexer : public lex::lexer<Lexer> { public: typedef lex::token_def<operation::type> operator_token_type; typedef lex::token_def<double> value_token_type; typedef lex::token_def<std::string> variable_token_type; typedef lex::token_def<lex::omit> parenthesis_token_type; typedef std::pair<parenthesis_token_type, parenthesis_token_type> parenthesis_token_pair_type; typedef lex::token_def<lex::omit> whitespace_token_type; expression_lexer() : operator_add('+'), operator_sub('-'), operator_mul("[x*]"), operator_div("[:/]"), value("\\d+(\\.\\d+)?"), variable("%(\\w+)"), parenthesis({ std::make_pair(parenthesis_token_type('('), parenthesis_token_type(')')), std::make_pair(parenthesis_token_type('['), parenthesis_token_type(']')) }), whitespace("[ \\t]+") { this->self += operator_add [lex::_val = operation::add] | operator_sub [lex::_val = operation::sub] | operator_mul [lex::_val = operation::mul] | operator_div [lex::_val = operation::div] | value | variable [lex::_val = phoenix::construct<std::string>(lex::_start + 1, lex::_end)] | whitespace [lex::_pass = lex::pass_flags::pass_ignore] ; std::for_each(parenthesis.cbegin(), parenthesis.cend(), [&](parenthesis_token_pair_type const& token_pair) { this->self += token_pair.first | token_pair.second; } ); } operator_token_type operator_add; operator_token_type operator_sub; operator_token_type operator_mul; operator_token_type operator_div; value_token_type value; variable_token_type variable; std::vector<parenthesis_token_pair_type> parenthesis; whitespace_token_type whitespace; }; template<typename Iterator> class expression_grammar : public qi::grammar<Iterator> { public: template<typename Tokens> explicit expression_grammar(Tokens const& tokens) : expression_grammar::base_type(start) { start %= expression >> qi::eoi; expression %= sum_operand >> -(sum_operator >> expression); sum_operator %= tokens.operator_add | tokens.operator_sub; sum_operand %= fac_operand >> -(fac_operator >> sum_operand); fac_operator %= tokens.operator_mul | tokens.operator_div; if(!tokens.parenthesis.empty()) fac_operand %= parenthesised | terminal; else fac_operand %= terminal; terminal %= tokens.value | tokens.variable; if(!tokens.parenthesis.empty()) { parenthesised %= tokens.parenthesis.front().first >> expression >> tokens.parenthesis.front().second; std::for_each(tokens.parenthesis.cbegin() + 1, tokens.parenthesis.cend(), [&](typename Tokens::parenthesis_token_pair_type const& token_pair) { parenthesised %= parenthesised.copy() | (token_pair.first >> expression >> token_pair.second); } ); } } private: qi::rule<Iterator> start; qi::rule<Iterator> expression; qi::rule<Iterator> sum_operand; qi::rule<Iterator> sum_operator; qi::rule<Iterator> fac_operand; qi::rule<Iterator> fac_operator; qi::rule<Iterator> terminal; qi::rule<Iterator> parenthesised; }; int main() { typedef lex::lexertl::token<std::string::const_iterator, boost::mpl::vector<operation::type, double, std::string>> token_type; typedef expression_lexer<lex::lexertl::actor_lexer<token_type>> expression_lexer_type; typedef expression_lexer_type::iterator_type expression_lexer_iterator_type; typedef expression_grammar<expression_lexer_iterator_type> expression_grammar_type; expression_lexer_type lexer; expression_grammar_type grammar(lexer); while(std::cin) { std::string line; std::getline(std::cin, line); std::string::const_iterator first = line.begin(); std::string::const_iterator const last = line.end(); bool const result = lex::tokenize_and_parse(first, last, lexer, grammar); if(!result) std::cout << "Parsing failed! Reminder: >" << std::string(first, last) << "<" << std::endl; else { if(first != last) std::cout << "Parsing succeeded! Reminder: >" << std::string(first, last) << "<" << std::endl; else std::cout << "Parsing succeeded!" << std::endl; } } },c++,boost,boost-spirit,boost-spirit-qi,boost-spirit-lex,C++,Boost,Boost Spirit,Boost Spirit Qi,Boost Spirit Lex,您将得到编译错误。我认为这是可行的,因为operation::type是operator\u add和operator\u sub的属性,也是它们的可选属性。但它仍然无法编译。从_迭代器将_分配给_属性_中的错误判断,解析器似乎试图直接从输入流范围构建属性值。这意味着它将忽略我在lexer中指定的[lex::\u val=operation::add] 改成 qi::rule<Iterator, operation::type (operation::type)> sum_opera

您将得到编译错误。我认为这是可行的,因为
operation::type
operator\u add
operator\u sub
的属性,也是它们的可选属性。但它仍然无法编译。从_迭代器将_分配给_属性_中的错误判断,解析器似乎试图直接从输入流范围构建属性值。这意味着它将忽略我在lexer中指定的
[lex::\u val=operation::add]

改成

qi::rule<Iterator, operation::type (operation::type)> sum_operator;
也没用

如何解决这个问题?我知道我可以使用Qi的
符号。但是我想使用lexer,以便为令牌配置正则表达式。我还可以像文档中描述的那样,从_迭代器
扩展
将_分配给_属性_,但这种工作会加倍。我想我也可以跳过lexer上的属性,只把它们放在语法上。但是在
variable
token(在我的实际案例中,有稍微多一些的逻辑,因此它也可以配置,token的哪一部分构成变量的实际名称,而在这里它被固定为只跳过第一个字符)。还有别的吗


还有一个附带的问题——也许任何人都知道。是否有一种方法可以从tokens操作中捕获令牌正则表达式的组?因此,与其

variable [lex::_val = phoenix::construct<std::string>(lex::_start + 1, lex::_end)]
变量[lex::_val=phoenix::construct(lex::_start+1,lex:_end)]
相反,我可以从捕获组生成一个字符串,这样就可以轻松处理
$var$
等格式



编辑!我改进了从结论中跳过的空白。这是一种简化,不会影响此处提出的问题。

好的,以下是我对RPN“要求”的看法。我非常喜欢自然(自动)属性传播,而不是语义动作(参见)

我考虑其他选项(美化)优化。如果您对整体设计感到满意,并且不介意使其更难维护,您可以这样做:)

//#define BOOST_SPIRIT_DEBUG
#include <boost/phoenix.hpp>
#include <boost/bind.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <algorithm>
#include <iostream>
#include <string>
#include <utility>
#include <vector>

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

struct operation
{
    enum type
    {
        add,
        sub,
        mul,
        div
    };

    friend std::ostream& operator<<(std::ostream& os, type op) {
        switch (op) {
            case type::add: return os << "+";
            case type::sub: return os << "-";
            case type::mul: return os << "*";
            case type::div: return os << "/";
        }
        return os << "<" << static_cast<int>(op) << ">";
    }
};

template<typename Lexer>
class expression_lexer
    : public lex::lexer<Lexer>
{
public:
    //typedef lex::token_def<operation::type> operator_token_type;
    typedef lex::token_def<lex::omit> operator_token_type;
    typedef lex::token_def<double> value_token_type;
    typedef lex::token_def<std::string> variable_token_type;

    typedef lex::token_def<lex::omit> parenthesis_token_type;
    typedef std::pair<parenthesis_token_type, parenthesis_token_type> parenthesis_token_pair_type;
    typedef lex::token_def<lex::omit> whitespace_token_type;

    expression_lexer()
        : operator_add('+'),
          operator_sub('-'),
          operator_mul("[x*]"),
          operator_div("[:/]"),
          value("\\d+(\\.\\d+)?"),
          variable("%(\\w+)"),
          parenthesis({
            std::make_pair(parenthesis_token_type('('), parenthesis_token_type(')')),
            std::make_pair(parenthesis_token_type('['), parenthesis_token_type(']'))
          }),
          whitespace("[ \\t]+")
    {
        this->self
            += operator_add [lex::_val = operation::add]
             | operator_sub [lex::_val = operation::sub]
             | operator_mul [lex::_val = operation::mul]
             | operator_div [lex::_val = operation::div]
             | value
             | variable [lex::_val = phoenix::construct<std::string>(lex::_start + 1, lex::_end)]
             | whitespace [lex::_pass = lex::pass_flags::pass_ignore]
             ;

        std::for_each(parenthesis.cbegin(), parenthesis.cend(),
            [&](parenthesis_token_pair_type const& token_pair)
            {
                this->self += token_pair.first | token_pair.second;
            }
        );
    }

    operator_token_type operator_add;
    operator_token_type operator_sub;
    operator_token_type operator_mul;
    operator_token_type operator_div;

    value_token_type value;
    variable_token_type variable;

    std::vector<parenthesis_token_pair_type> parenthesis;

    whitespace_token_type whitespace;
};

namespace AST {
    using operation = operation::type;

    using value     = double;
    using variable  = std::string;

    struct bin_expr;
    using expression = boost::variant<value, variable, boost::recursive_wrapper<bin_expr> >;

    struct bin_expr {
        expression lhs, rhs;
        operation op;

        friend std::ostream& operator<<(std::ostream& os, bin_expr const& be) {
            return os << "(" << be.lhs << " " << be.op << " " << be.rhs << ")";
        }
    };
}

BOOST_FUSION_ADAPT_STRUCT(AST::bin_expr, lhs, op, rhs)

template<typename Iterator>
class expression_grammar : public qi::grammar<Iterator, AST::expression()>
{
public:
    template<typename Tokens>
    explicit expression_grammar(Tokens const& tokens)
        : expression_grammar::base_type(start)
    {
        start                     = expression >> qi::eoi;

        bin_sum_expr              = sum_operand >> sum_operator >> expression;
        bin_fac_expr              = fac_operand >> fac_operator >> sum_operand;

        expression                = bin_sum_expr | sum_operand;
        sum_operand               = bin_fac_expr | fac_operand;

        sum_operator              = tokens.operator_add >> qi::attr(AST::operation::add) | tokens.operator_sub >> qi::attr(AST::operation::sub);
        fac_operator              = tokens.operator_mul >> qi::attr(AST::operation::mul) | tokens.operator_div >> qi::attr(AST::operation::div);

        if(tokens.parenthesis.empty()) {
            fac_operand           = terminal;
        }
        else {
            fac_operand           = parenthesised | terminal;

            parenthesised         = tokens.parenthesis.front().first >> expression >> tokens.parenthesis.front().second;
            std::for_each(tokens.parenthesis.cbegin() + 1, tokens.parenthesis.cend(),
                    [&](typename Tokens::parenthesis_token_pair_type const& token_pair)
                    {
                        parenthesised = parenthesised.copy() | (token_pair.first >> expression >> token_pair.second);
                    });
        }

        terminal                  = tokens.value | tokens.variable;

        BOOST_SPIRIT_DEBUG_NODES(
                (start) (expression) (bin_sum_expr) (bin_fac_expr)
                (fac_operand) (terminal) (parenthesised) (sum_operand)
                (sum_operator) (fac_operator)
            );
    }

private:
    qi::rule<Iterator, AST::expression()> start;
    qi::rule<Iterator, AST::expression()> expression;
    qi::rule<Iterator, AST::expression()> sum_operand;
    qi::rule<Iterator, AST::expression()> fac_operand;
    qi::rule<Iterator, AST::expression()> terminal;
    qi::rule<Iterator, AST::expression()> parenthesised;

    qi::rule<Iterator, int()> sum_operator;
    qi::rule<Iterator, int()> fac_operator;

    // extra rules to help with AST creation
    qi::rule<Iterator, AST::bin_expr()> bin_sum_expr;
    qi::rule<Iterator, AST::bin_expr()> bin_fac_expr;
};

namespace RPN {
    using cell      = boost::variant<AST::operation, AST::value, AST::variable>;
    using rpn_stack = std::vector<cell>;

    struct transform : boost::static_visitor<> {
        void operator()(rpn_stack& stack, AST::expression const& e) const {
            boost::apply_visitor(boost::bind(*this, boost::ref(stack), ::_1), e);
        }
        void operator()(rpn_stack& stack, AST::bin_expr const& e) const {
            (*this)(stack, e.lhs);
            (*this)(stack, e.rhs);
            stack.push_back(e.op);
        }
        void operator()(rpn_stack& stack, AST::value    const& v) const { stack.push_back(v); }
        void operator()(rpn_stack& stack, AST::variable const& v) const { stack.push_back(v); }
    };
}

int main()
{
    typedef lex::lexertl::token<std::string::const_iterator, boost::mpl::vector<operation::type, double, std::string>> token_type;
    typedef expression_lexer<lex::lexertl::actor_lexer<token_type>> expression_lexer_type;
    typedef expression_lexer_type::iterator_type expression_lexer_iterator_type;
    typedef expression_grammar<expression_lexer_iterator_type> expression_grammar_type;

    expression_lexer_type lexer;
    expression_grammar_type grammar(lexer);
    RPN::transform compiler;

    std::string line;
    while(std::getline(std::cin, line) && !line.empty())
    {
        std::string::const_iterator first = line.begin();
        std::string::const_iterator const last = line.end();

        AST::expression expr;
        bool const result = lex::tokenize_and_parse(first, last, lexer, grammar, expr);
        if(!result)
            std::cout << "Parsing failed!\n";
        else
        {
            std::cout << "Parsing success: " << expr << "\n";

            RPN::rpn_stack program;
            compiler(program, expr);

            for (auto& instr : program) {
                std::cout << instr << " ";
            }
        }

        if(first != last)
            std::cout << "Remainder: >" << std::string(first, last) << "<\n";
    }
}
除了您已经研究过的我的评论中的示例之外,我还添加了RPN转换步骤:

namespace RPN {
    using cell      = boost::variant<AST::operation, AST::value, AST::variable>;
    using rpn_stack = std::vector<cell>;

    struct transform : boost::static_visitor<> {
        void operator()(rpn_stack& stack, AST::expression const& e) const {
            boost::apply_visitor(boost::bind(*this, boost::ref(stack), ::_1), e);
        }
        void operator()(rpn_stack& stack, AST::bin_expr const& e) const {
            (*this)(stack, e.lhs);
            (*this)(stack, e.rhs);
            stack.push_back(e.op);
        }
        void operator()(rpn_stack& stack, AST::value    const& v) const { stack.push_back(v); }
        void operator()(rpn_stack& stack, AST::variable const& v) const { stack.push_back(v); }
    };
}
完整列表

//#define BOOST_SPIRIT_DEBUG
#include <boost/phoenix.hpp>
#include <boost/bind.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <algorithm>
#include <iostream>
#include <string>
#include <utility>
#include <vector>

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

struct operation
{
    enum type
    {
        add,
        sub,
        mul,
        div
    };

    friend std::ostream& operator<<(std::ostream& os, type op) {
        switch (op) {
            case type::add: return os << "+";
            case type::sub: return os << "-";
            case type::mul: return os << "*";
            case type::div: return os << "/";
        }
        return os << "<" << static_cast<int>(op) << ">";
    }
};

template<typename Lexer>
class expression_lexer
    : public lex::lexer<Lexer>
{
public:
    //typedef lex::token_def<operation::type> operator_token_type;
    typedef lex::token_def<lex::omit> operator_token_type;
    typedef lex::token_def<double> value_token_type;
    typedef lex::token_def<std::string> variable_token_type;

    typedef lex::token_def<lex::omit> parenthesis_token_type;
    typedef std::pair<parenthesis_token_type, parenthesis_token_type> parenthesis_token_pair_type;
    typedef lex::token_def<lex::omit> whitespace_token_type;

    expression_lexer()
        : operator_add('+'),
          operator_sub('-'),
          operator_mul("[x*]"),
          operator_div("[:/]"),
          value("\\d+(\\.\\d+)?"),
          variable("%(\\w+)"),
          parenthesis({
            std::make_pair(parenthesis_token_type('('), parenthesis_token_type(')')),
            std::make_pair(parenthesis_token_type('['), parenthesis_token_type(']'))
          }),
          whitespace("[ \\t]+")
    {
        this->self
            += operator_add [lex::_val = operation::add]
             | operator_sub [lex::_val = operation::sub]
             | operator_mul [lex::_val = operation::mul]
             | operator_div [lex::_val = operation::div]
             | value
             | variable [lex::_val = phoenix::construct<std::string>(lex::_start + 1, lex::_end)]
             | whitespace [lex::_pass = lex::pass_flags::pass_ignore]
             ;

        std::for_each(parenthesis.cbegin(), parenthesis.cend(),
            [&](parenthesis_token_pair_type const& token_pair)
            {
                this->self += token_pair.first | token_pair.second;
            }
        );
    }

    operator_token_type operator_add;
    operator_token_type operator_sub;
    operator_token_type operator_mul;
    operator_token_type operator_div;

    value_token_type value;
    variable_token_type variable;

    std::vector<parenthesis_token_pair_type> parenthesis;

    whitespace_token_type whitespace;
};

namespace AST {
    using operation = operation::type;

    using value     = double;
    using variable  = std::string;

    struct bin_expr;
    using expression = boost::variant<value, variable, boost::recursive_wrapper<bin_expr> >;

    struct bin_expr {
        expression lhs, rhs;
        operation op;

        friend std::ostream& operator<<(std::ostream& os, bin_expr const& be) {
            return os << "(" << be.lhs << " " << be.op << " " << be.rhs << ")";
        }
    };
}

BOOST_FUSION_ADAPT_STRUCT(AST::bin_expr, lhs, op, rhs)

template<typename Iterator>
class expression_grammar : public qi::grammar<Iterator, AST::expression()>
{
public:
    template<typename Tokens>
    explicit expression_grammar(Tokens const& tokens)
        : expression_grammar::base_type(start)
    {
        start                     = expression >> qi::eoi;

        bin_sum_expr              = sum_operand >> sum_operator >> expression;
        bin_fac_expr              = fac_operand >> fac_operator >> sum_operand;

        expression                = bin_sum_expr | sum_operand;
        sum_operand               = bin_fac_expr | fac_operand;

        sum_operator              = tokens.operator_add >> qi::attr(AST::operation::add) | tokens.operator_sub >> qi::attr(AST::operation::sub);
        fac_operator              = tokens.operator_mul >> qi::attr(AST::operation::mul) | tokens.operator_div >> qi::attr(AST::operation::div);

        if(tokens.parenthesis.empty()) {
            fac_operand           = terminal;
        }
        else {
            fac_operand           = parenthesised | terminal;

            parenthesised         = tokens.parenthesis.front().first >> expression >> tokens.parenthesis.front().second;
            std::for_each(tokens.parenthesis.cbegin() + 1, tokens.parenthesis.cend(),
                    [&](typename Tokens::parenthesis_token_pair_type const& token_pair)
                    {
                        parenthesised = parenthesised.copy() | (token_pair.first >> expression >> token_pair.second);
                    });
        }

        terminal                  = tokens.value | tokens.variable;

        BOOST_SPIRIT_DEBUG_NODES(
                (start) (expression) (bin_sum_expr) (bin_fac_expr)
                (fac_operand) (terminal) (parenthesised) (sum_operand)
                (sum_operator) (fac_operator)
            );
    }

private:
    qi::rule<Iterator, AST::expression()> start;
    qi::rule<Iterator, AST::expression()> expression;
    qi::rule<Iterator, AST::expression()> sum_operand;
    qi::rule<Iterator, AST::expression()> fac_operand;
    qi::rule<Iterator, AST::expression()> terminal;
    qi::rule<Iterator, AST::expression()> parenthesised;

    qi::rule<Iterator, int()> sum_operator;
    qi::rule<Iterator, int()> fac_operator;

    // extra rules to help with AST creation
    qi::rule<Iterator, AST::bin_expr()> bin_sum_expr;
    qi::rule<Iterator, AST::bin_expr()> bin_fac_expr;
};

namespace RPN {
    using cell      = boost::variant<AST::operation, AST::value, AST::variable>;
    using rpn_stack = std::vector<cell>;

    struct transform : boost::static_visitor<> {
        void operator()(rpn_stack& stack, AST::expression const& e) const {
            boost::apply_visitor(boost::bind(*this, boost::ref(stack), ::_1), e);
        }
        void operator()(rpn_stack& stack, AST::bin_expr const& e) const {
            (*this)(stack, e.lhs);
            (*this)(stack, e.rhs);
            stack.push_back(e.op);
        }
        void operator()(rpn_stack& stack, AST::value    const& v) const { stack.push_back(v); }
        void operator()(rpn_stack& stack, AST::variable const& v) const { stack.push_back(v); }
    };
}

int main()
{
    typedef lex::lexertl::token<std::string::const_iterator, boost::mpl::vector<operation::type, double, std::string>> token_type;
    typedef expression_lexer<lex::lexertl::actor_lexer<token_type>> expression_lexer_type;
    typedef expression_lexer_type::iterator_type expression_lexer_iterator_type;
    typedef expression_grammar<expression_lexer_iterator_type> expression_grammar_type;

    expression_lexer_type lexer;
    expression_grammar_type grammar(lexer);
    RPN::transform compiler;

    std::string line;
    while(std::getline(std::cin, line) && !line.empty())
    {
        std::string::const_iterator first = line.begin();
        std::string::const_iterator const last = line.end();

        AST::expression expr;
        bool const result = lex::tokenize_and_parse(first, last, lexer, grammar, expr);
        if(!result)
            std::cout << "Parsing failed!\n";
        else
        {
            std::cout << "Parsing success: " << expr << "\n";

            RPN::rpn_stack program;
            compiler(program, expr);

            for (auto& instr : program) {
                std::cout << instr << " ";
            }
        }

        if(first != last)
            std::cout << "Remainder: >" << std::string(first, last) << "<\n";
    }
}
/#定义BOOST_SPIRIT_调试
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
名称空间lex=boost::spirit::lex;
名称空间qi=boost::spirit::qi;
名称空间phoenix=boost::phoenix;
结构操作
{
枚举类型
{
添加
附属的,
穆尔,
div
};
friend std::ostream&operator>qi::attr(AST::operation::mul)| tokens.operator_div>>qi::attr(AST::operation::div);
if(tokens.圆括号.empty()){
fac_操作数=终端;
}
否则{
fac|U操作数=括号内的|终端;
圆括号=标记。圆括号。前()。第一个>>表达式>>标记。圆括号。前()。第二个;
std::for_each(tokens.contracts.cbegin()+1,tokens.contracts.cend(),
[&](类型名称标记::括号\u标记\u对\u类型常量和标记\u对)
{
圆括号=圆括号中的.copy()|(token_pair.first>>表达式>>token_pair.second);
});
}
终端=tokens.value | tokens.variable;
BOOST_SPIRIT_DEBUG_节点(
(开始)(表达)(宾瑟姆表达)(宾瑟姆表达)
(fac_操作数)(终端)(括号内)(求和操作数)
(sum_运算符)(fac_运算符)
);
}
私人:
qi::规则开始;
qi:规则表达;
qi::规则和操作数;
qi::规则fac_操作数;
qi:规则终端;
qi::括号内的规则;
qi::规则求和算子;
qi::规则fac_运算符;
//帮助创建AST的额外规则
qi::规则bin_sum_expr;
qi::rule bin_fac_expr;
};
名称空间RPN{
使用cell=boost::variant;
使用rpn_stack=std::vector;
结构转换:boost::static\u visitor{
void操作符(){
boost::apply_visitor(boost::bind(*this,boost::ref(stack),:_1),e);
}
void操作符(){
(*此)(堆栈,e.lhs);
(*此)(烟囱,东右侧);
堆叠。推回(e.op);
}
void操作符()(rpn_stack&stack,AST::value const&v)const{stack.push_back(v);}
void操作符()(rpn_stack&stack,AST::variable const&v)const{stack.push_back(v);}
};
}
int main()
{
typedef lex::lexertl::token token_type;
typedef expression\u lexer expression\u lexer\u type;
typedef expression_lexer_type::迭代器_type expression_lexer_iterator_type;
typedef表达式\语法表达式\语法\类型;
表达式\ lexer \类型lexer;
表达式语法类型语法(lexer);
转换编译器;
std::字符串行;
while(std::getline(std::cin,line)和&!line.empty()
{
std::string::const_iterator first=line.begin();
std::string::const_迭代器const last=line.end();
AST::表达式表达式;
bool const result=lex::tokenize_和_parse(first、last、lexer、grammar、expr);
如果(!结果)

std::cout Re“附带问题[…]捕获令牌的[…]组”-你不能。它们不是正则表达式。语法非常类似于其中的一个子集,是的。我将解析为AST,然后转换为RPN。我会在有时间的时候完成一个示例,现在是:@sehe根据你上面的评论和我收集的一些经验,我终于能够回答我自己在这方面的前一个问题。你可以吗I don’我不想看一看是否还有更多的东西需要添加或扩展
RPN::transform compiler;
RPN::rpn_stack program;
compiler(program, expr);

for (auto& instr : program) {
    std::cout << instr << " ";
}
Parsing success: (3 + (8 * 9))
3 8 9 * + 
//#define BOOST_SPIRIT_DEBUG
#include <boost/phoenix.hpp>
#include <boost/bind.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <algorithm>
#include <iostream>
#include <string>
#include <utility>
#include <vector>

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

struct operation
{
    enum type
    {
        add,
        sub,
        mul,
        div
    };

    friend std::ostream& operator<<(std::ostream& os, type op) {
        switch (op) {
            case type::add: return os << "+";
            case type::sub: return os << "-";
            case type::mul: return os << "*";
            case type::div: return os << "/";
        }
        return os << "<" << static_cast<int>(op) << ">";
    }
};

template<typename Lexer>
class expression_lexer
    : public lex::lexer<Lexer>
{
public:
    //typedef lex::token_def<operation::type> operator_token_type;
    typedef lex::token_def<lex::omit> operator_token_type;
    typedef lex::token_def<double> value_token_type;
    typedef lex::token_def<std::string> variable_token_type;

    typedef lex::token_def<lex::omit> parenthesis_token_type;
    typedef std::pair<parenthesis_token_type, parenthesis_token_type> parenthesis_token_pair_type;
    typedef lex::token_def<lex::omit> whitespace_token_type;

    expression_lexer()
        : operator_add('+'),
          operator_sub('-'),
          operator_mul("[x*]"),
          operator_div("[:/]"),
          value("\\d+(\\.\\d+)?"),
          variable("%(\\w+)"),
          parenthesis({
            std::make_pair(parenthesis_token_type('('), parenthesis_token_type(')')),
            std::make_pair(parenthesis_token_type('['), parenthesis_token_type(']'))
          }),
          whitespace("[ \\t]+")
    {
        this->self
            += operator_add [lex::_val = operation::add]
             | operator_sub [lex::_val = operation::sub]
             | operator_mul [lex::_val = operation::mul]
             | operator_div [lex::_val = operation::div]
             | value
             | variable [lex::_val = phoenix::construct<std::string>(lex::_start + 1, lex::_end)]
             | whitespace [lex::_pass = lex::pass_flags::pass_ignore]
             ;

        std::for_each(parenthesis.cbegin(), parenthesis.cend(),
            [&](parenthesis_token_pair_type const& token_pair)
            {
                this->self += token_pair.first | token_pair.second;
            }
        );
    }

    operator_token_type operator_add;
    operator_token_type operator_sub;
    operator_token_type operator_mul;
    operator_token_type operator_div;

    value_token_type value;
    variable_token_type variable;

    std::vector<parenthesis_token_pair_type> parenthesis;

    whitespace_token_type whitespace;
};

namespace AST {
    using operation = operation::type;

    using value     = double;
    using variable  = std::string;

    struct bin_expr;
    using expression = boost::variant<value, variable, boost::recursive_wrapper<bin_expr> >;

    struct bin_expr {
        expression lhs, rhs;
        operation op;

        friend std::ostream& operator<<(std::ostream& os, bin_expr const& be) {
            return os << "(" << be.lhs << " " << be.op << " " << be.rhs << ")";
        }
    };
}

BOOST_FUSION_ADAPT_STRUCT(AST::bin_expr, lhs, op, rhs)

template<typename Iterator>
class expression_grammar : public qi::grammar<Iterator, AST::expression()>
{
public:
    template<typename Tokens>
    explicit expression_grammar(Tokens const& tokens)
        : expression_grammar::base_type(start)
    {
        start                     = expression >> qi::eoi;

        bin_sum_expr              = sum_operand >> sum_operator >> expression;
        bin_fac_expr              = fac_operand >> fac_operator >> sum_operand;

        expression                = bin_sum_expr | sum_operand;
        sum_operand               = bin_fac_expr | fac_operand;

        sum_operator              = tokens.operator_add >> qi::attr(AST::operation::add) | tokens.operator_sub >> qi::attr(AST::operation::sub);
        fac_operator              = tokens.operator_mul >> qi::attr(AST::operation::mul) | tokens.operator_div >> qi::attr(AST::operation::div);

        if(tokens.parenthesis.empty()) {
            fac_operand           = terminal;
        }
        else {
            fac_operand           = parenthesised | terminal;

            parenthesised         = tokens.parenthesis.front().first >> expression >> tokens.parenthesis.front().second;
            std::for_each(tokens.parenthesis.cbegin() + 1, tokens.parenthesis.cend(),
                    [&](typename Tokens::parenthesis_token_pair_type const& token_pair)
                    {
                        parenthesised = parenthesised.copy() | (token_pair.first >> expression >> token_pair.second);
                    });
        }

        terminal                  = tokens.value | tokens.variable;

        BOOST_SPIRIT_DEBUG_NODES(
                (start) (expression) (bin_sum_expr) (bin_fac_expr)
                (fac_operand) (terminal) (parenthesised) (sum_operand)
                (sum_operator) (fac_operator)
            );
    }

private:
    qi::rule<Iterator, AST::expression()> start;
    qi::rule<Iterator, AST::expression()> expression;
    qi::rule<Iterator, AST::expression()> sum_operand;
    qi::rule<Iterator, AST::expression()> fac_operand;
    qi::rule<Iterator, AST::expression()> terminal;
    qi::rule<Iterator, AST::expression()> parenthesised;

    qi::rule<Iterator, int()> sum_operator;
    qi::rule<Iterator, int()> fac_operator;

    // extra rules to help with AST creation
    qi::rule<Iterator, AST::bin_expr()> bin_sum_expr;
    qi::rule<Iterator, AST::bin_expr()> bin_fac_expr;
};

namespace RPN {
    using cell      = boost::variant<AST::operation, AST::value, AST::variable>;
    using rpn_stack = std::vector<cell>;

    struct transform : boost::static_visitor<> {
        void operator()(rpn_stack& stack, AST::expression const& e) const {
            boost::apply_visitor(boost::bind(*this, boost::ref(stack), ::_1), e);
        }
        void operator()(rpn_stack& stack, AST::bin_expr const& e) const {
            (*this)(stack, e.lhs);
            (*this)(stack, e.rhs);
            stack.push_back(e.op);
        }
        void operator()(rpn_stack& stack, AST::value    const& v) const { stack.push_back(v); }
        void operator()(rpn_stack& stack, AST::variable const& v) const { stack.push_back(v); }
    };
}

int main()
{
    typedef lex::lexertl::token<std::string::const_iterator, boost::mpl::vector<operation::type, double, std::string>> token_type;
    typedef expression_lexer<lex::lexertl::actor_lexer<token_type>> expression_lexer_type;
    typedef expression_lexer_type::iterator_type expression_lexer_iterator_type;
    typedef expression_grammar<expression_lexer_iterator_type> expression_grammar_type;

    expression_lexer_type lexer;
    expression_grammar_type grammar(lexer);
    RPN::transform compiler;

    std::string line;
    while(std::getline(std::cin, line) && !line.empty())
    {
        std::string::const_iterator first = line.begin();
        std::string::const_iterator const last = line.end();

        AST::expression expr;
        bool const result = lex::tokenize_and_parse(first, last, lexer, grammar, expr);
        if(!result)
            std::cout << "Parsing failed!\n";
        else
        {
            std::cout << "Parsing success: " << expr << "\n";

            RPN::rpn_stack program;
            compiler(program, expr);

            for (auto& instr : program) {
                std::cout << instr << " ";
            }
        }

        if(first != last)
            std::cout << "Remainder: >" << std::string(first, last) << "<\n";
    }
}