我如何找到 Spirit 解析器匹配的位置?

how do i find the location where a Spirit parser matched?

我正在解析一个由名称-值对组成的简单配置文件格式:

an_int_option 42;
a_string_option "foo";
an_identifier_option somevalue;

我有一个基本规则来解析每个项目:

  typedef boost::variant<int, double, std::string> config_value;
  struct config_item {
    std::string name;
    config_value value;
  };

  qi::rule<Iterator, config_value(), ascii::space_type> value;
  qi::rule<Iterator, config_item(), ascii::space_type> item;

  value = 
      identifier 
    | qstring
    | my_double 
    | qi::int_
    ;
  item = 
       identifier[at_c<0>(_val) = _1]
    >> value[at_c<1>(_val) = _1]
    >> ';'
    ;

这很好用,并为我提供了每个项目的 config_value。

现在我想将找到每个值的位置存储在输入文件中,这样如果用户配置了一个无效的选项,我可以报告发生错误的文件行和列号。

到目前为止我找到的最佳选择是 raw[],它可以让我做类似的事情:

  item = 
       raw[ identifier ] [do_something_with_iterators(_1)]
    >> raw[ value ]      [do_something_with_iterators(_1)]
    >> ';'
    ;

...但是由于 raw[] 丢弃了该属性,我的 do_something_with_iterators 现在必须像旧式 Spirit 一样手动解析该值 - 当我已经这样做时,这似乎是很多不必要的工作解析值就在那里。

您可以使用 qi::raw[] 获取跨越匹配项的源迭代器对。

Qi Repository 中有一个方便的助手 iter_pos,您可以使用它直接获取源迭代器而无需使用 qi::raw[]

此外,通过一些语义动作技巧,您可以同时获得:

raw[ identifier [ do_something_with_attribute(_1) ] ]
   [do_something_with_iterators(_1)]

事实上,

raw[ identifier [ _val = _1 ] ] [do_something_with_iterators(_1)]

将接近“自然行为”。

加倍努力

要获取文件 name/line/column 值,您可以执行一些迭代器算法或使用 line_pos_iterator 适配器:

#include <boost/spirit/include/support_line_pos_iterator.hpp>

这有一些访问函数可以帮助行 number/column 跟踪。您可能可以在这里找到我的一些答案和示例。