Reputation: 1042
I'm trying to parse multiline content that include the following pattern: {{some_dynamic_string}}
I tried defining the rule as follows, but the parse fails:
token_rule = qi::lit("{{") >> +qi::char_ >> qi::lit("}}");
The debug output for parsing shows the following:
<start_rule>
<try>{{foo|bar}}\n</try>
<token_rule>
<try>{{foo|bar}}\n</try>
<fail/>
</token_rule>
<fail/>
</start_rule>
It is trying to parse the first line in the multiline content, which happens to include the pattern by itself. What is wrong with the rule? Do I need to exclude {{
and }}
from the second item in the sequence? If so, how do I do that?
Upvotes: 2
Views: 100
Reputation: 393114
You have to prevent char_
from matching where }}
would match.
The simplest way:
token_rule = "{{" >> +(qi::char_ - "}}") >> "}}";
Full demo with debug info for comparison:
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
using string = std::string;
using strings = std::vector<std::string>;
template <typename It>
struct Grammar: qi::grammar<It, strings()>
{
Grammar() : Grammar::base_type(start) {
start = qi::skip(qi::space) [tokens_rule];
tokens_rule = *token_rule;
token_rule = "{{" >> +(qi::char_ - "}}") >> "}}";
BOOST_SPIRIT_DEBUG_NODES((start)(tokens_rule)(token_rule))
}
private:
// implicit lexemes
qi::rule<It, strings()> start;
qi::rule<It, strings(), qi::space_type> tokens_rule;
qi::rule<It, string()> token_rule;
};
int main() {
using It = std::string::const_iterator;
Grammar<It> g;
for (std::string const input : { "{{a}}", " {{a b}} {{more}}\n", "{{a{b} }}" })
{
It f = input.begin(), l = input.end();
strings parsed;
if (parse(f, l, g, parsed)) {
std::cout << "Parsed '" << input << "'\n";
for(auto& tok : parsed)
std::cout << " -- '" << tok << "'\n";
} else {
std::cout << "Parse failed\n";
}
if (f != l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
}
Printing
Parsed '{{a}}'
-- 'a'
Parsed ' {{a b}} {{more}}
'
-- 'a b'
-- 'more'
Parsed '{{a{b} }}'
-- 'a{b} '
With debug info:
<start>
<try>{{a}}</try>
<tokens_rule>
<try>{{a}}</try>
<token_rule>
<try>{{a}}</try>
<success></success>
<attributes>[[a]]</attributes>
</token_rule>
<token_rule>
<try></try>
<fail/>
</token_rule>
<success></success>
<attributes>[[[a]]]</attributes>
</tokens_rule>
<success></success>
<attributes>[[[a]]]</attributes>
</start>
Parsed '{{a}}'
-- 'a'
<start>
<try> {{a b}} {{more}}\n</try>
<tokens_rule>
<try> {{a b}} {{more}}\n</try>
<token_rule>
<try>{{a b}} {{more}}\n</try>
<success> {{more}}\n</success>
<attributes>[[a, , b]]</attributes>
</token_rule>
<token_rule>
<try>{{more}}\n</try>
<success>\n</success>
<attributes>[[m, o, r, e]]</attributes>
</token_rule>
<token_rule>
<try></try>
<fail/>
</token_rule>
<success></success>
<attributes>[[[a, , b], [m, o, r, e]]]</attributes>
</tokens_rule>
<success></success>
<attributes>[[[a, , b], [m, o, r, e]]]</attributes>
</start>
Parsed ' {{a b}} {{more}}
'
-- 'a b'
-- 'more'
<start>
<try>{{a{b} }}</try>
<tokens_rule>
<try>{{a{b} }}</try>
<token_rule>
<try>{{a{b} }}</try>
<success></success>
<attributes>[[a, {, b, }, ]]</attributes>
</token_rule>
<token_rule>
<try></try>
<fail/>
</token_rule>
<success></success>
<attributes>[[[a, {, b, }, ]]]</attributes>
</tokens_rule>
<success></success>
<attributes>[[[a, {, b, }, ]]]</attributes>
</start>
Parsed '{{a{b} }}'
-- 'a{b} '
Upvotes: 2
Reputation: 1042
I was able to parse the line successfully with the Qi Confix Parser Directive.
#include <boost/spirit/repository/include/qi_confix.hpp>
namespace qi_repo = boost::spirit::repository;
token_rule = qi_repo::confix("{{", "}}")[+(qi::char_ - "}}")];
Upvotes: 1