【问题标题】:Problems with boost::phoenix::bind and boost::phoenix::actors in a semantic action for boost::spirit::qiboost::phoenix::bind 和 boost::phoenix::actors 在 boost::spirit::qi 的语义动作中的问题
【发布时间】:2014-08-25 21:06:20
【问题描述】:

我认为我在理解我的 boost::spirit::qi 解析器应该如何编写时遇到了问题。我只是想通过语义操作将匹配的子字符串传递给函数。为了大致模仿this boost tutorial,我想出了以下代码:

template<class Iterator> 
struct _Calculator : public qi::grammar<Iterator> {                                                                                               

    qi::rule<Iterator> number, result; //and a whole bunch of other ones too                                                            

    qi::rule<Iterator,std::string()> variable;                                                                                      

    Code& code;                                                                                                    
    Variables& variables;                                                                                                          

    _Calculator(Code& code_, Variables& variables_)
      : _Calculator::base_type(result),                                                                                                           
        code(code_),
        variables(variables_)                                                                                                                     
   {  
          number =
                lexeme[(qi::char_("1-9") >> +qi::char_("0-9"))[boost::phoenix::bind(&fPushIntCV, qi::_1, boost::ref(code), boost::ref(variables))]]
              | lexeme[("0x" >> +qi::char_("0-9a-fA-F"))      [boost::phoenix::bind(&fPushIntCV, qi::_1, boost::ref(code), boost::ref(variables))]]
              | lexeme[("0b" >> +qi::char_("0-1"))            [boost::phoenix::bind(&fPushIntCV, qi::_1, boost::ref(code), boost::ref(variables))]]
              | lexeme[("0" >>  +qi::char_("0-7"))            [boost::phoenix::bind(&fPushIntCV, qi::_1, boost::ref(code), boost::ref(variables))]]
          //some other junk
    }
};
typedef _Calculator<std::string::const_iterator> Calculator;

fPushIntCV 的声明如下:

void fPushIntCV (vector<char> my_str, Code& c, Variables& v);

我收到此错误:

function_ptr.hpp:89: error: conversion from 'char' to non-scalar type 'std::vector&lt;char, std::allocator&lt;char&gt; &gt;' requested

当我将fPushIntCV 的声明更改为如下所示:

void fPushIntCV (char my_str, Code& c, Variables& v);

我收到此错误:

function_ptr.hpp:89: error: cannot convert 'std::vector&lt;char, std::allocator&lt;char&gt; &gt;' to 'char' in argument passing

我认为qi::_1 的属性正在发生变化,但是如果我同时包含两个函数原型并且现在传递boost::phoenix::bind 一些模棱两可的重载函数指针,我会得到未解析的引用:

error: no matching function for call to 'bind(&lt;unresolved overloaded function type&gt;, const boost::spirit::_1_type&amp;, ...(我的 ... 用于尾随无关垃圾)

我知道这可能是一个非常简单的错误和一个非常简单的修复,但我有一个很好的时间来理解这个咒语,让增强魔法发挥作用。这个语义动作所期望的函数原型是什么?

