Parse a '.' chained identifier list, with qi::lexeme and prevent space skipping

丶灬走出姿态 提交于 2021-02-05 08:21:33

问题


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


回答1:


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


来源:https://stackoverflow.com/questions/60819236/parse-a-chained-identifier-list-with-qilexeme-and-prevent-space-skipping

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!