解析一个 '.'链式标识符列表,带有 qi::lexeme 并防止 space 跳过
Parse a '.' chained identifier list, with qi::lexeme and prevent space skipping
我目前正在开发一个基于 Spirit 的表达式解析器,它应该允许最终(在很远的将来)像
这样的表达式
"a*b*c"
"10+20*x.y.z"
"a.b.c[ a.b ][ e.c( d.e()*4 )].e.f( (a.b+23)*d, -23*b.e(a.b.c) ).x.y"
成员访问、数组订阅、函数调用和表达式的混合
[] -> subscription
() -> function call or expression bracket
. member chaining
目前我正在与 space 跳过成员链接
作斗争
"a . b . c"
在我的世界中无效 - 但由于 space 跳过功能
而被解析
在线试用我的缩减样本:https://wandbox.org/permlink/o5kcYtUQEfKZqJgw
问题是第 23 行:
qi::rule<std::string::iterator, qi::blank_type, utree()> identifier_chain
= identifier >> *('.' >> identifier);
我不能在规则周围使用 qi::lexeme,我会得到一个 not castable to Skipper 编译错误
但如果我将完整的标识符规则复制到 identifier_chain 规则
中,它就会起作用
qi::rule<std::string::iterator, qi::blank_type, utree()> identifer_chain
= qi::lexeme[qi::ascii::alpha >> *(qi::ascii::alnum | '_')
>> *('.' >> qi::ascii::alpha >> *(qi::ascii::alnum | '_'))];
但这似乎非常多余,而且我认为在解析器增长时复制会在未来给我带来麻烦
知道如何使用词素或其他东西来保留我的“.”吗?连接无白色spaces
这样订阅结束和成员链就紧密相连了
].a
a.b
这是我的解析器中唯一不需要 space 跳过的地方,其余的它完美地减少了解析器代码
thx 对于任何 help/hints
这就是船长的工作方式(参见Boost spirit skipper issues)
您的规则声明船长:
qi::rule<std::string::iterator, qi::blank_type, utree()> identifier_chain;
因此,要禁止它,您可以用词素包围它,但您也可以将船长从声明中删除。标识符规则实际上也是如此,因为它也完全包含在 lexeme[]
.
中
建议的最小修复:
#include <iostream>
#include <iomanip>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_utree.hpp>
namespace qi = boost::spirit::qi;
using boost::spirit::utree;
int main() {
auto tests = std::vector<std::string>{
"a", // ok
"a.b", // ok
" a.b ", // ok
"a . b", // error
"a . b. c" // error
};
for (std::string const str : tests) {
auto iter = str.begin(), end = str.end();
qi::rule<std::string::const_iterator, utree()>
identifier = qi::ascii::alpha >> *(qi::ascii::alnum | '_'),
identifier_chain = identifier >> *('.' >> identifier);
utree ut;
bool r = qi::phrase_parse(iter, end, identifier_chain >> qi::eoi, qi::blank, ut);
std::cout << std::quoted(str) << " ";
if (r) {
std::cout << "OK: " << ut << "\n";
} else {
std::cout << "Failed\n";
}
if (iter!=end) {
std::cout << "Remaining unparsed: " << std::quoted(std::string(iter,end)) << "\n";
}
std::cout << "----\n";
}
return 0;
}
打印:
"a" OK: ( "a" )
----
"a.b" OK: ( "a" "b" )
----
" a.b " OK: ( "a" "b" )
----
"a . b" Failed
Remaining unparsed: "a . b"
----
"a . b. c" Failed
Remaining unparsed: "a . b. c"
----
我目前正在开发一个基于 Spirit 的表达式解析器,它应该允许最终(在很远的将来)像
这样的表达式"a*b*c"
"10+20*x.y.z"
"a.b.c[ a.b ][ e.c( d.e()*4 )].e.f( (a.b+23)*d, -23*b.e(a.b.c) ).x.y"
成员访问、数组订阅、函数调用和表达式的混合
[] -> subscription
() -> function call or expression bracket
. member chaining
目前我正在与 space 跳过成员链接
作斗争"a . b . c"
在我的世界中无效 - 但由于 space 跳过功能
而被解析在线试用我的缩减样本:https://wandbox.org/permlink/o5kcYtUQEfKZqJgw
问题是第 23 行:
qi::rule<std::string::iterator, qi::blank_type, utree()> identifier_chain
= identifier >> *('.' >> identifier);
我不能在规则周围使用 qi::lexeme,我会得到一个 not castable to Skipper 编译错误 但如果我将完整的标识符规则复制到 identifier_chain 规则
中,它就会起作用qi::rule<std::string::iterator, qi::blank_type, utree()> identifer_chain
= qi::lexeme[qi::ascii::alpha >> *(qi::ascii::alnum | '_')
>> *('.' >> qi::ascii::alpha >> *(qi::ascii::alnum | '_'))];
但这似乎非常多余,而且我认为在解析器增长时复制会在未来给我带来麻烦
知道如何使用词素或其他东西来保留我的“.”吗?连接无白色spaces 这样订阅结束和成员链就紧密相连了
].a
a.b
这是我的解析器中唯一不需要 space 跳过的地方,其余的它完美地减少了解析器代码
thx 对于任何 help/hints
这就是船长的工作方式(参见Boost spirit skipper issues)
您的规则声明船长:
qi::rule<std::string::iterator, qi::blank_type, utree()> identifier_chain;
因此,要禁止它,您可以用词素包围它,但您也可以将船长从声明中删除。标识符规则实际上也是如此,因为它也完全包含在 lexeme[]
.
建议的最小修复:
#include <iostream>
#include <iomanip>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_utree.hpp>
namespace qi = boost::spirit::qi;
using boost::spirit::utree;
int main() {
auto tests = std::vector<std::string>{
"a", // ok
"a.b", // ok
" a.b ", // ok
"a . b", // error
"a . b. c" // error
};
for (std::string const str : tests) {
auto iter = str.begin(), end = str.end();
qi::rule<std::string::const_iterator, utree()>
identifier = qi::ascii::alpha >> *(qi::ascii::alnum | '_'),
identifier_chain = identifier >> *('.' >> identifier);
utree ut;
bool r = qi::phrase_parse(iter, end, identifier_chain >> qi::eoi, qi::blank, ut);
std::cout << std::quoted(str) << " ";
if (r) {
std::cout << "OK: " << ut << "\n";
} else {
std::cout << "Failed\n";
}
if (iter!=end) {
std::cout << "Remaining unparsed: " << std::quoted(std::string(iter,end)) << "\n";
}
std::cout << "----\n";
}
return 0;
}
打印:
"a" OK: ( "a" )
----
"a.b" OK: ( "a" "b" )
----
" a.b " OK: ( "a" "b" )
----
"a . b" Failed
Remaining unparsed: "a . b"
----
"a . b. c" Failed
Remaining unparsed: "a . b. c"
----