代码之家  ›  专栏  ›  技术社区  ›  pschulz

使用至少一个空格来增强spirit skip解析器

  •  1
  • pschulz  · 技术社区  · 6 年前

    在我要实现的语法中,有一些元素被空格隔开。使用skip解析器,元素之间的空格将自动跳过,但这也允许 空间,这不是我想要的。当然,我可以显式地编写包含这些空格的语法,但在我看来(凭借spirit提供的复杂性和灵活性),有更好的方法可以做到这一点。有?

    #include <cstdlib>
    #include <iostream>
    #include <string>
    
    #include <boost/spirit/include/qi.hpp>    
    
    namespace qi = boost::spirit::qi;
    
    int main(int argc, char** argv)
    {
        if(argc != 2)
        {
            std::exit(1);
        }
        std::string str = argv[1];
        auto iter = str.begin();
        bool r = qi::phrase_parse(iter, str.end(), qi::char_ >> qi::char_, qi::blank);
    
        if (r && iter == str.end())
        {
            std::cout << "parse succeeded\n";
        }
        else
        {
            std::cout << "parse failed. Remaining unparsed: " << std::string(iter, str.end()) << '\n';
        }
    }
    

    这允许 ab 以及 a b . 我只希望后者被允许。

    one   = char_("X") >> repeat(2)[omit[+blank] >> +alnum] >> qi::omit[+qi::blank] >> +alnum;
    two   = char_("Y") >> repeat(3)[omit[+blank] >> +alnum];
    three = char_("Z") >> repeat(4)[omit[+blank] >> +alnum] >> qi::omit[+qi::blank] >> +alnum;
    
    main = one | two | three;
    

    这使得语法很混乱,我想避免。

    1 回复  |  直到 6 年前
        1
  •  2
  •   sehe    6 年前

    首先,我通常在RFCs中看到的语法规范是(总是?)RFCs。在99%的情况下没有问题,例如:

     myrule = skip(space) [ uint_ >> uint_ ];
    

    Boost.Spirit qi value sequence vector ).


    这样一来,根据定义,skipper应用了零次或多次,因此没有一种方法可以通过现有的有状态指令(如 skip() http://stackoverflow.com/questions/17072987/boost-spirit-skipper-issues/17073965#17073965 或者 docs -低于 lexeme [no_]skip skip_flag::dont_postskip ).


    看看你具体的语法,我会这么做:

    bool r = qi::phrase_parse(iter, end, token >> token, qi::blank);
    

    在这里,您可以在lexeme中添加一个否定的lookahead断言,以断言“到达了令牌的末尾”——在解析器中,这将被强制为 !qi::graph

        auto token = qi::copy(qi::lexeme [ qi::char_ >> !qi::graph ]);
    

    查看演示:

    Live On Coliru

    #include <iostream>
    #include <iomanip>
    #include <boost/spirit/include/qi.hpp>
    
    namespace qi = boost::spirit::qi;
    
    int main() {
        for (std::string const str : { "ab", " ab ", " a b ", "a b" }) {
            auto iter = str.begin(), end = str.end();
    
            auto token = qi::copy(qi::lexeme [ qi::char_ >> !qi::graph ]);
    
            bool r = qi::phrase_parse(iter, end, token >> token, qi::blank);
    
            std::cout << " --- " << std::quoted(str) << " --- ";
            if (r) {
                std::cout << "parse succeeded.";
            } else {
                std::cout << "parse failed.";
            }
    
            if (iter != end) {
                std::cout << " Remaining unparsed: " << std::string(iter, str.end());
            }
    
            std::cout << std::endl;
        }
    }
    

    印刷品

     --- "ab" --- parse failed. Remaining unparsed: ab
     --- " ab " --- parse failed. Remaining unparsed:  ab 
     --- " a b " --- parse succeeded.
     --- "a b" --- parse succeeded.
    

    奖金审查说明

    1. 你的船长应该是语法的责任。令人难过的是,所有的Qi样本都让人们相信你需要让打电话的人来决定
    2. 结束迭代器检查 相等错误检查。很有可能 parse things correctly without consuming all input . 这就是为什么在解析失败的情况下不应该只报告“剩余输入”的原因。
    3. 如果尾随未分析的输入 spell it out :

    Live On Coliru

    #include <iostream>
    #include <iomanip>
    #include <boost/spirit/include/qi.hpp>
    
    namespace qi = boost::spirit::qi;
    
    int main() {
        for (std::string const str : { "ab", " ab ", " a b ", "a b happy trees are trailing" }) {
            auto iter = str.begin(), end = str.end();
    
            auto token = qi::copy(qi::lexeme [ qi::char_ >> !qi::graph ]);
    
            bool r = qi::parse(iter, end, qi::skip(qi::space) [ token >> token >> qi::eoi ]);
    
            std::cout << " --- " << std::quoted(str) << " --- ";
            if (r) {
                std::cout << "parse succeeded.";
            } else {
                std::cout << "parse failed.";
            }
    
            if (iter != end) {
                std::cout << " Remaining unparsed: " << std::quoted(std::string(iter, str.end()));
            }
    
            std::cout << std::endl;
        }
    }
    

    印刷品

     --- "ab" --- parse failed. Remaining unparsed: "ab"
     --- " ab " --- parse failed. Remaining unparsed: " ab "
     --- " a b " --- parse succeeded.
     --- "a b happy trees are trailing" --- parse failed. Remaining unparsed: "a b happy trees are trailing"