【问题讨论】:

    标签: c++ boost boost-spirit boost-phoenix


    【解决方案1】:

    一些观察:

    • 您似乎没有使用船长,因此使用lexeme 是多余的(请参阅Boost spirit skipper issues

    • 你想知道如何检测解析器表达式暴露的属性类型:见Detecting the parameter types in a Spirit semantic action

      不过,类型是用解析器指令记录的,例如as_string[(qi::char_("1-9") &gt;&gt; +qi::char_("0-9"))]导致boost::fusion::vector2&lt;char, std::vector&lt;char&gt; &gt;,直接反映在GCC上的错误信息中:

      boost/phoenix/bind/detail/preprocessed/function_ptr_10.hpp|50 col 39| error: could not convert ‘a0’ from ‘boost::fusion::vector2<char, std::vector<char> >’ to ‘std::vector<char>’
      
    • 不希望混合和匹配库占位符/包装器,例如boost::refboost::phoenix::ref

    • 您似乎在重新发明整数解析;考虑改用qi::int_parser

    • 似乎缺少解析0的情况:)

    假设您希望 my_str 简单地反映包含数字基前缀的输入字符串,我可以建议使用:

    number =
         as_string[(qi::char_("1-9") >> +qi::char_("0-9"))] [phx::bind(&fPushIntCV, qi::_1, phx::ref(code), phx::ref(variables))]
       | as_string[("0x" >> +qi::char_("0-9a-fA-F"))      ] [phx::bind(&fPushIntCV, qi::_1, phx::ref(code), phx::ref(variables))]
       | as_string[("0b" >> +qi::char_("0-1"))            ] [phx::bind(&fPushIntCV, qi::_1, phx::ref(code), phx::ref(variables))]
       | as_string[("0" >>  +qi::char_("0-7"))            ] [phx::bind(&fPushIntCV, qi::_1, phx::ref(code), phx::ref(variables))]
       //some other junk
       ;
    

    但是,这可以简化为:

    number = as_string[
           (qi::char_("1-9") >> +qi::char_("0-9"))
         | ("0x" >> +qi::char_("0-9a-fA-F"))
         | ("0b" >> +qi::char_("01"))
         | ("0"  >> +qi::char_("0-7"))
       ]        [phx::bind(&fPushIntCV, qi::_1, phx::ref(code), phx::ref(variables))]
       ;
    

    现在,您可能只想解析一个整数值:

    number = 
         ( 
           ("0x" >> qi::int_parser<int, 16, 1>())
         | ("0b" >> qi::int_parser<int,  2, 1>())
         | ("0"  >> qi::int_parser<int,  8, 1>())
         | qi::int_ /* accepts "0" */) [phx::bind(&fPushIntCV, qi::_1, phx::ref(code), phx::ref(variables))]
       ;
    

    转化效果非常好[1],您只需发送int

    void fPushIntCV (int my_number, Code& c, Variables& v) {
        std::cout << "fPushIntCV: " << my_number << "\n";
    }
    

    [1](还有uint_parser,你可以解析longlong long等;甚至像boost::multiprecision::cpp_int这样的大整数应该没问题)

    这是一个使用它的演示程序,显示值被正确转换(并且:“0”被接受:)):Live On Coliru

    int main()
    {
        Code code;
        Variables variables;
        Calculator g(code, variables); 
    
        for (std::string const input : { "0", "0xef1A", "010", "0b10101" })
        {
            It f(input.begin()), l(input.end());
    
            if(qi::parse(f, l, g))
                std::cout << "Parse success ('" << input << "')\n";
            else std::cout << "Parse failed ('" << input << "')\n";
    
            if (f != l)
                std::cout << "Input remaining: '" << std::string(f, l) << "'\n";
        }
    }
    

    打印

    fPushIntCV: 0
    Parse success ('0')
    
    fPushIntCV: 61210
    Parse success ('0xef1A')
    
    fPushIntCV: 8
    Parse success ('010')
    
    fPushIntCV: 21
    Parse success ('0b10101')
    

    【讨论】:

    • 据我了解,复制字符串可能会对性能造成显着影响。有没有办法传递我的函数string::iterator 而不是完整的string
    • 请注意,在我的最终产品中,我根本不传递字符串。否则,您可以使用 qi::raw[] 来传递迭代器。我过去曾将其与 boost::string_ref 一起使用:a mustache parsera CSV parser
    • 我正在升级一些旧的boost::spirit::classic 代码,遗憾的是char* start, char *end 预期的相当复杂的动作功能。我正在改进系统以使用boost::spirit::qi 来轻松提升性能和更简洁、更现代的代码,但是我还没有深入了解细节,还没有执行完全取消字符串的优化(尽管它肯定在待办事项列表)。目前,我只是想尽可能地提高字符串性能。
    • 好的。似乎 qi::raw 是要走的路,以获得快速的结果
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多