i'm parsing a simple configuration file format consisting of name-value pairs:
an_int_option 42;
a_string_option "foo";
an_identifier_option somevalue;
i have a basic rule to parse each item:
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]
>> ';'
;
this works fine and gives me the config_value for each item.
now i want to store the location in the input file where each value was found, so that if the user configures an invalid option, i can report the file line and column number where the error happened.
the best option i've found so far is raw[]
, which would let me do something like:
item =
raw[ identifier ] [do_something_with_iterators(_1)]
>> raw[ value ] [do_something_with_iterators(_1)]
>> ';'
;
... but since raw[]
discards the attribute, my do_something_with_iterators
now has to manually parse the value like in old-style Spirit - which seems like a lot of unnecessary work when i already have the parsed value right there.
You can use qi::raw[]
to get the source iterator pair spanning a match.
There's a convenient helper iter_pos
in Qi Repository that you can use to directly get a source iterator without using qi::raw[]
.
Also, with some semantic action trickery you can get both:
raw[ identifier [ do_something_with_attribute(_1) ] ]
[do_something_with_iterators(_1)]
In fact,
raw[ identifier [ _val = _1 ] ] [do_something_with_iterators(_1)]
would be close to "natural behaviour".
To get file name/line/column values you can either do some iterator arithmetics or use the line_pos_iterator
adaptor:
#include <boost/spirit/include/support_line_pos_iterator.hpp>
This has some accessor functions that help with line number/column tracking. You can probably find a few answers of mine on here with examples.