在语义动作中提升精神改变变量值

hay*_*art 4 c++ boost boost-spirit boost-phoenix boost-spirit-qi

我想在语义操作中更改局部变量值,如下所示:

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>

namespace qi = boost::spirit::qi;
namespace spirit = boost::spirit;
namespace ascii = boost::spirit::ascii;
using boost::phoenix::ref;
using boost::phoenix::bind;

void dummy(const std::vector<char>& v, int& var)
{
    var = 7;
}

template <typename Iterator>
struct x_grammar : public qi::grammar<Iterator, std::string(), ascii::space_type>
{
public:
    x_grammar() : x_grammar::base_type(start_rule, "x_grammar")
    {
        using namespace qi;
        int local_var = 0;
        start_rule = (+(char_ - ";"))[bind(dummy, _1, ref(local_var))];
        //repeat(ref(local_var))[some_rule];
    }
private:
    qi::rule<Iterator, std::string(), ascii::space_type> start_rule;
};

int main()
{
    typedef std::string::const_iterator iter;
    std::string storage("string;aaa");
    iter it_begin(storage.begin());
    iter it_end(storage.end());
    std::string read_data;
    using boost::spirit::ascii::space;
    x_grammar<iter> g;
    try {
        bool r = qi::phrase_parse(it_begin, it_end, g, space, read_data);
        std::cout << "Pass!\n";
    } catch (const qi::expectation_failure<iter>& x) {
        std::cout << "Error!\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用GCC 4.6.1和boost 1.55获得了一些烦人的编译错误.

seh*_*ehe 6

我不禁要注意,如果编译器错误惹恼了你,那么也许你应该编写有效的代码:/


教育帽子......

虽然这当然是一个轻率的评论,但它也有点启发.

我已经告诉过你两次了,在你的语法中使用构造函数局部变量的整个想法从根本上被打破了:

你想要的是什么

  • 继承属性
  • 齐::当地人
  • maayyyyybe,maaaayyybe语法成员变量; 需要注意的是,他们会使您的规则不可重入.

真正深入了解的重要一点是

Boost Spirit从表达式模板生成解析器.表达式模板是90%的静态信息(仅限类型),并将"编译"(.compile())转换为"可调用的"(.parse())形式.

最重要的是,虽然您可以在语义操作中编写控制流,但实际上并没有在定义站点执行.它被"编译"成一个懒惰的actor,以后可以被调用.

生成的解析将在相应的解析表达式匹配时有条件地调用惰性actor


建设性帽子......

看起来您只想使用函数转换属性.

这是你可以做的:

  1. 转换为语义动作的一部分,将结果放入常规属性(维护解析器组合的"功能"语义):

    qi::rule<Iterator, exposed(), Skipper> myrule;
    myrule = int_ [ _val = phx::bind(custom_xform, _1) ];
    
    Run Code Online (Sandbox Code Playgroud)

    custom_xform任何老派calleable(包括多态的):

    exposed custom_xform(int i) { return make_new_exposed(i); } 
    // or
    struct custom_xfrom_t {
    
      template <typename> struct result { typedef exposed type; };
    
      template <typename Int>
        exposed operator()(Int i) const {
            return make_new_exposed(i);
        }
    };
    static const custom_xform_t custom_xform;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 你可以添加一些语法糖[1]

    qi::rule<Iterator, exposed(), Skipper> myrule;
    myrule = int_ [ _val = custom_xform(_1) ];
    
    Run Code Online (Sandbox Code Playgroud)

    这个要求custom_xform被定义为一个懒惰的演员:

    phx::function<custom_xform_t> custom_xform; // `custom_xform_t` again the (polymorphic) functor
    
    Run Code Online (Sandbox Code Playgroud)

    您可能会注意到这对常规功能不起作用.您可以将其包装在可调用对象中,或使用BOOST_PHOENIX_ADAPT_FUNCTION宏为您执行此操作

  3. 如果您想要更频繁地应用更多涉及的转换,请考虑使用Spirit Customization Points:

    这些工作的大部分顺利,如果你选择特定类型的属性(例如Ast::MultiplicityAst::VelocityRanking代替intdouble


[1]使用BOOST_SPIRIT_USE_PHOENIX_V3