如何使用语义动作(boost :: spirit)中的查找将已解析的字符串更改为int?

时间:2012-05-21 00:43:39

标签: c++ boost boost-spirit

boost::spirit中,如何阅读string,立即在数据库中查找其int值并boost::spirit将值分配给int }}?因此规则的属性将是int,即使它被解析为字符串。

例如,此输入

myCoolKey 3.4

可以解析为(int,double)对:(87,3.4),其中字符串“myCoolKey”通过(Berkeley)数据库查找映射到87

我想要这样的代码:

typedef std::pair<int, double> Entry;
qi::rule<Iterator, Entry(), Skipper> entry;
entry %= +qi::char_[qi::_val = mylookup(qi::_1)]
         >> qi::double_;

这是一个完整的代码示例。如何调用查找已解析字符串的函数,并使boost::spirit将查找的值分配给int

#include <iostream>
#include <boost/foreach.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/fusion/include/std_pair.hpp>
namespace qi = boost::spirit::qi;

typedef std::pair<int, double> Entry;

struct Lookup {
  MyDB db;
  int lookup(std::string const& str) {
    return db.lookup(str);
  }
};

template <typename Iterator, typename Skipper>
struct MyGrammar : qi::grammar<Iterator, std::vector<Entry>(), Skipper> {
  MyGrammar() : MyGrammar::base_type(entries) {
    entry %= +qi::char_[qi::_val = myLookup.lookup(qi::_1)]
        >> qi::double_;
    entries = +entry;
  }
  Lookup myLookup;
  qi::rule<Iterator, Entry(), Skipper> entry;
  qi::rule<Iterator, std::vector<Entry>(), Skipper> entries;
};

int main() {
  typedef boost::spirit::istream_iterator It;
  std::cin.unsetf(std::ios::skipws);
  It it(std::cin), end;

  MyGrammar<It, qi::space_type> entry_grammar;
  std::vector<Entry> entries;
  if (qi::phrase_parse(it, end, entry_grammar, qi::space, entries)
      && it == end) {
    BOOST_FOREACH(Entry const& entry, entries) {
      std::cout << entry.first << " and " << entry.second << std::endl;
    }
  }
  else {
    std::cerr << "FAIL" << std::endl;
    exit(1);
  }
  return 0;
}

1 个答案:

答案 0 :(得分:1)

最快的方法是使用phoenix bind

qi::_val = phx::bind(&Lookup::lookup, myLookup, qi::_1)

使用融合函数或'Polymorphic Calleable Objects'有更优雅的解决方案,但我现在参考文档:

编辑我发现你的其余代码无法编译(因为其他原因)。这是一个编译示例(带有存根查找功能):

#include <boost/spirit/include/phoenix.hpp>
namespace phx = boost::phoenix;
//  ...

template <typename Iterator, typename Skipper>
struct MyGrammar : qi::grammar<Iterator, std::vector<Entry>(), Skipper>
{
    MyGrammar() : MyGrammar::base_type(entries)
    {
        using namespace qi;
        intpart = as_string [+char_] 
                 [ _val = phx::bind(&Lookup::lookup, myLookup, _1) ];
        entry = intpart >> double_;
        entries = +entry;
    }
  private:
    Lookup myLookup;
    qi::rule<Iterator, int(), Skipper> intpart;
    qi::rule<Iterator, Entry(), Skipper> entry;
    qi::rule<Iterator, std::vector<Entry>(), Skipper> entries;
};

您可以通过intpartqi::as<>魔法来解决qi::attr_cast<>的额外规则,但坦率地说,这种方式更具可读性。