使用至少一个空格来增强Spirit Skip解析器

时间:2018-11-01 15:01:21

标签: boost boost-spirit

在我实现的语法中,有些元素由空格分隔。使用跳过解析器,将自动跳过元素之间的空格,但这也允许 no 空间,这不是我想要的。当然,我可以明确地编写一个包含这些空格的语法,但是在我看来(凭借精神提供的复杂性和灵活性),有一种更好的方法可以做到这一点。在那儿? 这是一个示例:

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

这允许aba b。我只希望允许后者。

与此相关:跳过解析器如何工作?一个提供了诸如qi :: blank之类的东西,然后将星星应用到跳过分析器中吗?我想在这里得到一些启示,也许这也有助于解决这个问题。

其他信息:我的真实解析器如下所示:

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 个答案:

答案 0 :(得分:2)

首先,我通常在(总是?)RFC中看到这种语法要求。在99%的情况下,没有问题,请考虑例如:

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

这已经隐含地要求数字之间至少有1个空格字符,原因很简单,否则会有1个数字。在令人惊讶的许多情况下,也会发生相同的简化(例如,上周Boost.Spirit qi value sequence vector,请参见此答案中有关无处不在的WSP生产的简化)。


根据定义,跳过程序将应用零次或多次,因此,没有任何方法可以通过现有的有状态指令(例如skip())来获得所需的内容。另请参见{{1},lexeme[no_]skip下的http://stackoverflow.com/questions/17072987/boost-spirit-skipper-issues/17073965#17073965docs-。


看看您的特定语法,我会这样做:

skip_flag::dont_postskip

在这里,您可以在词素中添加否定的超前断言,以断言“已到达令牌的末尾”-在解析器中,其将强制为bool r = qi::phrase_parse(iter, end, token >> token, qi::blank);

!qi::graph

观看演示:

Live On Coliru

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

打印

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

奖励评论笔记

我的准则是:

  1. 您的船长应该是语法的责任。令人遗憾的是,所有Qi样本都导致人们相信您需要让呼叫者决定
  2. 最终迭代器检查等同于错误检查。 parse things correctly without consuming all input很有可能。这就是为什么不应仅在解析失败的情况下报告“剩余输入”的原因。
  3. 如果跟踪未解析的输入 是错误,spell it out

Live On Coliru

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

打印

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