解析一个“."链接的标识符列表,带有qi :: lexeme并防止空间跳过 [英] Parse a '.' chained identifier list, with qi::lexeme and prevent space skipping

查看:43
本文介绍了解析一个“."链接的标识符列表,带有qi :: lexeme并防止空间跳过的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

im目前正在开发基于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" 

成员访问,数组订阅,函数调用和表达式的混合使用

  []->订阅()->函数调用或表达式括号.成员链接 

当前我正在与成员链接跳过的空间作斗争

 "a.b.c" 

在我的世界中无效-但是由于空间跳过功能而被解析

在线尝试我的简化样本: https://wandbox.org/permlink/o5kcYtUQEfKZqJgw

问题在第23行:

  qi :: rule< std :: string :: iterator,qi :: blank_type,utree()>标识符链=标识符>>*('.'>>标识符); 

我不能在规则周围使用qi :: lexeme,我会得到一个无法转换为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 |'_'))]]; 

但是这似乎非常多余,我认为在解析器增长时,复制将使我将来陷入困境

关于如何使用lexeme或其他方式保持我的."的任何想法.连接无空格从而使订阅结束和成员链接紧密相连

 ].a. 

那是我的解析器中唯一不希望空间跳过的地方,剩下的地方可以减少解析器代码的完美表现

thx以获取任何帮助/提示

解决方案

这是船长的工作方式(请参见在Coliru上直播

  #include< iostream>#include< iomanip>#include< string>#include< boost/spirit/include/qi.hpp>#include< boost/spirit/include/support_utree.hpp>命名空间qi = boost :: spirit :: qi;使用boost :: spirit :: utree;int main(){自动测试= std :: vector< std :: string> {一个OK"a.b",//好的"a.b",//好的"a.b",//错误"a.b.c"//错误};for(std :: string const str:tests){自动迭代= str.begin(),end = str.end();qi :: rule< std :: string :: const_iterator,utree()>标识符= qi :: ascii :: alpha>>*(qi :: ascii :: alnum |'_'),identifier_chain =标识符>>*('.'>>标识符);utree ut;bool r = qi :: phrase_parse(iter,end,identifier_chain>> qi :: eoi,qi :: blank,ut);std :: cout<<std :: quoted(str)<<";如果(r){std :: cout<<确定:"<<ut<<"\ n";} 别的 {std :: cout<<失败\ n";}如果(iter!= end){std :: cout<<未解析的内容:"<<std :: quoted(std :: string(iter,end))<<"\ n";}std :: cout<<"---- \ n";}返回0;} 

打印:

 "a" OK:("a")-"a.b" OK:("a""b")-"a.b" OK:("a""b")-"a.b"失败剩余的未分析内容:"a.b"-"a.b.c"失败剩余的未分析内容:"a.b.c"- 

im currently working on a Spirit based Expression Parser that should allow in the end (far far in the future) expressions like

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

wild mix of member accesses, array subscriptions, function calling and expressions

[] -> subscription
() -> function call or expression bracket
. member chaining

currently im fighting with the space skipping on member-chaining

"a  . b  . c"

is not valid in my world - but gets parsed due to space skipping feature

try online my reduced sample: https://wandbox.org/permlink/o5kcYtUQEfKZqJgw

Problem is line 23:

qi::rule<std::string::iterator, qi::blank_type, utree()> identifier_chain 
    = identifier >> *('.' >> identifier);

i can't use an qi::lexeme around the rule, i'll get an not castable to Skipper compile error but it works if i copy my complete identifier rule into the identifier_chain rule

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 | '_'))];

but that seems very redundant and i think that copying will get me into trouble in the future when the parser is growing

any idea how to use the lexeme or something else to keep my '.' connects free of whitespaces so that subscription ends and member-chaining are strongly connected

].a
a.b

that is the only place in my parser where space skipping is not wanted for the rest its perfect to reduce the parser code

thx for any help/hints

解决方案

This is how the skippers work (see Boost spirit skipper issues)

Your rule declares the skipper:

qi::rule<std::string::iterator, qi::blank_type, utree()> identifier_chain;

So to inhibit it you could surround with a lexeme, but you might just as well just drop the skipper from the declaration. The same actually goes for the the identifier rule, since it is also completely wrapped in lexeme[].

Suggested minimal fix:

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;
}

Prints:

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

这篇关于解析一个“."链接的标识符列表,带有qi :: lexeme并防止空间跳过的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