3

通过boost::spirit::qi::symbols 文档的开头段落,我认为从语义操作向 qi::symbols 添加符号不会太难。不幸的是,它似乎并不像我想象的那么简单。

以下测试代码显示了该问题:

#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;

typedef qi::symbols<char, unsigned int> constants_dictionary;

template <typename Iter> struct parser : public qi::grammar<Iter, qi::space_type> {

    parser(constants_dictionary &dict) : parser::base_type(start) {

        start = qi::lit("@") >> ((+qi::char_) >> qi::uint_)[dict.add(qi::_1, qi::_2)];
    }

    qi::rule<Iter> start;
};

int main() {
    constants_dictionary dict;
    parser<std::string::const_iterator> prsr(dict);
    std::string test = "@foo 3";
    parse(test.begin(), test.end(), prsr, qi::space);
}

从 VS2010 给出与 qi::_2 相关的类型错误:

C:\Users\k\Coding\dashCompiler\spirit_test.cpp(12) : error C2664: 'const boost::
spirit::qi::symbols<Char,T>::adder &boost::spirit::qi::symbols<Char,T>::adder::o
perator ()<boost::spirit::_1_type>(const Str &,const T &) const' : cannot conver
t parameter 2 from 'const boost::spirit::_2_type' to 'const unsigned int &'
        with
        [
            Char=char,
            T=unsigned int,
            Str=boost::spirit::_1_type
        ]
        Reason: cannot convert from 'const boost::spirit::_2_type' to 'const uns
igned int'
        No user-defined-conversion operator available that can perform this conv
ersion, or the operator cannot be called
        C:\Users\k\Coding\dashCompiler\spirit_test.cpp(10) : while compiling cla
ss template member function 'parser<Iter>::parser(constants_dictionary &)'
        with
        [
            Iter=std::_String_const_iterator<char,std::char_traits<char>,std::al
locator<char>>
        ]
        C:\Users\k\Coding\dashCompiler\spirit_test.cpp(21) : see reference to cl
ass template instantiation 'parser<Iter>' being compiled
        with
        [
            Iter=std::_String_const_iterator<char,std::char_traits<char>,std::al
locator<char>>
        ]

(为讨厌的 VS2010 错误风格道歉)

我应该使用什么语法从该表中添加(以及稍后删除)符号?

4

1 回答 1

6

这个问题之前已经回答过了。但是,您发布的代码存在相当多的问题,因此我将一一修复它们,以免您不必要地盯着错误消息页面。

工作代码(加上输出验证)在 liveworkspace.org 上

笔记:

  1. 语义动作必须是凤凰演员,即你需要

    • boost::bind, phoenix::bind,std::bind
    • phoenix::lambda<>或者phoenix::function<>
    • 函数指针或多态可调用对象(根据文档)

      我建议phoenix::bind(在这种特殊情况下),我在下面展示

  2. 解析器的船长和开始规则不匹配
  3. qi::char_吃掉所有角色。结合船长,这导致解析失败,因为(显然)值中的数字也被+qi::char_. 我向您展示了许多解决方案之一,基于qi::lexeme[+qi::graph]
  4. 用于qi::lexeme“绕过”船长(即防止 +qi::graph 跨越空白,因为船长跳过了它)
  5. qi::parse不带船长;用于qi::phrase_parse此(它似乎起作用的原因是任何尾随的“可变参数”参数都绑定到解析器的公开属性,在这种情况下未指定,因此qi::unused_type)。
  6. 如果您想直接 传递test.begin()和,则需要明确表示您需要 const 迭代器。更典型的解决方案是引入明确类型的变量(和,例如)test.end()qi::phrase_parsefirstlast


#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 phx = boost::phoenix;

typedef qi::symbols<char, unsigned int> constants_dictionary;

template <typename Iter> struct parser : qi::grammar<Iter, qi::space_type> 
{
    parser(constants_dictionary &dict) : parser::base_type(start) 
    {
        start = qi::lit("@") >> (qi::lexeme [+qi::graph] >> qi::uint_)
            [ phx::bind(dict.add, qi::_1, qi::_2) ]
            ;
    }

    qi::rule<Iter, qi::space_type> start;
};

int main() {
    constants_dictionary dict;
    parser<std::string::const_iterator> prsr(dict);
    const std::string test = "@foo 3";

    if (qi::phrase_parse(test.begin(), test.end(), prsr, qi::space))
    {
        std::cout << "check: " << dict.at("foo") << "\n";
    }
}
于 2012-08-31T10:16:26.627 回答