如何结合跳过和不跳过(lexeme)规则?

时间:2020-03-25 09:12:32

标签: c++ boost-spirit boost-spirit-qi

我的解析器快要工作了:) (仍然让Spirit功能集(和编译时)以及非常欢迎的社区在堆栈溢出时感到惊讶)

在线尝试的小样本: http://coliru.stacked-crooked.com/a/1c1bf88909dce7e3

所以我学会了使用更多的lexeme-rules并尝试防止no_skip- 我的规则较小,因此更易于阅读,但现在我坚持使用 将lexeme-rules和skipping-rules结合起来似乎是不可能的(编译时出现错误,并警告说无法将其投射到Skipper)

我的问题是订阅中用逗号分隔的列表 不会跳过表达式周围的空格

解析:

"a.b[a,b]"

失败:

"a.b[ a , b ]"

这些是我的规则:

qi::rule<std::string::const_iterator, std::string()> identifier_chain;

qi::rule<std::string::const_iterator, std::string()>
    expression_list = identifier_chain >> *(qi::char_(',') >> identifier_chain);

qi::rule < std::string::const_iterator, std::string() >
    subscription = qi::char_('[') >> expression_list >> qi::char_(']');

qi::rule<std::string::const_iterator, std::string()>
    identifier = qi::ascii::alpha >> *(qi::ascii::alnum | '_');

identifier_chain = identifier >> *(('.' >> identifier) | subscription);

如您所见,所有规则都是“ lexeme”,我认为订阅规则应为ascii :: space_type跳过程序,但不能编译

我应该在expression_list的identifier_chains的前面和后面添加空格符吗?

感觉就像写一个正则表达式:(

expression_list = *qi::blank >> identifier_chain >> *(*qi::blank >> qi::char_(',') >> *qi::blank >> identifier_chain >> *qi::blank);

它可以工作,但是我已经读到,这最终将使我进入一个更大的解析器(处理所有由我自己跳过的空间)

任何建议

btw:任何想法,如果用'.'包围indentifier_chain中的qi::char_('.'),为什么我不能编译

identifier_chain = identifier >> *(('.' >> identifier) | subscription);

更新

我已经按照sehe的建议更新了我的表情列表

qi::rule<std::string::const_iterator, spirit::ascii::blank_type, std::string()>
expression_list = identifier_chain >> *(qi::char_(',') >> identifier_chain);

qi::rule < std::string::const_iterator, std::string() >
subscription = qi::char_('[') >> qi::skip(qi::blank)[expression_list] >> qi::char_(']');

但由于不可转换的船长,仍会出现编译错误:http://coliru.stacked-crooked.com/a/adcf665742b055dd

我还尝试将identifer_chain更改为

identifier_chain = identifier >> *(('.' >> identifier) | qi::skip(qi::blank)[subscription]);

但我仍然无法编译示例

1 个答案:

答案 0 :(得分:1)

我先前链接的答案描述了所有组合(如果我没记错的话):Boost spirit skipper issues

简而言之:

  • 任何声明了船长的规则(因此rule<It, Skipper[, Attr()]>rule<It, Attr(), Skipper>)都必须使用兼容的船长(可以分配为Skipper类型的表达式)调用

  • 任何不声明船长的规则(格式为rule<It[, Attr()]>)将隐式表现为 lexeme ,这意味着不会跳过任何输入字符。

就是这样。较微妙的结果是给出了两个规则:

rule<It, blank_type> a;
rule<It> b; // b is implicitly lexeme

可以b调用a

a = "test" >> b;

但是,当您希望从a调用b时,您会发现必须提供船长:

b = "oops" >> a; // DOES NOT COMPILE
b = "okay" >> qi::skip(qi::blank) [ a ];

这几乎就是所有内容。关于Qi中的船长和词素,还有其他一些指令,请再次参见上面链接的答案。

侧面问题:

我应该在expression_list的identifier_chains的前面和后面添加空格符吗?

如果您仔细查看Parse a '.' chained identifier list, with qi::lexeme and prevent space skipping的答案示例,您会发现它已经 已经正确地进行了跳过,因为我使用了phrase_parse

" a.b " OK: ( "a" "b" ) 
----
"a . b" Failed
Remaining unparsed: "a . b"
----

您也可以将整个内容包装在“外部”规则中:

rule<std::string::const_iterator> main_rule = 
     qi::skip(qi::blank) [ identifier_chain ];

这是相同的,但是允许用户调用parse而不指定船长。