解析一个 '.'链式标识符列表,带有 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[].

建议的最小修复:

Live On Coliru

#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"
----